Merge from 2.5 r21112 through r21160
authorArystanbek Dyussenov <arystan.d@gmail.com>
Fri, 26 Jun 2009 13:00:23 +0000 (13:00 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Fri, 26 Jun 2009 13:00:23 +0000 (13:00 +0000)
27 files changed:
release/io/export_obj.py [new file with mode: 0644]
release/scripts/export_obj-2.5.py [new file with mode: 0644]
release/ui/buttons_data_armature.py
release/ui/buttons_data_camera.py
release/ui/buttons_data_curve.py
release/ui/buttons_data_empty.py
release/ui/buttons_data_lamp.py
release/ui/buttons_data_lattice.py
release/ui/buttons_data_text.py
release/ui/buttons_material.py
release/ui/buttons_particle.py [deleted file]
release/ui/buttons_physic_cloth.py
release/ui/buttons_texture.py
release/ui/buttons_world.py
release/ui/space_script.py [new file with mode: 0644]
source/blender/blenkernel/BKE_anim.h
source/blender/blenkernel/intern/mesh.c
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_mesh_api.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_object_api.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_scene_api.c [new file with mode: 0644]

diff --git a/release/io/export_obj.py b/release/io/export_obj.py
new file mode 100644 (file)
index 0000000..8b3bcfb
--- /dev/null
@@ -0,0 +1,83 @@
+import bpy
+
+def write_obj(filepath, scene, ob):
+       out = open(filepath, 'w')
+
+       # create a temporary mesh
+       mesh = ob.create_render_mesh(scene)
+
+       # for vert in mesh.verts:
+       # ^ iterating that way doesn't work atm for some reason
+
+       for i in range(len(mesh.verts)):
+               vert = mesh.verts[i]
+               out.write('v {0} {1} {2}\n'.format(vert.co[0], vert.co[1], vert.co[2]))
+       
+       for i in range(len(mesh.faces)):
+               face = mesh.faces[i]
+               out.write('f')
+
+               # but this works
+               for index in face.verts:
+                       out.write(' {0}'.format(index + 1))
+               out.write('\n')
+
+       # delete mesh gain
+       bpy.data.remove_mesh(mesh)
+
+       out.close()
+       
+class SCRIPT_OT_export_obj(bpy.types.Operator):
+       '''A very basic OBJ exporter, writes only active object's mesh.'''
+
+       __label__ = 'Export OBJ'
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+       __props__ = [
+               bpy.props.StringProperty(attr="filename", name="filename")
+               ]
+
+       def debug(self, message):
+               print("{0}: {1}".format(self.__class__.__name__, message))
+
+       def execute_(self, context):
+               self.debug("exec")
+               self.debug("filename = " + self.filename)
+
+               act = context.active_object
+
+               if act.type == 'MESH':
+                       write_obj(self.filename, context.scene, act)
+               else:
+                       self.debug("Active object is not a MESH.")
+
+               # XXX errors are silenced for some reason
+#              raise Exception("oops!")
+
+               return ('FINISHED',)
+
+       def execute(self, context):
+               self.debug("exec")
+               
+               act = context.active_object
+
+               act.create_dupli_list()
+               print("{0} has {1} dupli objects".format(act.name, len(act.dupli_list)))
+
+               act.free_dupli_list()
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):
+               self.debug("invoke")
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+       
+       def poll(self, context): # poll isnt working yet
+               self.debug("poll")
+               return True
+
+bpy.ops.add(SCRIPT_OT_export_obj)
+
diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py
new file mode 100644 (file)
index 0000000..cd8e423
--- /dev/null
@@ -0,0 +1,1217 @@
+#!BPY
+
+"""
+Name: 'Wavefront (.obj)...'
+Blender: 248
+Group: 'Export'
+Tooltip: 'Save a Wavefront OBJ File'
+"""
+
+__author__ = "Campbell Barton, Jiri Hnidek, Paolo Ciccone"
+__url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org']
+__version__ = "1.21"
+
+__bpydoc__ = """\
+This script is an exporter to OBJ file format.
+
+Usage:
+
+Select the objects you wish to export and run this script from "File->Export" menu.
+Selecting the default options from the popup box will be good in most cases.
+All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d)
+will be exported as mesh data.
+"""
+
+
+# --------------------------------------------------------------------------
+# OBJ Export v1.1 by Campbell Barton (AKA Ideasman)
+# --------------------------------------------------------------------------
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA         02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+
+import bpy
+# import BPySys
+
+# import Blender
+# from Blender import Mesh, Scene, Window, sys, Image, Draw
+# import BPyMesh
+# import BPyObject
+# import BPySys
+# import BPyMessages
+
+# Returns a tuple - path,extension.
+# 'hello.obj' >         ('hello', '.obj')
+def splitExt(path):
+       dotidx = path.rfind('.')
+       if dotidx == -1:
+               return path, ''
+       else:
+               return path[:dotidx], path[dotidx:] 
+
+def fixName(name):
+       if name == None:
+               return 'None'
+       else:
+               return name.replace(' ', '_')
+
+# A Dict of Materials
+# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
+MTL_DICT = {} 
+
+def write_mtl(scene, filename):
+
+       world = bpy.data.worlds[0]
+       worldAmb = world.ambient_color
+
+#      world = Blender.World.GetCurrent()
+#      if world:
+#              worldAmb = world.getAmb()
+#      else:
+#              worldAmb = (0,0,0) # Default value
+       
+       file = open(filename, "w")
+       # XXX
+#      file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
+       file.write('# Material Count: %i\n' % len(MTL_DICT))
+       # Write material/image combinations we have used.
+       for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems():
+               
+               # Get the Blender data for the material and the image.
+               # Having an image named None will make a bug, dont do it :)
+               
+               file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
+               
+               if mat:
+                       file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's 
+                       file.write('Ka %.6f %.6f %.6f\n' %      tuple([c*mat.amb for c in worldAmb])  ) # Ambient, uses mirror colour,
+                       file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse
+                       file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular
+                       file.write('Ni %.6f\n' % mat.IOR) # Refraction index
+                       file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
+                       
+                       # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
+                       if mat.getMode() & Blender.Material.Modes['SHADELESS']:
+                               file.write('illum 0\n') # ignore lighting
+                       elif mat.getSpec() == 0:
+                               file.write('illum 1\n') # no specular.
+                       else:
+                               file.write('illum 2\n') # light normaly 
+               
+               else:
+                       #write a dummy material here?
+                       file.write('Ns 0\n')
+                       file.write('Ka %.6f %.6f %.6f\n' %      tuple([c for c in worldAmb])  ) # Ambient, uses mirror colour,
+                       file.write('Kd 0.8 0.8 0.8\n')
+                       file.write('Ks 0.8 0.8 0.8\n')
+                       file.write('d 1\n') # No alpha
+                       file.write('illum 2\n') # light normaly
+               
+               # Write images!
+               if img:  # We have an image on the face!
+                       file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image                 
+               
+               elif mat: # No face image. if we havea material search for MTex image.
+                       for mtex in mat.getTextures():
+                               if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
+                                       try:
+                                               filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
+                                               file.write('map_Kd %s\n' % filename) # Diffuse mapping image
+                                               break
+                                       except:
+                                               # Texture has no image though its an image type, best ignore.
+                                               pass
+               
+               file.write('\n\n')
+       
+       file.close()
+
+def copy_file(source, dest):
+       file = open(source, 'rb')
+       data = file.read()
+       file.close()
+       
+       file = open(dest, 'wb')
+       file.write(data)
+       file.close()
+
+
+def copy_images(dest_dir):
+       if dest_dir[-1] != sys.sep:
+               dest_dir += sys.sep
+       
+       # Get unique image names
+       uniqueImages = {}
+       for matname, mat, image in MTL_DICT.itervalues(): # Only use image name
+               # Get Texface images
+               if image:
+                       uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default.
+               
+               # Get MTex images
+               if mat:
+                       for mtex in mat.getTextures():
+                               if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
+                                       image_tex = mtex.tex.image
+                                       if image_tex:
+                                               try:
+                                                       uniqueImages[image_tex] = image_tex
+                                               except:
+                                                       pass
+       
+       # Now copy images
+       copyCount = 0
+       
+       for bImage in uniqueImages.itervalues():
+               image_path = sys.expandpath(bImage.filename)
+               if sys.exists(image_path):
+                       # Make a name for the target path.
+                       dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
+                       if not sys.exists(dest_image_path): # Image isnt alredy there
+                               print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
+                               copy_file(image_path, dest_image_path)
+                               copyCount+=1
+       print '\tCopied %d images' % copyCount
+
+
+def test_nurbs_compat(ob):
+       if ob.type != 'CURVE':
+               return False
+       
+       for nu in ob.data:
+               if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier
+                       return True
+       
+       return False
+
+def write_nurb(file, ob, ob_mat):
+       tot_verts = 0
+       cu = ob.data
+       
+       # use negative indices
+       Vector = Blender.Mathutils.Vector
+       for nu in cu:
+               
+               if nu.type==0:          DEG_ORDER_U = 1
+               else:                           DEG_ORDER_U = nu.orderU-1  # Tested to be correct
+               
+               if nu.type==1:
+                       print "\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported"
+                       continue
+               
+               if nu.knotsV:
+                       print "\tWarning, surface:", ob.name, "only poly and nurbs curves supported"
+                       continue
+               
+               if len(nu) <= DEG_ORDER_U:
+                       print "\tWarning, orderU is lower then vert count, skipping:", ob.name
+                       continue
+               
+               pt_num = 0
+               do_closed = (nu.flagU & 1)
+               do_endpoints = (do_closed==0) and (nu.flagU & 2)
+               
+               for pt in nu:
+                       pt = Vector(pt[0], pt[1], pt[2]) * ob_mat
+                       file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2]))
+                       pt_num += 1
+               tot_verts += pt_num
+               
+               file.write('g %s\n' % (fixName(ob.name))) # fixName(ob.getData(1)) could use the data name too
+               file.write('cstype bspline\n') # not ideal, hard coded
+               file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still
+               
+               curve_ls = [-(i+1) for i in xrange(pt_num)]
+               
+               # 'curv' keyword
+               if do_closed:
+                       if DEG_ORDER_U == 1:
+                               pt_num += 1
+                               curve_ls.append(-1)
+                       else:
+                               pt_num += DEG_ORDER_U
+                               curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U]
+               
+               file.write('curv 0.0 1.0 %s\n' % (' '.join( [str(i) for i in curve_ls] ))) # Blender has no U and V values for the curve
+               
+               # 'parm' keyword
+               tot_parm = (DEG_ORDER_U + 1) + pt_num
+               tot_parm_div = float(tot_parm-1)
+               parm_ls = [(i/tot_parm_div) for i in xrange(tot_parm)]
+               
+               if do_endpoints: # end points, force param
+                       for i in xrange(DEG_ORDER_U+1):
+                               parm_ls[i] = 0.0
+                               parm_ls[-(1+i)] = 1.0
+               
+               file.write('parm u %s\n' % ' '.join( [str(i) for i in parm_ls] ))
+
+               file.write('end\n')
+       
+       return tot_verts
+
+def write(filename, objects, scene, \
+EXPORT_TRI=False,  EXPORT_EDGES=False,  EXPORT_NORMALS=False,  EXPORT_NORMALS_HQ=False,\
+EXPORT_UV=True,  EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
+EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\
+EXPORT_GROUP_BY_OB=False,  EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\
+EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
+       '''
+       Basic write function. The context and options must be alredy set
+       This can be accessed externaly
+       eg.
+       write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
+       '''
+       
+       def veckey3d(v):
+               return round(v.x, 6), round(v.y, 6), round(v.z, 6)
+               
+       def veckey2d(v):
+               return round(v.x, 6), round(v.y, 6)
+       
+       def findVertexGroupName(face, vWeightMap):
+               """
+               Searches the vertexDict to see what groups is assigned to a given face.
+               We use a frequency system in order to sort out the name because a given vetex can
+               belong to two or more groups at the same time. To find the right name for the face
+               we list all the possible vertex group names with their frequency and then sort by
+               frequency in descend order. The top element is the one shared by the highest number
+               of vertices is the face's group 
+               """
+               weightDict = {}
+               for vert_index in face.verts:
+#              for vert in face:
+                       vWeights = vWeightMap[vert_index]
+#                      vWeights = vWeightMap[vert]
+                       for vGroupName, weight in vWeights:
+                               weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
+               
+               if weightDict:
+                       alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight
+                       alist.sort()
+                       return(alist[-1][1]) # highest value last
+               else:
+                       return '(null)'
+
+       # TODO: implement this in C? dunno how it should be called...
+       def getVertsFromGroup(me, group_index):
+               ret = []
+
+               for i, v in enumerate(me.verts):
+                       for g in v.groups:
+                               if g.group == group.index:
+                                       ret.append((i, g.weight))
+
+               return ret
+
+
+       print 'OBJ Export path: "%s"' % filename
+       temp_mesh_name = '~tmp-mesh'
+
+       time1 = sys.time()
+#      scn = Scene.GetCurrent()
+       scene = context.scene
+
+       file = open(filename, "w")
+       
+       # Write Header
+       file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
+       file.write('# www.blender3d.org\n')
+
+       # Tell the obj file what material file to use.
+       if EXPORT_MTL:
+               mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
+               file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
+       
+       # Get the container mesh. - used for applying modifiers and non mesh objects.
+
+#      containerMesh = meshName = tempMesh = None
+#      for meshName in Blender.NMesh.GetNames():
+#              if meshName.startswith(temp_mesh_name):
+#                      tempMesh = Mesh.Get(meshName)
+#                      if not tempMesh.users:
+#                              containerMesh = tempMesh
+#      if not containerMesh:
+#              containerMesh = Mesh.New(temp_mesh_name)
+
+    # XXX this mesh is not removed
+    # XXX this mesh should not be in database
+    containerMesh = bpy.data.add_mesh(temp_mesh_name)
+       
+       if EXPORT_ROTX90:
+               mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
+               
+#      del meshName
+#      del tempMesh
+       
+       # Initialize totals, these are updated each object
+       totverts = totuvco = totno = 1
+       
+       face_vert_index = 1
+       
+       globalNormals = {}
+
+       # Get all meshes
+       for ob_main in objects:
+
+               if ob_main.dupli_type != 'NONE':
+                       ob_main.create_dupli_list()
+
+               # ignore dupli children
+               if ob_main.parent.dupli_type != 'NONE':
+                       continue
+
+               obs = []
+               if ob_main.dupli_type != 'NONE':
+                       obs = [(dob.matrix, dob.object) for dob in ob_main.dupli_list]
+               else:
+                       obs = [ob.matrix, ob]
+
+               for ob, ob_mat in obs:
+                       # XXX postponed
+#                      # Nurbs curve support
+#                      if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
+#                              if EXPORT_ROTX90:
+#                                      ob_mat = ob_mat * mat_xrot90
+                               
+#                              totverts += write_nurb(file, ob, ob_mat)
+                               
+#                              continue
+#                      end nurbs
+
+                       if ob.type != 'MESH':
+                               continue
+
+                       # XXX EXPORT_APPLY_MODIFIERS is not used (always true)
+                       # we also need influences to be copied... for EXPORT_POLYGROUPS to work
+                       # which create_preview_mesh presumably does (CD_MASK_MDEFORMVERT flag)
+                       me = ob.create_preview_mesh()
+
+#                      # Will work for non meshes now! :)
+#                      me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
+#                      if not me:
+#                              continue
+
+                       if EXPORT_UV:
+                               faceuv = len(me.uv_layers) > 0
+                       else:
+                               faceuv = False
+
+                       # We have a valid mesh
+                       if EXPORT_TRI and me.faces:
+                               # Add a dummy object to it.
+                               has_quads = False
+                               for f in me.faces:
+#                                      if len(f) == 4:
+                                       if len(f.verts) == 4:
+                                               has_quads = True
+                                               break
+                               
+                               if has_quads:
+                                       newob = bpy.data.add_object('MESH', 'temp_object')
+                                       scene.add_object(newob)
+                                       newob.convert_to_triface(scene)
+                                       # me will still be there
+                                       scene.remove_object(newob)
+#                                      oldmode = Mesh.Mode()
+#                                      Mesh.Mode(Mesh.SelectModes['FACE'])
+                                       
+#                                      me.sel = True
+#                                      tempob = scn.objects.new(me)
+#                                      me.quadToTriangle(0) # more=0 shortest length
+#                                      oldmode = Mesh.Mode(oldmode)
+#                                      scn.objects.unlink(tempob)
+                                       
+#                                      Mesh.Mode(oldmode)
+
+                       if EXPORT_ROTX90:
+                               ob_mat *= mat_xrot90
+
+                       # Make our own list so it can be sorted to reduce context switching
+                       face_index_pairs = [ (face, index) for index, face in enumerate(me.faces)]
+                       # faces = [ f for f in me.faces ]
+                       
+                       if EXPORT_EDGES:
+                               edges = me.edges
+                       else:
+                               edges = []
+
+                       if not (len(face_index_pairs)+len(edges)+len(me.verts)): # Make sure there is somthing to write                         
+#                      if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
+
+                               bpy.data.remove_mesh(me)
+
+                               continue # dont bother with this mesh.
+
+                       if EXPORT_ROTX90:
+                               me.transform(ob_mat*mat_xrot90)
+                       else:
+                               me.transform(ob_mat)
+                       
+                       # High Quality Normals
+                       if EXPORT_NORMALS and face_index_pairs:
+#                      if EXPORT_NORMALS and faces:
+                               # XXX
+                               pass
+#                              if EXPORT_NORMALS_HQ:
+#                                      BPyMesh.meshCalcNormals(me)
+#                              else:
+#                                      # transforming normals is incorrect
+#                                      # when the matrix is scaled,
+#                                      # better to recalculate them
+#                                      me.calcNormals()
+                       
+                       # # Crash Blender
+                       #materials = me.getMaterials(1) # 1 == will return None in the list.
+                       materials = me.materials
+                       
+                       materialNames = []
+                       materialItems = materials[:]
+                       if materials:
+                               for mat in materials:
+                                       if mat: # !=None
+                                               materialNames.append(mat.name)
+                                       else:
+                                               materialNames.append(None)
+                               # Cant use LC because some materials are None.
+                               # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.  
+                       
+                       # Possible there null materials, will mess up indicies
+                       # but at least it will export, wait until Blender gets fixed.
+                       materialNames.extend((16-len(materialNames)) * [None])
+                       materialItems.extend((16-len(materialItems)) * [None])
+                       
+                       # Sort by Material, then images
+                       # so we dont over context switch in the obj file.
+                       if EXPORT_KEEP_VERT_ORDER:
+                               pass
+                       elif faceuv:
+                               # XXX update
+                               tface = me.active_uv_layer.data
+
+                               # exception only raised if Python 2.3 or lower...
+                               try:    face_index_pairs.sort(key = lambda a: (a[0].material_index, tface[a[1]].image, a[0].smooth))
+                               except: face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, tface[a[1]].image, a[0].smooth),
+                                                                                                                         (b[0].material_index, tface[b[1]].image, b[0].smooth)))
+                       elif len(materials) > 1:
+                               try:    face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].smooth))
+                               except: face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, a[0].smooth),
+                                                                                                                         (b[0].material_index, b[0].smooth)))
+                       else:
+                               # no materials
+                               try:    face_index_pairs.sort(key = lambda a: a[0].smooth)
+                               except: face_index_pairs.sort(lambda a,b: cmp(a[0].smooth, b[0].smooth))
+#                      if EXPORT_KEEP_VERT_ORDER:
+#                              pass
+#                      elif faceuv:
+#                              try:    faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
+#                              except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
+#                      elif len(materials) > 1:
+#                              try:    faces.sort(key = lambda a: (a.mat, a.smooth))
+#                              except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
+#                      else:
+#                              # no materials
+#                              try:    faces.sort(key = lambda a: a.smooth)
+#                              except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
+
+                       faces = [pair[0] for pair in face_index_pairs]
+                       
+                       # Set the default mat to no material and no image.
+                       contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
+                       contextSmooth = None # Will either be true or false,  set bad to force initialization switch.
+                       
+                       if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
+                               name1 = ob.name
+                               name2 = ob.data.name
+                               # name2 = ob.getData(1)
+                               if name1 == name2:
+                                       obnamestring = fixName(name1)
+                               else:
+                                       obnamestring = '%s_%s' % (fixName(name1), fixName(name2))
+                               
+                               if EXPORT_BLEN_OBS:
+                                       file.write('o %s\n' % obnamestring) # Write Object name
+                               else: # if EXPORT_GROUP_BY_OB:
+                                       file.write('g %s\n' % obnamestring)
+                       
+                       
+                       # Vert
+                       for v in me.verts:
+                               file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
+                       
+                       # UV
+                       if faceuv:
+                               uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
+
+                               uv_dict = {} # could use a set() here
+                               uv_layer = me.active_uv_layer
+                               for f, f_index in face_index_pairs:
+
+                                       tface = uv_layer.data[f_index]
+
+                                       uvs = [tface.uv1, tface.uv2, tface.uv3]
+
+                                       # add another UV if it's a quad
+                                       if tface.verts[3] != 0:
+                                               uvs.append(tface.uv4)
+
+                                       for uv_index, uv in enumerate(uvs):
+                                               uvkey = veckey2d(uv)
+                                               try:
+                                                       uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
+                                               except:
+                                                       uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
+                                                       file.write('vt %.6f %.6f\n' % tuple(uv))
+
+#                              uv_dict = {} # could use a set() here
+#                              for f_index, f in enumerate(faces):
+                                       
+#                                      for uv_index, uv in enumerate(f.uv):
+#                                              uvkey = veckey2d(uv)
+#                                              try:
+#                                                      uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
+#                                              except:
+#                                                      uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
+#                                                      file.write('vt %.6f %.6f\n' % tuple(uv))
+                               
+                               uv_unique_count = len(uv_dict)
+                               del uv, uvkey, uv_dict, f_index, uv_index
+                               # Only need uv_unique_count and uv_face_mapping
+                       
+                       # NORMAL, Smooth/Non smoothed.
+                       if EXPORT_NORMALS:
+                               for f in faces:
+                                       if f.smooth:
+                                               for v in f:
+                                                       noKey = veckey3d(v.normal)
+#                                                      noKey = veckey3d(v.no)
+                                                       if not globalNormals.has_key( noKey ):
+                                                               globalNormals[noKey] = totno
+                                                               totno +=1
+                                                               file.write('vn %.6f %.6f %.6f\n' % noKey)
+                                       else:
+                                               # Hard, 1 normal from the face.
+                                               noKey = veckey3d(f.normal)
+#                                              noKey = veckey3d(f.no)
+                                               if not globalNormals.has_key( noKey ):
+                                                       globalNormals[noKey] = totno
+                                                       totno +=1
+                                                       file.write('vn %.6f %.6f %.6f\n' % noKey)
+                       
+                       if not faceuv:
+                               f_image = None
+
+                       # XXX
+                       if EXPORT_POLYGROUPS:
+                               # Retrieve the list of vertex groups
+#                              vertGroupNames = me.getVertGroupNames()
+
+                               currentVGroup = ''
+                               # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
+                               vgroupsMap = [[] for _i in range(len(me.verts))]
+#                              vgroupsMap = [[] for _i in xrange(len(me.verts))]
+                               for g in ob.vertex_groups:
+#                              for vertexGroupName in vertGroupNames:
+                                       for vIdx, vWeight in getVertsFromGroup(me, g.index)
+#                                      for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
+                                               vgroupsMap[vIdx].append((g.name, vWeight))
+
+                       for f_index, f in enumerate(faces):
+                               f_v = [{"index": index, "vertex": me.verts[index]} for index in f.verts]
+#                              f_v= f.v
+                               f_smooth= f.smooth
+                               f_mat = min(f.material_index, len(materialNames)-1)
+#                              f_mat = min(f.mat, len(materialNames)-1)
+                               if faceuv:
+
+                                       tface = me.active_uv_layer.data[face_index_pairs[f_index][1]]
+
+                                       f_image = tface.image
+                                       f_uv= [tface.uv1, tface.uv2, tface.uv3]
+                                       if f.verts[4] != 0:
+                                               f_uv.append(tface.uv4)
+#                                      f_image = f.image
+#                                      f_uv= f.uv
+                               
+                               # MAKE KEY
+                               if faceuv and f_image: # Object is always true.
+                                       key = materialNames[f_mat],      f_image.name
+                               else:
+                                       key = materialNames[f_mat],      None # No image, use None instead.
+
+                               # XXX
+                               # Write the vertex group
+                               if EXPORT_POLYGROUPS:
+                                       if len(ob.vertex_groups):
+                                               # find what vertext group the face belongs to
+                                               theVGroup = findVertexGroupName(f,vgroupsMap)
+                                               if      theVGroup != currentVGroup:
+                                                       currentVGroup = theVGroup
+                                                       file.write('g %s\n' % theVGroup)
+#                              # Write the vertex group
+#                              if EXPORT_POLYGROUPS:
+#                                      if vertGroupNames:
+#                                              # find what vertext group the face belongs to
+#                                              theVGroup = findVertexGroupName(f,vgroupsMap)
+#                                              if      theVGroup != currentVGroup:
+#                                                      currentVGroup = theVGroup
+#                                                      file.write('g %s\n' % theVGroup)
+
+                               # CHECK FOR CONTEXT SWITCH
+                               if key == contextMat:
+                                       pass # Context alredy switched, dont do anything
+                               else:
+                                       if key[0] == None and key[1] == None:
+                                               # Write a null material, since we know the context has changed.
+                                               if EXPORT_GROUP_BY_MAT:
+                                                       # can be mat_image or (null)
+                                                       file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.data.name)) ) 
+#                                                      file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
+                                               file.write('usemtl (null)\n') # mat, image
+                                               
+                                       else:
+                                               mat_data= MTL_DICT.get(key)
+                                               if not mat_data:
+                                                       # First add to global dict so we can export to mtl
+                                                       # Then write mtl
+                                                       
+                                                       # Make a new names from the mat and image name,
+                                                       # converting any spaces to underscores with fixName.
+                                                       
+                                                       # If none image dont bother adding it to the name
+                                                       if key[1] == None:
+                                                               mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
+                                                       else:
+                                                               mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
+                                               
+                                               if EXPORT_GROUP_BY_MAT:
+                                                       file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.data.name), mat_data[0]) ) # can be mat_image or (null)
+#                                                      file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)
+
+                                               file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
+                                       
+                               contextMat = key
+                               if f_smooth != contextSmooth:
+                                       if f_smooth: # on now off
+                                               file.write('s 1\n')
+                                               contextSmooth = f_smooth
+                                       else: # was off now on
+                                               file.write('s off\n')
+                                               contextSmooth = f_smooth
+                               
+                               file.write('f')
+                               if faceuv:
+                                       if EXPORT_NORMALS:
+                                               if f_smooth: # Smoothed, use vertex normals
+                                                       for vi, v in enumerate(f_v):
+                                                               file.write( ' %d/%d/%d' % \
+                                                                                               (v["index"] + totverts,
+                                                                                                totuvco + uv_face_mapping[f_index][vi],
+                                                                                                globalNormals[ veckey3d(v["vertex"].normal) ]) ) # vert, uv, normal
+#                                                              file.write( ' %d/%d/%d' % (\
+#                                                                v.index+totverts,\
+#                                                                totuvco + uv_face_mapping[f_index][vi],\
+#                                                                globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
+                                                       
+                                               else: # No smoothing, face normals
+                                                       no = globalNormals[ veckey3d(f.normal) ]
+#                                                      no = globalNormals[ veckey3d(f.no) ]
+                                                       for vi, v in enumerate(f_v):
+                                                               file.write( ' %d/%d/%d' % \
+                                                                                               (v["index"] + totverts,
+                                                                                                totuvco + uv_face_mapping[f_index][vi],
+                                                                                                no) ) # vert, uv, normal
+#                                                              file.write( ' %d/%d/%d' % (\
+#                                                                v.index+totverts,\
+#                                                                totuvco + uv_face_mapping[f_index][vi],\
+#                                                                no)) # vert, uv, normal
+                                       
+                                       else: # No Normals
+                                               for vi, v in enumerate(f_v):
+                                                       file.write( ' %d/%d' % (\
+                                                         v["index"] + totverts,\
+                                                         totuvco + uv_face_mapping[f_index][vi])) # vert, uv
+#                                                      file.write( ' %d/%d' % (\
+#                                                        v.index+totverts,\
+#                                                        totuvco + uv_face_mapping[f_index][vi])) # vert, uv
+                                       
+                                       face_vert_index += len(f_v)
+                               
+                               else: # No UV's
+                                       if EXPORT_NORMALS:
+                                               if f_smooth: # Smoothed, use vertex normals
+                                                       for v in f_v:
+                                                               file.write( ' %d//%d' %
+                                                                                       (v["index"] + totverts, globalNormals[ veckey3d(v["vertex"].normal) ]) )
+
+#                                                              file.write( ' %d//%d' % (\
+#                                                                v.index+totverts,\
+#                                                                globalNormals[ veckey3d(v.no) ]))
+                                               else: # No smoothing, face normals
+                                                       no = globalNormals[ veckey3d(f.normal) ]
+#                                                      no = globalNormals[ veckey3d(f.no) ]
+                                                       for v in f_v:
+                                                               file.write( ' %d//%d' % (v["index"] + totverts, no) )
+#                                                              file.write( ' %d//%d' % (\
+#                                                                v.index+totverts,\
+#                                                                no))
+                                       else: # No Normals
+                                               for v in f_v:
+                                                       file.write( ' %d' % (v["index"] + totverts) )
+#                                                      file.write( ' %d' % (\
+#                                                        v.index+totverts))
+                                               
+                               file.write('\n')
+                       
+                       # Write edges.
+                       if EXPORT_EDGES:
+                               for ed in edges:
+                                       if ed.loose:
+                                               file.write('f %d %d\n' % (ed.verts[0] + totverts, ed.verts[1] + totverts))
+#                              LOOSE= Mesh.EdgeFlags.LOOSE
+#                              for ed in edges:
+#                                      if ed.flag & LOOSE:
+#                                              file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
+                               
+                       # Make the indicies global rather then per mesh
+                       totverts += len(me.verts)
+                       if faceuv:
+                               totuvco += uv_unique_count
+
+                       # clean up
+                       bpy.data.remove_mesh(me)
+#                      me.verts= None
+
+               if ob_main.dupli_type != 'NONE':
+                       ob_main.free_dupli_list()
+
+       file.close()
+       
+       
+       # Now we have all our materials, save them
+       if EXPORT_MTL:
+               write_mtl(scene, mtlfilename)
+       if EXPORT_COPY_IMAGES:
+               dest_dir = filename
+               # Remove chars until we are just the path.
+               while dest_dir and dest_dir[-1] not in '\\/':
+                       dest_dir = dest_dir[:-1]
+               if dest_dir:
+                       copy_images(dest_dir)
+               else:
+                       print '\tError: "%s" could not be used as a base for an image path.' % filename
+       
+       print "OBJ Export time: %.2f" % (sys.time() - time1)
+       
+
+# replaced by do_export
+def write_ui(filename):
+       
+       if not filename.lower().endswith('.obj'):
+               filename += '.obj'
+       
+       if not BPyMessages.Warning_SaveOver(filename):
+               return
+       
+       global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
+               EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
+               EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
+               EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
+               EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
+               EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
+       
+       EXPORT_APPLY_MODIFIERS = Draw.Create(0)
+       EXPORT_ROTX90 = Draw.Create(1)
+       EXPORT_TRI = Draw.Create(0)
+       EXPORT_EDGES = Draw.Create(1)
+       EXPORT_NORMALS = Draw.Create(0)
+       EXPORT_NORMALS_HQ = Draw.Create(0)
+       EXPORT_UV = Draw.Create(1)
+       EXPORT_MTL = Draw.Create(1)
+       EXPORT_SEL_ONLY = Draw.Create(1)
+       EXPORT_ALL_SCENES = Draw.Create(0)
+       EXPORT_ANIMATION = Draw.Create(0)
+       EXPORT_COPY_IMAGES = Draw.Create(0)
+       EXPORT_BLEN_OBS = Draw.Create(0)
+       EXPORT_GROUP_BY_OB = Draw.Create(0)
+       EXPORT_GROUP_BY_MAT = Draw.Create(0)
+       EXPORT_KEEP_VERT_ORDER = Draw.Create(1)
+       EXPORT_POLYGROUPS = Draw.Create(0)
+       EXPORT_CURVE_AS_NURBS = Draw.Create(1)
+       
+       
+       # Old UI
+       '''
+       # removed too many options are bad!
+       
+       # Get USER Options
+       pup_block = [\
+       ('Context...'),\
+       ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\
+       ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\
+       ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\
+       ('Object Prefs...'),\
+       ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\
+       ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\
+       ('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
+       ('Extra Data...'),\
+       ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
+       ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\
+       ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\
+       ('UVs', EXPORT_UV, 'Export texface UV coords.'),\
+       ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\
+       ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\
+       ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\
+       ('Grouping...'),\
+       ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\
+       ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\
+       ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\
+       ]
+       
+       if not Draw.PupBlock('Export...', pup_block):
+               return
+       '''
+       
+       # BEGIN ALTERNATIVE UI *******************
+       if True: 
+               
+               EVENT_NONE = 0
+               EVENT_EXIT = 1
+               EVENT_REDRAW = 2
+               EVENT_EXPORT = 3
+               
+               GLOBALS = {}
+               GLOBALS['EVENT'] = EVENT_REDRAW
+               #GLOBALS['MOUSE'] = Window.GetMouseCoords()
+               GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
+               
+               def obj_ui_set_event(e,v):
+                       GLOBALS['EVENT'] = e
+               
+               def do_split(e,v):
+                       global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER, EXPORT_POLYGROUPS
+                       if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val:
+                               EXPORT_KEEP_VERT_ORDER.val = 0
+                       else:
+                               EXPORT_KEEP_VERT_ORDER.val = 1
+                       
+               def do_vertorder(e,v):
+                       global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER
+                       if EXPORT_KEEP_VERT_ORDER.val:
+                               EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0
+                       else:
+                               if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val):
+                                       EXPORT_KEEP_VERT_ORDER.val = 1
+                       
+                       
+               def do_help(e,v):
+                       url = __url__[0]
+                       print 'Trying to open web browser with documentation at this address...'
+                       print '\t' + url
+                       
+                       try:
+                               import webbrowser
+                               webbrowser.open(url)
+                       except:
+                               print '...could not open a browser window.'
+               
+               def obj_ui():
+                       ui_x, ui_y = GLOBALS['MOUSE']
+                       
+                       # Center based on overall pup size
+                       ui_x -= 165
+                       ui_y -= 140
+                       
+                       global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
+                               EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
+                               EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
+                               EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
+                               EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
+                               EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
+
+                       Draw.Label('Context...', ui_x+9, ui_y+239, 220, 20)
+                       Draw.BeginAlign()
+                       EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+219, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.')
+                       EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+219, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.')
+                       EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+219, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.')
+                       Draw.EndAlign()
+                       
+                       
+                       Draw.Label('Output Options...', ui_x+9, ui_y+189, 220, 20)
+                       Draw.BeginAlign()
+                       EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+170, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split)
+                       EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+170, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP')
+                       EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+170, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.')
+                       Draw.EndAlign()
+                       
+                       
+                       Draw.Label('Export...', ui_x+9, ui_y+139, 220, 20)
+                       Draw.BeginAlign()
+                       EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+120, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.')
+                       EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+120, 70, 20, EXPORT_TRI.val, 'Triangulate quads.')
+                       Draw.EndAlign()
+                       Draw.BeginAlign()
+                       EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+120, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.')
+                       EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+120, 31, 20, EXPORT_UV.val, 'Export texface UV coords.')
+                       Draw.EndAlign()
+                       Draw.BeginAlign()
+                       EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+120, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).')
+                       EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+120, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.')
+                       Draw.EndAlign()
+                       EXPORT_POLYGROUPS = Draw.Toggle('Polygroups', EVENT_REDRAW, ui_x+9, ui_y+95, 120, 20, EXPORT_POLYGROUPS.val, 'Export vertex groups as OBJ groups (one group per face approximation).')
+                       
+                       EXPORT_CURVE_AS_NURBS = Draw.Toggle('Nurbs', EVENT_NONE, ui_x+139, ui_y+95, 100, 20, EXPORT_CURVE_AS_NURBS.val, 'Export 3D nurbs curves and polylines as OBJ curves, (bezier not supported).')
+                       
+                       
+                       Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20)
+                       Draw.BeginAlign()
+                       EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split)
+                       EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split)
+                       EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split)
+                       Draw.EndAlign()
+                       
+                       EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder)
+                       
+                       Draw.BeginAlign()
+                       Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help)
+                       Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event)
+                       Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event)
+                       Draw.EndAlign()
+
+               
+               # hack so the toggle buttons redraw. this is not nice at all
+               while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT):
+                       Draw.UIBlock(obj_ui, 0)
+               
+               if GLOBALS['EVENT'] != EVENT_EXPORT:
+                       return
+               
+       # END ALTERNATIVE UI *********************
+       
+       
+       if EXPORT_KEEP_VERT_ORDER.val:
+               EXPORT_BLEN_OBS.val = False
+               EXPORT_GROUP_BY_OB.val = False
+               EXPORT_GROUP_BY_MAT.val = False
+               EXPORT_APPLY_MODIFIERS.val = False
+       
+       Window.EditMode(0)
+       Window.WaitCursor(1)
+       
+       EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
+       EXPORT_ROTX90 = EXPORT_ROTX90.val
+       EXPORT_TRI = EXPORT_TRI.val
+       EXPORT_EDGES = EXPORT_EDGES.val
+       EXPORT_NORMALS = EXPORT_NORMALS.val
+       EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val
+       EXPORT_UV = EXPORT_UV.val
+       EXPORT_MTL = EXPORT_MTL.val
+       EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val
+       EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val
+       EXPORT_ANIMATION = EXPORT_ANIMATION.val
+       EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val
+       EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val
+       EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val
+       EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val
+       EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val
+       EXPORT_POLYGROUPS = EXPORT_POLYGROUPS.val
+       EXPORT_CURVE_AS_NURBS = EXPORT_CURVE_AS_NURBS.val
+       
+       
+       base_name, ext = splitExt(filename)
+       context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension
+       
+       # Use the options to export the data using write()
+       # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
+       orig_scene = Scene.GetCurrent()
+       if EXPORT_ALL_SCENES:
+               export_scenes = Scene.Get()
+       else:
+               export_scenes = [orig_scene]
+       
+       # Export all scenes.
+       for scn in export_scenes:
+               scn.makeCurrent() # If alredy current, this is not slow.
+               context = scn.getRenderingContext()
+               orig_frame = Blender.Get('curframe')
+               
+               if EXPORT_ALL_SCENES: # Add scene name into the context_name
+                       context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
+               
+               # Export an animation?
+               if EXPORT_ANIMATION:
+                       scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
+               else:
+                       scene_frames = [orig_frame] # Dont export an animation.
+               
+               # Loop through all frames in the scene and export.
+               for frame in scene_frames:
+                       if EXPORT_ANIMATION: # Add frame to the filename.
+                               context_name[2] = '_%.6d' % frame
+                       
+                       Blender.Set('curframe', frame)
+                       if EXPORT_SEL_ONLY:
+                               export_objects = scn.objects.context
+                       else:   
+                               export_objects = scn.objects
+                       
+                       full_path= ''.join(context_name)
+                       
+                       # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
+                       # EXPORT THE FILE.
+                       write(full_path, export_objects,\
+                       EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
+                       EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
+                       EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\
+                       EXPORT_ROTX90, EXPORT_BLEN_OBS,\
+                       EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
+                       EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
+               
+               Blender.Set('curframe', orig_frame)
+       
+       # Restore old active scene.
+       orig_scene.makeCurrent()
+       Window.WaitCursor(0)
+
+
+def do_export(filename, context):
+       #       Window.EditMode(0)
+       #       Window.WaitCursor(1)
+       
+       EXPORT_APPLY_MODIFIERS = True
+       EXPORT_ROTX90 = True
+       EXPORT_TRI = False
+       EXPORT_EDGES = False
+       EXPORT_NORMALS = False
+       EXPORT_NORMALS_HQ = False
+       EXPORT_UV = True
+       EXPORT_MTL = True
+       EXPORT_SEL_ONLY = True
+       EXPORT_ALL_SCENES = False # XXX not working atm
+       EXPORT_ANIMATION = False
+       EXPORT_COPY_IMAGES = False
+       EXPORT_BLEN_OBS = True
+       EXPORT_GROUP_BY_OB = False
+       EXPORT_GROUP_BY_MAT = False
+       EXPORT_KEEP_VERT_ORDER = False
+       EXPORT_POLYGROUPS = False
+       EXPORT_CURVE_AS_NURBS = True
+
+       base_name, ext = splitExt(filename)
+       context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension
+       
+       orig_scene = context.scene
+
+#      if EXPORT_ALL_SCENES:
+#              export_scenes = bpy.data.scenes
+#      else:
+#              export_scenes = [orig_scene]
+
+       # XXX only exporting one scene atm since changing 
+       # current scene is not possible.
+       # Brecht says that ideally in 2.5 we won't need such a function,
+       # allowing multiple scenes open at once.
+       export_scenes = [orig_scene]
+
+       # Export all scenes.
+       for scn in export_scenes:
+               #               scn.makeCurrent() # If already current, this is not slow.
+               #               context = scn.getRenderingContext()
+               orig_frame = scn.current_frame
+               
+               if EXPORT_ALL_SCENES: # Add scene name into the context_name
+                       context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
+               
+               # Export an animation?
+               if EXPORT_ANIMATION:
+                       scene_frames = xrange(scn.start_frame, context.end_frame+1) # Up to and including the end frame.
+               else:
+                       scene_frames = [orig_frame] # Dont export an animation.
+               
+               # Loop through all frames in the scene and export.
+               for frame in scene_frames:
+                       if EXPORT_ANIMATION: # Add frame to the filename.
+                               context_name[2] = '_%.6d' % frame
+                       
+                       scn.current_frame = frame
+                       if EXPORT_SEL_ONLY:
+                               export_objects = context.selected_objects
+                       else:   
+                               export_objects = scn.objects
+                       
+                       full_path= ''.join(context_name)
+                       
+                       # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
+                       # EXPORT THE FILE.
+                       write(full_path, export_objects, scn,
+                                 EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,
+                                 EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,
+                                 EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,
+                                 EXPORT_ROTX90, EXPORT_BLEN_OBS,
+                                 EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,
+                                 EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
+
+               
+               scn.current_frame = orig_frame
+       
+       # Restore old active scene.
+#      orig_scene.makeCurrent()
+#      Window.WaitCursor(0)
+
+
+class EXPORT_OT_obj(bpy.types.Operator):
+       '''
+       Currently the exporter lacks these features:
+       * nurbs
+       * multiple scene export (only active scene is written)
+       * particles
+       '''
+       __label__ = 'Export OBJ'
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+       __props__ = [
+               #               bpy.types.FloatProperty(attr="setting_1", name="Example 1",
+               #               default=10.0, min=0, max=10, description="Add info here"),
+               #               bpy.types.IntProperty(attr="setting_2", default=2),
+               #               bpy.types.BoolProperty(attr="toggle", default=True)
+               ]
+       
+       def execu(self, context):
+               print("Selected: " + context.active_object.name)
+
+               do_export("/tmp/test.obj", context)
+
+               return 'FINISHED'
+       
+       def invoke(self, event):
+               print("Invoke")
+               return 'FINISHED'
+       
+       def poll(self, context): # Poll isnt working yet
+               print("Poll")
+               return True
+
+if (hasattr(bpy.ops, "SCRIPT_OT_export_obj")):
+       bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj)
+
+bpy.ops.add(SCRIPT_OT_export_obj)
+
+bpy.ops.SCRIPT_OT_export_obj()
+
+bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj)
index 112724bea911fc5cc3fe82bc9133164fb7c70d4f..226f28d90b8ac9e48d89803dfdade750c5f69e3a 100644 (file)
@@ -14,7 +14,7 @@ class DATA_PT_skeleton(DataButtonsPanel):
        __label__ = "Skeleton"
        
        def poll(self, context):
-               return ((context.object and context.object.type == 'ARMATURE') or context.armature)
+               return (context.object.type == 'ARMATURE' or context.armature)
 
        def draw(self, context):
                layout = self.layout
@@ -127,4 +127,4 @@ class DATA_PT_ghost(DataButtonsPanel):
 bpy.types.register(DATA_PT_skeleton)
 bpy.types.register(DATA_PT_display)
 bpy.types.register(DATA_PT_paths)
-bpy.types.register(DATA_PT_ghost)
+bpy.types.register(DATA_PT_ghost)
\ No newline at end of file
index 9f3a062b4299e03bfabda9d26485281e9322b288..2b56c03ee3403f520ac08de9706e0259e300b3dd 100644 (file)
@@ -14,7 +14,7 @@ class DATA_PT_camera(DataButtonsPanel):
        __label__ = "Lens"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'CAMERA')
+               return (context.object.type == 'CAMERA')
 
        def draw(self, context):
                layout = self.layout
@@ -87,4 +87,4 @@ class DATA_PT_camera_display(DataButtonsPanel):
                col.itemR(cam, "draw_size", text="Size")
                
 bpy.types.register(DATA_PT_camera)
-bpy.types.register(DATA_PT_camera_display)
+bpy.types.register(DATA_PT_camera_display)
\ No newline at end of file
index e60f9591d2907fe13629cc4bd3f26247bbaa412b..05ff37c6c62bd1666bab33e34e5bff9717999c2a 100644 (file)
@@ -7,14 +7,14 @@ class DataButtonsPanel(bpy.types.Panel):
        __context__ = "data"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'CURVE' and context.curve)
+               return (context.object.type == 'CURVE' and context.curve)
 
 class DATA_PT_shape_curve(DataButtonsPanel):
        __idname__ = "DATA_PT_shape_curve"
        __label__ = "Shape"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'CURVE')
+               return (context.object.type == 'CURVE')
 
        def draw(self, context):
                layout = self.layout
@@ -144,4 +144,4 @@ class DATA_PT_current_curve(DataButtonsPanel):
 bpy.types.register(DATA_PT_shape_curve)
 bpy.types.register(DATA_PT_geometry)
 bpy.types.register(DATA_PT_pathanim)
-bpy.types.register(DATA_PT_current_curve)
+bpy.types.register(DATA_PT_current_curve)
\ No newline at end of file
index f97dedcf6cf1080cba57abdd9c887759067faf7d..7eed54d1db6346e5eaa8464a83024c4cb30e7f03 100644 (file)
@@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel):
        __context__ = "data"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'EMPTY')
+               return (context.object.type == 'EMPTY')
        
 class DATA_PT_empty(DataButtonsPanel):
        __idname__ = "DATA_PT_empty"
@@ -20,4 +20,4 @@ class DATA_PT_empty(DataButtonsPanel):
                layout.itemR(ob, "empty_draw_type")
                layout.itemR(ob, "empty_draw_size")
                
-bpy.types.register(DATA_PT_empty)
+bpy.types.register(DATA_PT_empty)
\ No newline at end of file
index a556aceb98dd67319fd1ded437ab7c990e5a35a6..9424eb1fbdb12c54bfd18722c286637d454f5cf4 100644 (file)
@@ -24,7 +24,7 @@ class DATA_PT_lamp(DataButtonsPanel):
        __label__ = "Lamp"
        
        def poll(self, context):
-               return ((context.object and context.object.type == 'LAMP') or context.lamp)
+               return (context.object.type == 'LAMP')
 
        def draw(self, context):
                layout = self.layout
@@ -249,4 +249,4 @@ bpy.types.register(DATA_PT_lamp)
 bpy.types.register(DATA_PT_shadow)
 bpy.types.register(DATA_PT_sunsky)
 bpy.types.register(DATA_PT_spot)
-bpy.types.register(DATA_PT_falloff_curve)
+bpy.types.register(DATA_PT_falloff_curve)
\ No newline at end of file
index bf2aaad5a97865e79177947a649c32df4bc86686..0555efdddb3a9b673dddd111a691da0ffb1f0284 100644 (file)
@@ -14,7 +14,7 @@ class DATA_PT_lattice(DataButtonsPanel):
        __label__ = "Lattice"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'LATTICE')
+               return (context.object.type == 'LATTICE')
 
        def draw(self, context):
                layout = self.layout
@@ -51,4 +51,4 @@ class DATA_PT_lattice(DataButtonsPanel):
                        row.itemR(lat, "outside")
                        row.itemR(lat, "shape_keys")
 
-bpy.types.register(DATA_PT_lattice)
+bpy.types.register(DATA_PT_lattice)
\ No newline at end of file
index 5f4cdd3f8389ca7e9e218e57be37c3e7532c2bff..9a7981f236d33b9a715387efc3665707056e02d3 100644 (file)
@@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel):
        __context__ = "data"
        
        def poll(self, context):
-               return (context.object and context.object.type == 'TEXT' and context.curve)
+               return (context.object.type == 'TEXT' and context.curve)
                
 class DATA_PT_shape_text(DataButtonsPanel):
        __idname__ = "DATA_PT_shape_text"
@@ -15,7 +15,7 @@ class DATA_PT_shape_text(DataButtonsPanel):
        
        def poll(self, context):
                ob = context.object
-               return (context.object and context.object.type == 'TEXT')
+               return (context.object.type == 'TEXT')
 
        def draw(self, context):
                layout = self.layout
index 8b0ef82b62822c645dcb92e953293259c7e623f8..a52ecc20307ea69adfc8feb7a982958ab25d4a48 100644 (file)
@@ -13,9 +13,6 @@ class MATERIAL_PT_preview(MaterialButtonsPanel):
        __idname__= "MATERIAL_PT_preview"
        __label__ = "Preview"
 
-       def poll(self, context):
-               return (context.material or context.material_slot)
-
        def draw(self, context):
                layout = self.layout
                mat = context.material
@@ -27,7 +24,7 @@ class MATERIAL_PT_material(MaterialButtonsPanel):
        __label__ = "Material"
 
        def poll(self, context):
-               return (context.material or context.material_slot)
+               return (context.object != None)
 
        def draw(self, context):
                layout = self.layout
@@ -422,4 +419,4 @@ bpy.types.register(MATERIAL_PT_raytransp)
 bpy.types.register(MATERIAL_PT_sss)
 bpy.types.register(MATERIAL_PT_halo)
 bpy.types.register(MATERIAL_PT_strand)
-bpy.types.register(MATERIAL_PT_options)
+bpy.types.register(MATERIAL_PT_options)
\ No newline at end of file
diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py
deleted file mode 100644 (file)
index f82324d..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-
-import bpy
-
-def particle_panel_enabled(psys):
-       return psys.point_cache.baked==False and psys.editable==False
-       
-def particle_panel_poll(context):
-       psys = context.particle_system
-       if psys==None:  return False
-       return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
-
-class ParticleButtonsPanel(bpy.types.Panel):
-       __space_type__ = "BUTTONS_WINDOW"
-       __region_type__ = "WINDOW"
-       __context__ = "particle"
-
-       def poll(self, context):
-               return particle_panel_poll(context)
-
-class PARTICLE_PT_particles(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_particles"
-       __label__ = "Particle System"
-
-       def poll(self, context):
-               return (context.particle_system or context.object)
-
-       def draw(self, context):
-               layout = self.layout
-               ob = context.object
-               psys = context.particle_system
-
-               split = layout.split(percentage=0.65)
-
-               if psys:
-                       split.template_ID(psys, "settings")
-
-               if psys:
-                       #row = layout.row()
-                       #row.itemL(text="Viewport")
-                       #row.itemL(text="Render")
-                       
-                       part = psys.settings
-                       ptype = psys.settings.type
-                       
-                       if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
-                               layout.itemL(text="No settings for fluid particles")
-                               return
-                               
-                       split = layout.split(percentage=0.65)
-                       
-                       split.enabled = particle_panel_enabled(psys)
-                       split.itemR(part, "type")
-                       split.itemR(psys, "seed")
-                       
-                       split = layout.split(percentage=0.65)
-                       if part.type=='HAIR':
-                               if psys.editable==True:
-                                       split.itemO("PARTICLE_OT_editable_set", text="Free Edit")
-                               else:
-                                       split.itemO("PARTICLE_OT_editable_set", text="Make Editable")
-                               row = split.row()
-                               row.enabled = particle_panel_enabled(psys)
-                               row.itemR(part, "hair_step")
-                       elif part.type=='REACTOR':
-                               split.enabled = particle_panel_enabled(psys)
-                               split.itemR(psys, "reactor_target_object")
-                               split.itemR(psys, "reactor_target_particle_system", text="Particle System")
-               
-class PARTICLE_PT_emission(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_emission"
-       __label__ = "Emission"
-       
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               layout.enabled = particle_panel_enabled(psys)
-               
-               row = layout.row()
-               row.itemR(part, "amount")
-               
-               split = layout.split()
-               
-               col = split.column(align=True)
-               col.itemR(part, "start")
-               col.itemR(part, "end")
-
-               col = split.column(align=True)
-               col.itemR(part, "lifetime")
-               col.itemR(part, "random_lifetime", slider=True)
-               
-               layout.row().itemL(text="Emit From:")
-               
-               row = layout.row()
-               row.itemR(part, "emit_from", expand=True)
-               row = layout.row()
-               row.itemR(part, "trand")
-               if part.distribution!='GRID':
-                       row.itemR(part, "even_distribution")
-               
-               if part.emit_from=='FACE' or part.emit_from=='VOLUME':
-                       row = layout.row()
-                       row.itemR(part, "distribution", expand=True)
-                       
-                       row = layout.row()
-
-                       if part.distribution=='JIT':
-                               row.itemR(part, "userjit", text="Particles/Face")
-                               row.itemR(part, "jitter_factor", text="Jittering Amount", slider=True)
-                       elif part.distribution=='GRID':
-                               row.itemR(part, "grid_resolution")
-
-class PARTICLE_PT_cache(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_cache"
-       __label__ = "Cache"
-       __default_closed__ = True
-       
-       def poll(self, context):
-               psys = context.particle_system
-               if psys==None:  return False
-               return psys.settings.type in ('EMITTER', 'REACTOR')
-
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               cache = psys.point_cache
-               
-               row = layout.row()
-               row.itemR(cache, "name", text="")
-               if cache.outdated:
-                       row.itemL(text="Cache is outdated.")
-               else:
-                       row.itemL(text="")
-               
-               row = layout.row()
-               
-               if cache.baked == True:
-                       row.itemO("PTCACHE_OT_free_bake_particle_system", text="Free Bake")
-               else:
-                       row.item_booleanO("PTCACHE_OT_cache_particle_system", "bake", True, text="Bake")
-                       
-               row = layout.row()
-               row.enabled = particle_panel_enabled(psys)
-               row.itemO("PTCACHE_OT_bake_from_particles_cache", text="Current Cache to Bake")
-               if cache.autocache == 0:
-                       row.itemO("PTCACHE_OT_cache_particle_system", text="Cache to Current Frame")
-       
-               row = layout.row()
-               row.enabled = particle_panel_enabled(psys)
-               #row.itemR(cache, "autocache")
-               row.itemR(cache, "disk_cache")
-               row.itemL(text=cache.info)
-               
-               # for particles these are figured out automatically
-               #row.itemR(cache, "start_frame")
-               #row.itemR(cache, "end_frame")
-
-class PARTICLE_PT_initial(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_initial"
-       __label__ = "Velocity"
-
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               layout.enabled = particle_panel_enabled(psys)
-                               
-               layout.row().itemL(text="Direction:")
-       
-               split = layout.split()
-                       
-               sub = split.column()
-               sub.itemR(part, "normal_factor")
-               if part.emit_from=='PARTICLE':
-                       sub.itemR(part, "particle_factor")
-               else:
-                       sub.itemR(part, "object_factor", slider=True)
-               sub.itemR(part, "random_factor")
-               sub.itemR(part, "tangent_factor")
-               sub.itemR(part, "tangent_phase", slider=True)
-               
-               sub = split.column()
-               sub.itemL(text="TODO:")
-               sub.itemL(text="Object aligned")
-               sub.itemL(text="direction: X, Y, Z")
-               
-               if part.type=='REACTOR':
-                       sub.itemR(part, "reactor_factor")
-                       sub.itemR(part, "reaction_shape", slider=True)
-               else:
-                       sub.itemL(text="")
-               
-               layout.row().itemL(text="Rotation:")
-               split = layout.split()
-                       
-               sub = split.column()
-               
-               sub.itemR(part, "rotation_mode", text="Axis")
-               split = layout.split()
-                       
-               sub = split.column()
-               sub.itemR(part, "rotation_dynamic")
-               sub.itemR(part, "random_rotation_factor", slider=True)
-               sub = split.column()
-               sub.itemR(part, "phase_factor", slider=True)
-               sub.itemR(part, "random_phase_factor", text="Random", slider=True)
-
-               layout.row().itemL(text="Angular velocity:")
-               layout.row().itemR(part, "angular_velocity_mode", expand=True)
-               split = layout.split()
-                       
-               sub = split.column()
-               
-               sub.itemR(part, "angular_velocity_factor", text="")
-               
-class PARTICLE_PT_physics(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_physics"
-       __label__ = "Physics"
-
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               layout.enabled = layout.enabled = particle_panel_enabled(psys)
-
-               row = layout.row()
-               row.itemR(part, "physics_type", expand=True)
-               if part.physics_type != 'NO':
-                       layout.itemR(part, "effector_group")
-               
-                       row = layout.row()
-                       col = row.column(align=True)
-                       col.itemR(part, "particle_size")
-                       col.itemR(part, "random_size", slider=True)
-                       col = row.column(align=True)
-                       col.itemR(part, "mass")
-                       col.itemR(part, "sizemass", text="Multiply mass with size")
-                                                       
-                       split = layout.split()
-                       
-                       sub = split.column()
-                       
-               if part.physics_type == 'NEWTON':
-                       
-                       sub.itemL(text="Forces:")
-                       sub.itemR(part, "brownian_factor")
-                       sub.itemR(part, "drag_factor", slider=True)
-                       sub.itemR(part, "damp_factor", slider=True)
-                       sub.itemR(part, "integrator")
-                       sub = split.column()
-                       sub.itemR(part, "acceleration")
-                       
-               elif part.physics_type == 'KEYED':
-                       sub.itemR(psys, "keyed_first")
-                       if psys.keyed_first==True:
-                               sub.itemR(psys, "timed_keys", text="Key timing")
-                       else:
-                               sub.itemR(part, "keyed_time")
-                       sub = split.column()
-                       sub.itemL(text="Next key from object:")
-                       sub.itemR(psys, "keyed_object", text="")
-                       sub.itemR(psys, "keyed_particle_system")
-               
-               if part.physics_type=='NEWTON' or part.physics_type=='BOIDS':
-
-                       sub.itemR(part, "size_deflect")
-                       sub.itemR(part, "die_on_collision")
-                       sub.itemR(part, "sticky")
-
-class PARTICLE_PT_render(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_render"
-       __label__ = "Render"
-       
-       def poll(self, context):
-               return (context.particle_system != None)
-               
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               row = layout.row()
-               row.itemR(part, "material")
-               row.itemR(psys, "parent");
-               
-               split = layout.split()
-                       
-               sub = split.column()
-               sub.itemR(part, "emitter");
-               sub.itemR(part, "parent");
-               sub = split.column()
-               sub.itemR(part, "unborn");
-               sub.itemR(part, "died");
-               
-               row = layout.row()
-               row.itemR(part, "ren_as", expand=True)
-               
-               split = layout.split()
-                       
-               sub = split.column()
-               
-               if part.ren_as == 'LINE':
-                       sub.itemR(part, "line_length_tail")
-                       sub.itemR(part, "line_length_head")
-                       sub = split.column()
-                       sub.itemR(part, "velocity_length")
-               elif part.ren_as == 'PATH':
-               
-                       if (part.type!='HAIR' and psys.point_cache.baked==False):
-                               box = layout.box()
-                               box.itemL(text="Baked or keyed particles needed for correct rendering.")
-                               return
-                               
-                       sub.itemR(part, "render_strand")
-                       colsub = sub.column()
-                       colsub.active = part.render_strand == False
-                       colsub.itemR(part, "render_adaptive")
-                       colsub = sub.column()
-                       colsub.active = part.render_adaptive or part.render_strand == True
-                       colsub.itemR(part, "adaptive_angle")
-                       colsub = sub.column()
-                       colsub.active = part.render_adaptive == True and part.render_strand == False
-                       colsub.itemR(part, "adaptive_pix")
-                       sub.itemR(part, "hair_bspline")
-                       sub.itemR(part, "render_step", text="Steps")
-                       sub = split.column()
-                       sub.itemL(text="Length:")
-                       sub.itemR(part, "abs_length", text="Absolute")
-                       sub.itemR(part, "absolute_length", text="Maximum")
-                       sub.itemR(part, "random_length", text="Random", slider=True)
-                       
-                       #row = layout.row()
-                       #row.itemR(part, "timed_path")
-                       #col = row.column(align=True)
-                       #col.active = part.timed_path == True
-                       #col.itemR(part, "line_length_tail", text="Start")
-                       #col.itemR(part, "line_length_head", text="End")
-                       
-                       row = layout.row()
-                       col = row.column()
-                       
-                       if part.type=='HAIR' and part.render_strand==True and part.child_type=='FACES':
-                               layout.itemR(part, "enable_simplify")
-                               if part.enable_simplify==True:
-                                       row = layout.row()
-                                       row.itemR(part, "simplify_refsize")
-                                       row.itemR(part, "simplify_rate")
-                                       row.itemR(part, "simplify_transition")
-                                       row = layout.row()
-                                       row.itemR(part, "viewport")
-                                       subrow = row.row()
-                                       subrow.active = part.viewport==True
-                                       subrow.itemR(part, "simplify_viewport")
-                       
-
-               elif part.ren_as == 'OBJECT':
-                       #sub = split.column()
-                       sub.itemR(part, "dupli_object")
-               elif part.ren_as == 'GROUP':
-                       sub.itemR(part, "dupli_group")
-                       split = layout.split()
-                       sub = split.column()
-                       sub.itemR(part, "whole_group")
-                       sub = split.column()
-                       colsub = sub.column()
-                       colsub.active = part.whole_group == False
-                       colsub.itemR(part, "rand_group")
-                       
-               elif part.ren_as == 'BILLBOARD':
-                       sub.itemL(text="Align:")
-                       
-                       row = layout.row()
-                       row.itemR(part, "billboard_align", expand=True)
-                       row.itemR(part, "billboard_lock", text="Lock")
-                       row = layout.row()
-                       row.itemR(part, "billboard_object")
-               
-                       row = layout.row()
-                       col = row.column(align=True)
-                       col.itemL(text="Tilt:")
-                       col.itemR(part, "billboard_tilt", text="Angle", slider=True)
-                       col.itemR(part, "billboard_random_tilt", slider=True)
-                       col = row.column()
-                       col.itemR(part, "billboard_offset")
-                       
-                       row = layout.row()
-                       row.itemR(psys, "billboard_normal_uv")
-                       row = layout.row()
-                       row.itemR(psys, "billboard_time_index_uv")
-                       
-                       row = layout.row()
-                       row.itemL(text="Split uv's:")
-                       row.itemR(part, "billboard_uv_split", text="Number of splits")
-                       row = layout.row()
-                       row.itemR(psys, "billboard_split_uv")
-                       row = layout.row()
-                       row.itemL(text="Animate:")
-                       row.itemR(part, "billboard_animation", expand=True)
-                       row.itemL(text="Offset:")
-                       row.itemR(part, "billboard_split_offset", expand=True)
-               
-class PARTICLE_PT_draw(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_draw"
-       __label__ = "Display"
-       __default_closed__ = True
-       
-       def poll(self, context):
-               return (context.particle_system != None)
-       
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               row = layout.row()
-               row.itemR(part, "draw_as", expand=True)
-               
-               if part.draw_as=='NONE' or (part.ren_as=='NONE' and part.draw_as=='RENDER'):
-                       return
-                       
-               path = (part.ren_as=='PATH' and part.draw_as=='RENDER') or part.draw_as=='PATH'
-                       
-               if path and part.type!='HAIR' and psys.point_cache.baked==False:
-                       box = layout.box()
-                       box.itemL(text="Baked or keyed particles needed for correct drawing.")
-                       return
-               
-               row = layout.row()
-               row.itemR(part, "display", slider=True)
-               if part.draw_as!='RENDER' or part.ren_as=='HALO':
-                       row.itemR(part, "draw_size")
-               else:
-                       row.itemL(text="")
-               
-               row = layout.row()
-               col = row.column()
-               col.itemR(part, "show_size")
-               col.itemR(part, "velocity")
-               col.itemR(part, "num")
-               if part.physics_type == 'BOIDS':
-                       col.itemR(part, "draw_health")
-               
-               col = row.column()
-               if (path):
-                       box = col.box()                         
-                       box.itemR(part, "draw_step")
-               else:
-                       col.itemR(part, "material_color", text="Use material color")
-                       subcol = col.column()
-                       subcol.active = part.material_color==False
-                       #subcol.itemL(text="color")
-                       #subcol.itemL(text="Override material color")
-
-class PARTICLE_PT_children(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_children"
-       __label__ = "Children"
-       __default_closed__ = True
-
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               layout.row().itemR(part, "child_type", expand=True)
-               
-               if part.child_type=='NONE':
-                       return
-               
-               row = layout.row()
-               
-               col = row.column(align=True)
-               col.itemR(part, "child_nbr", text="Display")
-               col.itemR(part, "rendered_child_nbr", text="Render")
-               
-               col = row.column(align=True)
-               
-               if part.child_type=='FACES':
-                       col.itemR(part, "virtual_parents", slider=True)
-               else:
-                       col.itemR(part, "child_radius", text="Radius")
-                       col.itemR(part, "child_roundness", text="Roundness", slider=True)
-               
-                       col = row.column(align=True)
-                       col.itemR(part, "child_size", text="Size")
-                       col.itemR(part, "child_random_size", text="Random")
-               
-               layout.row().itemL(text="Effects:")
-               
-               row = layout.row()
-               
-               col = row.column(align=True)
-               col.itemR(part, "clump_factor", slider=True)
-               col.itemR(part, "clumppow", slider=True)
-               
-               col = row.column(align=True)
-               col.itemR(part, "rough_endpoint")
-               col.itemR(part, "rough_end_shape")
-
-               row = layout.row()
-               
-               col = row.column(align=True)
-               col.itemR(part, "rough1")
-               col.itemR(part, "rough1_size")
-
-               col = row.column(align=True)
-               col.itemR(part, "rough2")
-               col.itemR(part, "rough2_size")
-               col.itemR(part, "rough2_thres", slider=True)
-               
-               layout.row().itemL(text="Kink:")
-               layout.row().itemR(part, "kink", expand=True)
-               
-               split = layout.split()
-               
-               sub = split.column()
-               sub.itemR(part, "kink_amplitude")
-               sub.itemR(part, "kink_frequency")
-               sub = split.column()
-               sub.itemR(part, "kink_shape", slider=True)
-
-class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
-       __idname__= "PARTICLE_PT_vertexgroups"
-       __label__ = "Vertexgroups"
-       __default_closed__ = True
-
-       def draw(self, context):
-               layout = self.layout
-
-               psys = context.particle_system
-               part = psys.settings
-               
-               layout.itemL(text="Nothing here yet.")
-
-               #row = layout.row()
-               #row.itemL(text="Vertex Group")
-               #row.itemL(text="Negate")
-
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_density")
-               #row.itemR(psys, "vertex_group_density_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_velocity")
-               #row.itemR(psys, "vertex_group_velocity_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_length")
-               #row.itemR(psys, "vertex_group_length_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_clump")
-               #row.itemR(psys, "vertex_group_clump_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_kink")
-               #row.itemR(psys, "vertex_group_kink_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_roughness1")
-               #row.itemR(psys, "vertex_group_roughness1_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_roughness2")
-               #row.itemR(psys, "vertex_group_roughness2_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_roughness_end")
-               #row.itemR(psys, "vertex_group_roughness_end_negate", text="")
-
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_size")
-               #row.itemR(psys, "vertex_group_size_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_tangent")
-               #row.itemR(psys, "vertex_group_tangent_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_rotation")
-               #row.itemR(psys, "vertex_group_rotation_negate", text="")
-               
-               #row = layout.row()
-               #row.itemR(psys, "vertex_group_field")
-               #row.itemR(psys, "vertex_group_field_negate", text="")
-               
-bpy.types.register(PARTICLE_PT_particles)
-bpy.types.register(PARTICLE_PT_cache)
-bpy.types.register(PARTICLE_PT_emission)
-bpy.types.register(PARTICLE_PT_initial)
-bpy.types.register(PARTICLE_PT_physics)
-bpy.types.register(PARTICLE_PT_render)
-bpy.types.register(PARTICLE_PT_draw)
-bpy.types.register(PARTICLE_PT_children)
-bpy.types.register(PARTICLE_PT_vertexgroups)
index bd65392ad63426d5d2350b74d84b73bf95f66d6e..09c21b4eb641d3e5714ce612cdafdd092f990fff 100644 (file)
@@ -50,13 +50,13 @@ class Physic_PT_cloth_collision(PhysicButtonsPanel):
        
        def draw_header(self, context):
                layout = self.layout
-               cloth = context.cloth.collision_settings
+               cloth = context.cloth.settings
        
                layout.itemR(cloth, "enable_collision", text="")
 
        def draw(self, context):
                layout = self.layout
-               cloth = context.cloth.collision_settings
+               cloth = context.cloth.settings
                
                layout.active = cloth.enable_collision  
                
@@ -103,4 +103,4 @@ class Physic_PT_cloth_stiffness(PhysicButtonsPanel):
                
 bpy.types.register(Physic_PT_cloth)
 bpy.types.register(Physic_PT_cloth_collision)
-bpy.types.register(Physic_PT_cloth_stiffness)
+bpy.types.register(Physic_PT_cloth_stiffness)
\ No newline at end of file
index 31908d5ec9c72b6c14a0e29165eda0fec132d20a..619b1903b484852ec2417dd719229af673d4ea1e 100644 (file)
@@ -13,9 +13,6 @@ class TEXTURE_PT_preview(TextureButtonsPanel):
        __idname__= "TEXTURE_PT_preview"
        __label__ = "Preview"
 
-       def poll(self, context):
-               return (context.material or context.world or context.lamp or context.texture)
-
        def draw(self, context):
                layout = self.layout
                tex = context.texture
@@ -27,7 +24,7 @@ class TEXTURE_PT_texture(TextureButtonsPanel):
        __label__ = "Texture"
 
        def poll(self, context):
-               return (context.material or context.world or context.lamp or context.texture)
+               return (context.material or context.world or context.lamp)
 
        def draw(self, context):
                layout = self.layout
index 39b5eca04ff284dbe028f716c7c2cb93061a6167..88104c60efc2aa010ea6b95aa26bcb8381fc0112 100644 (file)
@@ -12,9 +12,6 @@ class WorldButtonsPanel(bpy.types.Panel):
 class WORLD_PT_preview(WorldButtonsPanel):
        __label__ = "Preview"
 
-       def poll(self, context):
-               return (context.scene or context.world)
-
        def draw(self, context):
                layout = self.layout
                world = context.world
@@ -179,4 +176,4 @@ bpy.types.register(WORLD_PT_world)
 bpy.types.register(WORLD_PT_ambient_occlusion)
 bpy.types.register(WORLD_PT_mist)
 bpy.types.register(WORLD_PT_stars)
-bpy.types.register(WORLD_PT_color_correction)
+bpy.types.register(WORLD_PT_color_correction)
\ No newline at end of file
diff --git a/release/ui/space_script.py b/release/ui/space_script.py
new file mode 100644 (file)
index 0000000..d35f2d3
--- /dev/null
@@ -0,0 +1,132 @@
+import sys
+import os
+import imp
+# import glob
+import bpy
+
+operators = []
+
+def register_op(opclass):
+    if (hasattr(bpy.ops, opclass.__name__)):
+        bpy.ops.remove(getattr(bpy.ops, opclass.__name__))
+
+    bpy.ops.add(opclass)
+
+    global operators
+    if opclass.__name__ not in operators:
+        operators.append(opclass.__name__)
+
+
+# hint for myself: for interface api documentation, see source/blender/editors/interface/interface_api.c
+# another hint: reloading ui scripts in scripts window is Shift + P
+
+class SCRIPT_HT_header(bpy.types.Header):
+       __space_type__ = "SCRIPTS_WINDOW"
+       __idname__ = "SCRIPT_HT_header"
+
+       def draw(self, context):
+               st = context.space_data
+               layout = self.layout
+
+               layout.template_header(context)
+
+               if context.area.show_menus:
+                       row = layout.row(align=True)
+                       row.itemM(context, "SCRIPT_MT_scripts")
+
+class SCRIPT_MT_scripts(bpy.types.Menu):
+    __space_type__ = "SCRIPTS_WINDOW"
+    __label__ = "Scripts"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.column()
+        layout.itemM(context, "SCRIPT_MT_export")
+        layout.itemO("SCRIPT_OT_reload_scripts")
+
+class SCRIPT_MT_export(bpy.types.Menu):
+    __space_type__ = "SCRIPTS_WINDOW"
+    __label__ = "Export"
+
+    def draw(self, context):
+        global operators
+
+        print("drawing {0} operators: {1}".format(len(operators), operators))
+
+        layout = self.layout
+        layout.column()
+        for opname in operators:
+            layout.itemO(opname)
+
+class SCRIPT_OT_reload_scripts(bpy.types.Operator):
+    __label__ = 'Reload Scripts'
+
+    def execute(self, context):
+        print("SCRIPT_OT_reload_scripts: execute")
+
+        # add ../io to sys.path
+
+        # this module's absolute path
+        abspath = os.path.abspath(sys.modules[__name__].__file__)
+        print("Current abspath: {0}".format(abspath))
+
+        # ../io
+        io = os.path.normpath(os.path.dirname(abspath) + "/../io")
+        print("abspath = " + io)
+
+        if io not in sys.path:
+            sys.path.append(io)
+
+        # for each .py file in release/io,
+        # import/reload module, in the module:
+        # find subclasses of bpy.types.Operator,
+        # for each subclass create menus under "Export"
+        # with (row.)itemO
+
+        global operators
+        operators = []
+
+        # glob unavailable :(
+#         for path in glob.glob("../io/*.py"):
+        for path in os.listdir(io):
+            modname, ext = os.path.splitext(os.path.basename(path))
+
+            if ext != ".py":
+                continue
+
+            print("Found module {0}.".format(modname))
+
+            if modname in sys.modules:
+                mod = imp.reload(sys.modules[modname])
+                print("Reloaded it.")
+            else:
+                mod = __import__(modname)
+                print("Imported it.")
+
+            for attr in dir(mod):
+                cls = getattr(mod, attr)
+                
+                # XXX is there a better way to check that cls is a class?
+                if type(cls) == bpy.types.Operator.__class__ and issubclass(cls, bpy.types.Operator):
+                    print("Found class {0}.".format(cls.__name__))
+                    register_op(cls)
+                    print("Registered it.")
+
+        return ('FINISHED',)
+
+    def invoke(self, context, event):
+        print("SCRIPT_OT_reload_scripts: invoke")
+        return self.execute(context)
+
+    def poll(self, context):
+        pass
+
+bpy.types.register(SCRIPT_HT_header)
+bpy.types.register(SCRIPT_MT_scripts)
+bpy.types.register(SCRIPT_MT_export)
+
+if (hasattr(bpy.ops, "SCRIPT_OT_reload_scripts")):
+    bpy.ops.remove(bpy.ops.SCRIPT_OT_reload_scripts)
+
+bpy.ops.add(SCRIPT_OT_reload_scripts)
+
index 5ea511738add0bc3bc12fed02399e69a9cc26200..091887a4eb7241712cfa20d524c09589498ba6e9 100644 (file)
@@ -39,14 +39,7 @@ struct PartEff;
 struct Scene;
 struct ListBase;
 
-typedef struct DupliObject {
-       struct DupliObject *next, *prev;
-       struct Object *ob;
-       unsigned int origlay;
-       int index, no_draw, type, animated;
-       float mat[4][4], omat[4][4];
-       float orco[3], uv[2];
-} DupliObject;
+#include "DNA_object_types.h"
 
 void free_path(struct Path *path);
 void calc_curvepath(struct Object *ob);
index 3facf9759926f84be1c471cef1863d837c5369ae..9fc8d0ed6091d0b9ceec89e3ebb06c7aecb2b61c 100644 (file)
@@ -542,7 +542,8 @@ void set_mesh(Object *ob, Mesh *me)
        
        if(ob->type==OB_MESH) {
                old= ob->data;
-               old->id.us--;
+               if (old) /* to make set_mesh work on objects created with add_only_object, i.e. having ob->data == NULL */
+                       old->id.us--;
                ob->data= me;
                id_us_plus((ID *)me);
        }
index febf2fe59cd46f060747802074cd3eff37bee6dd..445a948c5cb8561fb3c9bbbb3d27e8316df73009 100644 (file)
@@ -230,6 +230,7 @@ typedef struct Object {
        int pad2;
 
        ListBase gpulamp;               /* runtime, for lamps only */
+       ListBase *duplilist;    /* only for internal use by RNA API functions. To get dupli list, use object_duplilist instead */
 } Object;
 
 /* Warning, this is not used anymore because hooks are now modifiers */
@@ -250,6 +251,14 @@ typedef struct ObHook {
        float force;
 } ObHook;
 
+typedef struct DupliObject {
+       struct DupliObject *next, *prev;
+       struct Object *ob;
+       unsigned int origlay;
+       int index, no_draw, type, animated;
+       float mat[4][4], omat[4][4];
+       float orco[3], uv[2];
+} DupliObject;
 
 /* this work object is defined in object.c */
 extern Object workob;
index e7ca3fc59321946b23675ea91fcb37a2cedef9d9..f7bf176a325f557ad6ae89f27b8343e6162e5af4 100644 (file)
@@ -1853,7 +1853,7 @@ RNAProcessItem PROCESS_ITEMS[]= {
        {"rna_particle.c", NULL, RNA_def_particle},
        {"rna_pose.c", NULL, RNA_def_pose},
        {"rna_property.c", NULL, RNA_def_gameproperty},
-       {"rna_scene.c", NULL, RNA_def_scene},
+       {"rna_scene.c", "rna_scene_api.c", RNA_def_scene},
        {"rna_screen.c", NULL, RNA_def_screen},
        {"rna_scriptlink.c", NULL, RNA_def_scriptlink},
        {"rna_sensor.c", NULL, RNA_def_sensor},
index 7538f103245eca4d50a7b6d914f1a4f806af4f17..09b46a32cb9f3ebbe8de9fdea0ca31115fc9437e 100644 (file)
@@ -192,6 +192,7 @@ void RNA_api_mesh(struct StructRNA *srna);
 void RNA_api_object(struct StructRNA *srna);
 void RNA_api_ui_layout(struct StructRNA *srna);
 void RNA_api_wm(struct StructRNA *srna);
+void RNA_api_scene(struct StructRNA *srna); 
 
 /* ID Properties */
 
index 6d56b2b00f971f94f4bb9d65256f9bb557b54855..08a3b7cee25c81412d3f07cec7574319ecde93da 100644 (file)
 #include "RNA_define.h"
 #include "RNA_types.h"
 
+#include "DNA_object_types.h"
+
 #ifdef RNA_RUNTIME
 
 #include "BKE_main.h"
 #include "BKE_mesh.h"
 #include "BKE_library.h"
+#include "BKE_object.h"
 
 #include "DNA_mesh_types.h"
 
-Mesh *rna_Main_add_mesh(Main *main, char *name)
+static Mesh *rna_Main_add_mesh(Main *main, char *name)
 {
        Mesh *me= add_mesh(name);
        me->id.us--;
        return me;
 }
 
-void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me)
+static void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me)
 {
        if(me->id.us == 0)
                free_libblock(&main->mesh, me);
@@ -57,24 +60,82 @@ void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me)
        /* XXX python now has invalid pointer? */
 }
 
+static Object* rna_Main_add_object(Main *main, int type, char *name)
+{
+       Object *ob= add_only_object(type, name);
+       ob->id.us--;
+       return ob;
+}
+
+/*
+  WARNING: the following example shows when this function should not be called
+
+  ob = bpy.data.add_object()
+  scene.add_object(ob)
+
+  # ob is freed here
+  scene.remove_object(ob)
+
+  # don't do this since ob is already freed!
+  bpy.data.remove_object(ob)
+*/
+static void rna_Main_remove_object(Main *main, ReportList *reports, Object *ob)
+{
+       if(ob->id.us == 0)
+               free_libblock(&main->object, ob);
+       else
+               BKE_report(reports, RPT_ERROR, "Object must have zero users to be removed.");
+}
+
 #else
 
 void RNA_api_main(StructRNA *srna)
 {
        FunctionRNA *func;
-       PropertyRNA *prop;
+       PropertyRNA *parm;
+
+       /* copied from rna_def_object */
+       static EnumPropertyItem object_type_items[] = {
+               {OB_EMPTY, "EMPTY", 0, "Empty", ""},
+               {OB_MESH, "MESH", 0, "Mesh", ""},
+               {OB_CURVE, "CURVE", 0, "Curve", ""},
+               {OB_SURF, "SURFACE", 0, "Surface", ""},
+               {OB_FONT, "TEXT", 0, "Text", ""},
+               {OB_MBALL, "META", 0, "Meta", ""},
+               {OB_LAMP, "LAMP", 0, "Lamp", ""},
+               {OB_CAMERA, "CAMERA", 0, "Camera", ""},
+               {OB_WAVE, "WAVE", 0, "Wave", ""},
+               {OB_LATTICE, "LATTICE", 0, "Lattice", ""},
+               {OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
+               {0, NULL, 0, NULL, NULL}};
+
+       func= RNA_def_function(srna, "add_object", "rna_Main_add_object");
+       RNA_def_function_ui_description(func, "Add a new object.");
+       parm= RNA_def_enum(func, "type", object_type_items, 0, "", "Type of Object.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_string(func, "name", "Object", 0, "", "New name for the datablock.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "object", "Object", "", "New object.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "remove_object", "rna_Main_remove_object");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+       RNA_def_function_ui_description(func, "Remove an object if it has zero users.");
+       parm= RNA_def_pointer(func, "object", "Object", "", "Object to remove.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
 
        func= RNA_def_function(srna, "add_mesh", "rna_Main_add_mesh");
        RNA_def_function_ui_description(func, "Add a new mesh.");
-       prop= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock.");
-       prop= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh.");
-       RNA_def_function_return(func, prop);
+       parm= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh.");
+       RNA_def_function_return(func, parm);
 
        func= RNA_def_function(srna, "remove_mesh", "rna_Main_remove_mesh");
        RNA_def_function_flag(func, FUNC_USE_REPORTS);
        RNA_def_function_ui_description(func, "Remove a mesh if it has zero users.");
-       prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove.");
-       RNA_def_property_flag(prop, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
 }
 
 #endif
index da90b9f4c76dd153d500302cc2fffad2da84a13d..4b4c9b97871c31e2629382c72777d2ed2a6d2823 100644 (file)
@@ -38,6 +38,9 @@
 
 #ifdef RNA_RUNTIME
 
+#include "BLI_arithb.h" /* CalcNormFloat */
+
+
 static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
 {
        MVert *mvert= (MVert*)ptr->data;
@@ -183,6 +186,26 @@ static void rna_MeshFace_material_index_range(PointerRNA *ptr, int *min, int *ma
        *max= me->totcol-1;
 }
 
+static void rna_MeshFace_normal_get(PointerRNA *ptr, float *value)
+{
+       float *vert[4];
+       MFace *face = (MFace*)ptr->data;
+       Mesh *me= (Mesh*)ptr->id.data;
+
+       vert[0] = me->mvert[face->v1].co;
+       vert[1] = me->mvert[face->v2].co;
+       vert[2] = me->mvert[face->v3].co;
+
+       /* copied from MFace_getNormal (old python API) */
+       if (face->v4) {
+               vert[3] = me->mvert[face->v4].co;
+               CalcNormFloat4(vert[0], vert[1], vert[2], vert[3], value);
+       }
+       else {
+               CalcNormFloat(vert[0], vert[1], vert[2], value);
+       }
+}
+
 static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
 {
        Mesh *me= (Mesh*)ptr->id.data;
@@ -234,6 +257,23 @@ static int rna_Mesh_uv_layers_length(PointerRNA *ptr)
        return rna_CustomDataLayer_length(ptr, CD_MTFACE);
 }
 
+static PointerRNA rna_Mesh_active_uv_layer_get(PointerRNA *ptr)
+{
+       CustomDataLayer *active_layer;
+       Mesh *me;
+       int layer_index;
+
+       active_layer= NULL;
+       me= (Mesh*)ptr->data;
+
+       if (CustomData_has_layer(&me->fdata, CD_MTFACE)) {
+               layer_index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
+               active_layer= &me->fdata.layers[layer_index];
+       }
+
+       return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, active_layer);
+}
+
 static void rna_MeshTextureFace_uv1_get(PointerRNA *ptr, float *values)
 {
        MTFace *mtface= (MTFace*)ptr->data;
@@ -696,6 +736,11 @@ static void rna_def_medge(BlenderRNA *brna)
        prop= RNA_def_property(srna, "sharp", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP);
        RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier");
+
+       prop= RNA_def_property(srna, "loose", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Loose", "Loose edge");
 }
 
 static void rna_def_mface(BlenderRNA *brna)
@@ -732,6 +777,12 @@ static void rna_def_mface(BlenderRNA *brna)
        prop= RNA_def_property(srna, "smooth", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
        RNA_def_property_ui_text(prop, "Smooth", "");
+
+       prop= RNA_def_property(srna, "normal", PROP_FLOAT, PROP_VECTOR);
+       RNA_def_property_array(prop, 3);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_float_funcs(prop, "rna_MeshFace_normal_get", NULL, NULL);
+       RNA_def_property_ui_text(prop, "Normal", "Face normal");
 }
 
 static void rna_def_mtface(BlenderRNA *brna)
@@ -1081,6 +1132,11 @@ static void rna_def_mesh(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
        RNA_def_property_ui_text(prop, "UV Layers", "");
 
+       prop= RNA_def_property(srna, "active_uv_layer", PROP_POINTER, PROP_NONE);
+       RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
+       RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_uv_layer_get", NULL, NULL);
+       RNA_def_property_ui_text(prop, "Active UV layer", "Active UV layer.");
+
        prop= RNA_def_property(srna, "vcol_layers", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
        RNA_def_property_collection_funcs(prop, "rna_Mesh_vcol_layers_begin", 0, 0, 0, "rna_Mesh_vcol_layers_length", 0, 0, 0, 0);
index 26fb77777d7c92f830d66ccf69de27e15c76f7a9..984e6a5d30f1b16fe205dca86e11d7329fabacaa 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "BKE_customdata.h"
 #include "BKE_DerivedMesh.h"
+#include "BLI_arithb.h"
 
 #include "DNA_mesh_types.h"
 #include "DNA_scene_types.h"
@@ -54,8 +55,15 @@ void rna_Mesh_copy_applied(Mesh *me, Scene *sce, Object *ob)
 }
 */
 
-void rna_Mesh_transform(Mesh *me, float **mat)
+void rna_Mesh_transform(Mesh *me, float *mat)
 {
+       /* TODO: old API transform had recalc_normals option */
+       int i;
+       MVert *mvert= me->mvert;
+
+       for(i= 0; i < me->totvert; i++, mvert++) {
+               Mat4MulVecfl(mat, mvert->co);
+       }
 }
 
 #if 0
@@ -85,14 +93,13 @@ static void rna_Mesh_verts_add(PointerRNA *ptr, PointerRNA *ptr_item)
 
 void RNA_api_mesh(StructRNA *srna)
 {
-       /*FunctionRNA *func;
-       PropertyRNA *prop;*/
+       FunctionRNA *func;
+       PropertyRNA *parm;
 
-       /*
-       func= RNA_def_function(srna, "copy", "rna_Mesh_copy");
-       RNA_def_function_ui_description(func, "Copy mesh data.");
-       prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from.");
-       RNA_def_property_flag(prop, PROP_REQUIRED);*/
+       func= RNA_def_function(srna, "transform", "rna_Mesh_transform");
+       RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix.");
+       parm= RNA_def_float_matrix(func, "matrix", 16, NULL, 0.0f, 0.0f, "", "Matrix.", 0.0f, 0.0f);
+       RNA_def_property_flag(parm, PROP_REQUIRED);
 
        /*
        func= RNA_def_function(srna, "add_geom", "rna_Mesh_add_geom");
index 3721c7d4ccb0de5c5423960ba9048345dd8a4692..76553e09fb2b97677e3962891ed89707224d2c8b 100644 (file)
@@ -364,6 +364,14 @@ static void rna_GameObjectSettings_state_set(PointerRNA *ptr, const int *values)
        }
 }
 
+static PointerRNA rna_DupliObject_object_get(PointerRNA *ptr)
+{
+       DupliObject *dob= (DupliObject*)ptr->data;
+       PointerRNA newptr;
+       RNA_pointer_create(&dob->ob->id, &RNA_Object, dob->ob, &newptr);
+       return newptr;
+}
+
 #else
 
 static void rna_def_vertex_group(BlenderRNA *brna)
@@ -1022,6 +1030,12 @@ static void rna_def_object(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Dupli Frames Off", "Recurring frames to exclude from the Dupliframes.");
        RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_update");
 
+       prop= RNA_def_property(srna, "dupli_list", PROP_COLLECTION, PROP_NONE);
+       RNA_def_property_collection_sdna(prop, NULL, "duplilist", NULL);
+       RNA_def_property_struct_type(prop, "DupliObject");
+       RNA_def_property_ui_text(prop, "Dupli list", "Object duplis.");
+
+
        /* time offset */
 
        prop= RNA_def_property(srna, "time_offset", PROP_FLOAT, PROP_NONE);
@@ -1158,12 +1172,43 @@ static void rna_def_object(BlenderRNA *brna)
        RNA_api_object(srna);
 }
 
+static void rna_def_dupli_object(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna= RNA_def_struct(brna, "DupliObject", NULL);
+       RNA_def_struct_sdna(srna, "DupliObject");
+       RNA_def_struct_ui_text(srna, "Dupli Object", "Dupli Object data."); 
+       /* RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); */
+
+       prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+       RNA_def_property_struct_type(prop, "Object");
+       RNA_def_property_pointer_sdna(prop, NULL, "ob");
+       RNA_def_property_pointer_funcs(prop, "rna_DupliObject_object_get", NULL, NULL);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Object", "Object this DupliObject represents.");
+
+       prop= RNA_def_property(srna, "ob_matrix", PROP_FLOAT, PROP_MATRIX);
+       RNA_def_property_float_sdna(prop, NULL, "omat");
+       RNA_def_property_array(prop, 16);
+       RNA_def_property_ui_text(prop, "Object Matrix", "Object transformation matrix.");
+
+       prop= RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX);
+       RNA_def_property_float_sdna(prop, NULL, "mat");
+       RNA_def_property_array(prop, 16);
+       RNA_def_property_ui_text(prop, "DupliObject Matrix", "DupliObject transformation matrix.");
+
+       /* TODO: DupliObject has more properties that can be wrapped */
+}
+
 void RNA_def_object(BlenderRNA *brna)
 {
        rna_def_object(brna);
        rna_def_object_game_settings(brna);
        rna_def_vertex_group(brna);
        rna_def_material_slot(brna);
+       rna_def_dupli_object(brna);
 }
 
 #endif
index 053ab115b3b19e669a1f42221055a895e8b9c125..1b6c298eba4b2f8b726203b533ccd0865211aed8 100644 (file)
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
+#include <time.h>
 
 #include "RNA_define.h"
 #include "RNA_types.h"
 
+#include "DNA_object_types.h"
+
 #ifdef RNA_RUNTIME
 
 #include "BKE_customdata.h"
 #include "BKE_DerivedMesh.h"
+#include "BKE_anim.h"
+#include "BKE_report.h"
+#include "BKE_depsgraph.h"
 
 #include "DNA_mesh_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_arithb.h"
+
+#include "BLO_sys_types.h" /* needed for intptr_t used in ED_mesh.h */
+
+#include "ED_mesh.h"
 
 /* copied from init_render_mesh (render code) */
-Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene)
+static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int render_mesh)
 {
-       CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL;
+       /* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
+       CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
+                                                                                  for example, needs CD_MASK_MDEFORMVERT */
        DerivedMesh *dm;
        Mesh *me;
+       Scene *sce;
+
+       sce= CTX_data_scene(C);
        
        /* TODO: other types */
-       if(ob->type != OB_MESH)
+       if(ob->type != OB_MESH) {
+               BKE_report(reports, RPT_ERROR, "Object should be of type MESH.");
                return NULL;
+       }
        
-       dm= mesh_create_derived_render(scene, ob, mask);
+       dm= render_mesh ? mesh_create_derived_render(sce, ob, mask) : mesh_create_derived_view(sce, ob, mask);
 
-       if(!dm)
+       if(!dm) {
+               /* TODO: report */
                return NULL;
+       }
 
        me= add_mesh("tmp_render_mesh");
        me->id.us--; /* we don't assign it to anything */
@@ -64,19 +87,121 @@ Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene)
        return me;
 }
 
+static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports)
+{
+       return create_mesh(ob, C, reports, 1);
+}
+
+static Mesh *rna_Object_create_preview_mesh(Object *ob, bContext *C, ReportList *reports)
+{
+       return create_mesh(ob, C, reports, 0);
+}
+
+/* When no longer needed, duplilist should be freed with Object.free_duplilist */
+static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports)
+{
+       if (!(ob->transflag & OB_DUPLI)) {
+               BKE_report(reports, RPT_ERROR, "Object does not have duplis.");
+               return;
+       }
+
+       /* free duplilist if a user forgets to */
+       if (ob->duplilist) {
+               BKE_reportf(reports, RPT_WARNING, "%s.dupli_list has not been freed.", RNA_struct_identifier(&RNA_Object));
+
+               free_object_duplilist(ob->duplilist);
+               ob->duplilist= NULL;
+       }
+
+       ob->duplilist= object_duplilist(CTX_data_scene(C), ob);
+
+       /* ob->duplilist should now be freed with Object.free_duplilist */
+}
+
+static void rna_Object_free_duplilist(Object *ob, ReportList *reports)
+{
+       if (ob->duplilist) {
+               free_object_duplilist(ob->duplilist);
+               ob->duplilist= NULL;
+       }
+}
+
+static void rna_Object_convert_to_triface(Object *ob, bContext *C, ReportList *reports, Scene *sce)
+{
+       Mesh *me;
+       int ob_editing = CTX_data_edit_object(C) == ob;
+
+       if (ob->type != OB_MESH) {
+               BKE_report(reports, RPT_ERROR, "Object should be of type MESH.");
+               return;
+       }
+
+       me= (Mesh*)ob->data;
+
+       if (!ob_editing)
+               make_editMesh(sce, ob);
+
+       /* select all */
+       EM_set_flag_all(me->edit_mesh, SELECT);
+
+       convert_to_triface(me->edit_mesh, 0);
+
+       load_editMesh(sce, ob);
+
+       if (!ob_editing)
+               free_editMesh(me->edit_mesh);
+
+       DAG_object_flush_update(sce, ob, OB_RECALC_DATA);
+}
+
+
 #else
 
 void RNA_api_object(StructRNA *srna)
 {
        FunctionRNA *func;
-       PropertyRNA *prop;
+       PropertyRNA *parm;
+
+       /* copied from rna_def_object */
+       static EnumPropertyItem object_type_items[] = {
+               {OB_EMPTY, "EMPTY", 0, "Empty", ""},
+               {OB_MESH, "MESH", 0, "Mesh", ""},
+               {OB_CURVE, "CURVE", 0, "Curve", ""},
+               {OB_SURF, "SURFACE", 0, "Surface", ""},
+               {OB_FONT, "TEXT", 0, "Text", ""},
+               {OB_MBALL, "META", 0, "Meta", ""},
+               {OB_LAMP, "LAMP", 0, "Lamp", ""},
+               {OB_CAMERA, "CAMERA", 0, "Camera", ""},
+               {OB_WAVE, "WAVE", 0, "Wave", ""},
+               {OB_LATTICE, "LATTICE", 0, "Lattice", ""},
+               {OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
+               {0, NULL, 0, NULL, NULL}};
 
        func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh");
-       RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied.");
-       prop= RNA_def_pointer(func, "scene", "Scene", "", "");
-       RNA_def_property_flag(prop, PROP_REQUIRED);
-       prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
-       RNA_def_function_return(func, prop);
+       RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for rendering.");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
+       parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "create_preview_mesh", "rna_Object_create_preview_mesh");
+       RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for preview.");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
+       parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
+       RNA_def_function_return(func, parm);
+       
+       func= RNA_def_function(srna, "create_dupli_list", "rna_Object_create_duplilist");
+       RNA_def_function_ui_description(func, "Create a list of dupli objects for this object, needs to be freed manually with free_dupli_list.");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
+
+       func= RNA_def_function(srna, "free_dupli_list", "rna_Object_free_duplilist");
+       RNA_def_function_ui_description(func, "Free the list of dupli objects.");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+
+       func= RNA_def_function(srna, "convert_to_triface", "rna_Object_convert_to_triface");
+       RNA_def_function_ui_description(func, "Convert all mesh faces to triangles.");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
+       parm= RNA_def_pointer(func, "scene", "Scene", "", "Scene where the object belongs.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
 }
 
 #endif
index 47c9025149ab84a7493e00ca23a9c08f88f04d32..1017703c56b91eaf0ae9b90c16f3f9f60e590b06 100644 (file)
@@ -1018,6 +1018,8 @@ void RNA_def_scene(BlenderRNA *brna)
 
        rna_def_tool_settings(brna);
        rna_def_scene_render_data(brna);
+
+       RNA_api_scene(srna);
 }
 
 #endif
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
new file mode 100644 (file)
index 0000000..a38622b
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * $Id: rna_object_api.c 21115 2009-06-23 19:17:59Z kazanbas $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * 
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_object_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_scene.h"
+#include "ED_object.h"
+
+static void rna_Scene_add_object(Scene *sce, ReportList *reports, Object *ob)
+{
+       Base *base= object_in_scene(ob, sce);
+       if (base) {
+               BKE_report(reports, RPT_ERROR, "Object is already in this scene.");
+               return;
+       }
+       base= scene_add_base(sce, ob);
+       ob->id.us++;
+
+       /* this is similar to what object_add_type and add_object do */
+       ob->lay= base->lay= sce->lay;
+       ob->recalc |= OB_RECALC;
+
+       DAG_scene_sort(sce);
+}
+
+static void rna_Scene_remove_object(Scene *sce, ReportList *reports, Object *ob)
+{
+       Base *base= object_in_scene(ob, sce);
+       if (!base) {
+               BKE_report(reports, RPT_ERROR, "Object is not in this scene.");
+               return;
+       }
+       /* as long as ED_base_object_free_and_unlink calls free_libblock_us, we don't have to decrement ob->id.us */
+       ED_base_object_free_and_unlink(sce, base);
+}
+
+#else
+
+void RNA_api_scene(StructRNA *srna)
+{
+       FunctionRNA *func;
+       PropertyRNA *parm;
+
+       func= RNA_def_function(srna, "add_object", "rna_Scene_add_object");
+       RNA_def_function_ui_description(func, "Add object to scene.");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+       parm= RNA_def_pointer(func, "object", "Object", "", "Object to add to scene.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
+       func= RNA_def_function(srna, "remove_object", "rna_Scene_remove_object");
+       RNA_def_function_ui_description(func, "Remove object from scene.");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+       parm= RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+}
+
+#endif
+