Merge from 2.5 r21160 through r21285
authorArystanbek Dyussenov <arystan.d@gmail.com>
Wed, 1 Jul 2009 13:37:52 +0000 (13:37 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Wed, 1 Jul 2009 13:37:52 +0000 (13:37 +0000)
33 files changed:
release/io/export_obj.py [new file with mode: 0644]
release/io/export_ply.py
release/scripts/3ds_export.py
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]
source/blender/python/intern/bpy_interface.c
source/blender/python/intern/bpy_operator_wrap.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_sys.c [new file with mode: 0644]
source/blender/python/intern/bpy_sys.h [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..d139e87
--- /dev/null
@@ -0,0 +1,961 @@
+#!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 os # os.sep
+import Mathutils
+
+# 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(' ', '_')
+
+
+# this used to be in BPySys module
+# frankly, I don't understand how it works
+def BPySys_cleanName(name):
+
+       v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]
+
+       invalid = ''.join([chr(i) for i in v])
+
+       for ch in invalid:
+               name = name.replace(ch, '_')
+       return name
+
+# A Dict of Materials
+# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
+MTL_DICT = {} 
+
+def write_mtl(scene, filename):
+
+       world = scene.world
+       worldAmb = world.ambient_color
+
+       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.items():
+               
+               # 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.specular_hardness-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
+                       file.write('Ka %.6f %.6f %.6f\n' %      tuple([c*mat.ambient for c in worldAmb])  ) # Ambient, uses mirror colour,
+                       file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.diffuse_reflection for c in mat.diffuse_color]) ) # Diffuse
+                       file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_reflection for c in mat.specular_color]) ) # 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.shadeless:
+                               file.write('illum 0\n') # ignore lighting
+                       elif mat.specular_reflection == 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.textures:
+                               if mtex and mtex.texure.type == 'IMAGE':
+                                       try:
+                                               filename = mtex.texture.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] != os.sep:
+               dest_dir += os.sep
+#      if dest_dir[-1] != sys.sep:
+#              dest_dir += sys.sep
+       
+       # Get unique image names
+       uniqueImages = {}
+       for matname, mat, image in MTL_DICT.values(): # 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.textures:
+                               if mtex and mtex.texture.type == 'IMAGE':
+                                       image_tex = mtex.texture.image
+                                       if image_tex:
+                                               try:
+                                                       uniqueImages[image_tex] = image_tex
+                                               except:
+                                                       pass
+       
+       # Now copy images
+       copyCount = 0
+       
+       for bImage in uniqueImages.values():
+               image_path = bpy.sys.expandpath(bImage.filename)
+               if bpy.sys.exists(image_path):
+                       # Make a name for the target path.
+                       dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
+                       if not bpy.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)
+
+# XXX not converted
+def test_nurbs_compat(ob):
+       if ob.type != 'CURVE':
+               return False
+       
+       for nu in ob.data.curves:
+               if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier
+                       return True
+
+#      for nu in ob.data:
+#              if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier
+#                      return True
+       
+       return False
+
+# XXX not converted
+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 range(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 range(tot_parm)]
+               
+               if do_endpoints: # end points, force param
+                       for i in range(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.items()] # 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 = bpy.sys.time()
+#      time1 = sys.time()
+#      scn = Scene.GetCurrent()
+
+       file = open(filename, "w")
+       
+       # Write Header
+       version = "2.5"
+       file.write('# Blender3D v%s OBJ File: %s\n' % (version, bpy.data.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] ))
+       
+       if EXPORT_ROTX90:
+               mat_xrot90= Mathutils.RotationMatrix(-90, 4, 'x')
+               
+       # 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':
+                       # XXX
+                       print('creating dupli_list on', ob_main.name)
+                       ob_main.create_dupli_list()
+
+               # ignore dupli children
+               if ob_main.parent and ob_main.parent.dupli_type != 'NONE':
+                       # XXX
+                       print(ob_main.name, 'is a dupli child - ignoring')
+                       continue
+
+               obs = []
+               if ob_main.dupli_type != 'NONE':
+                       obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list]
+
+                       # XXX
+                       print(ob_main.name, 'has', len(obs), 'dupli children')
+               else:
+                       obs = [(ob_main, ob_main.matrix)]
+
+               for ob, ob_mat in obs:
+
+                       if EXPORT_ROTX90:
+                               ob_mat = ob_mat * mat_xrot90
+
+                       # 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
+
+                       if EXPORT_APPLY_MODIFIERS:
+                               me = ob.create_mesh('PREVIEW')
+                       else:
+                               me = ob.data.create_copy()
+
+                       me.transform(ob_mat)
+
+#                      # 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 f.verts[3] != 0:
+                                               has_quads = True
+                                               break
+                               
+                               if has_quads:
+                                       newob = bpy.data.add_object('MESH', 'temp_object')
+                                       newob.data = me
+                                       # if we forget to set Object.data - crash
+                                       scene.add_object(newob)
+                                       newob.convert_to_triface(scene)
+                                       # mesh will still be there
+                                       scene.remove_object(newob)
+
+                       # 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                         
+
+                               # clean up
+                               bpy.data.remove_mesh(me)
+
+                               continue # dont bother with this mesh.
+                       
+                       # XXX
+                       # High Quality Normals
+                       if EXPORT_NORMALS and face_index_pairs:
+                               pass
+#                              if EXPORT_NORMALS_HQ:
+#                                      BPyMesh.meshCalcNormals(me)
+#                              else:
+#                                      # transforming normals is incorrect
+#                                      # when the matrix is scaled,
+#                                      # better to recalculate them
+#                                      me.calcNormals()
+                       
+                       materials = me.materials
+                       
+                       materialNames = []
+                       materialItems = [m for m in 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
+                               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 f.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)
+                                                       if noKey not in globalNormals:
+                                                               globalNormals[noKey] = totno
+                                                               totno +=1
+                                                               file.write('vn %.6f %.6f %.6f\n' % noKey)
+                                       else:
+                                               # Hard, 1 normal from the face.
+                                               noKey = veckey3d(f.normal)
+                                               if noKey not in globalNormals:
+                                                       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]
+
+                               if f.verts[3] == 0:
+                                       f_v.pop()
+
+#                              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[3] != 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.
+
+                               # 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)) ) # 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('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
+                                                       
+                                               else: # No smoothing, face normals
+                                                       no = globalNormals[ veckey3d(f.normal) ]
+                                                       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
+                                       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
+                                       
+                                       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) ]) )
+                                               else: # No smoothing, face normals
+                                                       no = globalNormals[ veckey3d(f.normal) ]
+                                                       for v in f_v:
+                                                               file.write( ' %d//%d' % (v["index"] + totverts, no) )
+                                       else: # No Normals
+                                               for v in f_v:
+                                                       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))
+                               
+                       # 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)
+
+               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" % (bpy.sys.time() - time1))
+#      print "OBJ Export time: %.2f" % (sys.time() - time1)
+
+def do_export(filename, context, 
+                         EXPORT_APPLY_MODIFIERS = True, # not used
+                         EXPORT_ROTX90 = True, # wrong
+                         EXPORT_TRI = False, # ok
+                         EXPORT_EDGES = False,
+                         EXPORT_NORMALS = False, # not yet
+                         EXPORT_NORMALS_HQ = False, # not yet
+                         EXPORT_UV = True, # ok
+                         EXPORT_MTL = True,
+                         EXPORT_SEL_ONLY = True, # ok
+                         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):
+       #       Window.EditMode(0)
+       #       Window.WaitCursor(1)
+
+       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 = range(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.props.StringProperty(attr="filename", name="File Name", description="File name used for exporting the PLY file", maxlen= 1024, default= ""),
+
+               # context group
+               bpy.props.BoolProperty(attr="use_selection", name="Selection Only", description="", default= True),
+               bpy.props.BoolProperty(attr="use_all_scenes", name="All Scenes", description="", default= False),
+               bpy.props.BoolProperty(attr="use_animation", name="All Animation", description="", default= False),
+
+               # object group
+               bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="", default= True),
+               bpy.props.BoolProperty(attr="use_rotate90", name="Rotate X90", description="", default= True),
+
+               # extra data group
+               bpy.props.BoolProperty(attr="use_edges", name="Edges", description="", default= True),
+               bpy.props.BoolProperty(attr="use_normals", name="Normals", description="", default= False),
+               bpy.props.BoolProperty(attr="use_hq_normals", name="High Quality Normals", description="", default= True),
+               bpy.props.BoolProperty(attr="use_uvs", name="UVs", description="", default= True),
+               bpy.props.BoolProperty(attr="use_materials", name="Materials", description="", default= True),
+               bpy.props.BoolProperty(attr="copy_images", name="Copy Images", description="", default= False),
+               bpy.props.BoolProperty(attr="use_triangles", name="Triangulate", description="", default= False),
+               bpy.props.BoolProperty(attr="use_vertex_groups", name="Polygroups", description="", default= False),
+               bpy.props.BoolProperty(attr="use_nurbs", name="Nurbs", description="", default= False),
+
+               # grouping group
+               bpy.props.BoolProperty(attr="use_blen_objects", name="Objects as OBJ Objects", description="", default= True),
+               bpy.props.BoolProperty(attr="group_by_object", name="Objects as OBJ Groups ", description="", default= False),
+               bpy.props.BoolProperty(attr="group_by_material", name="Material Groups", description="", default= False),
+               bpy.props.BoolProperty(attr="keep_vertex_order", name="Keep Vertex Order", description="", default= False)
+       ]
+       
+       def execute(self, context):
+
+               do_export(self.filename, context,
+                                 EXPORT_TRI=self.use_triangles,
+                                 EXPORT_EDGES=self.use_edges,
+                                 EXPORT_NORMALS=self.use_normals,
+                                 EXPORT_NORMALS_HQ=self.use_hq_normals,
+                                 EXPORT_UV=self.use_uvs,
+                                 EXPORT_MTL=self.use_materials,
+                                 EXPORT_COPY_IMAGES=self.copy_images,
+                                 EXPORT_APPLY_MODIFIERS=self.use_modifiers,
+                                 EXPORT_ROTX90=self.use_rotate90,
+                                 EXPORT_BLEN_OBS=self.use_blen_objects,
+                                 EXPORT_GROUP_BY_OB=self.group_by_object,
+                                 EXPORT_GROUP_BY_MAT=self.group_by_material,
+                                 EXPORT_KEEP_VERT_ORDER=self.keep_vertex_order,
+                                 EXPORT_POLYGROUPS=self.use_vertex_groups,
+                                 EXPORT_CURVE_AS_NURBS=self.use_nurbs,
+                                 EXPORT_SEL_ONLY=self.use_selection,
+                                 EXPORT_ALL_SCENES=self.use_all_scenes)
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+       
+       def poll(self, context): # Poll isnt working yet
+               print("Poll")
+               return context.active_object != None
+
+bpy.ops.add(EXPORT_OT_obj)
+
+if __name__ == "__main__":
+       bpy.ops.EXPORT_OT_obj(filename="/tmp/test.obj")
+
+# CONVERSION ISSUES
+# - matrix problem
+# - duplis - only tested dupliverts
+# - NURBS - needs API additions
+# - all scenes export
+# - normals calculation
index ed983c2b1695d8897826de6144170fe35c0d3717..ce1cdc55d09ed663ba7a94ecc58d28edbdf3eb3d 100644 (file)
@@ -64,7 +64,7 @@ def write(filename, scene, ob, \
                raise Exception("Error, Select 1 active object")
                return
        
-       file = open(filename, 'wb')
+       file = open(filename, 'w')
        
        
        #EXPORT_EDGES = Draw.Create(0)
@@ -123,8 +123,8 @@ def write(filename, scene, ob, \
        mesh_verts = mesh.verts # save a lookup
        ply_verts = [] # list of dictionaries
        # vdict = {} # (index, normal, uv) -> new index
-       vdict = [{} for i in xrange(len(mesh_verts))]
-       ply_faces = [[] for f in xrange(len(mesh.faces))]
+       vdict = [{} for i in range(len(mesh_verts))]
+       ply_faces = [[] for f in range(len(mesh.faces))]
        vert_count = 0
        for i, f in enumerate(mesh.faces):
                
index 87680bce1b0cb0b236c1180b54ddb2b53c7a2326..69b4d00b4d81dfba7a14b97df9128a7b3bde2a29 100644 (file)
@@ -863,19 +863,24 @@ def make_kf_obj_node(obj, name_to_id):
 """
 
 import BPyMessages
-def save_3ds(filename):
+def save_3ds(filename, context):
        '''Save the Blender scene to a 3ds file.'''
        # Time the export
        
        if not filename.lower().endswith('.3ds'):
                filename += '.3ds'
-       
-       if not BPyMessages.Warning_SaveOver(filename):
-               return
-       
-       time1= Blender.sys.time()
-       Blender.Window.WaitCursor(1)
-       sce= bpy.data.scenes.active
+
+       # XXX
+#      if not BPyMessages.Warning_SaveOver(filename):
+#              return
+
+       # XXX
+    time1 = bpy.sys.time()
+#      time1= Blender.sys.time()
+#      Blender.Window.WaitCursor(1)
+
+       sce = context.scene
+#      sce= bpy.data.scenes.active
        
        # Initialize the main chunk (primary):
        primary = _3ds_chunk(PRIMARY)
@@ -901,7 +906,8 @@ def save_3ds(filename):
        # each material is added once):
        materialDict = {}
        mesh_objects = []
-       for ob in sce.objects.context:
+       for ob in context.selected_objects:
+#      for ob in sce.objects.context:
                for ob_derived, mat in getDerivedObjects(ob, False):
                        data = getMeshFromObject(ob_derived, None, True, False, sce)
                        if data:
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 85580c9..0000000
+++ /dev/null
@@ -1,630 +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
-       if psys.settings==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
-
-               if ob:
-                       row = layout.row()
-
-                       row.template_list(ob, "particle_systems", "active_particle_system_index")
-
-                       col = row.column(align=True)
-                       col.itemO("OBJECT_OT_particle_system_add", icon="ICON_ZOOMIN", text="")
-                       col.itemO("OBJECT_OT_particle_system_remove", icon="ICON_ZOOMOUT", text="")
-
-               if psys:
-                       split = layout.split(percentage=0.65)
-                       
-                       split.template_ID(psys, "settings", new="PARTICLE_OT_new")
-                       
-                       #row = layout.row()
-                       #row.itemL(text="Viewport")
-                       #row.itemL(text="Render")
-                       
-                       part = psys.settings
-                       
-                       if part:
-                               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
-               if psys.settings==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")
-               
-               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")
-               
-               subrow = row.row()
-               subrow.enabled = (cache.frames_skipped or cache.outdated) and particle_panel_enabled(psys)
-               subrow.itemO("PTCACHE_OT_cache_particle_system", text="Calculate to Current Frame")
-               
-               row = layout.row()
-               row.enabled = particle_panel_enabled(psys)
-               row.itemO("PTCACHE_OT_bake_from_particles_cache", text="Current Cache to Bake")
-               row.itemR(cache, "step");
-       
-               row = layout.row()
-               row.enabled = particle_panel_enabled(psys)
-               row.itemR(cache, "quick_cache")
-               row.itemR(cache, "disk_cache")
-               
-               layout.itemL(text=cache.info)
-               
-               layout.itemS()
-               
-               row = layout.row()
-               row.item_booleanO("PTCACHE_OT_bake_all", "bake", True, text="Bake All Dynamics")
-               row.itemO("PTCACHE_OT_free_bake_all", text="Free All Bakes")
-               layout.itemO("PTCACHE_OT_bake_all", text="Update All Dynamics to current frame")
-               
-               # 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):
-               psys = context.particle_system
-               if psys==None: return False
-               if psys.settings==None: return False
-               return True;
-               
-       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):
-               psys = context.particle_system
-               if psys==None: return False
-               if psys.settings==None: return False
-               return True;
-       
-       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 a06c644322ad8f26e52072b356d29009108da80d..df4b84454749a25196ab8711dfca85353d913ce8 100644 (file)
@@ -97,13 +97,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  
                
@@ -151,4 +151,4 @@ class Physic_PT_cloth_stiffness(PhysicButtonsPanel):
 bpy.types.register(Physic_PT_cloth)
 bpy.types.register(PHYSICS_PT_cloth_cache)
 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..9b0809f
--- /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("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("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 c42bc866f99528bd279cc41dc7ff5a90b732d6b0..e779f901b3c4ef494704357c0384e0bdab20323c 100644 (file)
@@ -1922,7 +1922,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 3d66682771dd7b3616dcbc947f1689c87244722b..f465e733d68b475919eb8f0d923c4d8828970d2c 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 41d64a8dbb95b73bf05cd098d17fd9c9cc478241..2133ff2615773052e9df38f1c070e8c69a92e5ed 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;
@@ -742,6 +765,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)
@@ -778,6 +806,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)
index c98b3fb7b09f1b8d53b8ed2dd765717b934b0025..00d5bacfef0f9b44d87b2c61a37208ce5677a4ea 100644 (file)
 #include "BKE_main.h"
 #include "BKE_mesh.h"
 
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_arithb.h"
 #include "BLI_edgehash.h"
 
 #include "WM_api.h"
@@ -118,6 +122,18 @@ static void rna_Mesh_update(Mesh *mesh, bContext *C)
        }
 }
 
+static 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);
+       }
+}
+
 static void rna_Mesh_add_verts(Mesh *mesh, int len)
 {
        CustomData vdata;
@@ -148,6 +164,14 @@ static void rna_Mesh_add_verts(Mesh *mesh, int len)
        mesh->totvert= totvert;
 }
 
+Mesh *rna_Mesh_create_copy(Mesh *me)
+{
+       Mesh *ret= copy_mesh(me);
+       ret->id.us--;
+       
+       return ret;
+}
+
 static void rna_Mesh_add_edges(Mesh *mesh, int len)
 {
        CustomData edata;
@@ -225,6 +249,11 @@ void RNA_api_mesh(StructRNA *srna)
        FunctionRNA *func;
        PropertyRNA *parm;
 
+       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_geometry", "rna_Mesh_add_geometry");
        parm= RNA_def_int(func, "verts", 0, 0, INT_MAX, "Number", "Number of vertices to add.", 0, INT_MAX);
        RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -233,6 +262,20 @@ void RNA_api_mesh(StructRNA *srna)
        parm= RNA_def_int(func, "faces", 0, 0, INT_MAX, "Number", "Number of faces to add.", 0, INT_MAX);
        RNA_def_property_flag(parm, PROP_REQUIRED);
 
+       func= RNA_def_function(srna, "create_copy", "rna_Mesh_create_copy");
+       RNA_def_function_ui_description(func, "Create a copy of this Mesh datablock.");
+       parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh, remove it if it is only used for export.");
+       RNA_def_function_return(func, parm);
+
+       /*
+       func= RNA_def_function(srna, "add_geom", "rna_Mesh_add_geom");
+       RNA_def_function_ui_description(func, "Add geometry data to mesh.");
+       prop= RNA_def_collection(func, "verts", "?", "", "Vertices.");
+       RNA_def_property_flag(prop, PROP_REQUIRED);
+       prop= RNA_def_collection(func, "faces", "?", "", "Faces.");
+       RNA_def_property_flag(prop, PROP_REQUIRED);
+       */
+
        func= RNA_def_function(srna, "update", "rna_Mesh_update");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 }
index 9b3100c733bde43fa68514fcd5d7de3f681c71a0..4166eb9bc2c3df5a98537dec433fd2604023b1a2 100644 (file)
@@ -384,6 +384,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)
@@ -1046,6 +1054,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);
@@ -1182,12 +1196,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..b09acb510840075a3b1832945555475b4c5274ba 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"
+
+/* parameter to rna_Object_create_mesh */
+typedef enum CreateMeshType {
+       CREATE_MESH_PREVIEW = 0,
+       CREATE_MESH_RENDER = 1
+} CreateMeshType;
+
 #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 *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports, int type)
 {
-       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);
+       }
 
-       if(!dm)
+       if (type == CREATE_MESH_PREVIEW) {
+               dm= mesh_create_derived_view(sce, ob, mask);
+       }
+       else {
+               dm= mesh_create_derived_render(sce, ob, mask);
+       }
+
+       if(!dm) {
+               /* TODO: report */
                return NULL;
+       }
 
        me= add_mesh("tmp_render_mesh");
        me->id.us--; /* we don't assign it to anything */
@@ -64,19 +98,98 @@ Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene)
        return me;
 }
 
+/* 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;
 
-       func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh");
+       static EnumPropertyItem mesh_type_items[] = {
+               {CREATE_MESH_PREVIEW, "PREVIEW", 0, "Preview", "Apply preview settings."},
+               {CREATE_MESH_RENDER, "RENDER", 0, "Render", "Apply render settings."},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       func= RNA_def_function(srna, "create_mesh", "rna_Object_create_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_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
+       parm= RNA_def_enum(func, "type", mesh_type_items, 0, "", "Type of mesh settings to apply.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       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
+
index 8b5ad36f349fd22e09458a99867de346f9cfd6a3..96ef796839b7a899a124961212ef0b8664e4d7b7 100644 (file)
@@ -19,6 +19,7 @@
 #include "bpy_rna.h"
 #include "bpy_operator.h"
 #include "bpy_ui.h"
+#include "bpy_sys.h"
 #include "bpy_util.h"
 
 #include "DNA_anim_types.h"
@@ -91,6 +92,7 @@ void BPY_update_modules( void )
        PyObject *mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
        PyModule_AddObject( mod, "data", BPY_rna_module() );
        PyModule_AddObject( mod, "types", BPY_rna_types() );
+       PyModule_AddObject( mod, "sys", BPY_sys_module() );
 }
 
 /*****************************************************************************
index 60a9afda0c4c5f77bd9939a8b2032f965ecef5df..17029412f4df6f66ec252bd6b23d09ae1760ea84 100644 (file)
@@ -331,7 +331,7 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
                {PYOP_ATTR_UINAME,              's', 0, BPY_CLASS_ATTR_OPTIONAL},
                {PYOP_ATTR_PROP,                'l', 0, BPY_CLASS_ATTR_OPTIONAL},
                {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK},
-               {"execute",     'f', 2, BPY_CLASS_ATTR_OPTIONAL},
+               {"execute",     'f', 2, 0},
                {"invoke",      'f', 3, BPY_CLASS_ATTR_OPTIONAL},
                {"poll",        'f', 2, BPY_CLASS_ATTR_OPTIONAL},
                {NULL, 0, 0, 0}
index e13f02c5529ffe9f245b331a153b9d91d924944b..c5c56aeb5b08c73ce0fbf8e4123f2c86bfb65841 100644 (file)
@@ -1621,8 +1621,12 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
                                newptr= *(PointerRNA*)data;
                        }
                        else {
-                               /* XXX this is missing the ID part! */
-                               RNA_pointer_create(NULL, type, *(void**)data, &newptr);
+                               if (RNA_struct_is_ID(type)) {
+                                       RNA_id_pointer_create(*(void**)data, &newptr);
+                               }
+                               else {
+                                       RNA_pointer_create(NULL, type, *(void**)data, &newptr);
+                               }
                        }
 
                        if (newptr.data) {
diff --git a/source/blender/python/intern/bpy_sys.c b/source/blender/python/intern/bpy_sys.c
new file mode 100644 (file)
index 0000000..4d80d3b
--- /dev/null
@@ -0,0 +1,460 @@
+/* 
+ * $Id: Sys.c 17889 2008-12-16 11:26:55Z campbellbarton $
+ *
+ * ***** 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "bpy_sys.h" /*This must come first*/
+#include "bpy_util.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_context.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_scene_types.h" /* G.scene-"r.cfra */
+
+#include "PIL_time.h"
+/* #include "gen_utils.h" */
+
+#ifdef WIN32
+#define DIRSEP '\\'
+#define DIRSEP_STR "\\"
+#else
+#define DIRSEP '/'
+#define DIRSEP_STR "/"
+#endif
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the sys module.                        */
+/*****************************************************************************/
+static PyObject *M_sys_basename( PyObject * self, PyObject * value );
+static PyObject *M_sys_dirname( PyObject * self, PyObject * value );
+static PyObject *M_sys_join( PyObject * self, PyObject * args );
+static PyObject *M_sys_splitext( PyObject * self, PyObject * value );
+static PyObject *M_sys_makename( PyObject * self, PyObject * args,
+       PyObject * kw );
+static PyObject *M_sys_exists( PyObject * self, PyObject * value );
+static PyObject *M_sys_time( PyObject * self );
+static PyObject *M_sys_sleep( PyObject * self, PyObject * args );
+static PyObject *M_sys_expandpath( PyObject *self, PyObject *value);
+static PyObject *M_sys_cleanpath( PyObject *self, PyObject *value);
+static PyObject *M_sys_relpath( PyObject *self, PyObject *args);
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings.      */
+/* In Python these will be written to the console when doing a               */
+/* Blender.sys.__doc__                                                       */
+/*****************************************************************************/
+static char M_sys_doc[] = "The Blender.sys submodule\n\
+\n\
+This is a minimal system module to supply simple functionality available\n\
+in the default Python module os.";
+
+static char M_sys_basename_doc[] =
+       "(path) - Split 'path' in dir and filename.\n\
+Return the filename.";
+
+static char M_sys_dirname_doc[] =
+       "(path) - Split 'path' in dir and filename.\n\
+Return the dir.";
+
+static char M_sys_join_doc[] =
+       "(dir, file) - Join dir and file to form a full filename.\n\
+Return the filename.";
+
+static char M_sys_splitext_doc[] =
+       "(path) - Split 'path' in root and extension:\n\
+/this/that/file.ext -> ('/this/that/file','.ext').\n\
+Return the pair (root, extension).";
+
+static char M_sys_makename_doc[] =
+       "(path = Blender.Get('filename'), ext = \"\", strip = 0) -\n\
+Strip dir and extension from path, leaving only a name, then append 'ext'\n\
+to it (if given) and return the resulting string.\n\n\
+(path) - string: a pathname -- Blender.Get('filename') if 'path' isn't given;\n\
+(ext = \"\") - string: the extension to append.\n\
+(strip = 0) - int: strip dirname from 'path' if given and non-zero.\n\
+Ex: makename('/path/to/file/myfile.foo','-01.abc') returns 'myfile-01.abc'\n\
+Ex: makename(ext='.txt') returns 'untitled.txt' if Blender.Get('filename')\n\
+returns a path to the file 'untitled.blend'";
+
+static char M_sys_time_doc[] =
+       "() - Return a float representing time elapsed in seconds.\n\
+Each successive call is garanteed to return values greater than or\n\
+equal to the previous call.";
+
+static char M_sys_sleep_doc[] =
+       "(milliseconds = 10) - Sleep for the specified time.\n\
+(milliseconds = 10) - the amount of time in milliseconds to sleep.\n\
+This function can be necessary in tight 'get event' loops.";
+
+static char M_sys_exists_doc[] =
+       "(path) - Check if the given pathname exists.\n\
+The return value is as follows:\n\
+\t 0: path doesn't exist;\n\
+\t 1: path is an existing filename;\n\
+\t 2: path is an existing dirname;\n\
+\t-1: path exists but is neither a regular file nor a dir.";
+
+static char M_sys_expandpath_doc[] =
+"(path) - Expand this Blender internal path to a proper file system path.\n\
+(path) - the string path to convert.\n\n\
+Note: internally Blender paths can contain two special character sequences:\n\
+- '//' (at start) for base path directory (the current .blend's dir path);\n\
+- '#' characters in the filename will be replaced by the frame number.\n\n\
+This function expands these to their actual content, returning a valid path.\n\
+If the special chars are not found in the given path, it is simply returned.";
+
+static char M_sys_cleanpath_doc[] =
+"(path) - Removes parts of a path that are not needed paths such as '../foo/../bar/' and '//./././'";
+
+static char M_sys_relpath_doc[] =
+"(path, start=\"//\") - Returns the path relative to the current blend file or start if spesified";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.sys module:                */
+/*****************************************************************************/
+struct PyMethodDef M_sys_methods[] = {
+       {"basename", M_sys_basename, METH_O, M_sys_basename_doc},
+       {"dirname", M_sys_dirname, METH_O, M_sys_dirname_doc},
+       {"join", M_sys_join, METH_VARARGS, M_sys_join_doc},
+       {"splitext", M_sys_splitext, METH_O, M_sys_splitext_doc},
+       {"makename", ( PyCFunction ) M_sys_makename,
+        METH_VARARGS | METH_KEYWORDS,
+        M_sys_makename_doc},
+       {"exists", M_sys_exists, METH_O, M_sys_exists_doc},
+       {"sleep", M_sys_sleep, METH_VARARGS, M_sys_sleep_doc},
+       {"time", ( PyCFunction ) M_sys_time, METH_NOARGS, M_sys_time_doc},
+       {"expandpath", M_sys_expandpath, METH_O, M_sys_expandpath_doc},
+       {"cleanpath", M_sys_cleanpath, METH_O, M_sys_cleanpath_doc},
+       {"relpath", M_sys_relpath, METH_VARARGS, M_sys_relpath_doc},
+       {NULL, NULL, 0, NULL}
+};
+
+#if PY_VERSION_HEX >= 0x03000000
+static struct PyModuleDef sys_module = {
+       PyModuleDef_HEAD_INIT,
+       "bpysys",
+       M_sys_doc,
+       -1,/* multiple "initialization" just copies the module dict. */
+       M_sys_methods,
+       NULL, NULL, NULL, NULL
+};
+#endif
+
+/* Module Functions */
+
+PyObject *BPY_sys_module( void )
+{
+       PyObject *submodule, *dict;
+
+#if PY_VERSION_HEX >= 0x03000000
+       submodule= PyModule_Create(&sys_module);
+#else /* Py2.x */
+       submodule= Py_InitModule3( "bpysys", M_sys_methods, M_sys_doc );
+#endif
+
+       dict = PyModule_GetDict( submodule );
+       
+       /* EXPP_dict_set_item_str( dict, "dirsep", PyString_FromString(DIRSEP_STR) ); */
+       /* EXPP_dict_set_item_str( dict, "sep", PyString_FromString(DIRSEP_STR) ); */
+
+       return submodule;
+}
+
+static PyObject *M_sys_basename( PyObject * self, PyObject * value )
+{
+       char *name = _PyUnicode_AsString(value);
+       char *p, basename[FILE_MAXDIR + FILE_MAXFILE];
+       int n, len;
+
+       if( !name ) {
+               return PyErr_Format( PyExc_TypeError, "expected string argument" );
+       }
+
+       len = strlen( name );
+       
+#ifdef WIN32
+       p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
+#else
+       p = strrchr( name, DIRSEP );
+#endif
+
+       if( p ) {
+               n = name + len - p - 1; /* - 1 because we don't want the sep */
+
+               if( n > FILE_MAXDIR + FILE_MAXFILE ) {
+                       return PyErr_Format( PyExc_RuntimeError, "path too long" );
+               }
+
+               BLI_strncpy( basename, p + 1, n + 1 );
+               return PyUnicode_FromString( basename );
+       }
+
+       return PyUnicode_FromString( name );
+}
+
+static PyObject *M_sys_dirname( PyObject * self, PyObject * value )
+{
+       char *name = _PyUnicode_AsString(value);
+       char *p, dirname[FILE_MAXDIR + FILE_MAXFILE];
+       int n;
+
+       if( !name )
+               return PyErr_Format( PyExc_TypeError, "expected string argument" );
+
+#ifdef WIN32
+       p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
+#else
+       p = strrchr( name, DIRSEP );
+#endif
+
+       if( p ) {
+               n = p - name;
+
+               if( n > FILE_MAXDIR + FILE_MAXFILE )
+                       return PyErr_Format( PyExc_RuntimeError, "path too long" );
+
+               BLI_strncpy( dirname, name, n + 1 );
+               return PyUnicode_FromString( dirname );
+       }
+
+       return PyUnicode_FromString( "." );
+}
+
+static PyObject *M_sys_join( PyObject * self, PyObject * args )
+{
+       char *name = NULL, *path = NULL;
+       char filename[FILE_MAXDIR + FILE_MAXFILE];
+       int pathlen = 0, namelen = 0;
+
+       if( !PyArg_ParseTuple( args, "ss:Blender.sys.join", &path, &name ) )
+               return NULL;
+
+       pathlen = strlen( path ) + 1;
+       namelen = strlen( name ) + 1;   /* + 1 to account for '\0' for BLI_strncpy */
+
+       if( pathlen + namelen > FILE_MAXDIR + FILE_MAXFILE - 1 )
+               return PyErr_Format( PyExc_RuntimeError, "filename is too long." );
+
+       BLI_strncpy( filename, path, pathlen );
+
+       if( filename[pathlen - 2] != DIRSEP ) {
+               filename[pathlen - 1] = DIRSEP;
+               pathlen += 1;
+       }
+
+       BLI_strncpy( filename + pathlen - 1, name, namelen );
+
+       return PyUnicode_FromString( filename );
+}
+
+static PyObject *M_sys_splitext( PyObject * self, PyObject * value )
+{
+       char *name = _PyUnicode_AsString(value);
+       char *dot, *p, path[FILE_MAXDIR + FILE_MAXFILE], ext[FILE_MAXDIR + FILE_MAXFILE];
+       int n, len;
+
+       if( !name )
+               return PyErr_Format( PyExc_TypeError, "expected string argument" );
+
+       len = strlen( name );
+       dot = strrchr( name, '.' );
+
+       if( !dot )
+               return Py_BuildValue( "ss", name, "" );
+
+       p = strrchr( name, DIRSEP );
+
+       if( p ) {
+               if( p > dot )
+                       return Py_BuildValue( "ss", name, "" );
+       }
+
+       n = name + len - dot;
+
+       /* loong extensions are supported -- foolish, but Python's os.path.splitext
+        * supports them, so ... */
+        
+       if( n >= FILE_MAXDIR + FILE_MAXFILE || ( len - n ) >= FILE_MAXDIR + FILE_MAXFILE )
+               return PyErr_Format( PyExc_RuntimeError, "path too long" );
+
+       BLI_strncpy( ext, dot, n + 1 );
+       BLI_strncpy( path, name, dot - name + 1 );
+
+       return Py_BuildValue( "ss", path, ext );
+}
+
+static PyObject *M_sys_makename( PyObject * self, PyObject * args,
+                                PyObject * kw )
+{
+       char *path = G.sce, *ext = NULL;
+       int strip = 0;
+       static char *kwlist[] = { "path", "ext", "strip", NULL };
+       char *dot = NULL, *p = NULL, basename[FILE_MAXDIR + FILE_MAXFILE];
+       int n, len, lenext = 0;
+
+       if( !PyArg_ParseTupleAndKeywords( args, kw, "|ssi:Blender.sys.makename", kwlist, &path, &ext, &strip ) )
+               return NULL;
+
+       len = strlen( path ) + 1;       /* + 1 to consider ending '\0' */
+       if( ext )
+               lenext = strlen( ext ) + 1;
+
+       if( ( len + lenext ) > FILE_MAXDIR + FILE_MAXFILE )
+               return PyErr_Format( PyExc_RuntimeError, "path too long" );
+
+       p = strrchr( path, DIRSEP );
+
+       if( p && strip ) {
+               n = path + len - p;
+               BLI_strncpy( basename, p + 1, n );      /* + 1 to skip the sep */
+       } else
+               BLI_strncpy( basename, path, len );
+
+       dot = strrchr( basename, '.' );
+
+       /* now the extension: always remove the one in basename */
+       if( dot || ext ) {
+               if( !ext )
+                       basename[dot - basename] = '\0';
+               else {          /* if user gave an ext, append it */
+
+                       if( dot )
+                               n = dot - basename;
+                       else
+                               n = strlen( basename );
+
+                       BLI_strncpy( basename + n, ext, lenext );
+               }
+       }
+
+       return PyUnicode_FromString( basename );
+}
+
+static PyObject *M_sys_time( PyObject * self )
+{      
+       return PyFloat_FromDouble( PIL_check_seconds_timer(  ) );
+}
+
+static PyObject *M_sys_sleep( PyObject * self, PyObject * args )
+{
+       int millisecs = 10;
+
+       if( !PyArg_ParseTuple( args, "|i:Blender.sys.sleep", &millisecs ) )
+               return NULL;
+
+       PIL_sleep_ms( millisecs );
+       
+       Py_RETURN_NONE;
+}
+
+static PyObject *M_sys_exists( PyObject * self, PyObject * value )
+{
+       char *fname = _PyUnicode_AsString(value);
+       
+       int mode = 0, i = -1;
+
+       if( !fname )
+               return PyErr_Format( PyExc_TypeError, "expected string (pathname) argument" );
+
+       mode = BLI_exist(fname);
+       
+       if( mode == 0 )
+               i = 0;
+       else if( S_ISREG( mode ) )
+               i = 1;
+       else if( S_ISDIR( mode ) )
+               i = 2;
+       /* i stays as -1 if path exists but is neither a regular file nor a dir */
+       
+       return PyLong_FromLong(i);
+}
+
+static PyObject *M_sys_expandpath( PyObject * self, PyObject * value )
+{
+       char *path = _PyUnicode_AsString(value);
+       char expanded[FILE_MAXDIR + FILE_MAXFILE];
+       bContext *C = BPy_GetContext();
+       Scene *scene = CTX_data_scene(C);
+
+       if (!path)
+               return PyErr_Format( PyExc_TypeError, "expected string argument" );
+       
+       BLI_strncpy(expanded, path, FILE_MAXDIR + FILE_MAXFILE);
+       BLI_convertstringcode(expanded, G.sce);
+       BLI_convertstringframe(expanded, scene->r.cfra);
+
+       return PyUnicode_FromString(expanded);
+}
+
+static PyObject *M_sys_cleanpath( PyObject * self, PyObject * value )
+{
+       char *path = _PyUnicode_AsString(value);
+       char cleaned[FILE_MAXDIR + FILE_MAXFILE];
+       int trailing_slash = 0, last;
+       if (!path)
+               return PyErr_Format( PyExc_TypeError, "expected string argument" );
+       last = strlen(path)-1;
+       if ((last >= 0) && ((path[last]=='/') || (path[last]=='\\'))) {
+               trailing_slash = 1;
+       }
+       BLI_strncpy(cleaned, path, FILE_MAXDIR + FILE_MAXFILE);
+       BLI_cleanup_file(NULL, cleaned);
+       
+       if (trailing_slash) {
+               BLI_add_slash(cleaned);
+       }
+       
+       return PyUnicode_FromString(cleaned);
+}
+
+static PyObject *M_sys_relpath( PyObject * self, PyObject * args )
+{
+       char *base = G.sce;
+       char *path;
+       char relpath[FILE_MAXDIR + FILE_MAXFILE];
+       
+       if( !PyArg_ParseTuple( args, "s|s:Blender.sys.relpath", &path, &base ) )
+               return NULL;
+       
+       strncpy(relpath, path, sizeof(relpath));
+       BLI_makestringcode(base, relpath);
+       
+       return PyUnicode_FromString(relpath);
+}
+
+#if 0
+
+static PyObject *bpy_sys_get_blender_version()
+{
+       return PyUnicode_FromString(G.version);
+}
+
+#endif
diff --git a/source/blender/python/intern/bpy_sys.h b/source/blender/python/intern/bpy_sys.h
new file mode 100644 (file)
index 0000000..a045ed0
--- /dev/null
@@ -0,0 +1,41 @@
+/* 
+ * $Id: Sys.h 14444 2008-04-16 22:40:48Z hos $
+ *
+ * ***** 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef BPY_SYS_H
+
+/* #include <Python.h> */
+
+/* PyObject *sys_Init( void ); */
+
+#include <Python.h>
+
+PyObject *BPY_sys_module( void ); 
+
+
+#endif /* BPY_SYS_H */