-- cgit v1.2.3 From a5a2d8c871ac7eb104174467b5e8c074e267974d Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 26 May 2009 16:22:00 +0000 Subject: Start OBJ exporter conversion. Just copied export_obj.py to export_obj-2.5.py leaving old one for reference. Once conversion is done, the new one will replace it. --- release/scripts/export_obj-2.5.py | 791 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 791 insertions(+) create mode 100644 release/scripts/export_obj-2.5.py diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py new file mode 100644 index 00000000000..1eb34a62af0 --- /dev/null +++ b/release/scripts/export_obj-2.5.py @@ -0,0 +1,791 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 248 +Group: 'Export' +Tooltip: 'Save a Wavefront OBJ File' +""" + +__author__ = "Campbell Barton, Jiri Hnidek" +__url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org'] +__version__ = "1.2" + +__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 Blender +# from Blender import Mesh, Scene, Window, sys, Image, Draw +# import BPyMesh +# import BPyObject +# import BPySys +# import BPyMessages + +# Returns a tuple - path,extension. +# 'hello.obj' > ('hello', '.obj') +def splitExt(path): + dotidx = path.rfind('.') + if dotidx == -1: + return path, '' + else: + return path[:dotidx], path[dotidx:] + +def fixName(name): + if name == None: + return 'None' + else: + return name.replace(' ', '_') + +# A Dict of Materials +# (material.name, image.name):matname_imagename # matname_imagename has gaps removed. +MTL_DICT = {} + +def write_mtl(filename): + + world = Blender.World.GetCurrent() + if world: + worldAmb = world.getAmb() + else: + worldAmb = (0,0,0) # Default value + + file = open(filename, "w") + file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) + file.write('# Material Count: %i\n' % len(MTL_DICT)) + # Write material/image combinations we have used. + for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): + + # Get the Blender data for the material and the image. + # Having an image named None will make a bug, dont do it :) + + file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname + + if mat: + file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's + file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse + file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular + file.write('Ni %.6f\n' % mat.IOR) # Refraction index + file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve) + + # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting. + if mat.getMode() & Blender.Material.Modes['SHADELESS']: + file.write('illum 0\n') # ignore lighting + elif mat.getSpec() == 0: + file.write('illum 1\n') # no specular. + else: + file.write('illum 2\n') # light normaly + + else: + #write a dummy material here? + file.write('Ns 0\n') + file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd 0.8 0.8 0.8\n') + file.write('Ks 0.8 0.8 0.8\n') + file.write('d 1\n') # No alpha + file.write('illum 2\n') # light normaly + + # Write images! + if img: # We have an image on the face! + file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image + + elif mat: # No face image. if we havea material search for MTex image. + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + try: + filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1] + file.write('map_Kd %s\n' % filename) # Diffuse mapping image + break + except: + # Texture has no image though its an image type, best ignore. + pass + + file.write('\n\n') + + file.close() + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +def copy_images(dest_dir): + if dest_dir[-1] != sys.sep: + dest_dir += sys.sep + + # Get unique image names + uniqueImages = {} + for matname, mat, image in MTL_DICT.itervalues(): # Only use image name + # Get Texface images + if image: + uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. + + # Get MTex images + if mat: + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + image_tex = mtex.tex.image + if image_tex: + try: + uniqueImages[image_tex] = image_tex + except: + pass + + # Now copy images + copyCount = 0 + + for bImage in uniqueImages.itervalues(): + image_path = sys.expandpath(bImage.filename) + if sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + copy_file(image_path, dest_image_path) + copyCount+=1 + print '\tCopied %d images' % copyCount + +def write(filename, objects,\ +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): + ''' + 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) + + print 'OBJ Export path: "%s"' % filename + temp_mesh_name = '~tmp-mesh' + + time1 = sys.time() + scn = Scene.GetCurrent() + + file = open(filename, "w") + + # Write Header + file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) + file.write('# www.blender3d.org\n') + + # Tell the obj file what material file to use. + if EXPORT_MTL: + mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) + file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) + + # Get the container mesh. - used for applying modifiers and non mesh objects. + containerMesh = meshName = tempMesh = None + for meshName in Blender.NMesh.GetNames(): + if meshName.startswith(temp_mesh_name): + tempMesh = Mesh.Get(meshName) + if not tempMesh.users: + containerMesh = tempMesh + if not containerMesh: + containerMesh = Mesh.New(temp_mesh_name) + + if EXPORT_ROTX90: + mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') + + del meshName + del tempMesh + + # Initialize totals, these are updated each object + totverts = totuvco = totno = 1 + + face_vert_index = 1 + + globalNormals = {} + + # Get all meshs + for ob_main in objects: + for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + # Will work for non meshes now! :) + # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) + me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) + if not me: + continue + + if EXPORT_UV: + faceuv= me.faceUV + else: + faceuv = False + + # We have a valid mesh + if EXPORT_TRI and me.faces: + # Add a dummy object to it. + has_quads = False + for f in me.faces: + if len(f) == 4: + has_quads = True + break + + if has_quads: + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['FACE']) + + me.sel = True + tempob = scn.objects.new(me) + me.quadToTriangle(0) # more=0 shortest length + oldmode = Mesh.Mode(oldmode) + scn.objects.unlink(tempob) + + Mesh.Mode(oldmode) + + # Make our own list so it can be sorted to reduce context switching + faces = [ f for f in me.faces ] + + if EXPORT_EDGES: + edges = me.edges + else: + edges = [] + + if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + continue # dont bother with this mesh. + + if EXPORT_ROTX90: + me.transform(ob_mat*mat_xrot90) + else: + me.transform(ob_mat) + + # High Quality Normals + if EXPORT_NORMALS and faces: + if EXPORT_NORMALS_HQ: + BPyMesh.meshCalcNormals(me) + else: + # transforming normals is incorrect + # when the matrix is scaled, + # better to recalculate them + me.calcNormals() + + # # Crash Blender + #materials = me.getMaterials(1) # 1 == will return None in the list. + materials = me.materials + + materialNames = [] + materialItems = materials[:] + if materials: + for mat in materials: + if mat: # !=None + materialNames.append(mat.name) + else: + materialNames.append(None) + # Cant use LC because some materials are None. + # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. + + # Possible there null materials, will mess up indicies + # but at least it will export, wait until Blender gets fixed. + materialNames.extend((16-len(materialNames)) * [None]) + materialItems.extend((16-len(materialItems)) * [None]) + + # Sort by Material, then images + # so we dont over context switch in the obj file. + if EXPORT_KEEP_VERT_ORDER: + pass + elif faceuv: + 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)) + + # 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.getData(1) + if name1 == name2: + obnamestring = fixName(name1) + else: + obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) + + if EXPORT_BLEN_OBS: + file.write('o %s\n' % obnamestring) # Write Object name + else: # if EXPORT_GROUP_BY_OB: + file.write('g %s\n' % obnamestring) + + + # Vert + for v in me.verts: + file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) + + # UV + if faceuv: + uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ + + uv_dict = {} # could use a set() here + 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.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + else: + # Hard, 1 normal from the face. + noKey = veckey3d(f.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + + if not faceuv: + f_image = None + + for f_index, f in enumerate(faces): + f_v= f.v + f_smooth= f.smooth + f_mat = min(f.mat, len(materialNames)-1) + if faceuv: + 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. + + # CHECK FOR CONTEXT SWITCH + if key == contextMat: + pass # Context alredy switched, dont do anythoing + 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: + file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) + file.write('usemtl (null)\n') # mat, image + + else: + mat_data= MTL_DICT.get(key) + if not mat_data: + # First add to global dict so we can export to mtl + # Then write mtl + + # Make a new names from the mat and image name, + # converting any spaces to underscores with fixName. + + # If none image dont bother adding it to the name + if key[1] == None: + mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image + else: + mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image + + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) + file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) + + contextMat = key + if f_smooth != contextSmooth: + if f_smooth: # on now off + file.write('s 1\n') + contextSmooth = f_smooth + else: # was off now on + file.write('s off\n') + contextSmooth = f_smooth + + file.write('f') + if faceuv: + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + totuvco + uv_face_mapping[f_index][vi],\ + globalNormals[ veckey3d(v.no) ])) # vert, uv, normal + + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + totuvco + uv_face_mapping[f_index][vi],\ + no)) # vert, uv, normal + + 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.no) ])) + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + 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: + LOOSE= Mesh.EdgeFlags.LOOSE + for ed in edges: + if ed.flag & LOOSE: + file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) + + # Make the indicies global rather then per mesh + totverts += len(me.verts) + if faceuv: + totuvco += uv_unique_count + me.verts= None + file.close() + + + # Now we have all our materials, save them + if EXPORT_MTL: + write_mtl(mtlfilename) + if EXPORT_COPY_IMAGES: + dest_dir = filename + # Remove chars until we are just the path. + while dest_dir and dest_dir[-1] not in '\\/': + dest_dir = dest_dir[:-1] + if dest_dir: + copy_images(dest_dir) + else: + print '\tError: "%s" could not be used as a base for an image path.' % filename + + print "OBJ Export time: %.2f" % (sys.time() - time1) + + +# converted: 0% +def write_ui(filename): + + if not filename.lower().endswith('.obj'): + filename += '.obj' + + if not BPyMessages.Warning_SaveOver(filename): + return + + global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ + EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ + EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ + EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER + + EXPORT_APPLY_MODIFIERS = Draw.Create(0) + EXPORT_ROTX90 = Draw.Create(1) + EXPORT_TRI = Draw.Create(0) + EXPORT_EDGES = Draw.Create(1) + EXPORT_NORMALS = Draw.Create(0) + EXPORT_NORMALS_HQ = Draw.Create(0) + EXPORT_UV = Draw.Create(1) + EXPORT_MTL = Draw.Create(1) + EXPORT_SEL_ONLY = Draw.Create(1) + EXPORT_ALL_SCENES = Draw.Create(0) + EXPORT_ANIMATION = Draw.Create(0) + EXPORT_COPY_IMAGES = Draw.Create(0) + EXPORT_BLEN_OBS = Draw.Create(0) + EXPORT_GROUP_BY_OB = Draw.Create(0) + EXPORT_GROUP_BY_MAT = Draw.Create(0) + EXPORT_KEEP_VERT_ORDER = Draw.Create(1) + + # Old UI + ''' + # removed too many options are bad! + + # Get USER Options + pup_block = [\ + ('Context...'),\ + ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\ + ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\ + ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\ + ('Object Prefs...'),\ + ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\ + ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\ + ('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ + ('Extra Data...'),\ + ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\ + ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\ + ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\ + ('UVs', EXPORT_UV, 'Export texface UV coords.'),\ + ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\ + ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\ + ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ + ('Grouping...'),\ + ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\ + ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\ + ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\ + ] + + if not Draw.PupBlock('Export...', pup_block): + return + ''' + + # BEGIN ALTERNATIVE UI ******************* + if True: + + EVENT_NONE = 0 + EVENT_EXIT = 1 + EVENT_REDRAW = 2 + EVENT_EXPORT = 3 + + GLOBALS = {} + GLOBALS['EVENT'] = EVENT_REDRAW + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + + def obj_ui_set_event(e,v): + GLOBALS['EVENT'] = e + + def do_split(e,v): + global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER + if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val: + EXPORT_KEEP_VERT_ORDER.val = 0 + else: + EXPORT_KEEP_VERT_ORDER.val = 1 + + def do_vertorder(e,v): + global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER + if EXPORT_KEEP_VERT_ORDER.val: + EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0 + else: + if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val): + EXPORT_KEEP_VERT_ORDER.val = 1 + + def do_help(e,v): + url = __url__[0] + print 'Trying to open web browser with documentation at this address...' + print '\t' + url + + try: + import webbrowser + webbrowser.open(url) + except: + print '...could not open a browser window.' + + def obj_ui(): + ui_x, ui_y = GLOBALS['MOUSE'] + + # Center based on overall pup size + ui_x -= 165 + ui_y -= 110 + + global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ + EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ + EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ + EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER + + Draw.Label('Context...', ui_x+9, ui_y+209, 220, 20) + Draw.BeginAlign() + EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+189, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.') + EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+189, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.') + EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+189, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.') + Draw.EndAlign() + + + Draw.Label('Output Options...', ui_x+9, ui_y+159, 220, 20) + Draw.BeginAlign() + EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+140, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split) + EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+140, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP') + EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+140, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.') + Draw.EndAlign() + + + Draw.Label('Export...', ui_x+9, ui_y+109, 220, 20) + Draw.BeginAlign() + EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+90, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.') + EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+90, 70, 20, EXPORT_TRI.val, 'Triangulate quads.') + Draw.EndAlign() + Draw.BeginAlign() + EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+90, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.') + EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+90, 31, 20, EXPORT_UV.val, 'Export texface UV coords.') + Draw.EndAlign() + Draw.BeginAlign() + EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+90, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).') + EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+90, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.') + Draw.EndAlign() + + + Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20) + Draw.BeginAlign() + EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split) + EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split) + EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split) + Draw.EndAlign() + + EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder) + + Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event) + Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event) + Draw.EndAlign() + + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT): + Draw.UIBlock(obj_ui, 0) + + if GLOBALS['EVENT'] != EVENT_EXPORT: + return + + # END ALTERNATIVE UI ********************* + + + if EXPORT_KEEP_VERT_ORDER.val: + EXPORT_BLEN_OBS.val = False + EXPORT_GROUP_BY_OB.val = False + EXPORT_GROUP_BY_MAT.val = False + EXPORT_APPLY_MODIFIERS.val = False + + Window.EditMode(0) + Window.WaitCursor(1) + + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val + EXPORT_ROTX90 = EXPORT_ROTX90.val + EXPORT_TRI = EXPORT_TRI.val + EXPORT_EDGES = EXPORT_EDGES.val + EXPORT_NORMALS = EXPORT_NORMALS.val + EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val + EXPORT_UV = EXPORT_UV.val + EXPORT_MTL = EXPORT_MTL.val + EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val + EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val + EXPORT_ANIMATION = EXPORT_ANIMATION.val + EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val + EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val + EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val + EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val + EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val + + + + base_name, ext = splitExt(filename) + context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension + + # Use the options to export the data using write() + # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True): + orig_scene = Scene.GetCurrent() + if EXPORT_ALL_SCENES: + export_scenes = Scene.Get() + else: + export_scenes = [orig_scene] + + # Export all scenes. + for scn in export_scenes: + scn.makeCurrent() # If alredy current, this is not slow. + context = scn.getRenderingContext() + orig_frame = Blender.Get('curframe') + + if EXPORT_ALL_SCENES: # Add scene name into the context_name + context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. + + # Export an animation? + if EXPORT_ANIMATION: + scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame. + else: + scene_frames = [orig_frame] # Dont export an animation. + + # Loop through all frames in the scene and export. + for frame in scene_frames: + if EXPORT_ANIMATION: # Add frame to the filename. + context_name[2] = '_%.6d' % frame + + Blender.Set('curframe', frame) + if EXPORT_SEL_ONLY: + export_objects = scn.objects.context + else: + export_objects = scn.objects + + full_path= ''.join(context_name) + + # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. + # EXPORT THE FILE. + write(full_path, export_objects,\ + EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ + EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ + EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ + EXPORT_ROTX90, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER) + + Blender.Set('curframe', orig_frame) + + # Restore old active scene. + orig_scene.makeCurrent() + Window.WaitCursor(0) + + +if __name__ == '__main__': + Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj')) -- cgit v1.2.3 From ab6ec6be7bc8bbd0f22d5b5d8e37527c13aef308 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 26 May 2009 17:08:10 +0000 Subject: In bpy, renamed "exec" operator method to "execu" for compatibility with py 2.x ("exec" is a keyword in py 2.x). --- source/blender/python/intern/bpy_operator_wrap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 43d62b3005f..ab4d5c6169d 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -232,7 +232,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); } else if (mode==PYOP_EXEC) { - item= PyObject_GetAttrString(py_class, "exec"); + item= PyObject_GetAttrString(py_class, "execu"); args = PyTuple_New(1); } else if (mode==PYOP_POLL) { @@ -328,7 +328,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; - if (PyObject_HasAttrString(py_class, "exec")) + if (PyObject_HasAttrString(py_class, "execu")) ot->exec= PYTHON_OT_exec; if (PyObject_HasAttrString(py_class, "poll")) ot->poll= PYTHON_OT_poll; @@ -391,7 +391,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}, - {"exec", 'f', 1, BPY_CLASS_ATTR_OPTIONAL}, + {"execu", 'f', 1, BPY_CLASS_ATTR_OPTIONAL}, {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} -- cgit v1.2.3 From 628b06e9c551036d2e4f03610ce52c1b7aa3254e Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 1 Jun 2009 19:44:22 +0000 Subject: Woohoo! Context is now passed to operator's exec. Thanks Brecht and Campbell! --- source/blender/python/intern/bpy_operator_wrap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index ab4d5c6169d..215e42dd95d 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -189,6 +189,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *args; PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); + PointerRNA ptr_context; + PyObject *py_context; PyGILState_STATE gilstate = PyGILState_Ensure(); @@ -233,7 +235,11 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } else if (mode==PYOP_EXEC) { item= PyObject_GetAttrString(py_class, "execu"); - args = PyTuple_New(1); + args = PyTuple_New(2); + + RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); + py_context = pyrna_struct_CreatePyObject(&ptr_context); + PyTuple_SET_ITEM(args, 1, py_context); } else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); @@ -391,7 +397,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}, - {"execu", 'f', 1, BPY_CLASS_ATTR_OPTIONAL}, + {"execu", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} -- cgit v1.2.3 From c09cbacf975f429c7b3f535e5e0ae897499f2e15 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 2 Jun 2009 20:16:33 +0000 Subject: Continuing OBJ exporter conversion. - export is initiated by an operator, output filepath is hardcoded for now. - added code in bpy_interface.c to put 'scripts/bpymodules' in sys.path. - no UI atm, using default option values, don't know how to do it yet --- release/scripts/export_obj-2.5.py | 151 ++++++++++++++++++++++++--- source/blender/python/intern/bpy_interface.c | 56 +++++++++- 2 files changed, 189 insertions(+), 18 deletions(-) diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index 1eb34a62af0..2effe7556bc 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -35,18 +35,19 @@ will be exported as mesh data. # # 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 +# 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. +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- import bpy +import BPySys # import Blender # from Blender import Mesh, Scene, Window, sys, Image, Draw @@ -56,7 +57,7 @@ import bpy # import BPyMessages # Returns a tuple - path,extension. -# 'hello.obj' > ('hello', '.obj') +# 'hello.obj' > ('hello', '.obj') def splitExt(path): dotidx = path.rfind('.') if dotidx == -1: @@ -95,7 +96,7 @@ def write_mtl(filename): if mat: file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's - file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular file.write('Ni %.6f\n' % mat.IOR) # Refraction index @@ -112,14 +113,14 @@ def write_mtl(filename): 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('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! + 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. @@ -183,11 +184,12 @@ def copy_images(dest_dir): copyCount+=1 print '\tCopied %d images' % copyCount -def write(filename, objects,\ -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): +def write(filename, objects, + 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): ''' Basic write function. The context and options must be alredy set This can be accessed externaly @@ -409,9 +411,9 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=Fal # MAKE KEY if faceuv and f_image: # Object is always true. - key = materialNames[f_mat], f_image.name + key = materialNames[f_mat], f_image.name else: - key = materialNames[f_mat], None # No image, use None instead. + key = materialNames[f_mat], None # No image, use None instead. # CHECK FOR CONTEXT SWITCH if key == contextMat: @@ -528,7 +530,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=Fal print "OBJ Export time: %.2f" % (sys.time() - time1) -# converted: 0% +# replaced by do_export def write_ui(filename): if not filename.lower().endswith('.obj'): @@ -787,5 +789,122 @@ def write_ui(filename): Window.WaitCursor(0) -if __name__ == '__main__': - Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj')) +def do_export(filename, context): +# Window.EditMode(0) +# Window.WaitCursor(1) + + EXPORT_APPLY_MODIFIERS = True + EXPORT_ROTX90 = True + EXPORT_TRI = False + EXPORT_EDGES = False + EXPORT_NORMALS = False + EXPORT_NORMALS_HQ = False + EXPORT_UV = True + EXPORT_MTL = True + EXPORT_SEL_ONLY = True + EXPORT_ALL_SCENES = False # XXX not working atm + EXPORT_ANIMATION = False + EXPORT_COPY_IMAGES = False + EXPORT_BLEN_OBS = True + EXPORT_GROUP_BY_OB = False + EXPORT_GROUP_BY_MAT = False + EXPORT_KEEP_VERT_ORDER = False + + base_name, ext = splitExt(filename) + context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension + + orig_scene = context.scene + +# if EXPORT_ALL_SCENES: +# export_scenes = bpy.data.scenes +# else: +# export_scenes = [orig_scene] + + # XXX only exporting one scene atm since changing + # current scene is not possible. + # Brecht says that ideally in 2.5 we won't need such a function, + # allowing multiple scenes open at once. + export_scenes = [orig_scene] + + # Export all scenes. + for scn in export_scenes: +# scn.makeCurrent() # If already current, this is not slow. +# context = scn.getRenderingContext() + orig_frame = scn.current_frame + + if EXPORT_ALL_SCENES: # Add scene name into the context_name + context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. + + # Export an animation? + if EXPORT_ANIMATION: + scene_frames = xrange(scn.start_frame, context.end_frame+1) # Up to and including the end frame. + else: + scene_frames = [orig_frame] # Dont export an animation. + + # Loop through all frames in the scene and export. + for frame in scene_frames: + if EXPORT_ANIMATION: # Add frame to the filename. + context_name[2] = '_%.6d' % frame + + scn.current_frame = frame + if EXPORT_SEL_ONLY: + export_objects = context.selected_objects + else: + export_objects = scn.objects + + full_path= ''.join(context_name) + + # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. + # EXPORT THE FILE. +# write(full_path, export_objects, +# 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) + + scn.current_frame = orig_frame + + # Restore old active scene. +# orig_scene.makeCurrent() +# Window.WaitCursor(0) + + +class SCRIPT_OT_export_obj(bpy.types.Operator): + ''' + Operator documentatuon text, will be used for the operator tooltip and python docs. + ''' + __label__ = 'My Operator' + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + __props__ = [ + # bpy.types.FloatProperty(attr="setting_1", name="Example 1", + # default=10.0, min=0, max=10, description="Add info here"), + # bpy.types.IntProperty(attr="setting_2", default=2), + # bpy.types.BoolProperty(attr="toggle", default=True) + ] + + def execu(self, context): + print("Selected: " + context.active_object.name) + + do_export("/tmp/test.obj", context) + + return 'FINISHED' + + def invoke(self, event): + print("Invoke") + return 'FINISHED' + + def poll(self, context): # Poll isnt working yet + print("Poll") + return True + +if (hasattr(bpy.ops, "SCRIPT_OT_export_obj")): + bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj) + +bpy.ops.add(SCRIPT_OT_export_obj) + +bpy.ops.SCRIPT_OT_export_obj() + +bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 999f6d8e9cb..d6e3b0c3dd5 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -35,6 +35,8 @@ #include "BPY_extern.h" +static void bpy_init_syspath(); + void BPY_free_compiled_text( struct Text *text ) { if( text->compiled ) { @@ -126,14 +128,14 @@ void BPY_start_python( int argc, char **argv ) /* Initialize thread support (also acquires lock) */ PyEval_InitThreads(); - /* bpy.* and lets us import it */ bpy_init_modules(); + /* init sys.path */ + bpy_init_syspath(); py_tstate = PyGILState_GetThisThreadState(); PyEval_ReleaseThread(py_tstate); - } void BPY_end_python( void ) @@ -148,6 +150,56 @@ void BPY_end_python( void ) return; } +void syspath_append(char *dirname) +{ + PyObject *mod_sys= NULL, *dict= NULL, *path= NULL, *dir= NULL; + short ok=1; + + mod_sys = PyImport_ImportModule( "sys" ); /* new ref */ + + if (mod_sys) { + dict = PyModule_GetDict( mod_sys ); /* borrowed ref */ + path = PyDict_GetItemString( dict, "path" ); /* borrowed ref */ + if ( !PyList_Check( path ) ) { + ok = 0; + } + } else { + /* cant get the sys module */ + /* PyErr_Clear(); is called below */ + ok = 0; + } + + dir = PyString_FromString( dirname ); + + if (ok && PySequence_Contains(path, dir)==0) { /* Only add if we need to */ + if (PyList_Append( path, dir ) != 0) /* decref below */ + ok = 0; /* append failed */ + } + + if( (ok==0) || PyErr_Occurred( ) ) + fprintf(stderr, "Warning: could import or build sys.path\n" ); + + PyErr_Clear(); + Py_DECREF( dir ); + Py_XDECREF( mod_sys ); +} + +/* Adds bpymodules to sys.path */ +static void bpy_init_syspath() +{ + char *dir; + char mod_dir[FILE_MAX]; + + // make path to [home]/scripts/bpymodules + dir = BLI_gethome_folder("scripts"); + BLI_make_file_string("/", mod_dir, dir, "bpymodules"); + + if (BLI_exists(mod_dir)) { + syspath_append(mod_dir); + fprintf(stderr, "'%s' has been added to sys.path\n", mod_dir); + } +} + /* Can run a file or text block */ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text ) { -- cgit v1.2.3 From 0474acc4cb21ca5603579d8b5d835b7467dc6e5e Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 6 Jun 2009 16:22:54 +0000 Subject: Small fix: use PyUnicode_FromString instead of PyString_FromString in Python 3.x builds. PyString_FromString no longer exists in Python 3.x. --- source/blender/python/intern/bpy_interface.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index d6e3b0c3dd5..147358776bc 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -168,8 +168,12 @@ void syspath_append(char *dirname) /* PyErr_Clear(); is called below */ ok = 0; } - + +#if PY_MAJOR_VERSION >= 3 + dir = PyUnicode_FromString( dirname ); +#else dir = PyString_FromString( dirname ); +#endif if (ok && PySequence_Contains(path, dir)==0) { /* Only add if we need to */ if (PyList_Append( path, dir ) != 0) /* decref below */ -- cgit v1.2.3 From cb82ef0d5288aed62fcab2271b4b15ef15a71aaf Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 6 Jun 2009 17:23:06 +0000 Subject: Renamed "execu" python operator method back to "exec" - switched to Python 3.0... --- source/blender/python/intern/bpy_operator_wrap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 215e42dd95d..9c530bd63e1 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -234,7 +234,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); } else if (mode==PYOP_EXEC) { - item= PyObject_GetAttrString(py_class, "execu"); + item= PyObject_GetAttrString(py_class, "exec"); args = PyTuple_New(2); RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); @@ -334,7 +334,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; - if (PyObject_HasAttrString(py_class, "execu")) + if (PyObject_HasAttrString(py_class, "exec")) ot->exec= PYTHON_OT_exec; if (PyObject_HasAttrString(py_class, "poll")) ot->poll= PYTHON_OT_poll; @@ -397,7 +397,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}, - {"execu", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} -- cgit v1.2.3 From b429a65ed6f1d53e74bd6cc913a32092a1d191a9 Mon Sep 17 00:00:00 2001 From: Chingiz Dyussenov Date: Tue, 9 Jun 2009 14:53:19 +0000 Subject: Added two RNA struct functions - merely wrappers around the C api. - add_mesh to Main - calls C add_mesh and returns a new mesh - copy to Mesh - calls C copy_mesh and returns a new copy Not sure about function placement and naming though. Put both functions in editmesh.c, mesh editor module. Added prototypes to rna_internal.h. Prefixed both with "RNA_api_". Wanted to code Mesh.copy so that it copies Mesh data from another object instead of creating a new Mesh, but this needs CustomData manipulations which I should study later. Maybe we need a separate file for API functions? e.g. mesh_api.c? --- source/blender/editors/mesh/editmesh.c | 48 +++++++++++++++++++++++++++ source/blender/makesrna/intern/rna_internal.h | 2 ++ source/blender/makesrna/intern/rna_main.c | 9 +++++ source/blender/makesrna/intern/rna_mesh.c | 6 ++++ 4 files changed, 65 insertions(+) diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 40373c9f327..96348972f4f 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2027,3 +2027,51 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc) vc->em= me->edit_mesh; } } + +/* Python API */ +Mesh *RNA_api_add_mesh(Main *main, char *name) +{ + return add_mesh(name); +} + +Mesh *RNA_api_mesh_copy(Mesh *me) +{ + return copy_mesh(me); +} + +/* +void RNA_api_mesh_copy_(Mesh *me, Object *ob, int apply_transform) +{ + if (ob->type != OB_MESH) { + return; + } + + Mesh *src= (Mesh*)ob->data; + + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + + CustomData_copy(&src->vdata, &me->vdata, CD_MASK_MESH, CD_DUPLICATE, me->totvert); + CustomData_copy(&src->edata, &me->edata, CD_MASK_MESH, CD_DUPLICATE, me->totedge); + CustomData_copy(&src->fdata, &me->fdata, CD_MASK_MESH, CD_DUPLICATE, me->totface); + mesh_update_customdata_pointers(me); + + // ensure indirect linked data becomes lib-extern + for(i=0; ifdata.totlayer; i++) { + if(src->fdata.layers[i].type == CD_MTFACE) { + tface= (MTFace*)src->fdata.layers[i].data; + + for(a=0; atotface; a++, tface++) + if(tface->tpage) + id_lib_extern((ID*)tface->tpage); + } + } + + me->mselect= NULL; + me->bb= src->bb; + + //men->key= copy_key(me->key); + //if(men->key) men->key->from= (ID *)men; +} +*/ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 9071efe71f7..ee08465f544 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -189,6 +189,8 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, const char *value, ch /* API functions */ void RNA_api_ui_layout(struct StructRNA *srna); +struct Mesh *RNA_api_add_mesh(struct Main *main, char *name); +struct Mesh *RNA_api_mesh_copy(struct Mesh *me); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index fdd0349b25e..347aef69a76 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -218,6 +218,8 @@ void RNA_def_main(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + const char *lists[][5]= { {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera datablocks."}, {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene datablocks."}, @@ -265,6 +267,13 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_collection_funcs(prop, lists[i][2], "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0); RNA_def_property_ui_text(prop, lists[i][3], lists[i][4]); } + + func= RNA_def_function(srna, "add_mesh", "RNA_api_add_mesh"); + RNA_def_function_ui_description(func, "Add a new mesh."); + prop= RNA_def_string(func, "name", "", 0, "", "New name for the datablock."); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); + RNA_def_function_return(func, prop); } #endif diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 92e53cf7606..a15e36f947f 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1044,6 +1044,7 @@ static void rna_def_mesh(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; srna= RNA_def_struct(brna, "Mesh", "ID"); RNA_def_struct_ui_text(srna, "Mesh", "Mesh datablock to define geometric surfaces."); @@ -1126,6 +1127,11 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Shape Keys", ""); rna_def_texmat_common(srna, "rna_Mesh_texspace_editable"); + + func= RNA_def_function(srna, "copy", "RNA_api_mesh_copy"); + RNA_def_function_ui_description(func, "Create a copy of this mesh."); + prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); + RNA_def_function_return(func, prop); } void RNA_def_mesh(BlenderRNA *brna) -- cgit v1.2.3 From ad503a32d60459d627b74479064b0536e0a73ef2 Mon Sep 17 00:00:00 2001 From: Chingiz Dyussenov Date: Wed, 10 Jun 2009 09:56:22 +0000 Subject: - added copy_mesh_data C function which, unlike copy_mesh, copies data between two existing meshes. - API's Mesh.copy reflects copy_mesh_data. --- source/blender/editors/mesh/editmesh.c | 51 +++++++++++++++++++++++++-- source/blender/makesrna/intern/rna_internal.h | 2 +- source/blender/makesrna/intern/rna_mesh.c | 6 +++- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 96348972f4f..a1b6bc56742 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2029,15 +2029,62 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc) } /* Python API */ +void copy_mesh_data(Mesh *dest, Mesh *src); + Mesh *RNA_api_add_mesh(Main *main, char *name) { return add_mesh(name); } -Mesh *RNA_api_mesh_copy(Mesh *me) +void RNA_api_mesh_copy(Mesh *me, Mesh *from) +{ + copy_mesh_data(me, from); +} + +void RNA_api_mesh_copy_transformed() +{ +} + +/* + * This version of copy_mesh doesn't allocate a new mesh, + * instead it copies data between two existing meshes. + */ +void copy_mesh_data(Mesh *dest, Mesh *src) +{ + int totvert, totedge, totface; + int has_layer; + + CustomData_free(&dest->vdata, dest->totvert); + CustomData_free(&dest->edata, dest->totedge); + CustomData_free(&dest->fdata, dest->totface); + + memset(&dest->vdata, 0, sizeof(dest->vdata)); + memset(&dest->edata, 0, sizeof(dest->edata)); + memset(&dest->fdata, 0, sizeof(dest->fdata)); + + totvert = dest->totvert = src->totvert; + totedge = dest->totedge = src->totedge; + totface = dest->totface = src->totface; + + CustomData_copy(&src->vdata, &dest->vdata, CD_MASK_MESH, CD_DUPLICATE, totvert); + CustomData_copy(&src->edata, &dest->edata, CD_MASK_MESH, CD_DUPLICATE, totedge); + CustomData_copy(&src->fdata, &dest->fdata, CD_MASK_MESH, CD_DUPLICATE, totface); + + CustomData_has_layer(&dest->vdata, CD_MVERT); + + CustomData_add_layer(&dest->vdata, CD_MVERT, CD_ASSIGN, src->mvert, totvert); + CustomData_add_layer(&dest->edata, CD_MEDGE, CD_ASSIGN, src->medge, totedge); + CustomData_add_layer(&dest->fdata, CD_MFACE, CD_ASSIGN, src->mface, totface); + + mesh_update_customdata_pointers(dest); +} + +/* +void RNA_api_mesh_apply_transform(Mesh *me) { - return copy_mesh(me); + } +*/ /* void RNA_api_mesh_copy_(Mesh *me, Object *ob, int apply_transform) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index ee08465f544..d93c296ca93 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -190,7 +190,7 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, const char *value, ch void RNA_api_ui_layout(struct StructRNA *srna); struct Mesh *RNA_api_add_mesh(struct Main *main, char *name); -struct Mesh *RNA_api_mesh_copy(struct Mesh *me); +void RNA_api_mesh_copy(struct Mesh *me, struct Mesh *from); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index a15e36f947f..b330bf277d1 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1129,9 +1129,13 @@ static void rna_def_mesh(BlenderRNA *brna) rna_def_texmat_common(srna, "rna_Mesh_texspace_editable"); func= RNA_def_function(srna, "copy", "RNA_api_mesh_copy"); - RNA_def_function_ui_description(func, "Create a copy of this mesh."); + RNA_def_function_ui_description(func, "Copy mesh data."); + prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from."); + RNA_def_property_flag(prop, PROP_REQUIRED); + /* prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); RNA_def_function_return(func, prop); + */ } void RNA_def_mesh(BlenderRNA *brna) -- cgit v1.2.3 From aaa17a285dc46adf354678bf14e9c7043a9f645a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 11 Jun 2009 11:46:12 +0000 Subject: Allow defining string property on py operator - a first step towards interfacing the file selector :) --- source/blender/editors/mesh/editmesh.c | 2 +- source/blender/makesrna/intern/rna_object.c | 6 ++++++ source/blender/python/intern/bpy_interface.c | 1 + source/blender/python/intern/bpy_rna.c | 28 ++++++++++++++++++++++++++++ source/blender/python/intern/bpy_rna.h | 1 + 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index a1b6bc56742..bce5c202366 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2041,7 +2041,7 @@ void RNA_api_mesh_copy(Mesh *me, Mesh *from) copy_mesh_data(me, from); } -void RNA_api_mesh_copy_transformed() +void RNA_api_mesh_transform(Mesh *me, float **mat) { } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 08eca7b0528..86cf501295c 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -799,6 +799,12 @@ static StructRNA *rna_def_object(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale in the interface."); + /* + // error on compile + prop= RNA_def_float_matrix(srna, "mat", 16, NULL, 0.0f, 0.0f, "Matrix", "Transform matrix of the object.", 0.0f, 0.0f); + RNA_def_property_float_sdna(prop, NULL, "obmat"); + */ + /* collections */ prop= RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 49cc4d678e5..4903af475ed 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -102,6 +102,7 @@ static PyObject *CreateGlobalDictionary( bContext *C ) {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 12c19bd3471..3ef3c878826 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -38,6 +38,7 @@ #include "BKE_context.h" #include "BKE_global.h" /* evil G.* */ #include "BKE_report.h" +#include "BKE_utildefines.h" /* FILE_MAX */ static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b ) { @@ -1803,6 +1804,33 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) } } +PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) +{ + static char *kwlist[] = {"attr", "name", "description", "maxlen", "default", NULL}; + char *id, *name="", *description="", *def=""; + int maxlen=FILE_MAX; // XXX need greater? + + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssis:StringProperty", kwlist, &id, &name, &description, &maxlen, &def)) + return NULL; + + if (PyTuple_Size(args) > 0) { + PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this. + return NULL; + } + + if (self) { + StructRNA *srna = PyCObject_AsVoidPtr(self); + RNA_def_string(srna, id, def, maxlen, name, description); + Py_RETURN_NONE; + } else { + PyObject *ret = PyTuple_New(2); + PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_StringProperty, NULL)); + PyTuple_SET_ITEM(ret, 1, kw); + Py_INCREF(kw); + return ret; + } +} + /*-------------------- Type Registration ------------------------*/ static int rna_function_arg_count(FunctionRNA *func) diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index a2a3015912b..7789e083a4e 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -76,6 +76,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop); PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw); +PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw); /* function for registering types */ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args); -- cgit v1.2.3 From a892799db7a9019b592d742b1782c35fa53be01f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 11 Jun 2009 15:10:23 +0000 Subject: Pass context to the "invoke" operator method. "invoke" should have three args now: self, context and event respectively. --- source/blender/python/intern/bpy_operator_wrap.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 6ab990acdf5..a8f993f512b 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -190,7 +190,6 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PointerRNA ptr_context; - PyObject *py_context; PyGILState_STATE gilstate = PyGILState_Ensure(); @@ -226,20 +225,23 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve RNA_property_collection_end(&iter); } - + + RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); if (mode==PYOP_INVOKE) { item= PyObject_GetAttrString(py_class, "invoke"); - args = PyTuple_New(2); - PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); + args = PyTuple_New(3); + + // PyTuple_SET_ITEM "steals" object reference, it is + // an object passed shouldn't be DECREF'ed + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); + PyTuple_SET_ITEM(args, 2, pyop_dict_from_event(event)); } else if (mode==PYOP_EXEC) { item= PyObject_GetAttrString(py_class, "exec"); args = PyTuple_New(2); - RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); - py_context = pyrna_struct_CreatePyObject(&ptr_context); - PyTuple_SET_ITEM(args, 1, py_context); + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); } else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); @@ -398,7 +400,7 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) {PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL}, {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK}, {"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, - {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} }; -- cgit v1.2.3 From 6563e9ff8a6acd7f63038d8a9bbe727d312a2b29 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 11 Jun 2009 18:15:04 +0000 Subject: Started operator registration with python. This is a piece of cake! Made space_script header area customizable with python - need Brecht to check this. Added a base for operator registration: a menu in Scripts Window with two items "Reload Scripts" and "Export". The former will do guess what? The latter will be populated with submenu items each corresponding to an exporter :) --- release/ui/space_script.py | 73 ++++++++++++++++++++++ source/blender/editors/space_script/space_script.c | 31 ++++----- 2 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 release/ui/space_script.py diff --git a/release/ui/space_script.py b/release/ui/space_script.py new file mode 100644 index 00000000000..ea6f4be311c --- /dev/null +++ b/release/ui/space_script.py @@ -0,0 +1,73 @@ +import bpy + +class SCRIPT_HT_header(bpy.types.Header): + __space_type__ = "SCRIPTS_WINDOW" + __idname__ = "SCRIPT_HT_header" + + def draw(self, context): + st = context.space_data + layout = self.layout + + layout.template_header(context) + + if context.area.show_menus: + row = layout.row(align=True) + row.itemM(context, "SCRIPT_MT_scripts") + + # draw menu item to reload scripts from + # release/io + # + # it should call operator or + # a func that will: + # for each .py file in the dir, + # import/reload module, in the module: + # find subclasses of bpy.types.Operator, + # for each subclass create menus under "Export" + # with (row.)itemO + # + # for interface api documentation, see + # see source/blender/editors/interface/interface_api.c + # + # hint: reloading ui scripts in scripts window is Shift+P + + +class SCRIPT_MT_scripts(bpy.types.Menu): + __space_type__ = "SCRIPTS_WINDOW" + __label__ = "Scripts" + + def draw(self, context): + layout = self.layout + layout.column() + layout.itemM(context, "SCRIPT_MT_export") + layout.itemO("SCRIPT_OT_reload_scripts") + +class SCRIPT_MT_export(bpy.types.Menu): + __space_type__ = "SCRIPTS_WINDOW" + __label__ = "Export" + + def draw(self, context): + pass + +class SCRIPT_OT_reload_scripts(bpy.types.Operator): + __label__ = 'Reload Scripts' + + def exec(self, context): + print("SCRIPT_OT_reload_scripts: exec") + return 'FINISHED' + + def invoke(self, context, event): + print("SCRIPT_OT_reload_scripts: invoke") + return self.exec(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) diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index 4c17ed16475..01f19b3a0ab 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -175,29 +175,32 @@ static void script_main_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void script_header_area_init(wmWindowManager *wm, ARegion *ar) { - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); + /* UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); */ + ED_region_header_init(ar); } static void script_header_area_draw(const bContext *C, ARegion *ar) { - float col[3]; + /* float col[3]; */ - /* clear */ - if(ED_screen_area_active(C)) - UI_GetThemeColor3fv(TH_HEADER, col); - else - UI_GetThemeColor3fv(TH_HEADERDESEL, col); + /* /\* clear *\/ */ + /* if(ED_screen_area_active(C)) */ + /* UI_GetThemeColor3fv(TH_HEADER, col); */ + /* else */ + /* UI_GetThemeColor3fv(TH_HEADERDESEL, col); */ - glClearColor(col[0], col[1], col[2], 0.0); - glClear(GL_COLOR_BUFFER_BIT); + /* glClearColor(col[0], col[1], col[2], 0.0); */ + /* glClear(GL_COLOR_BUFFER_BIT); */ - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(C, &ar->v2d); + /* /\* set view2d view matrix for scrolling (without scrollers) *\/ */ + /* UI_view2d_view_ortho(C, &ar->v2d); */ - script_header_buttons(C, ar); + /* script_header_buttons(C, ar); */ - /* restore view matrix? */ - UI_view2d_view_restore(C); + /* /\* restore view matrix? *\/ */ + /* UI_view2d_view_restore(C); */ + + ED_region_header(C, ar); } static void script_main_area_listener(ARegion *ar, wmNotifier *wmn) -- cgit v1.2.3 From 23eecb1e6e1824b8f6b13448a7eb164e6c73bc0f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 12 Jun 2009 09:54:28 +0000 Subject: Import/export operator registration working. Written in python, it traverses scripts in .blender/io extracting and registering Operator subclasses, and binding to menu items under Scripts->Export in Scripts Window. release/io dir has to be copied to .blender manually for now. --- release/io/export_obj.py | 28 ++++++++++++++ release/ui/space_script.py | 96 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 release/io/export_obj.py diff --git a/release/io/export_obj.py b/release/io/export_obj.py new file mode 100644 index 00000000000..37039bb11cb --- /dev/null +++ b/release/io/export_obj.py @@ -0,0 +1,28 @@ +import bpy + +class SCRIPT_OT_export_obj(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __label__ = 'Export OBJ' + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + __props__ = [ +# FloatProperty(attr="setting_1", name="Example 1", default=10.0, min=0, max=10, description="Add info here"), +# StringProperty(attr="filename") + ] + + def debug(self, message): + print("{0}: {1}".format(self.__class__.__name__, message)) + + def exec(self, context): +# print(self.setting_1) + self.debug("exec") + return 'FINISHED' + + def invoke(self, context, event): + self.debug("invoke") + return self.exec(context) + + def poll(self, context): # poll isnt working yet + self.debug("poll") + return True diff --git a/release/ui/space_script.py b/release/ui/space_script.py index ea6f4be311c..0ab091e8fd5 100644 --- a/release/ui/space_script.py +++ b/release/ui/space_script.py @@ -1,5 +1,25 @@ +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" @@ -14,23 +34,6 @@ class SCRIPT_HT_header(bpy.types.Header): row = layout.row(align=True) row.itemM(context, "SCRIPT_MT_scripts") - # draw menu item to reload scripts from - # release/io - # - # it should call operator or - # a func that will: - # for each .py file in the dir, - # import/reload module, in the module: - # find subclasses of bpy.types.Operator, - # for each subclass create menus under "Export" - # with (row.)itemO - # - # for interface api documentation, see - # see source/blender/editors/interface/interface_api.c - # - # hint: reloading ui scripts in scripts window is Shift+P - - class SCRIPT_MT_scripts(bpy.types.Menu): __space_type__ = "SCRIPTS_WINDOW" __label__ = "Scripts" @@ -46,13 +49,69 @@ class SCRIPT_MT_export(bpy.types.Menu): __label__ = "Export" def draw(self, context): - pass + 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 exec(self, context): print("SCRIPT_OT_reload_scripts: exec") + + # 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): @@ -62,7 +121,6 @@ class SCRIPT_OT_reload_scripts(bpy.types.Operator): def poll(self, context): pass - bpy.types.register(SCRIPT_HT_header) bpy.types.register(SCRIPT_MT_scripts) bpy.types.register(SCRIPT_MT_export) -- cgit v1.2.3 From 93d21f36b3450803958ab0a5686ad0a16fa367cd Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sun, 14 Jun 2009 16:48:19 +0000 Subject: Make release/io dir installable on scons build. --- SConstruct | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/SConstruct b/SConstruct index dcea0f511eb..808fa09bea0 100644 --- a/SConstruct +++ b/SConstruct @@ -468,27 +468,17 @@ if env['OURPLATFORM']!='darwin': dotblenderinstall.append(env.Install(dir=td, source=srcfile)) if env['WITH_BF_PYTHON']: - #-- .blender/scripts - scriptpath='release/scripts' - for dp, dn, df in os.walk(scriptpath): - if 'CVS' in dn: - dn.remove('CVS') - if '.svn' in dn: - dn.remove('.svn') - dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):] - source=[dp+os.sep+f for f in df] - scriptinstall.append(env.Install(dir=dir,source=source)) - - #-- .blender/ui - scriptpath='release/ui' - for dp, dn, df in os.walk(scriptpath): - if 'CVS' in dn: - dn.remove('CVS') - if '.svn' in dn: - dn.remove('.svn') - dir=env['BF_INSTALLDIR']+'/.blender/ui'+dp[len(scriptpath):] - source=[dp+os.sep+f for f in df] - scriptinstall.append(env.Install(dir=dir,source=source)) + #-- .blender/scripts, .blender/ui, .blender/io + scriptpaths=['release/scripts', 'release/ui', 'release/io'] + for scriptpath in scriptpaths: + for dp, dn, df in os.walk(scriptpath): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + dir=env['BF_INSTALLDIR']+'/.blender/'+os.path.basename(scriptpath)+dp[len(scriptpath):] + source=[dp+os.sep+f for f in df] + scriptinstall.append(env.Install(dir=dir,source=source)) #-- icons if env['OURPLATFORM']=='linux2': -- cgit v1.2.3 From fd893819bcc3d4952e785fcf903ed9bc10d7830e Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 15 Jun 2009 07:47:09 +0000 Subject: Fix bug in BPY_flag_from_seq: reset the flag before adjusting it. Otherwise py operators ended up returning something like OPERATOR_CANCELLED | OPERATOR_FINISHED. --- source/blender/python/intern/bpy_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index c447e7de982..8dd81834213 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -81,6 +81,7 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) char *cstring; PyObject *item; BPY_flag_def *fd; + *flag = 0; if (PySequence_Check(seq)) { i= PySequence_Length(seq); -- cgit v1.2.3 From c7cdb9cc38aa1cbe0772041a21f0bb1640b06220 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 15 Jun 2009 08:12:28 +0000 Subject: File selector working. For now it is accessed as context.add_fileselect(self.__operator__). To allow file selector, I made the following changes: - moved property definition funcs (FloatProperty, etc.) to "bpy.props" to make them accessible from io scripts. Previously they were only accessible in scripts running from Text Editor. - added the "__operator__" instance attribute to py operators. The value is RNA operator pointer. Note that "context.add_fileselect" changes were mistakenly committed with my last merge. --- release/io/export_obj.py | 8 ++++++-- source/blender/python/intern/bpy_interface.c | 17 +---------------- source/blender/python/intern/bpy_operator_wrap.c | 8 ++++++++ source/blender/python/intern/bpy_rna.c | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 37039bb11cb..663ec6c0478 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -1,3 +1,4 @@ + import bpy class SCRIPT_OT_export_obj(bpy.types.Operator): @@ -7,6 +8,7 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. __props__ = [ + bpy.props["StringProperty"](attr="filename", name="filename", default="/tmp") # FloatProperty(attr="setting_1", name="Example 1", default=10.0, min=0, max=10, description="Add info here"), # StringProperty(attr="filename") ] @@ -17,11 +19,13 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): def exec(self, context): # print(self.setting_1) self.debug("exec") - return 'FINISHED' + self.debug("filename = " + self.filename) + return ('FINISHED',) def invoke(self, context, event): self.debug("invoke") - return self.exec(context) + context.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) #self.exec(context) def poll(self, context): # poll isnt working yet self.debug("poll") diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 4903af475ed..5c33c63028a 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -60,6 +60,7 @@ static void bpy_init_modules( void ) PyModule_AddObject( mod, "types", BPY_rna_types() ); PyModule_AddObject( mod, "ops", BPY_operator_module() ); PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experemental, consider this a test, especially PyCObject is not meant to be perminant + PyModule_AddObject( mod, "props", BPY_rna_props() ); /* add the module so we can import it */ PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); @@ -95,22 +96,6 @@ static PyObject *CreateGlobalDictionary( bContext *C ) // XXX - evil, need to access context BPy_SetContext(C); - // XXX - put somewhere more logical - { - PyMethodDef *ml; - static PyMethodDef bpy_prop_meths[] = { - {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {NULL, NULL, 0, NULL} - }; - - for(ml = bpy_prop_meths; ml->ml_name; ml++) { - PyDict_SetItemString( dict, ml->ml_name, PyCFunction_New(ml, NULL)); - } - } - /* add bpy to global namespace */ mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0); PyDict_SetItemString( dict, "bpy", mod ); diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index d951d40b9db..33715a97a43 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -225,6 +225,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PointerRNA ptr_context; + PyObject ptr_operator; + PyObject *py_operator; PyGILState_STATE gilstate = PyGILState_Ensure(); @@ -261,6 +263,12 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve RNA_property_collection_end(&iter); } + /* set operator pointer RNA as instance "__operator__" attribute */ + RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); + py_operator= pyrna_struct_CreatePyObject(&ptr_operator); + PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); + Py_DECREF(py_operator); + RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); if (mode==PYOP_INVOKE) { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 09e2ab15c56..d1c06802f0a 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1750,7 +1750,24 @@ PyObject *BPY_rna_types(void) return (PyObject *)self; } +PyObject *BPY_rna_props( void ) +{ + PyObject *dict = PyDict_New( ); + PyMethodDef *ml; + static PyMethodDef bpy_prop_meths[] = { + {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {NULL, NULL, 0, NULL} + }; + + for(ml = bpy_prop_meths; ml->ml_name; ml++) { + PyDict_SetItemString( dict, ml->ml_name, PyCFunction_New(ml, NULL)); + } + return dict; +} /* Orphan functions, not sure where they should go */ -- cgit v1.2.3 From 07e1b84ca8f2ad83b148df03b697a0bcfdb04e3a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 15 Jun 2009 09:26:31 +0000 Subject: Another fix in BPY_flag_from_seq: unrecognized flag is also an error. Print operator return value for debugging. --- release/ui/space_script.py | 2 +- source/blender/python/intern/bpy_operator_wrap.c | 26 +++++++++++++++++++++++- source/blender/python/intern/bpy_util.c | 3 +++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/release/ui/space_script.py b/release/ui/space_script.py index 0ab091e8fd5..d2c73adb00f 100644 --- a/release/ui/space_script.py +++ b/release/ui/space_script.py @@ -112,7 +112,7 @@ class SCRIPT_OT_reload_scripts(bpy.types.Operator): register_op(cls) print("Registered it.") - return 'FINISHED' + return ('FINISHED',) def invoke(self, context, event): print("SCRIPT_OT_reload_scripts: invoke") diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 33715a97a43..4624fe764b3 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -316,7 +316,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) { /* the returned value could not be converted into a flag */ pyop_error_report(op->reports); - + + ret_flag = OPERATOR_CANCELLED; } /* there is no need to copy the py keyword dict modified by * pyot->py_invoke(), back to the operator props since they are just @@ -329,6 +330,29 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(ret); } + /* print operator return value */ + if (mode != PYOP_POLL) { + char flag_str[100]; + char class_name[100]; + BPY_flag_def *flag_def = pyop_ret_flags; + + strcpy(flag_str, ""); + + while(flag_def->name) { + if (ret_flag & flag_def->flag) { + flag_str[1] ? sprintf(flag_str, "%s | %s", flag_str, flag_def->name) : strcpy(flag_str, flag_def->name); + } + flag_def++; + } + + /* get class name */ + item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); + Py_DECREF(item); + strcpy(class_name, _PyUnicode_AsString(item)); + + fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "exec" : "invoke", flag_str); + } + PyGILState_Release(gilstate); return ret_flag; diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 8dd81834213..2c7626fea7f 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -109,6 +109,9 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) error_val= 1; } + if (*flag == 0) + error_val = 1; + if (error_val) { char *buf = bpy_flag_error_str(flagdef); PyErr_SetString(PyExc_AttributeError, buf); -- cgit v1.2.3 From 678417b76c228d30417889aa91ad9c2b14cbe4fe Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 15 Jun 2009 13:49:02 +0000 Subject: Added copy_applied method on Mesh objects. Uses DerivedMesh funcs to get a mesh with all modifiers applied. --- release/io/export_obj.py | 29 ++++++++++---- source/blender/editors/mesh/editmesh.c | 56 ++++++--------------------- source/blender/makesrna/intern/rna_internal.h | 6 +++ source/blender/makesrna/intern/rna_mesh.c | 12 ++++-- 4 files changed, 48 insertions(+), 55 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 663ec6c0478..c5b8038a3d7 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -1,4 +1,3 @@ - import bpy class SCRIPT_OT_export_obj(bpy.types.Operator): @@ -8,24 +7,40 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. __props__ = [ - bpy.props["StringProperty"](attr="filename", name="filename", default="/tmp") -# FloatProperty(attr="setting_1", name="Example 1", default=10.0, min=0, max=10, description="Add info here"), -# StringProperty(attr="filename") + bpy.props["StringProperty"](attr="filename", name="filename") ] def debug(self, message): print("{0}: {1}".format(self.__class__.__name__, message)) def exec(self, context): -# print(self.setting_1) self.debug("exec") self.debug("filename = " + self.filename) + + self.debug("num selected objects: {0}".format(len(context.selected_objects))) + + ob = bpy.data.objects["Cube"] + o = ob.data + + m = bpy.data.add_mesh("tmpmesh") + m.copy_applied(context.scene, ob, True) + + def vert(co): + return "{0}, {1}, {2}".format(co[0], co[1], co[2]) + + print(" orig: {0} with totverts={1}".format(vert(o.verts[0].co), len(o.verts))) + print("applied: {0} with totverts={1}".format(vert(m.verts[0].co), len(m.verts))) + + # XXX errors are silenced for some reason +# raise Exception("oops!") + return ('FINISHED',) def invoke(self, context, event): self.debug("invoke") - context.add_fileselect(self.__operator__) - return ('RUNNING_MODAL',) #self.exec(context) +# context.add_fileselect(self.__operator__) +# return ('RUNNING_MODAL',) + return self.exec(context) def poll(self, context): # poll isnt working yet self.debug("poll") diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index bce5c202366..de4bab57a72 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2041,6 +2041,16 @@ void RNA_api_mesh_copy(Mesh *me, Mesh *from) copy_mesh_data(me, from); } +void RNA_api_mesh_copy_applied(Mesh *me, Scene *sce, Object *ob, int apply_obmat) +{ + DerivedMesh *dm= mesh_create_derived_view(sce, ob, CD_MASK_MESH); + DM_to_mesh(dm, me); + dm->release(dm); + + if (apply_obmat) { + } +} + void RNA_api_mesh_transform(Mesh *me, float **mat) { } @@ -2048,6 +2058,8 @@ void RNA_api_mesh_transform(Mesh *me, float **mat) /* * This version of copy_mesh doesn't allocate a new mesh, * instead it copies data between two existing meshes. + * + * XXX is this already possible with DerivedMesh? */ void copy_mesh_data(Mesh *dest, Mesh *src) { @@ -2078,47 +2090,3 @@ void copy_mesh_data(Mesh *dest, Mesh *src) mesh_update_customdata_pointers(dest); } - -/* -void RNA_api_mesh_apply_transform(Mesh *me) -{ - -} -*/ - -/* -void RNA_api_mesh_copy_(Mesh *me, Object *ob, int apply_transform) -{ - if (ob->type != OB_MESH) { - return; - } - - Mesh *src= (Mesh*)ob->data; - - CustomData_free(&me->vdata, me->totvert); - CustomData_free(&me->edata, me->totedge); - CustomData_free(&me->fdata, me->totface); - - CustomData_copy(&src->vdata, &me->vdata, CD_MASK_MESH, CD_DUPLICATE, me->totvert); - CustomData_copy(&src->edata, &me->edata, CD_MASK_MESH, CD_DUPLICATE, me->totedge); - CustomData_copy(&src->fdata, &me->fdata, CD_MASK_MESH, CD_DUPLICATE, me->totface); - mesh_update_customdata_pointers(me); - - // ensure indirect linked data becomes lib-extern - for(i=0; ifdata.totlayer; i++) { - if(src->fdata.layers[i].type == CD_MTFACE) { - tface= (MTFace*)src->fdata.layers[i].data; - - for(a=0; atotface; a++, tface++) - if(tface->tpage) - id_lib_extern((ID*)tface->tpage); - } - } - - me->mselect= NULL; - me->bb= src->bb; - - //men->key= copy_key(me->key); - //if(men->key) men->key->from= (ID *)men; -} -*/ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index d93c296ca93..4d3b9dfa327 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -188,9 +188,15 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, const char *value, ch /* API functions */ +struct Main; +struct Scene; +struct Object; +struct Mesh; + void RNA_api_ui_layout(struct StructRNA *srna); struct Mesh *RNA_api_add_mesh(struct Main *main, char *name); void RNA_api_mesh_copy(struct Mesh *me, struct Mesh *from); +void RNA_api_mesh_copy_applied(struct Mesh *me, struct Scene *sce, struct Object *ob, int apply_obmat); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index a071a79230e..35b8164fae3 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1132,10 +1132,14 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_function_ui_description(func, "Copy mesh data."); prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from."); RNA_def_property_flag(prop, PROP_REQUIRED); - /* - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); - RNA_def_function_return(func, prop); - */ + + func= RNA_def_function(srna, "copy_applied", "RNA_api_mesh_copy_applied"); + RNA_def_function_ui_description(func, "Copy mesh data from object with all modifiers and transformations applied."); + prop= RNA_def_pointer(func, "sce", "Scene", "", "Scene."); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop= RNA_def_pointer(func, "ob", "Object", "", "Object to copy data from."); + RNA_def_property_flag(prop, PROP_REQUIRED); + RNA_def_boolean(func, "apply_obmat", 1, "", "Apply object matrix."); } void RNA_def_mesh(BlenderRNA *brna) -- cgit v1.2.3 From 556369fe2fcb33ec4a028cc1a9c1ae1d0701e6ba Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 16 Jun 2009 08:54:38 +0000 Subject: The basic OBJ exporter working. The code is release/io/export_obj.py. To run it, switch to Scripts Window, click Scripts->Reload Scripts menu, it appears under Scripts->Export. --- release/io/export_obj.py | 54 +++++++++++++++++++-------- source/blender/editors/mesh/editmesh.c | 5 +-- source/blender/makesrna/intern/rna_internal.h | 2 +- source/blender/makesrna/intern/rna_mesh.c | 3 +- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index c5b8038a3d7..df10c3e9089 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -1,7 +1,37 @@ import bpy +def write_obj(filepath, scene, ob): + out = open(filepath, 'w') + + # create a temporary mesh + mesh = bpy.data.add_mesh("tmpmesh") + + # copy data with modifiers applied + mesh.copy_applied(scene, ob) + + # for vert in mesh.verts: + # ^ iterating that way doesn't work atm for some reason + + for i in range(len(mesh.verts)): + vert = mesh.verts[i] + out.write('v {0} {1} {2}\n'.format(vert.co[0], vert.co[1], vert.co[2])) + + for i in range(len(mesh.faces)): + face = mesh.faces[i] + out.write('f') + + # but this works + for index in face.verts: + out.write(' {0}'.format(index + 1)) + out.write('\n') + + # TODO: delete mesh here + + out.close() + class SCRIPT_OT_export_obj(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' + '''A very basic OBJ exporter, writes only active object's mesh.''' + __label__ = 'Export OBJ' # List of operator properties, the attributes will be assigned @@ -17,19 +47,12 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): self.debug("exec") self.debug("filename = " + self.filename) - self.debug("num selected objects: {0}".format(len(context.selected_objects))) - - ob = bpy.data.objects["Cube"] - o = ob.data - - m = bpy.data.add_mesh("tmpmesh") - m.copy_applied(context.scene, ob, True) - - def vert(co): - return "{0}, {1}, {2}".format(co[0], co[1], co[2]) + act = context.active_object - print(" orig: {0} with totverts={1}".format(vert(o.verts[0].co), len(o.verts))) - print("applied: {0} with totverts={1}".format(vert(m.verts[0].co), len(m.verts))) + if act.type == 'MESH': + write_obj(self.filename, context.scene, act) + else: + self.debug("Active object is not a MESH.") # XXX errors are silenced for some reason # raise Exception("oops!") @@ -38,9 +61,8 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): def invoke(self, context, event): self.debug("invoke") -# context.add_fileselect(self.__operator__) -# return ('RUNNING_MODAL',) - return self.exec(context) + context.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) def poll(self, context): # poll isnt working yet self.debug("poll") diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index de4bab57a72..33174e31df5 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2041,14 +2041,11 @@ void RNA_api_mesh_copy(Mesh *me, Mesh *from) copy_mesh_data(me, from); } -void RNA_api_mesh_copy_applied(Mesh *me, Scene *sce, Object *ob, int apply_obmat) +void RNA_api_mesh_copy_applied(Mesh *me, Scene *sce, Object *ob) { DerivedMesh *dm= mesh_create_derived_view(sce, ob, CD_MASK_MESH); DM_to_mesh(dm, me); dm->release(dm); - - if (apply_obmat) { - } } void RNA_api_mesh_transform(Mesh *me, float **mat) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 4d3b9dfa327..aad70ec57b0 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -196,7 +196,7 @@ struct Mesh; void RNA_api_ui_layout(struct StructRNA *srna); struct Mesh *RNA_api_add_mesh(struct Main *main, char *name); void RNA_api_mesh_copy(struct Mesh *me, struct Mesh *from); -void RNA_api_mesh_copy_applied(struct Mesh *me, struct Scene *sce, struct Object *ob, int apply_obmat); +void RNA_api_mesh_copy_applied(struct Mesh *me, struct Scene *sce, struct Object *ob); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 35b8164fae3..574bfee49f6 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1134,12 +1134,11 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REQUIRED); func= RNA_def_function(srna, "copy_applied", "RNA_api_mesh_copy_applied"); - RNA_def_function_ui_description(func, "Copy mesh data from object with all modifiers and transformations applied."); + RNA_def_function_ui_description(func, "Copy mesh data from object with all modifiers applied."); prop= RNA_def_pointer(func, "sce", "Scene", "", "Scene."); RNA_def_property_flag(prop, PROP_REQUIRED); prop= RNA_def_pointer(func, "ob", "Object", "", "Object to copy data from."); RNA_def_property_flag(prop, PROP_REQUIRED); - RNA_def_boolean(func, "apply_obmat", 1, "", "Apply object matrix."); } void RNA_def_mesh(BlenderRNA *brna) -- cgit v1.2.3 From 16d8cc633db5e1e3168d9ce9bbea62957d973024 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 16 Jun 2009 12:42:14 +0000 Subject: WARNING: I'm starting generic RNA collection add ;) --- source/blender/makesrna/intern/rna_access.c | 24 ++++++++++++++++++++++++ source/blender/makesrna/intern/rna_internal.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 870fa4d9aa3..71044cbfe13 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1342,6 +1342,8 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA else printf("RNA_property_collection_add %s.%s: only supported for id properties.\n", ptr->type->identifier, prop->identifier); + /* TODO: call cprop->add on non-ID props here */ + if(r_ptr) { if(idprop) { CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop; @@ -1510,6 +1512,13 @@ void rna_iterator_listbase_end(CollectionPropertyIterator *iter) iter->internal= NULL; } +void *rna_iterator_listbase_add(ListBase *lb, void *item) +{ + BLI_addtail(lb, item); + + return item; +} + void rna_iterator_array_begin(CollectionPropertyIterator *iter, void *ptr, int itemsize, int length, IteratorSkipFunc skip) { ArrayIterator *internal; @@ -1567,6 +1576,21 @@ void rna_iterator_array_end(CollectionPropertyIterator *iter) iter->internal= NULL; } +void *rna_iterator_array_add(void *ptr, int itemsize, int length, void *item) +{ + // alloc new block, copy old data + void *newptr= MEM_callocN(length * itemsize + itemsize, "RNA collection add"); + memcpy(newptr, ptr, length * itemsize); + + // copy new item + memcpy(((char*)newptr) + length * itemsize, item, itemsize); + + // free old block + MEM_freeN(ptr); + + return newptr; +} + /* RNA Path - Experiment */ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int bracket) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index aad70ec57b0..531268768d3 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -237,6 +237,9 @@ void rna_iterator_listbase_next(struct CollectionPropertyIterator *iter); void *rna_iterator_listbase_get(struct CollectionPropertyIterator *iter); void rna_iterator_listbase_end(struct CollectionPropertyIterator *iter); +/* experimental */ +void *rna_iterator_listbase_add(ListBase *lb, void *item); + typedef struct ArrayIterator { char *ptr; char *endptr; @@ -250,6 +253,9 @@ void *rna_iterator_array_get(struct CollectionPropertyIterator *iter); void *rna_iterator_array_dereference_get(struct CollectionPropertyIterator *iter); void rna_iterator_array_end(struct CollectionPropertyIterator *iter); +/* experimental */ +void *rna_iterator_array_add(void *ptr, void *data); + /* Duplicated code since we can't link in blenlib */ void rna_addtail(struct ListBase *listbase, void *vlink); -- cgit v1.2.3 From 7a54e45ccdaed5d7fa802fa20a31fda205b04294 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 16 Jun 2009 13:57:28 +0000 Subject: Just added another param to RNA_def_property_collection_funcs and zeroed it in each call. --- source/blender/makesrna/RNA_define.h | 2 +- source/blender/makesrna/intern/rna_color.c | 2 +- source/blender/makesrna/intern/rna_curve.c | 2 +- source/blender/makesrna/intern/rna_define.c | 5 +++-- source/blender/makesrna/intern/rna_group.c | 2 +- source/blender/makesrna/intern/rna_internal.h | 2 +- .../blender/makesrna/intern/rna_internal_types.h | 2 ++ source/blender/makesrna/intern/rna_key.c | 2 +- source/blender/makesrna/intern/rna_lattice.c | 4 ++-- source/blender/makesrna/intern/rna_main.c | 2 +- source/blender/makesrna/intern/rna_material.c | 2 +- source/blender/makesrna/intern/rna_mesh.c | 22 +++++++++++----------- source/blender/makesrna/intern/rna_modifier.c | 2 +- source/blender/makesrna/intern/rna_object.c | 2 +- source/blender/makesrna/intern/rna_rna.c | 10 +++++----- source/blender/makesrna/intern/rna_scene.c | 2 +- source/blender/makesrna/intern/rna_sequence.c | 2 +- 17 files changed, 35 insertions(+), 32 deletions(-) diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index c40f50c34fc..553d0ecf028 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -146,7 +146,7 @@ void RNA_def_property_float_funcs(PropertyRNA *prop, const char *get, const char void RNA_def_property_enum_funcs(PropertyRNA *prop, const char *get, const char *set, const char *item); void RNA_def_property_string_funcs(PropertyRNA *prop, const char *get, const char *length, const char *set); void RNA_def_property_pointer_funcs(PropertyRNA *prop, const char *get, const char *set, const char *typef); -void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, const char *end, const char *get, const char *length, const char *lookupint, const char *lookupstring); +void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, const char *end, const char *get, const char *length, const char *lookupint, const char *lookupstring, const char *add); /* Function */ diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index dcd5a494e5d..ef9bd86c2d9 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -212,7 +212,7 @@ static void rna_def_curvemapping(BlenderRNA *brna) RNA_def_property_float_funcs(prop, NULL, NULL, "rna_CurveMapping_clipmaxy_range"); prop= RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_CurveMapping_curves_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_CurveMapping_curves_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_CurveMapping_curves_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_CurveMapping_curves_length", 0, 0, 0); RNA_def_property_struct_type(prop, "CurveMap"); RNA_def_property_ui_text(prop, "Curves", ""); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index aac9d75c6a6..6b3c9767e2e 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -605,7 +605,7 @@ static void rna_def_curve_nurb(BlenderRNA *brna) prop= RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "bp", NULL); RNA_def_property_struct_type(prop, "CurvePoint"); - RNA_def_property_collection_funcs(prop, "rna_BPoint_array_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_Nurb_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_BPoint_array_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_Nurb_length", 0, 0, 0); RNA_def_property_ui_text(prop, "Points", "Collection of points for Poly and Nurbs curves."); prop= RNA_def_property(srna, "bezier_points", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 33d94e800d1..6b72646da4a 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -604,7 +604,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * if(DefRNA.preprocess) { RNA_def_property_struct_type(prop, "Property"); - RNA_def_property_collection_funcs(prop, "rna_builtin_properties_begin", "rna_builtin_properties_next", "rna_iterator_listbase_end", "rna_builtin_properties_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_builtin_properties_begin", "rna_builtin_properties_next", "rna_iterator_listbase_end", "rna_builtin_properties_get", 0, 0, 0, 0); } else { #ifdef RNA_RUNTIME @@ -1769,7 +1769,7 @@ void RNA_def_property_pointer_funcs(PropertyRNA *prop, const char *get, const ch } } -void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, const char *end, const char *get, const char *length, const char *lookupint, const char *lookupstring) +void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, const char *end, const char *get, const char *length, const char *lookupint, const char *lookupstring, const char *add) { StructRNA *srna= DefRNA.laststruct; @@ -1789,6 +1789,7 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, con if(length) cprop->length= (PropCollectionLengthFunc)length; if(lookupint) cprop->lookupint= (PropCollectionLookupIntFunc)lookupint; if(lookupstring) cprop->lookupstring= (PropCollectionLookupStringFunc)lookupstring; + if(add) cprop->add= (PropCollectionAddFunc)add; break; } default: diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index 059b2ce78f7..f284423ef7f 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -61,7 +61,7 @@ void RNA_def_group(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "gobject", NULL); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Objects", "A collection of this groups objects."); - RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_Group_objects_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_Group_objects_get", 0, 0, 0, 0); prop= RNA_def_property(srna, "layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "layer", 1); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 531268768d3..467e0dabb24 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -254,7 +254,7 @@ void *rna_iterator_array_dereference_get(struct CollectionPropertyIterator *iter void rna_iterator_array_end(struct CollectionPropertyIterator *iter); /* experimental */ -void *rna_iterator_array_add(void *ptr, void *data); +void *rna_iterator_array_add(void *ptr, int itemsize, int length, void *item); /* Duplicated code since we can't link in blenlib */ diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index d690251f503..1a3668813c8 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -78,6 +78,7 @@ typedef PointerRNA (*PropCollectionGetFunc)(struct CollectionPropertyIterator *i typedef int (*PropCollectionLengthFunc)(struct PointerRNA *ptr); typedef PointerRNA (*PropCollectionLookupIntFunc)(struct PointerRNA *ptr, int key); typedef PointerRNA (*PropCollectionLookupStringFunc)(struct PointerRNA *ptr, const char *key); +typedef void (*PropCollectionAddFunc)(PointerRNA *ptr, PointerRNA *item); /* Container - generic abstracted container of RNA properties */ typedef struct ContainerRNA { @@ -243,6 +244,7 @@ typedef struct CollectionPropertyRNA { PropCollectionLengthFunc length; /* optional */ PropCollectionLookupIntFunc lookupint; /* optional */ PropCollectionLookupStringFunc lookupstring; /* optional */ + PropCollectionAddFunc add; struct StructRNA *type; } CollectionPropertyRNA; diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index ae03cca74c2..3070e0a9076 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -335,7 +335,7 @@ static void rna_def_keyblock(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "data", "totelem"); RNA_def_property_struct_type(prop, "UnknownType"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_ShapeKey_data_begin", 0, 0, "rna_ShapeKey_data_get", "rna_ShapeKey_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_ShapeKey_data_begin", 0, 0, "rna_ShapeKey_data_get", "rna_ShapeKey_data_length", 0, 0, 0); } static void rna_def_key(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c index 26c4ebb7b23..de547eab617 100644 --- a/source/blender/makesrna/intern/rna_lattice.c +++ b/source/blender/makesrna/intern/rna_lattice.c @@ -99,7 +99,7 @@ static void rna_def_latticepoint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformed Location", ""); prop= RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_LatticePoint_groups_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_LatticePoint_groups_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0, 0); RNA_def_property_struct_type(prop, "VertexGroupElement"); RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this point is member of."); } @@ -159,7 +159,7 @@ static void rna_def_lattice(BlenderRNA *brna) prop= RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "LatticePoint"); - RNA_def_property_collection_funcs(prop, "rna_Lattice_points_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Lattice_points_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Points", "Points of the lattice."); } diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 347aef69a76..22f19d725cb 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -264,7 +264,7 @@ void RNA_def_main(BlenderRNA *brna) { prop= RNA_def_property(srna, lists[i][0], PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, lists[i][1]); - RNA_def_property_collection_funcs(prop, lists[i][2], "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, lists[i][2], "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, lists[i][3], lists[i][4]); } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a5dbb63adf2..1ab70154442 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1048,7 +1048,7 @@ void rna_def_mtex_common(StructRNA *srna, const char *begin, const char *activeg /* mtex */ prop= RNA_def_property(srna, "textures", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, structname); - RNA_def_property_collection_funcs(prop, begin, "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_dereference_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, begin, "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_dereference_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Textures", "Texture slots defining the mapping and influence of textures."); prop= RNA_def_property(srna, "active_texture", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 574bfee49f6..18a94d97296 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -646,7 +646,7 @@ static void rna_def_mvert(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Bevel Weight", "Weight used by the Bevel modifier 'Only Vertices' option"); prop= RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_MeshVertex_groups_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshVertex_groups_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0, 0); RNA_def_property_struct_type(prop, "VertexGroupElement"); RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this vertex is member of."); } @@ -761,7 +761,7 @@ static void rna_def_mtface(BlenderRNA *brna) prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MeshTextureFace"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshTextureFaceLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshTextureFaceLayer_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshTextureFaceLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshTextureFaceLayer_data_length", 0, 0, 0); srna= RNA_def_struct(brna, "MeshTextureFace", NULL); RNA_def_struct_sdna(srna, "MTFace"); @@ -902,7 +902,7 @@ static void rna_def_mcol(BlenderRNA *brna) prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MeshColor"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshColorLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshColorLayer_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshColorLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshColorLayer_data_length", 0, 0, 0); srna= RNA_def_struct(brna, "MeshColor", NULL); RNA_def_struct_sdna(srna, "MCol"); @@ -948,7 +948,7 @@ static void rna_def_mproperties(BlenderRNA *brna) prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MeshFloatProperty"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshFloatPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshFloatPropertyLayer_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshFloatPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshFloatPropertyLayer_data_length", 0, 0, 0); srna= RNA_def_struct(brna, "MeshFloatProperty", NULL); RNA_def_struct_sdna(srna, "MFloatProperty"); @@ -972,7 +972,7 @@ static void rna_def_mproperties(BlenderRNA *brna) prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MeshIntProperty"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshIntPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshIntPropertyLayer_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshIntPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshIntPropertyLayer_data_length", 0, 0, 0); srna= RNA_def_struct(brna, "MeshIntProperty", NULL); RNA_def_struct_sdna(srna, "MIntProperty"); @@ -996,7 +996,7 @@ static void rna_def_mproperties(BlenderRNA *brna) prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "MeshStringProperty"); RNA_def_property_ui_text(prop, "Data", ""); - RNA_def_property_collection_funcs(prop, "rna_MeshStringPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshStringPropertyLayer_data_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MeshStringPropertyLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshStringPropertyLayer_data_length", 0, 0, 0); srna= RNA_def_struct(brna, "MeshStringProperty", NULL); RNA_def_struct_sdna(srna, "MStringProperty"); @@ -1072,31 +1072,31 @@ static void rna_def_mesh(BlenderRNA *brna) prop= RNA_def_property(srna, "uv_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); - RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_layers_begin", 0, 0, 0, "rna_Mesh_uv_layers_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_layers_begin", 0, 0, 0, "rna_Mesh_uv_layers_length", 0, 0, 0); RNA_def_property_struct_type(prop, "MeshTextureFaceLayer"); RNA_def_property_ui_text(prop, "UV Layers", ""); prop= RNA_def_property(srna, "vcol_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); - RNA_def_property_collection_funcs(prop, "rna_Mesh_vcol_layers_begin", 0, 0, 0, "rna_Mesh_vcol_layers_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mesh_vcol_layers_begin", 0, 0, 0, "rna_Mesh_vcol_layers_length", 0, 0, 0); RNA_def_property_struct_type(prop, "MeshColorLayer"); RNA_def_property_ui_text(prop, "Vertex Color Layers", ""); prop= RNA_def_property(srna, "float_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); - RNA_def_property_collection_funcs(prop, "rna_Mesh_float_layers_begin", 0, 0, 0, "rna_Mesh_float_layers_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mesh_float_layers_begin", 0, 0, 0, "rna_Mesh_float_layers_length", 0, 0, 0); RNA_def_property_struct_type(prop, "MeshFloatPropertyLayer"); RNA_def_property_ui_text(prop, "Float Property Layers", ""); prop= RNA_def_property(srna, "int_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); - RNA_def_property_collection_funcs(prop, "rna_Mesh_int_layers_begin", 0, 0, 0, "rna_Mesh_int_layers_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mesh_int_layers_begin", 0, 0, 0, "rna_Mesh_int_layers_length", 0, 0, 0); RNA_def_property_struct_type(prop, "MeshIntPropertyLayer"); RNA_def_property_ui_text(prop, "Int Property Layers", ""); prop= RNA_def_property(srna, "string_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); - RNA_def_property_collection_funcs(prop, "rna_Mesh_string_layers_begin", 0, 0, 0, "rna_Mesh_string_layers_length", 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mesh_string_layers_begin", 0, 0, 0, "rna_Mesh_string_layers_length", 0, 0, 0); RNA_def_property_struct_type(prop, "MeshStringPropertyLayer"); RNA_def_property_ui_text(prop, "String Property Layers", ""); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index fe5bd6ad727..56e16a8f21e 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1089,7 +1089,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) prop= RNA_def_property(srna, "projectors", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_collection_funcs(prop, "rna_UVProject_projectors_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_dereference_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_UVProject_projectors_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_dereference_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Projectors", ""); prop= RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 86cf501295c..4d5cef123dc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -739,7 +739,7 @@ static StructRNA *rna_def_object(BlenderRNA *brna) prop= RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); RNA_def_property_struct_type(prop, "MaterialSlot"); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", 0, 0, 0); /* don't dereference pointer! */ + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", 0, 0, 0, 0); /* don't dereference pointer! */ RNA_def_property_ui_text(prop, "Materials", "Material slots in the object."); prop= RNA_def_property(srna, "active_material", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 8ea8844c65f..e0f670e8ded 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -611,13 +611,13 @@ static void rna_def_struct(BlenderRNA *brna) prop= RNA_def_property(srna, "properties", PROP_COLLECTION, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Property"); - RNA_def_property_collection_funcs(prop, "rna_Struct_properties_begin", "rna_Struct_properties_next", "rna_iterator_listbase_end", "rna_Struct_properties_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Struct_properties_begin", "rna_Struct_properties_next", "rna_iterator_listbase_end", "rna_Struct_properties_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Properties", "Properties in the struct."); prop= RNA_def_property(srna, "functions", PROP_COLLECTION, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Function"); - RNA_def_property_collection_funcs(prop, "rna_Struct_functions_begin", "rna_Struct_functions_next", "rna_iterator_listbase_end", "rna_Struct_functions_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Struct_functions_begin", "rna_Struct_functions_next", "rna_iterator_listbase_end", "rna_Struct_functions_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Functions", ""); } @@ -719,7 +719,7 @@ static void rna_def_function(BlenderRNA *brna) prop= RNA_def_property(srna, "parameters", PROP_COLLECTION, PROP_NONE); /*RNA_def_property_clear_flag(prop, PROP_EDITABLE);*/ RNA_def_property_struct_type(prop, "Property"); - RNA_def_property_collection_funcs(prop, "rna_Function_parameters_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Function_parameters_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Parameters", "Parameters for the function."); prop= RNA_def_property(srna, "registered", PROP_BOOLEAN, PROP_NONE); @@ -800,7 +800,7 @@ static void rna_def_enum_property(BlenderRNA *brna, StructRNA *srna) prop= RNA_def_property(srna, "items", PROP_COLLECTION, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "EnumPropertyItem"); - RNA_def_property_collection_funcs(prop, "rna_EnumProperty_items_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_EnumProperty_items_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Items", "Possible values for the property."); srna= RNA_def_struct(brna, "EnumPropertyItem", NULL); @@ -895,7 +895,7 @@ void RNA_def_rna(BlenderRNA *brna) prop= RNA_def_property(srna, "structs", PROP_COLLECTION, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Struct"); - RNA_def_property_collection_funcs(prop, "rna_BlenderRNA_structs_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_BlenderRNA_structs_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0, 0); RNA_def_property_ui_text(prop, "Structs", ""); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 3907a633e3d..83b6df502a6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -866,7 +866,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "base", NULL); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Objects", ""); - RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_Scene_objects_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_Scene_objects_get", 0, 0, 0, 0); prop= RNA_def_property(srna, "visible_layers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "lay", 1); diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index b21e08fcd1a..b3975e2469e 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -519,7 +519,7 @@ void rna_def_editor(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "metastack", NULL); RNA_def_property_struct_type(prop, "Sequence"); RNA_def_property_ui_text(prop, "Meta Stack", "Meta strip stack, last is currently edited meta strip."); - RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_SequenceEdtior_meta_stack_get", 0, 0, 0); + RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_SequenceEdtior_meta_stack_get", 0, 0, 0, 0); prop= RNA_def_property(srna, "active_strip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "act_seq"); -- cgit v1.2.3 From bbec5c03c989fca91ba8be9f3c002c6cb2980415 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 16 Jun 2009 16:15:19 +0000 Subject: Updated makesrna to generate correct CollectionPropertyRNAs. --- source/blender/makesrna/intern/makesrna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index ea587174f54..304a008229a 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1628,7 +1628,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr } case PROP_COLLECTION: { CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop; - fprintf(f, "\t%s, %s, %s, %s, %s, %s, %s, ", rna_function_string(cprop->begin), rna_function_string(cprop->next), rna_function_string(cprop->end), rna_function_string(cprop->get), rna_function_string(cprop->length), rna_function_string(cprop->lookupint), rna_function_string(cprop->lookupstring)); + fprintf(f, "\t%s, %s, %s, %s, %s, %s, %s, %s, ", rna_function_string(cprop->begin), rna_function_string(cprop->next), rna_function_string(cprop->end), rna_function_string(cprop->get), rna_function_string(cprop->length), rna_function_string(cprop->lookupint), rna_function_string(cprop->lookupstring), rna_function_string(cprop->add)); if(cprop->type) fprintf(f, "&RNA_%s\n", (char*)cprop->type); else fprintf(f, "NULL\n"); break; -- cgit v1.2.3 From 449555315a45fe4e58cc20d5685c60063444543f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 16 Jun 2009 18:02:38 +0000 Subject: RNA_property_collection_add should work now for non-ID properties. Since it's very limited, and has a doubtful interface, I need help on how improve and use it. I'll ask on ML. --- source/blender/makesrna/intern/rna_access.c | 8 ++++--- .../blender/makesrna/intern/rna_internal_types.h | 2 +- source/blender/makesrna/intern/rna_mesh.c | 28 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 71044cbfe13..f114e72e990 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1314,6 +1314,7 @@ int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop) void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr) { IDProperty *idprop; + CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop; if((idprop=rna_idproperty_check(&prop, ptr))) { IDPropertyTemplate val = {0}; @@ -1339,10 +1340,11 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA MEM_freeN(item); } } + else if(cprop->add){ + cprop->add(ptr, r_ptr); + } else - printf("RNA_property_collection_add %s.%s: only supported for id properties.\n", ptr->type->identifier, prop->identifier); - - /* TODO: call cprop->add on non-ID props here */ + printf("RNA_property_collection_add %s.%s: not implemented for this property.\n", ptr->type->identifier, prop->identifier); if(r_ptr) { if(idprop) { diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 1a3668813c8..840b5745681 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -78,7 +78,7 @@ typedef PointerRNA (*PropCollectionGetFunc)(struct CollectionPropertyIterator *i typedef int (*PropCollectionLengthFunc)(struct PointerRNA *ptr); typedef PointerRNA (*PropCollectionLookupIntFunc)(struct PointerRNA *ptr, int key); typedef PointerRNA (*PropCollectionLookupStringFunc)(struct PointerRNA *ptr, const char *key); -typedef void (*PropCollectionAddFunc)(PointerRNA *ptr, PointerRNA *item); +typedef void (*PropCollectionAddFunc)(PointerRNA *ptr, PointerRNA *ptr_item); /* Container - generic abstracted container of RNA properties */ typedef struct ContainerRNA { diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 18a94d97296..ec58d695105 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -484,6 +484,33 @@ static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value) tf->tpage= (struct Image*)id; } +static void rna_Mesh_verts_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Mesh *me= (Mesh*)ptr->data; + rna_iterator_array_begin(iter, me->mvert, sizeof(MVert), me->totvert, NULL); +} + +/* extern struct EditVert *addvertlist(EditMesh *em, float *vec, struct EditVert *example); */ + +static void rna_Mesh_verts_add(PointerRNA *ptr, PointerRNA *ptr_item) +{ + Mesh *me= (Mesh*)ptr->data; + + /* + // XXX if item is not MVert we fail silently + if (item->type == RNA_MeshVertex) + return; + + // XXX this must be slow... + EditMesh *em= BKE_mesh_get_editmesh(me); + + MVert *v = (MVert*)ptr_item->ptr->data; + addvertlist(em, v->co, NULL); + + BKE_mesh_end_editmesh(me, em); + */ +} + /* path construction */ static char *rna_VertexGroupElement_path(PointerRNA *ptr) @@ -1054,6 +1081,7 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "mvert", "totvert"); RNA_def_property_struct_type(prop, "MeshVertex"); RNA_def_property_ui_text(prop, "Vertices", "Vertices of the mesh."); + RNA_def_property_collection_funcs(prop, "rna_Mesh_verts_begin", 0, 0, 0, 0, 0, 0, "rna_Mesh_verts_add"); prop= RNA_def_property(srna, "edges", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "medge", "totedge"); -- cgit v1.2.3 From 29f5694ab8d2021bb0b9c197f95b228809b40897 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 18 Jun 2009 09:50:34 +0000 Subject: API structuring improvements according to design guidelines by Brecht, for more info see http://lists.blender.org/pipermail/bf-taskforce25/2009-June/000954.html. Created *_api.c files in makesrna/intern. Among these only rna_api.c is compiled on preprocesssing step. It contains code declaring RNA struct functions, for example RNA_api_mesh declares all functions on Mesh. The rest *_api.c files contain functions themselves. Removed interface_api.c and moved its contents to rna_api.c. Added remove_mesh function on Main. Replaced copy and copy_mesh on Mesh with make_rendermesh which currently does the same as copy_applied did (grasping mesh-related stuff needs time). SConscript tweaking so it builds ok. --- source/blender/editors/interface/SConscript | 4 +- source/blender/editors/interface/interface_api.c | 240 ------------------ source/blender/editors/mesh/editmesh.c | 26 +- source/blender/makesrna/intern/SConscript | 10 +- source/blender/makesrna/intern/main_api.c | 26 ++ source/blender/makesrna/intern/mesh_api.c | 42 ++++ source/blender/makesrna/intern/rna_api.c | 299 +++++++++++++++++++++++ source/blender/makesrna/intern/rna_context.c | 5 - source/blender/makesrna/intern/rna_internal.h | 24 +- source/blender/makesrna/intern/rna_main.c | 8 +- source/blender/makesrna/intern/rna_mesh.c | 13 +- source/blender/makesrna/intern/rna_wm.c | 2 + source/blender/makesrna/intern/wm_api.c | 9 + source/blender/python/intern/bpy_operator_wrap.c | 2 +- 14 files changed, 412 insertions(+), 298 deletions(-) delete mode 100644 source/blender/editors/interface/interface_api.c create mode 100644 source/blender/makesrna/intern/main_api.c create mode 100644 source/blender/makesrna/intern/mesh_api.c create mode 100644 source/blender/makesrna/intern/rna_api.c create mode 100644 source/blender/makesrna/intern/wm_api.c diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript index bac3742c12f..a05756ed9c6 100644 --- a/source/blender/editors/interface/SConscript +++ b/source/blender/editors/interface/SConscript @@ -3,8 +3,8 @@ Import ('env') sources = env.Glob('*.c') -for source in env.Glob('*_api.c'): - sources.remove(source) +# for source in env.Glob('*_api.c'): +# sources.remove(source) incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc' diff --git a/source/blender/editors/interface/interface_api.c b/source/blender/editors/interface/interface_api.c deleted file mode 100644 index b4e7dc03506..00000000000 --- a/source/blender/editors/interface/interface_api.c +++ /dev/null @@ -1,240 +0,0 @@ -/** - * $Id: - * - * ***** 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 -#include - -#include "RNA_define.h" -#include "RNA_types.h" - -#include "UI_interface.h" - -static void api_ui_item_common(FunctionRNA *func) -{ - RNA_def_string(func, "text", "", 0, "", "Override automatic text of the item."); - RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Override automatic icon of the item.", 0, INT_MAX); -} - -static void api_ui_item_op_common(FunctionRNA *func) -{ - PropertyRNA *parm; - - api_ui_item_common(func); - parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); -} - -void RNA_api_ui_layout(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *parm; - - static EnumPropertyItem curve_type_items[] = { - {0, "NONE", "None", ""}, - {'v', "VECTOR", "Vector", ""}, - {'c', "COLOR", "Color", ""}, - {0, NULL, NULL, NULL}}; - - /* simple layout specifiers */ - func= RNA_def_function(srna, "row", "uiLayoutRow"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - func= RNA_def_function(srna, "column", "uiLayoutColumn"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - func= RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow"); - parm= RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic.", 0, INT_MAX); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - /* box layout */ - func= RNA_def_function(srna, "box", "uiLayoutBox"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - /* split layout */ - func= RNA_def_function(srna, "split", "uiLayoutSplit"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_float(func, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at.", 0.0f, 1.0f); - - /* items */ - func= RNA_def_function(srna, "itemR", "uiItemR"); - api_ui_item_common(func); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); - RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); - RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); - - func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_menu_enumR", "uiItemMenuEnumR"); - api_ui_item_common(func); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - /*func= RNA_def_function(srna, "item_enumR", "uiItemEnumR"); - api_ui_item_common(func); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); - RNA_def_property_flag(parm, PROP_REQUIRED);*/ - - func= RNA_def_function(srna, "itemO", "uiItemO"); - api_ui_item_op_common(func); - - func= RNA_def_function(srna, "item_enumO", "uiItemEnumO_string"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "items_enumO", "uiItemsEnumO"); - parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_menu_enumO", "uiItemMenuEnumO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_booleanO", "uiItemBooleanO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_boolean(func, "value", 0, "", "Value of the property to call the operator with."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_intO", "uiItemIntO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "", "Value of the property to call the operator with.", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_floatO", "uiItemFloatO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "", "Value of the property to call the operator with.", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_stringO", "uiItemStringO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "value", "", 0, "", "Value of the property to call the operator with."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "itemL", "uiItemL"); - api_ui_item_common(func); - - func= RNA_def_function(srna, "itemM", "uiItemM"); - parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - api_ui_item_common(func); - parm= RNA_def_string(func, "menu", "", 0, "", "Identifier of the menu."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "itemS", "uiItemS"); - - /* context */ - func= RNA_def_function(srna, "set_context_pointer", "uiLayoutSetContextPointer"); - parm= RNA_def_string(func, "name", "", 0, "Name", "Name of entry in the context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - /* templates */ - func= RNA_def_function(srna, "template_header", "uiTemplateHeader"); - parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "template_ID", "uiTemplateID"); - parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of pointer property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block."); - RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a new ID block."); - RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block."); - - func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Modifier data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Constraint data."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_preview", "uiTemplatePreview"); - parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); - parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display."); - - func= RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp"); - parm= RNA_def_pointer(func, "ramp", "ColorRamp", "", "Color ramp pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); - - func= RNA_def_function(srna, "template_layers", "uiTemplateLayers"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of pointer property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); -} - diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 33174e31df5..b6cc57990a3 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -2028,35 +2028,11 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc) } } -/* Python API */ -void copy_mesh_data(Mesh *dest, Mesh *src); - -Mesh *RNA_api_add_mesh(Main *main, char *name) -{ - return add_mesh(name); -} - -void RNA_api_mesh_copy(Mesh *me, Mesh *from) -{ - copy_mesh_data(me, from); -} - -void RNA_api_mesh_copy_applied(Mesh *me, Scene *sce, Object *ob) -{ - DerivedMesh *dm= mesh_create_derived_view(sce, ob, CD_MASK_MESH); - DM_to_mesh(dm, me); - dm->release(dm); -} - -void RNA_api_mesh_transform(Mesh *me, float **mat) -{ -} - /* * This version of copy_mesh doesn't allocate a new mesh, * instead it copies data between two existing meshes. * - * XXX is this already possible with DerivedMesh? + * XXX not used anywhere... */ void copy_mesh_data(Mesh *dest, Mesh *src) { diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index 9c8e00da16d..0ad14553bfb 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -13,12 +13,17 @@ root_build_dir=normpath(env['BF_BUILDDIR']) source_files = env.Glob('*.c') source_files.remove('rna_access.c') +api_runtime_files = env.Glob('*_api.c') +for api_file in api_runtime_files: + source_files.remove(api_file) + generated_files = source_files[:] generated_files.remove('rna_define.c') generated_files.remove('makesrna.c') generated_files = [filename[:-2] + '_gen.c' for filename in generated_files] -source_files.extend(env.Glob('../../editors/*/*_api.c')) +# source_files.extend(env.Glob('../../editors/*/*_api.c')) +source_files.extend(env.Glob('rna_api.c')) makesrna_tool = env.Clone() rna = env.Clone() @@ -110,8 +115,9 @@ else: rna.Command (generated_files, '', root_build_dir+os.sep+"makesrna.exe " + build_dir) +api_runtime_files.remove('rna_api.c') obj = ['intern/rna_access.c'] -for generated_file in generated_files: +for generated_file in generated_files + api_runtime_files: obj += ['intern/' + generated_file] Return ('obj') diff --git a/source/blender/makesrna/intern/main_api.c b/source/blender/makesrna/intern/main_api.c new file mode 100644 index 00000000000..5d9e1f5e580 --- /dev/null +++ b/source/blender/makesrna/intern/main_api.c @@ -0,0 +1,26 @@ +#include + +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_library.h" + +#include "BLI_listbase.h" + +#include "DNA_mesh_types.h" + +Mesh *RNA_api_main_add_mesh(Main *main, char *name) +{ + return add_mesh(name); +} + +void RNA_api_main_remove_mesh(Main *main, Mesh *me) +{ + if (BLI_findindex(&main->mesh, me) == -1) { + /* XXX report error */ + return; + } + + /* XXX correct ? */ + if (me->id.us == 1) + free_libblock(&main->mesh, me); +} diff --git a/source/blender/makesrna/intern/mesh_api.c b/source/blender/makesrna/intern/mesh_api.c new file mode 100644 index 00000000000..e9437e29f81 --- /dev/null +++ b/source/blender/makesrna/intern/mesh_api.c @@ -0,0 +1,42 @@ +#include + +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" + + +/* +void RNA_api_mesh_copy(Mesh *me, Mesh *from) +{ + copy_mesh_data(me, from); +} + +void RNA_api_mesh_copy_applied(Mesh *me, Scene *sce, Object *ob) +{ + DerivedMesh *dm= mesh_create_derived_view(sce, ob, CD_MASK_MESH); + DM_to_mesh(dm, me); + dm->release(dm); +} +*/ + +/* copied from init_render_mesh (render code) */ +void RNA_api_mesh_make_rendermesh(Mesh *me, Scene *sce, Object *ob) +{ + CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; + DerivedMesh *dm= mesh_create_derived_render(sce, ob, mask); + + /* XXX report reason */ + if(dm==NULL) return; + + DM_to_mesh(dm, me); + dm->release(dm); +} + +void RNA_api_mesh_transform(Mesh *me, float **mat) +{ +} diff --git a/source/blender/makesrna/intern/rna_api.c b/source/blender/makesrna/intern/rna_api.c new file mode 100644 index 00000000000..fa594c5929e --- /dev/null +++ b/source/blender/makesrna/intern/rna_api.c @@ -0,0 +1,299 @@ +/** + * $Id: + * + * ***** 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 +#include + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "UI_interface.h" + + +void RNA_api_main(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *prop; + + func= RNA_def_function(srna, "add_mesh", "RNA_api_main_add_mesh"); + RNA_def_function_ui_description(func, "Add a new mesh."); + prop= RNA_def_string(func, "name", "", 0, "", "New name for the datablock."); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); + RNA_def_function_return(func, prop); + + func= RNA_def_function(srna, "remove_mesh", "RNA_api_main_remove_mesh"); + RNA_def_function_ui_description(func, "Remove a mesh if it has only one user."); + prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A mesh to remove."); + RNA_def_property_flag(prop, PROP_REQUIRED); +} + +void RNA_api_mesh(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *prop; + + /* + func= RNA_def_function(srna, "copy", "RNA_api_mesh_copy"); + RNA_def_function_ui_description(func, "Copy mesh data."); + prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from."); + RNA_def_property_flag(prop, PROP_REQUIRED);*/ + + func= RNA_def_function(srna, "make_rendermesh", "RNA_api_mesh_make_rendermesh"); + RNA_def_function_ui_description(func, "Copy mesh data from object with all modifiers applied."); + prop= RNA_def_pointer(func, "sce", "Scene", "", "Scene."); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop= RNA_def_pointer(func, "ob", "Object", "", "Object to copy data from."); + RNA_def_property_flag(prop, PROP_REQUIRED); + + /* + func= RNA_def_function(srna, "add_geom", "RNA_api_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); + */ +} + +void RNA_api_wm(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *prop; + + func= RNA_def_function(srna, "add_fileselect", "RNA_api_wm_add_fileselect"); + RNA_def_function_ui_description(func, "Show up the file selector."); + prop= RNA_def_pointer(func, "context", "Context", "", "Context."); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop= RNA_def_pointer(func, "op", "Operator", "", "Operator to call."); + RNA_def_property_flag(prop, PROP_REQUIRED); +} + +static void api_ui_item_common(FunctionRNA *func) +{ + RNA_def_string(func, "text", "", 0, "", "Override automatic text of the item."); + RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Override automatic icon of the item.", 0, INT_MAX); +} + +static void api_ui_item_op_common(FunctionRNA *func) +{ + PropertyRNA *parm; + + api_ui_item_common(func); + parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); +} + +void RNA_api_ui_layout(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + static EnumPropertyItem curve_type_items[] = { + {0, "NONE", "None", ""}, + {'v', "VECTOR", "Vector", ""}, + {'c', "COLOR", "Color", ""}, + {0, NULL, NULL, NULL}}; + + /* simple layout specifiers */ + func= RNA_def_function(srna, "row", "uiLayoutRow"); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); + + func= RNA_def_function(srna, "column", "uiLayoutColumn"); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); + + func= RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow"); + parm= RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic.", 0, INT_MAX); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); + + /* box layout */ + func= RNA_def_function(srna, "box", "uiLayoutBox"); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + + /* split layout */ + func= RNA_def_function(srna, "split", "uiLayoutSplit"); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + RNA_def_float(func, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at.", 0.0f, 1.0f); + + /* items */ + func= RNA_def_function(srna, "itemR", "uiItemR"); + api_ui_item_common(func); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); + RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); + RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); + + func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_menu_enumR", "uiItemMenuEnumR"); + api_ui_item_common(func); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /*func= RNA_def_function(srna, "item_enumR", "uiItemEnumR"); + api_ui_item_common(func); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); + RNA_def_property_flag(parm, PROP_REQUIRED);*/ + + func= RNA_def_function(srna, "itemO", "uiItemO"); + api_ui_item_op_common(func); + + func= RNA_def_function(srna, "item_enumO", "uiItemEnumO_string"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "items_enumO", "uiItemsEnumO"); + parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_menu_enumO", "uiItemMenuEnumO"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_booleanO", "uiItemBooleanO"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_boolean(func, "value", 0, "", "Value of the property to call the operator with."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_intO", "uiItemIntO"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "", "Value of the property to call the operator with.", INT_MIN, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_floatO", "uiItemFloatO"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "", "Value of the property to call the operator with.", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "item_stringO", "uiItemStringO"); + api_ui_item_op_common(func); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "value", "", 0, "", "Value of the property to call the operator with."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "itemL", "uiItemL"); + api_ui_item_common(func); + + func= RNA_def_function(srna, "itemM", "uiItemM"); + parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); + RNA_def_property_flag(parm, PROP_REQUIRED); + api_ui_item_common(func); + parm= RNA_def_string(func, "menu", "", 0, "", "Identifier of the menu."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "itemS", "uiItemS"); + + /* context */ + func= RNA_def_function(srna, "set_context_pointer", "uiLayoutSetContextPointer"); + parm= RNA_def_string(func, "name", "", 0, "Name", "Name of entry in the context."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /* templates */ + func= RNA_def_function(srna, "template_header", "uiTemplateHeader"); + parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "template_ID", "uiTemplateID"); + parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of pointer property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block."); + RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a new ID block."); + RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block."); + + func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Modifier data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Constraint data."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "template_preview", "uiTemplatePreview"); + parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); + parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer."); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display."); + + func= RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp"); + parm= RNA_def_pointer(func, "ramp", "ColorRamp", "", "Color ramp pointer."); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); + + func= RNA_def_function(srna, "template_layers", "uiTemplateLayers"); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of pointer property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); +} diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index b1ecf2c3a86..6bab4206dc6 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -146,11 +146,6 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_pointer_funcs(prop, "rna_Context_scene_get", NULL, NULL); - - func= RNA_def_function(srna, "add_fileselect", "WM_event_add_fileselect"); - RNA_def_function_ui_description(func, "Show up the file selector."); - prop= RNA_def_pointer(func, "op", "Operator", "", "Operator to call."); - RNA_def_property_flag(prop, PROP_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 467e0dabb24..f38c3aac71d 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -188,15 +188,29 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, const char *value, ch /* API functions */ +void RNA_api_ui_layout(struct StructRNA *srna); +void RNA_api_mesh(struct StructRNA *srna); +void RNA_api_wm(struct StructRNA *srna); +void RNA_api_main(StructRNA *srna); + +#ifdef RNA_RUNTIME + +struct wmWindowManager; +struct bContext; +struct wmOperator; struct Main; +struct Mesh; struct Scene; struct Object; -struct Mesh; -void RNA_api_ui_layout(struct StructRNA *srna); -struct Mesh *RNA_api_add_mesh(struct Main *main, char *name); -void RNA_api_mesh_copy(struct Mesh *me, struct Mesh *from); -void RNA_api_mesh_copy_applied(struct Mesh *me, struct Scene *sce, struct Object *ob); +void RNA_api_wm_add_fileselect(struct wmWindowManager *self, struct bContext *C, struct wmOperator *op); + +struct Mesh *RNA_api_main_add_mesh(struct Main *main, char *name); +void RNA_api_main_remove_mesh(struct Main *main, struct Mesh *me); + +void RNA_api_mesh_make_rendermesh(struct Mesh *me, struct Scene *sce, struct Object *ob); + +#endif /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 22f19d725cb..78e1c7fb435 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -33,6 +33,7 @@ #ifdef RNA_RUNTIME #include "BKE_main.h" +#include "BKE_mesh.h" /* all the list begin functions are added manually here, Main is not in SDNA */ @@ -268,12 +269,7 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_ui_text(prop, lists[i][3], lists[i][4]); } - func= RNA_def_function(srna, "add_mesh", "RNA_api_add_mesh"); - RNA_def_function_ui_description(func, "Add a new mesh."); - prop= RNA_def_string(func, "name", "", 0, "", "New name for the datablock."); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "A new mesh."); - RNA_def_function_return(func, prop); + RNA_api_main(srna); } #endif diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index ec58d695105..d7b17490826 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1071,7 +1071,6 @@ static void rna_def_mesh(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - FunctionRNA *func; srna= RNA_def_struct(brna, "Mesh", "ID"); RNA_def_struct_ui_text(srna, "Mesh", "Mesh datablock to define geometric surfaces."); @@ -1156,17 +1155,7 @@ static void rna_def_mesh(BlenderRNA *brna) rna_def_texmat_common(srna, "rna_Mesh_texspace_editable"); - func= RNA_def_function(srna, "copy", "RNA_api_mesh_copy"); - RNA_def_function_ui_description(func, "Copy mesh data."); - prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from."); - RNA_def_property_flag(prop, PROP_REQUIRED); - - func= RNA_def_function(srna, "copy_applied", "RNA_api_mesh_copy_applied"); - RNA_def_function_ui_description(func, "Copy mesh data from object with all modifiers applied."); - prop= RNA_def_pointer(func, "sce", "Scene", "", "Scene."); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop= RNA_def_pointer(func, "ob", "Object", "", "Object to copy data from."); - RNA_def_property_flag(prop, PROP_REQUIRED); + RNA_api_mesh(srna); } void RNA_def_mesh(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 22ce207c6a9..df07e03850a 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -160,6 +160,8 @@ static void rna_def_windowmanager(BlenderRNA *brna) prop= RNA_def_property(srna, "operators", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Operator"); RNA_def_property_ui_text(prop, "Operators", "Operator registry."); + + RNA_api_wm(srna); } void RNA_def_wm(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/wm_api.c b/source/blender/makesrna/intern/wm_api.c new file mode 100644 index 00000000000..a00c401b683 --- /dev/null +++ b/source/blender/makesrna/intern/wm_api.c @@ -0,0 +1,9 @@ +#include "WM_api.h" + +#include "BKE_context.h" + +void RNA_api_wm_add_fileselect(wmWindowManager *self, bContext *C, wmOperator *op) +{ + WM_event_add_fileselect(C, op); +} + diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 4624fe764b3..c0fac17dd97 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -225,7 +225,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PointerRNA ptr_context; - PyObject ptr_operator; + PointerRNA ptr_operator; PyObject *py_operator; PyGILState_STATE gilstate = PyGILState_Ensure(); -- cgit v1.2.3 From 5d78f56c1fb1208329ba9c40eaff6ee4a8cd59bb Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 19 Jun 2009 10:40:18 +0000 Subject: - added Object.create_dupli_list, Object.free_dupli_list - attempted to RNA-wrap DupliObject, Object.create_dupli_list returns a collection of these. Build fails probably because DupliObject is not defined in one of DNA_*.h headers. --- source/blender/makesrna/intern/rna_object.c | 30 ++++++++ source/blender/makesrna/intern/rna_object_api.c | 96 +++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index ff9777d283e..36e2ba2d8aa 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1113,12 +1113,42 @@ 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_pointer_sdna(prop, NULL, "ob"); + RNA_def_property_struct_type(prop, "Object"); + 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 diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 053ab115b3b..e54c8c712c1 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -32,13 +32,18 @@ #include "RNA_define.h" #include "RNA_types.h" +#define OBJECT_API_PROP_DUPLILIST "dupli_list" + #ifdef RNA_RUNTIME #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" +#include "BKE_anim.h" +#include "BKE_report.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" +#include "DNA_object_types.h" /* copied from init_render_mesh (render code) */ Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) @@ -64,19 +69,100 @@ Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) return me; } +/* When no longer needed, duplilist should be freed with Object.free_duplilist */ +void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) +{ + PointerRNA obptr; + PointerRNA dobptr; + Scene *sce; + ListBase *lb; + DupliObject *dob; + PropertyRNA *prop; + + if (!(ob->transflag & OB_DUPLI)) { + BKE_report(reports, RPT_ERROR, "Object does not have duplis."); + return; + } + + sce= CTX_data_scene(C); + + RNA_id_pointer_create(&ob->id, &obptr); + + if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { + // hint: all Objects will now have this property defined + prop= RNA_def_collection_runtime(obptr->type, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of object's duplis"); + } + + RNA_property_collection_clear(&obptr, prop); + lb= object_duplilist(sce, ob); + + for(dob= (DupliObject*)lb->first; dob; dob= dob->next) { + RNA_pointer_create(NULL, &RNA_Object, dob, &dobptr); + RNA_property_collection_add(&obptr, prop, &dobptr); + dob = dob->next; + } + + /* + Now we need to free duplilist with + + free_object_duplilist(lb); + + We can't to it here since DupliObjects are in use, + but we also can't do it in another function since lb + isn't stored... + + So we free lb, but not DupliObjects - these will have to be freed with Object.free_duplilist + */ + + MEM_freeN(lb); +} + +void rna_Object_free_duplilist(Object *ob, ReportList *reports) +{ + PointerRNA obptr; + PropertyRNA *prop; + CollectionPropertyIterator iter; + + RNA_id_pointer_create(&ob->id, &obptr); + + if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { + BKE_report(reports, RPT_ERROR, "Object has no duplilist property."); + return; + } + + /* free each allocated DupliObject */ + RNA_property_collection_begin(&obptr, prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + MEM_freeN(iter.ptr.data); + } + RNA_property_collection_end(&iter); + + RNA_property_collection_clear(&obptr, prop); +} + #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"); 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); + parm= RNA_def_pointer(func, "scene", "Scene", "", ""); + 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. When no longer needed, it should be freed with free_dupli_list."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); + parm= RNA_def_collection(func, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of objects's duplis."); + RNA_def_function_return(func, parm); + + 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); } #endif -- cgit v1.2.3 From f6267e2a26cac8c7b30c7b165df1df54e9cec474 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 19 Jun 2009 12:46:51 +0000 Subject: Moved struct DupliObject to DNA_object_types.h. Object.create_dupli_list now works ok. --- release/io/export_obj.py | 14 ++++++++- source/blender/blenkernel/BKE_anim.h | 9 +----- source/blender/makesdna/DNA_object_types.h | 9 ++++++ source/blender/makesrna/intern/rna_object_api.c | 38 +++++++------------------ 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 4354f9f9bb9..8b3bcfb26b3 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -41,7 +41,7 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): def debug(self, message): print("{0}: {1}".format(self.__class__.__name__, message)) - def execute(self, context): + def execute_(self, context): self.debug("exec") self.debug("filename = " + self.filename) @@ -56,6 +56,18 @@ class SCRIPT_OT_export_obj(bpy.types.Operator): # raise Exception("oops!") return ('FINISHED',) + + def execute(self, context): + self.debug("exec") + + act = context.active_object + + act.create_dupli_list() + print("{0} has {1} dupli objects".format(act.name, len(act.dupli_list))) + + act.free_dupli_list() + + return ('FINISHED',) def invoke(self, context, event): self.debug("invoke") diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 5ea511738ad..091887a4eb7 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -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); diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index febf2fe59cd..445a948c5cb 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index e54c8c712c1..3944dd72cec 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -32,8 +32,6 @@ #include "RNA_define.h" #include "RNA_types.h" -#define OBJECT_API_PROP_DUPLILIST "dupli_list" - #ifdef RNA_RUNTIME #include "BKE_customdata.h" @@ -45,6 +43,8 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" +#define OBJECT_API_PROP_DUPLILIST "dupli_list" + /* copied from init_render_mesh (render code) */ Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) { @@ -75,7 +75,6 @@ void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) PointerRNA obptr; PointerRNA dobptr; Scene *sce; - ListBase *lb; DupliObject *dob; PropertyRNA *prop; @@ -90,38 +89,27 @@ void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { // hint: all Objects will now have this property defined - prop= RNA_def_collection_runtime(obptr->type, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of object's duplis"); + prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of object's duplis"); } RNA_property_collection_clear(&obptr, prop); - lb= object_duplilist(sce, ob); + ob->duplilist= object_duplilist(sce, ob); - for(dob= (DupliObject*)lb->first; dob; dob= dob->next) { + for(dob= (DupliObject*)ob->duplilist->first; dob; dob= dob->next) { RNA_pointer_create(NULL, &RNA_Object, dob, &dobptr); RNA_property_collection_add(&obptr, prop, &dobptr); dob = dob->next; } - /* - Now we need to free duplilist with - - free_object_duplilist(lb); - - We can't to it here since DupliObjects are in use, - but we also can't do it in another function since lb - isn't stored... + /* ob->duplilist should now be freed with Object.free_duplilist */ - So we free lb, but not DupliObjects - these will have to be freed with Object.free_duplilist - */ - - MEM_freeN(lb); + return *((CollectionPropertyRNA*)prop); } void rna_Object_free_duplilist(Object *ob, ReportList *reports) { PointerRNA obptr; PropertyRNA *prop; - CollectionPropertyIterator iter; RNA_id_pointer_create(&ob->id, &obptr); @@ -130,14 +118,10 @@ void rna_Object_free_duplilist(Object *ob, ReportList *reports) return; } - /* free each allocated DupliObject */ - RNA_property_collection_begin(&obptr, prop, &iter); - for(; iter.valid; RNA_property_collection_next(&iter)) { - MEM_freeN(iter.ptr.data); - } - RNA_property_collection_end(&iter); - RNA_property_collection_clear(&obptr, prop); + + free_object_duplilist(ob->duplilist); + ob->duplilist= NULL; } #else @@ -157,8 +141,6 @@ void RNA_api_object(StructRNA *srna) 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. When no longer needed, it should be freed with free_dupli_list."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); - parm= RNA_def_collection(func, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of objects's duplis."); - RNA_def_function_return(func, parm); func= RNA_def_function(srna, "free_dupli_list", "rna_Object_free_duplilist"); RNA_def_function_ui_description(func, "Free the list of dupli objects."); -- cgit v1.2.3 From 705fbec7688c88a801c41bb3c8889cd0527adc30 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 20 Jun 2009 16:32:52 +0000 Subject: * Added Main.add_object(type, name) * Added optional params to Object.create_render_mesh(apply_matrix, custom_matrix) apply_matrix is a boolean, True to transform mesh by ob->obmat or custom_matrix if given * Fix subtle error in Object.create_dupli_list * Make RNA struct funcs static, hopefully didn't miss any Ignore export_obj-2.5.py changes for now ;) --- release/scripts/export_obj-2.5.py | 11 ++++++ source/blender/makesrna/intern/rna_main_api.c | 50 +++++++++++++++++++++---- source/blender/makesrna/intern/rna_object_api.c | 49 ++++++++++++++++++++---- 3 files changed, 95 insertions(+), 15 deletions(-) diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index e0b417d4ce5..a9abba22944 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -347,6 +347,17 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): face_vert_index = 1 globalNormals = {} + + for ob_main in objects: + + if ob_main.dupli_type != 'NONE': + ob_main.create_dupli_list() + + if ob_main.parent: + pass + + if ob_main.dupli_type != 'NONE': + ob_main.free_dupli_list() # Get all meshes for ob_main in objects: diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 6d56b2b00f9..2c78884a027 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -32,22 +32,25 @@ #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,55 @@ 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) +{ + return add_only_object(type, name); +} + #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", "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, "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 diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index d7f6f85eff4..61f074c00ab 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -32,6 +32,8 @@ #include "RNA_define.h" #include "RNA_types.h" +#include "DNA_object_types.h" + #ifdef RNA_RUNTIME #include "BKE_customdata.h" @@ -41,17 +43,19 @@ #include "DNA_mesh_types.h" #include "DNA_scene_types.h" -#include "DNA_object_types.h" +#include "DNA_meshdata_types.h" #define OBJECT_API_PROP_DUPLILIST "dupli_list" /* copied from init_render_mesh (render code) */ -Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports) +static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports, int apply_matrix, float *matrix) { CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; DerivedMesh *dm; Mesh *me; Scene *sce; + int a; + MVert *mvert; sce= CTX_data_scene(C); @@ -73,11 +77,25 @@ Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports DM_to_mesh(dm, me); dm->release(dm); + if (apply_matrix) { + float *mat = ob->obmat; + + if (matrix) { + /* apply custom matrix */ + mat = matrix; + } + + /* is this really that simple? :) */ + for(a= 0, mvert= me->mvert; a < me->totvert; a++, mvert++) { + Mat4MulVecfl(ob->obmat, mvert->co); + } + } + return me; } /* When no longer needed, duplilist should be freed with Object.free_duplilist */ -void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) +static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) { PointerRNA obptr; PointerRNA dobptr; @@ -96,7 +114,7 @@ void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { // hint: all Objects will now have this property defined - prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, "DupliObject", "Dupli list", "List of object's duplis"); + prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, &RNA_DupliObject, "Dupli list", "List of object's duplis"); } RNA_property_collection_clear(&obptr, prop); @@ -109,11 +127,9 @@ void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) } /* ob->duplilist should now be freed with Object.free_duplilist */ - - return *((CollectionPropertyRNA*)prop); } -void rna_Object_free_duplilist(Object *ob, ReportList *reports) +static void rna_Object_free_duplilist(Object *ob, ReportList *reports) { PointerRNA obptr; PropertyRNA *prop; @@ -138,9 +154,28 @@ void RNA_api_object(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; + /* copied from rna_def_object */ + static EnumPropertyItem object_type_items[] = { + {OB_EMPTY, "EMPTY", 0, "Empty", ""}, + {OB_MESH, "MESH", 0, "Mesh", ""}, + {OB_CURVE, "CURVE", 0, "Curve", ""}, + {OB_SURF, "SURFACE", 0, "Surface", ""}, + {OB_FONT, "TEXT", 0, "Text", ""}, + {OB_MBALL, "META", 0, "Meta", ""}, + {OB_LAMP, "LAMP", 0, "Lamp", ""}, + {OB_CAMERA, "CAMERA", 0, "Camera", ""}, + {OB_WAVE, "WAVE", 0, "Wave", ""}, + {OB_LATTICE, "LATTICE", 0, "Lattice", ""}, + {OB_ARMATURE, "ARMATURE", 0, "Armature", ""}, + {0, NULL, 0, NULL, NULL}}; + func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); + parm= RNA_def_boolean(func, "apply_matrix", 0, "", "True if object matrix or custom matrix should be applied to geometry."); + RNA_def_property_clear_flag(parm, PROP_REQUIRED); + parm= RNA_def_float_matrix(func, "custom_matrix", 16, NULL, 0.0f, 0.0f, "", "Optional custom matrix to apply.", 0.0f, 0.0f); + RNA_def_property_clear_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); -- cgit v1.2.3 From 01da493a0af3130652151640f867cfe6b4bc376a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 20 Jun 2009 20:08:11 +0000 Subject: * Object.create_dupli_list, Object.free_dupli_list tweaking * Defined custom "get" function for DupliObject.object Accessing Object.dupli_list[N].object produces a crash. --- source/blender/makesrna/intern/rna_object.c | 11 ++++++++++- source/blender/makesrna/intern/rna_object_api.c | 13 +++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 159362ef7e7..d566af1954c 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -364,6 +364,14 @@ static void rna_GameObjectSettings_state_set(PointerRNA *ptr, const int *values) } } +static PointerRNA rna_DupliObject_object_get(PointerRNA *ptr) +{ + DupliObject *dob= (DupliObject*)ptr->data; + PointerRNA newptr; + RNA_pointer_create(&dob->ob->id, &RNA_Object, dob->ob, &newptr); + return newptr; +} + #else static void rna_def_vertex_group(BlenderRNA *brna) @@ -1167,8 +1175,9 @@ static void rna_def_dupli_object(BlenderRNA *brna) /* RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); */ prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "ob"); 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."); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 61f074c00ab..c3740921f0f 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -108,20 +108,19 @@ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *rep return; } - sce= CTX_data_scene(C); - RNA_id_pointer_create(&ob->id, &obptr); if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { // hint: all Objects will now have this property defined - prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, &RNA_DupliObject, "Dupli list", "List of object's duplis"); + prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, &RNA_DupliObject, "Dupli list", ""); } RNA_property_collection_clear(&obptr, prop); + sce= CTX_data_scene(C); ob->duplilist= object_duplilist(sce, ob); for(dob= (DupliObject*)ob->duplilist->first; dob; dob= dob->next) { - RNA_pointer_create(NULL, &RNA_Object, dob, &dobptr); + RNA_pointer_create(NULL, &RNA_DupliObject, dob, &dobptr); RNA_property_collection_add(&obptr, prop, &dobptr); dob = dob->next; } @@ -143,8 +142,10 @@ static void rna_Object_free_duplilist(Object *ob, ReportList *reports) RNA_property_collection_clear(&obptr, prop); - free_object_duplilist(ob->duplilist); - ob->duplilist= NULL; + if (ob->duplilist) { + free_object_duplilist(ob->duplilist); + ob->duplilist= NULL; + } } #else -- cgit v1.2.3 From 3fce2f282644a632fe2768ae516a50e394c1179f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 23 Jun 2009 17:52:58 +0000 Subject: - added Mesh.transform - fixed Object.create_dupli_list - continuing OBJ exporter conversion --- release/scripts/export_obj-2.5.py | 326 +++++++++++++++++++++++- source/blender/makesrna/intern/rna_mesh_api.c | 22 +- source/blender/makesrna/intern/rna_object.c | 6 + source/blender/makesrna/intern/rna_object_api.c | 38 +-- 4 files changed, 351 insertions(+), 41 deletions(-) diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index a9abba22944..4fa02ce2efe 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -186,7 +186,7 @@ def copy_images(dest_dir): def test_nurbs_compat(ob): - if ob.type != 'Curve': + if ob.type != 'CURVE': return False for nu in ob.data: @@ -353,8 +353,328 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if ob_main.dupli_type != 'NONE': ob_main.create_dupli_list() - if ob_main.parent: - pass + # ignore dupli children + if ob_main.parent.dupli_type != 'NONE': + continue + + obs = [] + if ob_main.dupli_type != 'NONE': + obs = [(dob.matrix, dob.object) for dob in ob_main.dupli_list] + else: + obs = [ob.matrix, ob] + + for ob, ob_mat in obs: + # XXX postponed +# # Nurbs curve support +# if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): +# if EXPORT_ROTX90: +# ob_mat = ob_mat * mat_xrot90 + +# totverts += write_nurb(file, ob, ob_mat) + +# continue +# end nurbs + +# # Will work for non meshes now! :) +# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) +# if not me: +# continue + + if ob.type != 'MESH': + continue + + me = ob.data + + # XXX +# if EXPORT_UV: +# faceuv= me.faceUV +# else: +# faceuv = False + + convert_to_tri = False + + # We have a valid mesh + if EXPORT_TRI and me.faces: + # Add a dummy object to it. + has_quads = False + for f in me.faces: +# if len(f) == 4: + if len(f.verts) == 4: + has_quads = True + break + + convert_to_tri = has_quads +# oldmode = Mesh.Mode() +# Mesh.Mode(Mesh.SelectModes['FACE']) + +# me.sel = True +# tempob = scn.objects.new(me) +# me.quadToTriangle(0) # more=0 shortest length +# oldmode = Mesh.Mode(oldmode) +# scn.objects.unlink(tempob) + +# Mesh.Mode(oldmode) + + if EXPORT_ROTX90: + ob_mat *= mat_xrot90 + + me = ob.create_render_mesh(True, ob_mat, convert_to_tri) + + # Make our own list so it can be sorted to reduce context switching + faces = [ f for f in me.faces ] + + if EXPORT_EDGES: + edges = me.edges + else: + edges = [] + + if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + continue # dont bother with this mesh. + + # done above ^ +# if EXPORT_ROTX90: +# me.transform(ob_mat*mat_xrot90) +# else: +# me.transform(ob_mat) + + # High Quality Normals + if EXPORT_NORMALS and faces: + if EXPORT_NORMALS_HQ: + BPyMesh.meshCalcNormals(me) + else: + # transforming normals is incorrect + # when the matrix is scaled, + # better to recalculate them + me.calcNormals() + + # # Crash Blender + #materials = me.getMaterials(1) # 1 == will return None in the list. + materials = me.materials + + materialNames = [] + materialItems = materials[:] + if materials: + for mat in materials: + if mat: # !=None + materialNames.append(mat.name) + else: + materialNames.append(None) + # Cant use LC because some materials are None. + # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. + + # Possible there null materials, will mess up indicies + # but at least it will export, wait until Blender gets fixed. + materialNames.extend((16-len(materialNames)) * [None]) + materialItems.extend((16-len(materialItems)) * [None]) + + # Sort by Material, then images + # so we dont over context switch in the obj file. + if EXPORT_KEEP_VERT_ORDER: + pass + elif faceuv: + 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)) + + # 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.getData(1) + if name1 == name2: + obnamestring = fixName(name1) + else: + obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) + + if EXPORT_BLEN_OBS: + file.write('o %s\n' % obnamestring) # Write Object name + else: # if EXPORT_GROUP_BY_OB: + file.write('g %s\n' % obnamestring) + + + # Vert + for v in me.verts: + file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) + + # UV + if faceuv: + uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ + + uv_dict = {} # could use a set() here + 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.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + else: + # Hard, 1 normal from the face. + noKey = veckey3d(f.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + + if not faceuv: + f_image = None + + 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 xrange(len(me.verts))] + for vertexGroupName in vertGroupNames: + for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): + vgroupsMap[vIdx].append((vertexGroupName, vWeight)) + + for f_index, f in enumerate(faces): + f_v= f.v + f_smooth= f.smooth + f_mat = min(f.mat, len(materialNames)-1) + if faceuv: + 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 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: + file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) + file.write('usemtl (null)\n') # mat, image + + else: + mat_data= MTL_DICT.get(key) + if not mat_data: + # First add to global dict so we can export to mtl + # Then write mtl + + # Make a new names from the mat and image name, + # converting any spaces to underscores with fixName. + + # If none image dont bother adding it to the name + if key[1] == None: + mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image + else: + mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image + + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) + + file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) + + contextMat = key + if f_smooth != contextSmooth: + if f_smooth: # on now off + file.write('s 1\n') + contextSmooth = f_smooth + else: # was off now on + file.write('s off\n') + contextSmooth = f_smooth + + file.write('f') + if faceuv: + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + totuvco + uv_face_mapping[f_index][vi],\ + globalNormals[ veckey3d(v.no) ])) # vert, uv, normal + + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + totuvco + uv_face_mapping[f_index][vi],\ + no)) # vert, uv, normal + + 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.no) ])) + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + 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: + LOOSE= Mesh.EdgeFlags.LOOSE + for ed in edges: + if ed.flag & LOOSE: + file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) + + # Make the indicies global rather then per mesh + totverts += len(me.verts) + if faceuv: + totuvco += uv_unique_count + me.verts= None if ob_main.dupli_type != 'NONE': ob_main.free_dupli_list() diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 26fb77777d7..0aa4faeddd8 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -54,8 +54,15 @@ void rna_Mesh_copy_applied(Mesh *me, Scene *sce, Object *ob) } */ -void rna_Mesh_transform(Mesh *me, float **mat) +void rna_Mesh_transform(Mesh *me, float *mat) { + /* TODO: old API transform had recalc_normals option */ + int i; + MVert *mvert= me->mvert; + + for(i= 0; i < mesh->totvert; i++, mvert++) { + Mat4MulVecfl(mat, mvert->co); + } } #if 0 @@ -85,14 +92,13 @@ static void rna_Mesh_verts_add(PointerRNA *ptr, PointerRNA *ptr_item) void RNA_api_mesh(StructRNA *srna) { - /*FunctionRNA *func; - PropertyRNA *prop;*/ + FunctionRNA *func; + PropertyRNA *parm; - /* - func= RNA_def_function(srna, "copy", "rna_Mesh_copy"); - RNA_def_function_ui_description(func, "Copy mesh data."); - prop= RNA_def_pointer(func, "src", "Mesh", "", "A mesh to copy data from."); - RNA_def_property_flag(prop, PROP_REQUIRED);*/ + func= RNA_def_function(srna, "transform", "rna_Mesh_transform"); + RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix."); + parm= RNA_def_float_matrix(func, "matrix", 16, NULL, 0.0f, 0.0f, "", "Matrix.", 0.0f, 0.0f); + RNA_def_property_flag(parm, PROP_REQUIRED); /* func= RNA_def_function(srna, "add_geom", "rna_Mesh_add_geom"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index d566af1954c..14ce5954cb7 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1028,6 +1028,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); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c3740921f0f..69d3f48761c 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -45,7 +45,7 @@ #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" -#define OBJECT_API_PROP_DUPLILIST "dupli_list" +#include "BLI_arithb.h" /* copied from init_render_mesh (render code) */ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports, int apply_matrix, float *matrix) @@ -78,7 +78,7 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList * dm->release(dm); if (apply_matrix) { - float *mat = ob->obmat; + float *mat = (float*)ob->obmat; if (matrix) { /* apply custom matrix */ @@ -97,33 +97,20 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList * /* When no longer needed, duplilist should be freed with Object.free_duplilist */ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) { - PointerRNA obptr; - PointerRNA dobptr; - Scene *sce; - DupliObject *dob; - PropertyRNA *prop; - if (!(ob->transflag & OB_DUPLI)) { BKE_report(reports, RPT_ERROR, "Object does not have duplis."); return; } - RNA_id_pointer_create(&ob->id, &obptr); + /* free duplilist if a user forget to */ + if (ob->duplilist) { + BKE_report(reports, RPT_WARNING, "%s.dupli_list has not been freed.", RNA_struct_identifier(&RNA_Object)); - if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { - // hint: all Objects will now have this property defined - prop= RNA_def_collection_runtime(obptr.type, OBJECT_API_PROP_DUPLILIST, &RNA_DupliObject, "Dupli list", ""); + free_object_duplilist(ob->duplilist); + ob->duplilist= NULL; } - RNA_property_collection_clear(&obptr, prop); - sce= CTX_data_scene(C); - ob->duplilist= object_duplilist(sce, ob); - - for(dob= (DupliObject*)ob->duplilist->first; dob; dob= dob->next) { - RNA_pointer_create(NULL, &RNA_DupliObject, dob, &dobptr); - RNA_property_collection_add(&obptr, prop, &dobptr); - dob = dob->next; - } + ob->duplilist= object_duplilist(CTX_data_scene(C), ob); /* ob->duplilist should now be freed with Object.free_duplilist */ } @@ -133,15 +120,6 @@ static void rna_Object_free_duplilist(Object *ob, ReportList *reports) PointerRNA obptr; PropertyRNA *prop; - RNA_id_pointer_create(&ob->id, &obptr); - - if (!(prop= RNA_struct_find_property(&obptr, OBJECT_API_PROP_DUPLILIST))) { - BKE_report(reports, RPT_ERROR, "Object has no duplilist property."); - return; - } - - RNA_property_collection_clear(&obptr, prop); - if (ob->duplilist) { free_object_duplilist(ob->duplilist); ob->duplilist= NULL; -- cgit v1.2.3 From 3f2fef55c2bbeb1f837b48c76263e3e035d56792 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 24 Jun 2009 19:23:34 +0000 Subject: - added API functions: * Main.remove_object * Scene.add_object * Scene.remove_object * Object.convert_to_triface * Object.create_preview_mesh - a small tweak in set_mesh (blenkernel/inter/mesh.c) to make it work on objects having data == NULL --- release/scripts/export_obj-2.5.py | 20 ++++-- source/blender/blenkernel/intern/mesh.c | 3 +- source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_main_api.c | 33 ++++++++- source/blender/makesrna/intern/rna_mesh_api.c | 3 +- source/blender/makesrna/intern/rna_object_api.c | 91 +++++++++++++++++-------- source/blender/makesrna/intern/rna_scene.c | 2 + source/blender/makesrna/intern/rna_scene_api.c | 91 +++++++++++++++++++++++++ 8 files changed, 204 insertions(+), 41 deletions(-) create mode 100644 source/blender/makesrna/intern/rna_scene_api.c diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index 4fa02ce2efe..c0468f744b8 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -307,7 +307,8 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): temp_mesh_name = '~tmp-mesh' time1 = sys.time() - scn = Scene.GetCurrent() +# scn = Scene.GetCurrent() + scene = context.scene file = open(filename, "w") @@ -383,15 +384,15 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if ob.type != 'MESH': continue - me = ob.data - # XXX # if EXPORT_UV: # faceuv= me.faceUV # else: # faceuv = False - convert_to_tri = False + me = ob.create_render_mesh() + + newob = ob # We have a valid mesh if EXPORT_TRI and me.faces: @@ -403,7 +404,10 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): has_quads = True break - convert_to_tri = has_quads + if has_quads: + newob = bpy.data.add_object('MESH', 'temp_object') + scene.add_object(newob) + newob.convert_to_triface(scene) # oldmode = Mesh.Mode() # Mesh.Mode(Mesh.SelectModes['FACE']) @@ -418,8 +422,6 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if EXPORT_ROTX90: ob_mat *= mat_xrot90 - me = ob.create_render_mesh(True, ob_mat, convert_to_tri) - # Make our own list so it can be sorted to reduce context switching faces = [ f for f in me.faces ] @@ -429,6 +431,10 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): edges = [] if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + + if newob != ob: + scene.remove_object(newob) + continue # dont bother with this mesh. # done above ^ diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 3facf975992..9fc8d0ed609 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -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); } diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index e7ca3fc5932..f7bf176a325 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1853,7 +1853,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_particle.c", NULL, RNA_def_particle}, {"rna_pose.c", NULL, RNA_def_pose}, {"rna_property.c", NULL, RNA_def_gameproperty}, - {"rna_scene.c", NULL, RNA_def_scene}, + {"rna_scene.c", "rna_scene_api.c", RNA_def_scene}, {"rna_screen.c", NULL, RNA_def_screen}, {"rna_scriptlink.c", NULL, RNA_def_scriptlink}, {"rna_sensor.c", NULL, RNA_def_sensor}, diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 2c78884a027..08a3b7cee25 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -62,7 +62,29 @@ static void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me) static Object* rna_Main_add_object(Main *main, int type, char *name) { - return add_only_object(type, 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 @@ -89,13 +111,19 @@ void RNA_api_main(StructRNA *srna) 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", "Type of 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."); parm= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock."); @@ -108,7 +136,6 @@ void RNA_api_main(StructRNA *srna) RNA_def_function_ui_description(func, "Remove a mesh if it has zero users."); parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); RNA_def_property_flag(parm, PROP_REQUIRED); - } #endif diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 0aa4faeddd8..984e6a5d30f 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -36,6 +36,7 @@ #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" +#include "BLI_arithb.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" @@ -60,7 +61,7 @@ void rna_Mesh_transform(Mesh *me, float *mat) int i; MVert *mvert= me->mvert; - for(i= 0; i < mesh->totvert; i++, mvert++) { + for(i= 0; i < me->totvert; i++, mvert++) { Mat4MulVecfl(mat, mvert->co); } } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 69d3f48761c..5af12b696c4 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -28,6 +28,8 @@ #include #include +#include +#include #include "RNA_define.h" #include "RNA_types.h" @@ -40,6 +42,7 @@ #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" @@ -47,15 +50,17 @@ #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) */ -static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports, int apply_matrix, float *matrix) +static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int render_mesh) { CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; DerivedMesh *dm; Mesh *me; Scene *sce; - int a; - MVert *mvert; sce= CTX_data_scene(C); @@ -65,7 +70,7 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList * return NULL; } - dm= mesh_create_derived_render(sce, ob, mask); + dm= render_mesh ? mesh_create_derived_render(sce, ob, mask) : mesh_create_derived_view(sce, ob, mask); if(!dm) { /* TODO: report */ @@ -77,21 +82,17 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList * DM_to_mesh(dm, me); dm->release(dm); - if (apply_matrix) { - float *mat = (float*)ob->obmat; - - if (matrix) { - /* apply custom matrix */ - mat = matrix; - } + return me; +} - /* is this really that simple? :) */ - for(a= 0, mvert= me->mvert; a < me->totvert; a++, mvert++) { - Mat4MulVecfl(ob->obmat, mvert->co); - } - } +static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports) +{ + return create_mesh(ob, C, reports, 1); +} - return me; +static Mesh *rna_Object_create_preview_mesh(Object *ob, bContext *C, ReportList *reports) +{ + return create_mesh(ob, C, reports, 0); } /* When no longer needed, duplilist should be freed with Object.free_duplilist */ @@ -102,9 +103,9 @@ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *rep return; } - /* free duplilist if a user forget to */ + /* free duplilist if a user forgets to */ if (ob->duplilist) { - BKE_report(reports, RPT_WARNING, "%s.dupli_list has not been freed.", RNA_struct_identifier(&RNA_Object)); + 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; @@ -117,15 +118,41 @@ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *rep static void rna_Object_free_duplilist(Object *ob, ReportList *reports) { - PointerRNA obptr; - PropertyRNA *prop; - 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) @@ -149,22 +176,30 @@ void RNA_api_object(StructRNA *srna) {0, NULL, 0, NULL, NULL}}; func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied."); + RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for rendering."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); + parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "create_preview_mesh", "rna_Object_create_preview_mesh"); + RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for preview."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); - parm= RNA_def_boolean(func, "apply_matrix", 0, "", "True if object matrix or custom matrix should be applied to geometry."); - RNA_def_property_clear_flag(parm, PROP_REQUIRED); - parm= RNA_def_float_matrix(func, "custom_matrix", 16, NULL, 0.0f, 0.0f, "", "Optional custom matrix to apply.", 0.0f, 0.0f); - RNA_def_property_clear_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. When no longer needed, it should be freed with free_dupli_list."); + 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 is."); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 47c9025149a..1017703c56b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -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 index 00000000000..a38622b48ae --- /dev/null +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -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 +#include + +#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 + -- cgit v1.2.3 From e2e139c0ba91f6218af04748ab08fcb8dd1a9425 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 25 Jun 2009 13:33:21 +0000 Subject: Added Mesh.active_uv_layer read-only property. --- source/blender/makesrna/intern/rna_mesh.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index da90b9f4c76..00af79890be 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -234,6 +234,23 @@ static int rna_Mesh_uv_layers_length(PointerRNA *ptr) return rna_CustomDataLayer_length(ptr, CD_MTFACE); } +static PointerRNA rna_Mesh_active_uv_layer_get(PointerRNA *ptr) +{ + CustomDataLayer *active_layer; + Mesh *me; + int layer_index; + + active_layer= NULL; + me= (Mesh*)ptr->data; + + if (CustomData_has_layer(&me->fdata, CD_MTFACE)) { + layer_index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); + active_layer= &me->fdata.layers[layer_index]; + } + + return rna_pointer_inherit_refine(ptr, &RNA_MeshTextureFaceLayer, active_layer); +} + static void rna_MeshTextureFace_uv1_get(PointerRNA *ptr, float *values) { MTFace *mtface= (MTFace*)ptr->data; @@ -1081,6 +1098,11 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_struct_type(prop, "MeshTextureFaceLayer"); RNA_def_property_ui_text(prop, "UV Layers", ""); + prop= RNA_def_property(srna, "active_uv_layer", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MeshTextureFaceLayer"); + RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_uv_layer_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Active UV layer", "Active UV layer."); + prop= RNA_def_property(srna, "vcol_layers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_vcol_layers_begin", 0, 0, 0, "rna_Mesh_vcol_layers_length", 0, 0, 0, 0); -- cgit v1.2.3 From 18e7ec8463930947cfa9d76e7385be0b81482627 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 25 Jun 2009 18:04:32 +0000 Subject: - added MeshFace.normal property - continuing OBJ exporter conversion --- release/scripts/export_obj-2.5.py | 163 ++++++++++++++++-------- source/blender/makesrna/intern/rna_mesh.c | 29 +++++ source/blender/makesrna/intern/rna_object_api.c | 2 +- 3 files changed, 140 insertions(+), 54 deletions(-) diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index c0468f744b8..de1657402b3 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -384,16 +384,13 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if ob.type != 'MESH': continue - # XXX -# if EXPORT_UV: -# faceuv= me.faceUV -# else: -# faceuv = False + if EXPORT_UV: + faceuv = len(me.uv_layers) > 0 + else: + faceuv = False me = ob.create_render_mesh() - newob = ob - # We have a valid mesh if EXPORT_TRI and me.faces: # Add a dummy object to it. @@ -408,6 +405,8 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): newob = bpy.data.add_object('MESH', 'temp_object') scene.add_object(newob) newob.convert_to_triface(scene) + # me will still be there + scene.remove_object(newob) # oldmode = Mesh.Mode() # Mesh.Mode(Mesh.SelectModes['FACE']) @@ -423,35 +422,38 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): ob_mat *= mat_xrot90 # Make our own list so it can be sorted to reduce context switching - faces = [ f for f in me.faces ] + 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(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write - if newob != ob: - scene.remove_object(newob) + if not (len(face_index_pairs)+len(edges)+len(me.verts)): # Make sure there is somthing to write +# if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + + bpy.data.remove_mesh(me) continue # dont bother with this mesh. - # done above ^ -# if EXPORT_ROTX90: -# me.transform(ob_mat*mat_xrot90) -# else: -# me.transform(ob_mat) + if EXPORT_ROTX90: + me.transform(ob_mat*mat_xrot90) + else: + me.transform(ob_mat) # High Quality Normals - if EXPORT_NORMALS and faces: - if EXPORT_NORMALS_HQ: - BPyMesh.meshCalcNormals(me) - else: - # transforming normals is incorrect - # when the matrix is scaled, - # better to recalculate them - me.calcNormals() + if EXPORT_NORMALS and face_index_pairs: +# if EXPORT_NORMALS and faces: + # XXX + pass +# if EXPORT_NORMALS_HQ: +# BPyMesh.meshCalcNormals(me) +# else: +# # transforming normals is incorrect +# # when the matrix is scaled, +# # better to recalculate them +# me.calcNormals() # # Crash Blender #materials = me.getMaterials(1) # 1 == will return None in the list. @@ -478,15 +480,35 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): 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))) + # 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: faces.sort(key = lambda a: (a.mat, a.smooth)) - except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) + 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: faces.sort(key = lambda a: a.smooth) - except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) + 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. @@ -494,7 +516,8 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: name1 = ob.name - name2 = ob.getData(1) + name2 = ob.data.name + # name2 = ob.getData(1) if name1 == name2: obnamestring = fixName(name1) else: @@ -513,17 +536,37 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): # 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 - for f_index, f in enumerate(faces): - - for uv_index, uv in enumerate(f.uv): + uv_layer = me.active_uv_layer + for f, f_index in face_index_pairs: + + tface = uv_layer.data[f_index] + + uvs = [tface.uv1, tface.uv2, tface.uv3] + + # add another UV if it's a quad + if tface.verts[3] != 0: + uvs.append(tface.uv4) + + for uv_index, uv in enumerate(uvs): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) file.write('vt %.6f %.6f\n' % tuple(uv)) + +# uv_dict = {} # could use a set() here +# for f_index, f in enumerate(faces): + +# for uv_index, uv in enumerate(f.uv): +# uvkey = veckey2d(uv) +# try: +# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] +# except: +# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) +# file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index @@ -534,14 +577,16 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): for f in faces: if f.smooth: for v in f: - noKey = veckey3d(v.no) + noKey = veckey3d(v.normal) +# noKey = veckey3d(v.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) else: # Hard, 1 normal from the face. - noKey = veckey3d(f.no) + noKey = veckey3d(f.normal) +# noKey = veckey3d(f.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 @@ -549,14 +594,17 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if not faceuv: f_image = None - + + # XXX if EXPORT_POLYGROUPS: # Retrieve the list of vertex groups - vertGroupNames = me.getVertGroupNames() + vertGroupNames = [g.name for g in ob.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 xrange(len(me.verts))] + vgroupsMap = [[] for _i in range(len(me.verts))] +# vgroupsMap = [[] for _i in xrange(len(me.verts))] for vertexGroupName in vertGroupNames: for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): vgroupsMap[vIdx].append((vertexGroupName, vWeight)) @@ -564,25 +612,34 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth - f_mat = min(f.mat, len(materialNames)-1) + f_mat = min(f.material_index, len(materialNames)-1) +# f_mat = min(f.mat, len(materialNames)-1) if faceuv: - f_image = f.image - f_uv= f.uv + + tface = me.active_uv_layer.data[face_index_pairs[f_index][1]] + + f_image = tface.image + f_uv= [tface.uv1, tface.uv2, tface.uv3] + if f.verts[4] != 0: + f_uv.append(tface.uv4) +# f_image = f.image +# f_uv= f.uv # MAKE KEY if faceuv and f_image: # Object is always true. key = materialNames[f_mat], f_image.name else: key = materialNames[f_mat], None # No image, use None instead. - - # 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) + + # XXX +# # 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: diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 00af79890be..3127c352f60 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -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; @@ -749,6 +772,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) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 5af12b696c4..40f29360e9c 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -198,7 +198,7 @@ void RNA_api_object(StructRNA *srna) 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 is."); + parm= RNA_def_pointer(func, "scene", "Scene", "", "Scene where the object belongs."); RNA_def_property_flag(parm, PROP_REQUIRED); } -- cgit v1.2.3 From acb590e4b065505117a78786e2627c43e65c499a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 26 Jun 2009 12:33:07 +0000 Subject: * OBJ exporter almost converted * added MeshEdge.loose property * changed mask used in Object.create_*_mesh to CD_MASK_MESH. --- release/scripts/export_obj-2.5.py | 489 ++++++------------------ source/blender/makesrna/intern/rna_mesh.c | 5 + source/blender/makesrna/intern/rna_object_api.c | 4 +- 3 files changed, 135 insertions(+), 363 deletions(-) diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py index de1657402b3..cd8e423ed07 100644 --- a/release/scripts/export_obj-2.5.py +++ b/release/scripts/export_obj-2.5.py @@ -47,7 +47,7 @@ will be exported as mesh data. import bpy -import BPySys +# import BPySys # import Blender # from Blender import Mesh, Scene, Window, sys, Image, Draw @@ -75,16 +75,20 @@ def fixName(name): # (material.name, image.name):matname_imagename # matname_imagename has gaps removed. MTL_DICT = {} -def write_mtl(filename): - - world = Blender.World.GetCurrent() - if world: - worldAmb = world.getAmb() - else: - worldAmb = (0,0,0) # Default value +def write_mtl(scene, filename): + + world = bpy.data.worlds[0] + worldAmb = world.ambient_color + +# world = Blender.World.GetCurrent() +# if world: +# worldAmb = world.getAmb() +# else: +# worldAmb = (0,0,0) # Default value file = open(filename, "w") - file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) + # XXX +# file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) file.write('# Material Count: %i\n' % len(MTL_DICT)) # Write material/image combinations we have used. for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): @@ -261,7 +265,7 @@ def write_nurb(file, ob, ob_mat): return tot_verts -def write(filename, objects,\ +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,\ @@ -290,8 +294,10 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): of vertices is the face's group """ weightDict = {} - for vert in face: - vWeights = vWeightMap[vert.index] + 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 @@ -302,6 +308,17 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): 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' @@ -349,6 +366,7 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): globalNormals = {} + # Get all meshes for ob_main in objects: if ob_main.dupli_type != 'NONE': @@ -375,22 +393,25 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): # continue # end nurbs - + + if ob.type != 'MESH': + continue + + # XXX EXPORT_APPLY_MODIFIERS is not used (always true) + # we also need influences to be copied... for EXPORT_POLYGROUPS to work + # which create_preview_mesh presumably does (CD_MASK_MDEFORMVERT flag) + me = ob.create_preview_mesh() + # # Will work for non meshes now! :) # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) # if not me: # continue - if ob.type != 'MESH': - continue - if EXPORT_UV: faceuv = len(me.uv_layers) > 0 else: faceuv = False - me = ob.create_render_mesh() - # We have a valid mesh if EXPORT_TRI and me.faces: # Add a dummy object to it. @@ -598,19 +619,21 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): # XXX if EXPORT_POLYGROUPS: # Retrieve the list of vertex groups - vertGroupNames = [g.name for g in ob.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 vertexGroupName in vertGroupNames: - for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): - vgroupsMap[vIdx].append((vertexGroupName, vWeight)) + 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= f.v + f_v = [{"index": index, "vertex": me.verts[index]} for index in f.verts] +# f_v= f.v f_smooth= f.smooth f_mat = min(f.material_index, len(materialNames)-1) # f_mat = min(f.mat, len(materialNames)-1) @@ -632,6 +655,14 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): key = materialNames[f_mat], None # No image, use None instead. # XXX + # Write the vertex group + if EXPORT_POLYGROUPS: + if len(ob.vertex_groups): + # find what vertext group the face belongs to + theVGroup = findVertexGroupName(f,vgroupsMap) + if theVGroup != currentVGroup: + currentVGroup = theVGroup + file.write('g %s\n' % theVGroup) # # Write the vertex group # if EXPORT_POLYGROUPS: # if vertGroupNames: @@ -648,7 +679,9 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. if EXPORT_GROUP_BY_MAT: - file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) + # can be mat_image or (null) + file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.data.name)) ) +# file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) file.write('usemtl (null)\n') # mat, image else: @@ -667,7 +700,8 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): 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.getData(1)), mat_data[0]) ) # can be mat_image or (null) + file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.data.name), mat_data[0]) ) # can be mat_image or (null) +# file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) @@ -685,24 +719,36 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): 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.no) ])) # vert, uv, normal + file.write( ' %d/%d/%d' % \ + (v["index"] + totverts, + totuvco + uv_face_mapping[f_index][vi], + globalNormals[ veckey3d(v["vertex"].normal) ]) ) # vert, uv, normal +# file.write( ' %d/%d/%d' % (\ +# v.index+totverts,\ +# totuvco + uv_face_mapping[f_index][vi],\ +# globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] + no = globalNormals[ veckey3d(f.normal) ] +# no = globalNormals[ veckey3d(f.no) ] for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % (\ - v.index+totverts,\ - totuvco + uv_face_mapping[f_index][vi],\ - no)) # vert, uv, normal + file.write( ' %d/%d/%d' % \ + (v["index"] + totverts, + totuvco + uv_face_mapping[f_index][vi], + no) ) # vert, uv, normal +# 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,\ + v["index"] + totverts,\ totuvco + uv_face_mapping[f_index][vi])) # vert, uv +# file.write( ' %d/%d' % (\ +# v.index+totverts,\ +# totuvco + uv_face_mapping[f_index][vi])) # vert, uv face_vert_index += len(f_v) @@ -710,344 +756,56 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): 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.no) ])) + file.write( ' %d//%d' % + (v["index"] + totverts, globalNormals[ veckey3d(v["vertex"].normal) ]) ) + +# file.write( ' %d//%d' % (\ +# v.index+totverts,\ +# globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] + no = globalNormals[ veckey3d(f.normal) ] +# no = globalNormals[ veckey3d(f.no) ] for v in f_v: - file.write( ' %d//%d' % (\ - v.index+totverts,\ - no)) + file.write( ' %d//%d' % (v["index"] + totverts, no) ) +# file.write( ' %d//%d' % (\ +# v.index+totverts,\ +# no)) else: # No Normals for v in f_v: - file.write( ' %d' % (\ - v.index+totverts)) + file.write( ' %d' % (v["index"] + totverts) ) +# file.write( ' %d' % (\ +# v.index+totverts)) file.write('\n') # Write edges. if EXPORT_EDGES: - LOOSE= Mesh.EdgeFlags.LOOSE for ed in edges: - if ed.flag & LOOSE: - file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) + if ed.loose: + file.write('f %d %d\n' % (ed.verts[0] + totverts, ed.verts[1] + totverts)) +# LOOSE= Mesh.EdgeFlags.LOOSE +# for ed in edges: +# if ed.flag & LOOSE: +# file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) # Make the indicies global rather then per mesh totverts += len(me.verts) if faceuv: totuvco += uv_unique_count - me.verts= None + + # clean up + bpy.data.remove_mesh(me) +# me.verts= None if ob_main.dupli_type != 'NONE': ob_main.free_dupli_list() - - # Get all meshes - for ob_main in objects: - for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): - - # 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 - - # Will work for non meshes now! :) - # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) - me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) - if not me: - continue - - if EXPORT_UV: - faceuv= me.faceUV - else: - faceuv = False - - # We have a valid mesh - if EXPORT_TRI and me.faces: - # Add a dummy object to it. - has_quads = False - for f in me.faces: - if len(f) == 4: - has_quads = True - break - - if has_quads: - oldmode = Mesh.Mode() - Mesh.Mode(Mesh.SelectModes['FACE']) - - me.sel = True - tempob = scn.objects.new(me) - me.quadToTriangle(0) # more=0 shortest length - oldmode = Mesh.Mode(oldmode) - scn.objects.unlink(tempob) - - Mesh.Mode(oldmode) - - # Make our own list so it can be sorted to reduce context switching - faces = [ f for f in me.faces ] - - if EXPORT_EDGES: - edges = me.edges - else: - edges = [] - - if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write - continue # dont bother with this mesh. - - if EXPORT_ROTX90: - me.transform(ob_mat*mat_xrot90) - else: - me.transform(ob_mat) - - # High Quality Normals - if EXPORT_NORMALS and faces: - if EXPORT_NORMALS_HQ: - BPyMesh.meshCalcNormals(me) - else: - # transforming normals is incorrect - # when the matrix is scaled, - # better to recalculate them - me.calcNormals() - - # # Crash Blender - #materials = me.getMaterials(1) # 1 == will return None in the list. - materials = me.materials - - materialNames = [] - materialItems = materials[:] - if materials: - for mat in materials: - if mat: # !=None - materialNames.append(mat.name) - else: - materialNames.append(None) - # Cant use LC because some materials are None. - # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. - - # Possible there null materials, will mess up indicies - # but at least it will export, wait until Blender gets fixed. - materialNames.extend((16-len(materialNames)) * [None]) - materialItems.extend((16-len(materialItems)) * [None]) - - # Sort by Material, then images - # so we dont over context switch in the obj file. - if EXPORT_KEEP_VERT_ORDER: - pass - elif faceuv: - 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)) - - # 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.getData(1) - if name1 == name2: - obnamestring = fixName(name1) - else: - obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) - - if EXPORT_BLEN_OBS: - file.write('o %s\n' % obnamestring) # Write Object name - else: # if EXPORT_GROUP_BY_OB: - file.write('g %s\n' % obnamestring) - - - # Vert - for v in me.verts: - file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) - - # UV - if faceuv: - uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ - - uv_dict = {} # could use a set() here - 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.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - else: - # Hard, 1 normal from the face. - noKey = veckey3d(f.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - - if not faceuv: - f_image = None - - 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 xrange(len(me.verts))] - for vertexGroupName in vertGroupNames: - for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): - vgroupsMap[vIdx].append((vertexGroupName, vWeight)) - - for f_index, f in enumerate(faces): - f_v= f.v - f_smooth= f.smooth - f_mat = min(f.mat, len(materialNames)-1) - if faceuv: - 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 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: - file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) - file.write('usemtl (null)\n') # mat, image - - else: - mat_data= MTL_DICT.get(key) - if not mat_data: - # First add to global dict so we can export to mtl - # Then write mtl - - # Make a new names from the mat and image name, - # converting any spaces to underscores with fixName. - - # If none image dont bother adding it to the name - if key[1] == None: - mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image - else: - mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image - - if EXPORT_GROUP_BY_MAT: - file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) - file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) - - contextMat = key - if f_smooth != contextSmooth: - if f_smooth: # on now off - file.write('s 1\n') - contextSmooth = f_smooth - else: # was off now on - file.write('s off\n') - contextSmooth = f_smooth - - file.write('f') - if faceuv: - if EXPORT_NORMALS: - if f_smooth: # Smoothed, use vertex normals - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % (\ - v.index+totverts,\ - totuvco + uv_face_mapping[f_index][vi],\ - globalNormals[ veckey3d(v.no) ])) # vert, uv, normal - - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % (\ - v.index+totverts,\ - totuvco + uv_face_mapping[f_index][vi],\ - no)) # vert, uv, normal - - 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.no) ])) - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] - 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: - LOOSE= Mesh.EdgeFlags.LOOSE - for ed in edges: - if ed.flag & LOOSE: - file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) - - # Make the indicies global rather then per mesh - totverts += len(me.verts) - if faceuv: - totuvco += uv_unique_count - me.verts= None file.close() # Now we have all our materials, save them if EXPORT_MTL: - write_mtl(mtlfilename) + write_mtl(scene, mtlfilename) if EXPORT_COPY_IMAGES: dest_dir = filename # Remove chars until we are just the path. @@ -1332,8 +1090,8 @@ def write_ui(filename): def do_export(filename, context): -# Window.EditMode(0) -# Window.WaitCursor(1) + # Window.EditMode(0) + # Window.WaitCursor(1) EXPORT_APPLY_MODIFIERS = True EXPORT_ROTX90 = True @@ -1351,6 +1109,8 @@ def do_export(filename, context): EXPORT_GROUP_BY_OB = False EXPORT_GROUP_BY_MAT = False EXPORT_KEEP_VERT_ORDER = False + EXPORT_POLYGROUPS = False + EXPORT_CURVE_AS_NURBS = True base_name, ext = splitExt(filename) context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension @@ -1370,8 +1130,8 @@ def do_export(filename, context): # Export all scenes. for scn in export_scenes: -# scn.makeCurrent() # If already current, this is not slow. -# context = scn.getRenderingContext() + # 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 @@ -1398,12 +1158,14 @@ def do_export(filename, context): # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. # EXPORT THE FILE. -# write(full_path, export_objects, -# EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS, -# EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL, -# EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS, -# EXPORT_ROTX90, EXPORT_BLEN_OBS, -# EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER) + 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 @@ -1412,11 +1174,14 @@ def do_export(filename, context): # Window.WaitCursor(0) -class SCRIPT_OT_export_obj(bpy.types.Operator): +class EXPORT_OT_obj(bpy.types.Operator): ''' - Operator documentatuon text, will be used for the operator tooltip and python docs. + Currently the exporter lacks these features: + * nurbs + * multiple scene export (only active scene is written) + * particles ''' - __label__ = 'My Operator' + __label__ = 'Export OBJ' # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 3127c352f60..4b4c9b97871 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -736,6 +736,11 @@ static void rna_def_medge(BlenderRNA *brna) prop= RNA_def_property(srna, "sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP); RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier"); + + prop= RNA_def_property(srna, "loose", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Loose", "Loose edge"); } static void rna_def_mface(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 40f29360e9c..1b6c298eba4 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -57,7 +57,9 @@ /* copied from init_render_mesh (render code) */ static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int render_mesh) { - CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; + /* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */ + CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter, + for example, needs CD_MASK_MDEFORMVERT */ DerivedMesh *dm; Mesh *me; Scene *sce; -- cgit v1.2.3 From 1557736756b41dfa8fff4d7c887a7d6da2b1f468 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sun, 28 Jun 2009 13:29:03 +0000 Subject: OBJ exporter working (Python 3.0), but needs testing and fixing. Current issues: - NURBS - needs API additions - "all scenes" export - cannot switch scene in bpy - normal calculation, disabled - duplis - need testing, only dupliverts tested - matrix problem - UI, 18 options currently don't fit into filesel panel, will do manual lay out once it's available - probably others... BPY: - made operator "execute" method required to avoid crash - added bpy.sys module which replicates old "sys" module API: - replaced create_*_mesh with a single create_mesh accepting type parameter - added Mesh.create_copy to create a copy of a mesh with 0 users Ran `dos2unix` on source/blender/python/SConscript --- release/io/export_obj.py | 978 ++++++++++++++++- release/io/export_ply.py | 6 +- release/scripts/3ds_export.py | 24 +- release/scripts/export_obj-2.5.py | 1217 ---------------------- release/ui/space_script.py | 4 +- source/blender/makesrna/intern/rna_mesh_api.c | 15 + source/blender/makesrna/intern/rna_object_api.c | 60 +- source/blender/python/intern/bpy_interface.c | 2 + source/blender/python/intern/bpy_operator_wrap.c | 2 +- source/blender/python/intern/bpy_rna.c | 8 +- source/blender/python/intern/bpy_sys.c | 460 ++++++++ source/blender/python/intern/bpy_sys.h | 41 + 12 files changed, 1497 insertions(+), 1320 deletions(-) delete mode 100644 release/scripts/export_obj-2.5.py create mode 100644 source/blender/python/intern/bpy_sys.c create mode 100644 source/blender/python/intern/bpy_sys.h diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 8b3bcfb26b3..d139e872251 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -1,83 +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_obj(filepath, scene, ob): - out = open(filepath, 'w') +def write_mtl(scene, filename): - # create a temporary mesh - mesh = ob.create_render_mesh(scene) + world = scene.world + worldAmb = world.ambient_color - # for vert in mesh.verts: - # ^ iterating that way doesn't work atm for some reason + 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) - for i in range(len(mesh.verts)): - vert = mesh.verts[i] - out.write('v {0} {1} {2}\n'.format(vert.co[0], vert.co[1], vert.co[2])) + # 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') - for i in range(len(mesh.faces)): - face = mesh.faces[i] - out.write('f') + file.close() - # but this works - for index in face.verts: - out.write(' {0}'.format(index + 1)) - out.write('\n') +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() - # delete mesh gain - bpy.data.remove_mesh(mesh) - out.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 -class SCRIPT_OT_export_obj(bpy.types.Operator): - '''A very basic OBJ exporter, writes only active object's mesh.''' + # 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 - __label__ = 'Export OBJ' + print('\tCopied %d images' % copyCount) + +# XXX not converted +def test_nurbs_compat(ob): + if ob.type != 'CURVE': + return False - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - __props__ = [ - bpy.props.StringProperty(attr="filename", name="filename") - ] + for nu in ob.data.curves: + if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier + return True - def debug(self, message): - print("{0}: {1}".format(self.__class__.__name__, message)) +# for nu in ob.data: +# if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier +# return True + + return False - def execute_(self, context): - self.debug("exec") - self.debug("filename = " + self.filename) +# 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] )) - act = context.active_object + file.write('end\n') + + return tot_verts - if act.type == 'MESH': - write_obj(self.filename, context.scene, act) +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: - self.debug("Active object is not a MESH.") + return '(null)' - # XXX errors are silenced for some reason -# raise Exception("oops!") + # TODO: implement this in C? dunno how it should be called... + def getVertsFromGroup(me, group_index): + ret = [] - return ('FINISHED',) + for i, v in enumerate(me.verts): + for g in v.groups: + if g.group == group_index: + ret.append((i, g.weight)) - def execute(self, context): - self.debug("exec") + 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. - act = context.active_object + # 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) - act.create_dupli_list() - print("{0} has {1} dupli objects".format(act.name, len(act.dupli_list))) - act.free_dupli_list() +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): - self.debug("invoke") wm = context.manager wm.add_fileselect(self.__operator__) return ('RUNNING_MODAL',) - def poll(self, context): # poll isnt working yet - self.debug("poll") - return True + def poll(self, context): # Poll isnt working yet + print("Poll") + return context.active_object != None + +bpy.ops.add(EXPORT_OT_obj) -bpy.ops.add(SCRIPT_OT_export_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 diff --git a/release/io/export_ply.py b/release/io/export_ply.py index ed983c2b169..ce1cdc55d09 100644 --- a/release/io/export_ply.py +++ b/release/io/export_ply.py @@ -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): diff --git a/release/scripts/3ds_export.py b/release/scripts/3ds_export.py index 87680bce1b0..69b4d00b4d8 100644 --- a/release/scripts/3ds_export.py +++ b/release/scripts/3ds_export.py @@ -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: diff --git a/release/scripts/export_obj-2.5.py b/release/scripts/export_obj-2.5.py deleted file mode 100644 index cd8e423ed07..00000000000 --- a/release/scripts/export_obj-2.5.py +++ /dev/null @@ -1,1217 +0,0 @@ -#!BPY - -""" -Name: 'Wavefront (.obj)...' -Blender: 248 -Group: 'Export' -Tooltip: 'Save a Wavefront OBJ File' -""" - -__author__ = "Campbell Barton, Jiri Hnidek, Paolo Ciccone" -__url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org'] -__version__ = "1.21" - -__bpydoc__ = """\ -This script is an exporter to OBJ file format. - -Usage: - -Select the objects you wish to export and run this script from "File->Export" menu. -Selecting the default options from the popup box will be good in most cases. -All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d) -will be exported as mesh data. -""" - - -# -------------------------------------------------------------------------- -# OBJ Export v1.1 by Campbell Barton (AKA Ideasman) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - - -import bpy -# import BPySys - -# import Blender -# from Blender import Mesh, Scene, Window, sys, Image, Draw -# import BPyMesh -# import BPyObject -# import BPySys -# import BPyMessages - -# Returns a tuple - path,extension. -# 'hello.obj' > ('hello', '.obj') -def splitExt(path): - dotidx = path.rfind('.') - if dotidx == -1: - return path, '' - else: - return path[:dotidx], path[dotidx:] - -def fixName(name): - if name == None: - return 'None' - else: - return name.replace(' ', '_') - -# A Dict of Materials -# (material.name, image.name):matname_imagename # matname_imagename has gaps removed. -MTL_DICT = {} - -def write_mtl(scene, filename): - - world = bpy.data.worlds[0] - worldAmb = world.ambient_color - -# world = Blender.World.GetCurrent() -# if world: -# worldAmb = world.getAmb() -# else: -# worldAmb = (0,0,0) # Default value - - file = open(filename, "w") - # XXX -# file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) - file.write('# Material Count: %i\n' % len(MTL_DICT)) - # Write material/image combinations we have used. - for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): - - # Get the Blender data for the material and the image. - # Having an image named None will make a bug, dont do it :) - - file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname - - if mat: - file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's - file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, - file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse - file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular - file.write('Ni %.6f\n' % mat.IOR) # Refraction index - file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve) - - # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting. - if mat.getMode() & Blender.Material.Modes['SHADELESS']: - file.write('illum 0\n') # ignore lighting - elif mat.getSpec() == 0: - file.write('illum 1\n') # no specular. - else: - file.write('illum 2\n') # light normaly - - else: - #write a dummy material here? - file.write('Ns 0\n') - file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, - file.write('Kd 0.8 0.8 0.8\n') - file.write('Ks 0.8 0.8 0.8\n') - file.write('d 1\n') # No alpha - file.write('illum 2\n') # light normaly - - # Write images! - if img: # We have an image on the face! - file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image - - elif mat: # No face image. if we havea material search for MTex image. - for mtex in mat.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - try: - filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1] - file.write('map_Kd %s\n' % filename) # Diffuse mapping image - break - except: - # Texture has no image though its an image type, best ignore. - pass - - file.write('\n\n') - - file.close() - -def copy_file(source, dest): - file = open(source, 'rb') - data = file.read() - file.close() - - file = open(dest, 'wb') - file.write(data) - file.close() - - -def copy_images(dest_dir): - if dest_dir[-1] != sys.sep: - dest_dir += sys.sep - - # Get unique image names - uniqueImages = {} - for matname, mat, image in MTL_DICT.itervalues(): # Only use image name - # Get Texface images - if image: - uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. - - # Get MTex images - if mat: - for mtex in mat.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - image_tex = mtex.tex.image - if image_tex: - try: - uniqueImages[image_tex] = image_tex - except: - pass - - # Now copy images - copyCount = 0 - - for bImage in uniqueImages.itervalues(): - image_path = sys.expandpath(bImage.filename) - if sys.exists(image_path): - # Make a name for the target path. - dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] - if not sys.exists(dest_image_path): # Image isnt alredy there - print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) - copy_file(image_path, dest_image_path) - copyCount+=1 - print '\tCopied %d images' % copyCount - - -def test_nurbs_compat(ob): - if ob.type != 'CURVE': - return False - - for nu in ob.data: - if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier - return True - - return False - -def write_nurb(file, ob, ob_mat): - tot_verts = 0 - cu = ob.data - - # use negative indices - Vector = Blender.Mathutils.Vector - for nu in cu: - - if nu.type==0: DEG_ORDER_U = 1 - else: DEG_ORDER_U = nu.orderU-1 # Tested to be correct - - if nu.type==1: - print "\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported" - continue - - if nu.knotsV: - print "\tWarning, surface:", ob.name, "only poly and nurbs curves supported" - continue - - if len(nu) <= DEG_ORDER_U: - print "\tWarning, orderU is lower then vert count, skipping:", ob.name - continue - - pt_num = 0 - do_closed = (nu.flagU & 1) - do_endpoints = (do_closed==0) and (nu.flagU & 2) - - for pt in nu: - pt = Vector(pt[0], pt[1], pt[2]) * ob_mat - file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2])) - pt_num += 1 - tot_verts += pt_num - - file.write('g %s\n' % (fixName(ob.name))) # fixName(ob.getData(1)) could use the data name too - file.write('cstype bspline\n') # not ideal, hard coded - file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still - - curve_ls = [-(i+1) for i in xrange(pt_num)] - - # 'curv' keyword - if do_closed: - if DEG_ORDER_U == 1: - pt_num += 1 - curve_ls.append(-1) - else: - pt_num += DEG_ORDER_U - curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U] - - file.write('curv 0.0 1.0 %s\n' % (' '.join( [str(i) for i in curve_ls] ))) # Blender has no U and V values for the curve - - # 'parm' keyword - tot_parm = (DEG_ORDER_U + 1) + pt_num - tot_parm_div = float(tot_parm-1) - parm_ls = [(i/tot_parm_div) for i in xrange(tot_parm)] - - if do_endpoints: # end points, force param - for i in xrange(DEG_ORDER_U+1): - parm_ls[i] = 0.0 - parm_ls[-(1+i)] = 1.0 - - file.write('parm u %s\n' % ' '.join( [str(i) for i in parm_ls] )) - - file.write('end\n') - - return tot_verts - -def write(filename, objects, scene, \ -EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\ -EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ -EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\ -EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\ -EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): - ''' - Basic write function. The context and options must be alredy set - This can be accessed externaly - eg. - write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. - ''' - - def veckey3d(v): - return round(v.x, 6), round(v.y, 6), round(v.z, 6) - - def veckey2d(v): - return round(v.x, 6), round(v.y, 6) - - def findVertexGroupName(face, vWeightMap): - """ - Searches the vertexDict to see what groups is assigned to a given face. - We use a frequency system in order to sort out the name because a given vetex can - belong to two or more groups at the same time. To find the right name for the face - we list all the possible vertex group names with their frequency and then sort by - frequency in descend order. The top element is the one shared by the highest number - of vertices is the face's group - """ - weightDict = {} - for vert_index in face.verts: -# for vert in face: - vWeights = vWeightMap[vert_index] -# vWeights = vWeightMap[vert] - for vGroupName, weight in vWeights: - weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight - - if weightDict: - alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight - alist.sort() - return(alist[-1][1]) # highest value last - else: - return '(null)' - - # TODO: implement this in C? dunno how it should be called... - def getVertsFromGroup(me, group_index): - ret = [] - - for i, v in enumerate(me.verts): - for g in v.groups: - if g.group == group.index: - ret.append((i, g.weight)) - - return ret - - - print 'OBJ Export path: "%s"' % filename - temp_mesh_name = '~tmp-mesh' - - time1 = sys.time() -# scn = Scene.GetCurrent() - scene = context.scene - - file = open(filename, "w") - - # Write Header - file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) - file.write('# www.blender3d.org\n') - - # Tell the obj file what material file to use. - if EXPORT_MTL: - mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) - file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) - - # Get the container mesh. - used for applying modifiers and non mesh objects. - -# containerMesh = meshName = tempMesh = None -# for meshName in Blender.NMesh.GetNames(): -# if meshName.startswith(temp_mesh_name): -# tempMesh = Mesh.Get(meshName) -# if not tempMesh.users: -# containerMesh = tempMesh -# if not containerMesh: -# containerMesh = Mesh.New(temp_mesh_name) - - # XXX this mesh is not removed - # XXX this mesh should not be in database - containerMesh = bpy.data.add_mesh(temp_mesh_name) - - if EXPORT_ROTX90: - mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') - -# del meshName -# del tempMesh - - # Initialize totals, these are updated each object - totverts = totuvco = totno = 1 - - face_vert_index = 1 - - globalNormals = {} - - # Get all meshes - for ob_main in objects: - - if ob_main.dupli_type != 'NONE': - ob_main.create_dupli_list() - - # ignore dupli children - if ob_main.parent.dupli_type != 'NONE': - continue - - obs = [] - if ob_main.dupli_type != 'NONE': - obs = [(dob.matrix, dob.object) for dob in ob_main.dupli_list] - else: - obs = [ob.matrix, ob] - - for ob, ob_mat in obs: - # XXX postponed -# # Nurbs curve support -# if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): -# if EXPORT_ROTX90: -# ob_mat = ob_mat * mat_xrot90 - -# totverts += write_nurb(file, ob, ob_mat) - -# continue -# end nurbs - - if ob.type != 'MESH': - continue - - # XXX EXPORT_APPLY_MODIFIERS is not used (always true) - # we also need influences to be copied... for EXPORT_POLYGROUPS to work - # which create_preview_mesh presumably does (CD_MASK_MDEFORMVERT flag) - me = ob.create_preview_mesh() - -# # Will work for non meshes now! :) -# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) -# if not me: -# continue - - if EXPORT_UV: - faceuv = len(me.uv_layers) > 0 - else: - faceuv = False - - # We have a valid mesh - if EXPORT_TRI and me.faces: - # Add a dummy object to it. - has_quads = False - for f in me.faces: -# if len(f) == 4: - if len(f.verts) == 4: - has_quads = True - break - - if has_quads: - newob = bpy.data.add_object('MESH', 'temp_object') - scene.add_object(newob) - newob.convert_to_triface(scene) - # me will still be there - scene.remove_object(newob) -# oldmode = Mesh.Mode() -# Mesh.Mode(Mesh.SelectModes['FACE']) - -# me.sel = True -# tempob = scn.objects.new(me) -# me.quadToTriangle(0) # more=0 shortest length -# oldmode = Mesh.Mode(oldmode) -# scn.objects.unlink(tempob) - -# Mesh.Mode(oldmode) - - if EXPORT_ROTX90: - ob_mat *= mat_xrot90 - - # Make our own list so it can be sorted to reduce context switching - face_index_pairs = [ (face, index) for index, face in enumerate(me.faces)] - # faces = [ f for f in me.faces ] - - if EXPORT_EDGES: - edges = me.edges - else: - edges = [] - - if not (len(face_index_pairs)+len(edges)+len(me.verts)): # Make sure there is somthing to write -# if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write - - bpy.data.remove_mesh(me) - - continue # dont bother with this mesh. - - if EXPORT_ROTX90: - me.transform(ob_mat*mat_xrot90) - else: - me.transform(ob_mat) - - # High Quality Normals - if EXPORT_NORMALS and face_index_pairs: -# if EXPORT_NORMALS and faces: - # XXX - pass -# if EXPORT_NORMALS_HQ: -# BPyMesh.meshCalcNormals(me) -# else: -# # transforming normals is incorrect -# # when the matrix is scaled, -# # better to recalculate them -# me.calcNormals() - - # # Crash Blender - #materials = me.getMaterials(1) # 1 == will return None in the list. - materials = me.materials - - materialNames = [] - materialItems = materials[:] - if materials: - for mat in materials: - if mat: # !=None - materialNames.append(mat.name) - else: - materialNames.append(None) - # Cant use LC because some materials are None. - # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. - - # Possible there null materials, will mess up indicies - # but at least it will export, wait until Blender gets fixed. - materialNames.extend((16-len(materialNames)) * [None]) - materialItems.extend((16-len(materialItems)) * [None]) - - # Sort by Material, then images - # so we dont over context switch in the obj file. - if EXPORT_KEEP_VERT_ORDER: - pass - elif faceuv: - # XXX update - tface = me.active_uv_layer.data - - # exception only raised if Python 2.3 or lower... - try: face_index_pairs.sort(key = lambda a: (a[0].material_index, tface[a[1]].image, a[0].smooth)) - except: face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, tface[a[1]].image, a[0].smooth), - (b[0].material_index, tface[b[1]].image, b[0].smooth))) - elif len(materials) > 1: - try: face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].smooth)) - except: face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, a[0].smooth), - (b[0].material_index, b[0].smooth))) - else: - # no materials - try: face_index_pairs.sort(key = lambda a: a[0].smooth) - except: face_index_pairs.sort(lambda a,b: cmp(a[0].smooth, b[0].smooth)) -# if EXPORT_KEEP_VERT_ORDER: -# pass -# elif faceuv: -# try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) -# except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) -# elif len(materials) > 1: -# try: faces.sort(key = lambda a: (a.mat, a.smooth)) -# except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) -# else: -# # no materials -# try: faces.sort(key = lambda a: a.smooth) -# except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) - - faces = [pair[0] for pair in face_index_pairs] - - # Set the default mat to no material and no image. - contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. - contextSmooth = None # Will either be true or false, set bad to force initialization switch. - - if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: - name1 = ob.name - name2 = ob.data.name - # name2 = ob.getData(1) - if name1 == name2: - obnamestring = fixName(name1) - else: - obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) - - if EXPORT_BLEN_OBS: - file.write('o %s\n' % obnamestring) # Write Object name - else: # if EXPORT_GROUP_BY_OB: - file.write('g %s\n' % obnamestring) - - - # Vert - for v in me.verts: - file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) - - # UV - if faceuv: - uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ - - uv_dict = {} # could use a set() here - uv_layer = me.active_uv_layer - for f, f_index in face_index_pairs: - - tface = uv_layer.data[f_index] - - uvs = [tface.uv1, tface.uv2, tface.uv3] - - # add another UV if it's a quad - if tface.verts[3] != 0: - uvs.append(tface.uv4) - - for uv_index, uv in enumerate(uvs): - uvkey = veckey2d(uv) - try: - uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] - except: - uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) - file.write('vt %.6f %.6f\n' % tuple(uv)) - -# uv_dict = {} # could use a set() here -# for f_index, f in enumerate(faces): - -# for uv_index, uv in enumerate(f.uv): -# uvkey = veckey2d(uv) -# try: -# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] -# except: -# uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) -# file.write('vt %.6f %.6f\n' % tuple(uv)) - - uv_unique_count = len(uv_dict) - del uv, uvkey, uv_dict, f_index, uv_index - # Only need uv_unique_count and uv_face_mapping - - # NORMAL, Smooth/Non smoothed. - if EXPORT_NORMALS: - for f in faces: - if f.smooth: - for v in f: - noKey = veckey3d(v.normal) -# noKey = veckey3d(v.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - else: - # Hard, 1 normal from the face. - noKey = veckey3d(f.normal) -# noKey = veckey3d(f.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - - if not faceuv: - f_image = None - - # XXX - if EXPORT_POLYGROUPS: - # Retrieve the list of vertex groups -# vertGroupNames = me.getVertGroupNames() - - currentVGroup = '' - # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to - vgroupsMap = [[] for _i in range(len(me.verts))] -# vgroupsMap = [[] for _i in xrange(len(me.verts))] - for g in ob.vertex_groups: -# for vertexGroupName in vertGroupNames: - for vIdx, vWeight in getVertsFromGroup(me, g.index) -# for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): - vgroupsMap[vIdx].append((g.name, vWeight)) - - for f_index, f in enumerate(faces): - f_v = [{"index": index, "vertex": me.verts[index]} for index in f.verts] -# f_v= f.v - f_smooth= f.smooth - f_mat = min(f.material_index, len(materialNames)-1) -# f_mat = min(f.mat, len(materialNames)-1) - if faceuv: - - tface = me.active_uv_layer.data[face_index_pairs[f_index][1]] - - f_image = tface.image - f_uv= [tface.uv1, tface.uv2, tface.uv3] - if f.verts[4] != 0: - f_uv.append(tface.uv4) -# f_image = f.image -# f_uv= f.uv - - # MAKE KEY - if faceuv and f_image: # Object is always true. - key = materialNames[f_mat], f_image.name - else: - key = materialNames[f_mat], None # No image, use None instead. - - # XXX - # Write the vertex group - if EXPORT_POLYGROUPS: - if len(ob.vertex_groups): - # find what vertext group the face belongs to - theVGroup = findVertexGroupName(f,vgroupsMap) - if theVGroup != currentVGroup: - currentVGroup = theVGroup - file.write('g %s\n' % theVGroup) -# # Write the vertex group -# if EXPORT_POLYGROUPS: -# if vertGroupNames: -# # find what vertext group the face belongs to -# theVGroup = findVertexGroupName(f,vgroupsMap) -# if theVGroup != currentVGroup: -# currentVGroup = theVGroup -# file.write('g %s\n' % theVGroup) - - # CHECK FOR CONTEXT SWITCH - if key == contextMat: - pass # Context alredy switched, dont do anything - else: - if key[0] == None and key[1] == None: - # Write a null material, since we know the context has changed. - if EXPORT_GROUP_BY_MAT: - # can be mat_image or (null) - file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.data.name)) ) -# file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) - file.write('usemtl (null)\n') # mat, image - - else: - mat_data= MTL_DICT.get(key) - if not mat_data: - # First add to global dict so we can export to mtl - # Then write mtl - - # Make a new names from the mat and image name, - # converting any spaces to underscores with fixName. - - # If none image dont bother adding it to the name - if key[1] == None: - mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image - else: - mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image - - if EXPORT_GROUP_BY_MAT: - file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.data.name), mat_data[0]) ) # can be mat_image or (null) -# file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) - - file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) - - contextMat = key - if f_smooth != contextSmooth: - if f_smooth: # on now off - file.write('s 1\n') - contextSmooth = f_smooth - else: # was off now on - file.write('s off\n') - contextSmooth = f_smooth - - file.write('f') - if faceuv: - if EXPORT_NORMALS: - if f_smooth: # Smoothed, use vertex normals - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % \ - (v["index"] + totverts, - totuvco + uv_face_mapping[f_index][vi], - globalNormals[ veckey3d(v["vertex"].normal) ]) ) # vert, uv, normal -# file.write( ' %d/%d/%d' % (\ -# v.index+totverts,\ -# totuvco + uv_face_mapping[f_index][vi],\ -# globalNormals[ veckey3d(v.no) ])) # vert, uv, normal - - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.normal) ] -# no = globalNormals[ veckey3d(f.no) ] - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % \ - (v["index"] + totverts, - totuvco + uv_face_mapping[f_index][vi], - no) ) # vert, uv, normal -# file.write( ' %d/%d/%d' % (\ -# v.index+totverts,\ -# totuvco + uv_face_mapping[f_index][vi],\ -# no)) # vert, uv, normal - - else: # No Normals - for vi, v in enumerate(f_v): - file.write( ' %d/%d' % (\ - v["index"] + totverts,\ - totuvco + uv_face_mapping[f_index][vi])) # vert, uv -# file.write( ' %d/%d' % (\ -# v.index+totverts,\ -# totuvco + uv_face_mapping[f_index][vi])) # vert, uv - - face_vert_index += len(f_v) - - else: # No UV's - if EXPORT_NORMALS: - if f_smooth: # Smoothed, use vertex normals - for v in f_v: - file.write( ' %d//%d' % - (v["index"] + totverts, globalNormals[ veckey3d(v["vertex"].normal) ]) ) - -# file.write( ' %d//%d' % (\ -# v.index+totverts,\ -# globalNormals[ veckey3d(v.no) ])) - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.normal) ] -# no = globalNormals[ veckey3d(f.no) ] - for v in f_v: - file.write( ' %d//%d' % (v["index"] + totverts, no) ) -# file.write( ' %d//%d' % (\ -# v.index+totverts,\ -# no)) - else: # No Normals - for v in f_v: - file.write( ' %d' % (v["index"] + totverts) ) -# file.write( ' %d' % (\ -# v.index+totverts)) - - file.write('\n') - - # Write edges. - if EXPORT_EDGES: - for ed in edges: - if ed.loose: - file.write('f %d %d\n' % (ed.verts[0] + totverts, ed.verts[1] + totverts)) -# LOOSE= Mesh.EdgeFlags.LOOSE -# for ed in edges: -# if ed.flag & LOOSE: -# file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) - - # Make the indicies global rather then per mesh - totverts += len(me.verts) - if faceuv: - totuvco += uv_unique_count - - # clean up - bpy.data.remove_mesh(me) -# me.verts= None - - if ob_main.dupli_type != 'NONE': - ob_main.free_dupli_list() - - file.close() - - - # Now we have all our materials, save them - if EXPORT_MTL: - write_mtl(scene, mtlfilename) - if EXPORT_COPY_IMAGES: - dest_dir = filename - # Remove chars until we are just the path. - while dest_dir and dest_dir[-1] not in '\\/': - dest_dir = dest_dir[:-1] - if dest_dir: - copy_images(dest_dir) - else: - print '\tError: "%s" could not be used as a base for an image path.' % filename - - print "OBJ Export time: %.2f" % (sys.time() - time1) - - -# replaced by do_export -def write_ui(filename): - - if not filename.lower().endswith('.obj'): - filename += '.obj' - - if not BPyMessages.Warning_SaveOver(filename): - return - - global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ - EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ - EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ - EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS - - EXPORT_APPLY_MODIFIERS = Draw.Create(0) - EXPORT_ROTX90 = Draw.Create(1) - EXPORT_TRI = Draw.Create(0) - EXPORT_EDGES = Draw.Create(1) - EXPORT_NORMALS = Draw.Create(0) - EXPORT_NORMALS_HQ = Draw.Create(0) - EXPORT_UV = Draw.Create(1) - EXPORT_MTL = Draw.Create(1) - EXPORT_SEL_ONLY = Draw.Create(1) - EXPORT_ALL_SCENES = Draw.Create(0) - EXPORT_ANIMATION = Draw.Create(0) - EXPORT_COPY_IMAGES = Draw.Create(0) - EXPORT_BLEN_OBS = Draw.Create(0) - EXPORT_GROUP_BY_OB = Draw.Create(0) - EXPORT_GROUP_BY_MAT = Draw.Create(0) - EXPORT_KEEP_VERT_ORDER = Draw.Create(1) - EXPORT_POLYGROUPS = Draw.Create(0) - EXPORT_CURVE_AS_NURBS = Draw.Create(1) - - - # Old UI - ''' - # removed too many options are bad! - - # Get USER Options - pup_block = [\ - ('Context...'),\ - ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\ - ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\ - ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\ - ('Object Prefs...'),\ - ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\ - ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\ - ('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ - ('Extra Data...'),\ - ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\ - ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\ - ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\ - ('UVs', EXPORT_UV, 'Export texface UV coords.'),\ - ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\ - ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\ - ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ - ('Grouping...'),\ - ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\ - ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\ - ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\ - ] - - if not Draw.PupBlock('Export...', pup_block): - return - ''' - - # BEGIN ALTERNATIVE UI ******************* - if True: - - EVENT_NONE = 0 - EVENT_EXIT = 1 - EVENT_REDRAW = 2 - EVENT_EXPORT = 3 - - GLOBALS = {} - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - - def obj_ui_set_event(e,v): - GLOBALS['EVENT'] = e - - def do_split(e,v): - global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER, EXPORT_POLYGROUPS - if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val: - EXPORT_KEEP_VERT_ORDER.val = 0 - else: - EXPORT_KEEP_VERT_ORDER.val = 1 - - def do_vertorder(e,v): - global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER - if EXPORT_KEEP_VERT_ORDER.val: - EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0 - else: - if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val): - EXPORT_KEEP_VERT_ORDER.val = 1 - - - def do_help(e,v): - url = __url__[0] - print 'Trying to open web browser with documentation at this address...' - print '\t' + url - - try: - import webbrowser - webbrowser.open(url) - except: - print '...could not open a browser window.' - - def obj_ui(): - ui_x, ui_y = GLOBALS['MOUSE'] - - # Center based on overall pup size - ui_x -= 165 - ui_y -= 140 - - global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ - EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ - EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ - EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS - - Draw.Label('Context...', ui_x+9, ui_y+239, 220, 20) - Draw.BeginAlign() - EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+219, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.') - EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+219, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.') - EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+219, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.') - Draw.EndAlign() - - - Draw.Label('Output Options...', ui_x+9, ui_y+189, 220, 20) - Draw.BeginAlign() - EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+170, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split) - EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+170, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP') - EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+170, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.') - Draw.EndAlign() - - - Draw.Label('Export...', ui_x+9, ui_y+139, 220, 20) - Draw.BeginAlign() - EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+120, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.') - EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+120, 70, 20, EXPORT_TRI.val, 'Triangulate quads.') - Draw.EndAlign() - Draw.BeginAlign() - EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+120, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.') - EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+120, 31, 20, EXPORT_UV.val, 'Export texface UV coords.') - Draw.EndAlign() - Draw.BeginAlign() - EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+120, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).') - EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+120, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.') - Draw.EndAlign() - EXPORT_POLYGROUPS = Draw.Toggle('Polygroups', EVENT_REDRAW, ui_x+9, ui_y+95, 120, 20, EXPORT_POLYGROUPS.val, 'Export vertex groups as OBJ groups (one group per face approximation).') - - EXPORT_CURVE_AS_NURBS = Draw.Toggle('Nurbs', EVENT_NONE, ui_x+139, ui_y+95, 100, 20, EXPORT_CURVE_AS_NURBS.val, 'Export 3D nurbs curves and polylines as OBJ curves, (bezier not supported).') - - - Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20) - Draw.BeginAlign() - EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split) - EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split) - EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split) - Draw.EndAlign() - - EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder) - - Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event) - Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event) - Draw.EndAlign() - - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT): - Draw.UIBlock(obj_ui, 0) - - if GLOBALS['EVENT'] != EVENT_EXPORT: - return - - # END ALTERNATIVE UI ********************* - - - if EXPORT_KEEP_VERT_ORDER.val: - EXPORT_BLEN_OBS.val = False - EXPORT_GROUP_BY_OB.val = False - EXPORT_GROUP_BY_MAT.val = False - EXPORT_APPLY_MODIFIERS.val = False - - Window.EditMode(0) - Window.WaitCursor(1) - - EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val - EXPORT_ROTX90 = EXPORT_ROTX90.val - EXPORT_TRI = EXPORT_TRI.val - EXPORT_EDGES = EXPORT_EDGES.val - EXPORT_NORMALS = EXPORT_NORMALS.val - EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val - EXPORT_UV = EXPORT_UV.val - EXPORT_MTL = EXPORT_MTL.val - EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val - EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val - EXPORT_ANIMATION = EXPORT_ANIMATION.val - EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val - EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val - EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val - EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val - EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val - EXPORT_POLYGROUPS = EXPORT_POLYGROUPS.val - EXPORT_CURVE_AS_NURBS = EXPORT_CURVE_AS_NURBS.val - - - base_name, ext = splitExt(filename) - context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension - - # Use the options to export the data using write() - # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True): - orig_scene = Scene.GetCurrent() - if EXPORT_ALL_SCENES: - export_scenes = Scene.Get() - else: - export_scenes = [orig_scene] - - # Export all scenes. - for scn in export_scenes: - scn.makeCurrent() # If alredy current, this is not slow. - context = scn.getRenderingContext() - orig_frame = Blender.Get('curframe') - - if EXPORT_ALL_SCENES: # Add scene name into the context_name - context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. - - # Export an animation? - if EXPORT_ANIMATION: - scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame. - else: - scene_frames = [orig_frame] # Dont export an animation. - - # Loop through all frames in the scene and export. - for frame in scene_frames: - if EXPORT_ANIMATION: # Add frame to the filename. - context_name[2] = '_%.6d' % frame - - Blender.Set('curframe', frame) - if EXPORT_SEL_ONLY: - export_objects = scn.objects.context - else: - export_objects = scn.objects - - full_path= ''.join(context_name) - - # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. - # EXPORT THE FILE. - write(full_path, export_objects,\ - EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ - EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ - EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ - EXPORT_ROTX90, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS) - - Blender.Set('curframe', orig_frame) - - # Restore old active scene. - orig_scene.makeCurrent() - Window.WaitCursor(0) - - -def do_export(filename, context): - # Window.EditMode(0) - # Window.WaitCursor(1) - - EXPORT_APPLY_MODIFIERS = True - EXPORT_ROTX90 = True - EXPORT_TRI = False - EXPORT_EDGES = False - EXPORT_NORMALS = False - EXPORT_NORMALS_HQ = False - EXPORT_UV = True - EXPORT_MTL = True - EXPORT_SEL_ONLY = True - EXPORT_ALL_SCENES = False # XXX not working atm - EXPORT_ANIMATION = False - EXPORT_COPY_IMAGES = False - EXPORT_BLEN_OBS = True - EXPORT_GROUP_BY_OB = False - EXPORT_GROUP_BY_MAT = False - EXPORT_KEEP_VERT_ORDER = False - EXPORT_POLYGROUPS = False - EXPORT_CURVE_AS_NURBS = True - - base_name, ext = splitExt(filename) - context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension - - orig_scene = context.scene - -# if EXPORT_ALL_SCENES: -# export_scenes = bpy.data.scenes -# else: -# export_scenes = [orig_scene] - - # XXX only exporting one scene atm since changing - # current scene is not possible. - # Brecht says that ideally in 2.5 we won't need such a function, - # allowing multiple scenes open at once. - export_scenes = [orig_scene] - - # Export all scenes. - for scn in export_scenes: - # scn.makeCurrent() # If already current, this is not slow. - # context = scn.getRenderingContext() - orig_frame = scn.current_frame - - if EXPORT_ALL_SCENES: # Add scene name into the context_name - context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. - - # Export an animation? - if EXPORT_ANIMATION: - scene_frames = xrange(scn.start_frame, context.end_frame+1) # Up to and including the end frame. - else: - scene_frames = [orig_frame] # Dont export an animation. - - # Loop through all frames in the scene and export. - for frame in scene_frames: - if EXPORT_ANIMATION: # Add frame to the filename. - context_name[2] = '_%.6d' % frame - - scn.current_frame = frame - if EXPORT_SEL_ONLY: - export_objects = context.selected_objects - else: - export_objects = scn.objects - - full_path= ''.join(context_name) - - # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. - # EXPORT THE FILE. - write(full_path, export_objects, scn, - EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS, - EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL, - EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS, - EXPORT_ROTX90, EXPORT_BLEN_OBS, - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER, - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS) - - - scn.current_frame = orig_frame - - # Restore old active scene. -# orig_scene.makeCurrent() -# Window.WaitCursor(0) - - -class EXPORT_OT_obj(bpy.types.Operator): - ''' - Currently the exporter lacks these features: - * nurbs - * multiple scene export (only active scene is written) - * particles - ''' - __label__ = 'Export OBJ' - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - __props__ = [ - # bpy.types.FloatProperty(attr="setting_1", name="Example 1", - # default=10.0, min=0, max=10, description="Add info here"), - # bpy.types.IntProperty(attr="setting_2", default=2), - # bpy.types.BoolProperty(attr="toggle", default=True) - ] - - def execu(self, context): - print("Selected: " + context.active_object.name) - - do_export("/tmp/test.obj", context) - - return 'FINISHED' - - def invoke(self, event): - print("Invoke") - return 'FINISHED' - - def poll(self, context): # Poll isnt working yet - print("Poll") - return True - -if (hasattr(bpy.ops, "SCRIPT_OT_export_obj")): - bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj) - -bpy.ops.add(SCRIPT_OT_export_obj) - -bpy.ops.SCRIPT_OT_export_obj() - -bpy.ops.remove(bpy.ops.SCRIPT_OT_export_obj) diff --git a/release/ui/space_script.py b/release/ui/space_script.py index d35f2d389c8..9b0809ffc75 100644 --- a/release/ui/space_script.py +++ b/release/ui/space_script.py @@ -32,7 +32,7 @@ class SCRIPT_HT_header(bpy.types.Header): if context.area.show_menus: row = layout.row(align=True) - row.itemM(context, "SCRIPT_MT_scripts") + row.itemM("SCRIPT_MT_scripts") class SCRIPT_MT_scripts(bpy.types.Menu): __space_type__ = "SCRIPTS_WINDOW" @@ -41,7 +41,7 @@ class SCRIPT_MT_scripts(bpy.types.Menu): def draw(self, context): layout = self.layout layout.column() - layout.itemM(context, "SCRIPT_MT_export") + layout.itemM("SCRIPT_MT_export") layout.itemO("SCRIPT_OT_reload_scripts") class SCRIPT_MT_export(bpy.types.Menu): diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 984e6a5d30f..f4bc52bc517 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -36,6 +36,8 @@ #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" +#include "BKE_mesh.h" + #include "BLI_arithb.h" #include "DNA_mesh_types.h" @@ -66,6 +68,14 @@ void rna_Mesh_transform(Mesh *me, float *mat) } } +Mesh *rna_Mesh_create_copy(Mesh *me) +{ + Mesh *ret= copy_mesh(me); + ret->id.us--; + + return ret; +} + #if 0 /* extern struct EditVert *addvertlist(EditMesh *em, float *vec, struct EditVert *example); */ @@ -101,6 +111,11 @@ void RNA_api_mesh(StructRNA *srna) 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, "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."); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 1b6c298eba4..b09acb51084 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -36,6 +36,12 @@ #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" @@ -55,7 +61,7 @@ #include "ED_mesh.h" /* copied from init_render_mesh (render code) */ -static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int render_mesh) +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_MESH; /* this seems more suitable, exporter, @@ -71,8 +77,13 @@ static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int rende BKE_report(reports, RPT_ERROR, "Object should be of type MESH."); return NULL; } - - dm= render_mesh ? mesh_create_derived_render(sce, ob, mask) : mesh_create_derived_view(sce, ob, mask); + + 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 */ @@ -87,16 +98,6 @@ static Mesh *create_mesh(Object *ob, bContext *C, ReportList *reports, int rende return me; } -static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, ReportList *reports) -{ - return create_mesh(ob, C, reports, 1); -} - -static Mesh *rna_Object_create_preview_mesh(Object *ob, bContext *C, ReportList *reports) -{ - return create_mesh(ob, C, reports, 0); -} - /* When no longer needed, duplilist should be freed with Object.free_duplilist */ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *reports) { @@ -162,33 +163,20 @@ void RNA_api_object(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - /* copied from rna_def_object */ - static EnumPropertyItem object_type_items[] = { - {OB_EMPTY, "EMPTY", 0, "Empty", ""}, - {OB_MESH, "MESH", 0, "Mesh", ""}, - {OB_CURVE, "CURVE", 0, "Curve", ""}, - {OB_SURF, "SURFACE", 0, "Surface", ""}, - {OB_FONT, "TEXT", 0, "Text", ""}, - {OB_MBALL, "META", 0, "Meta", ""}, - {OB_LAMP, "LAMP", 0, "Lamp", ""}, - {OB_CAMERA, "CAMERA", 0, "Camera", ""}, - {OB_WAVE, "WAVE", 0, "Wave", ""}, - {OB_LATTICE, "LATTICE", 0, "Lattice", ""}, - {OB_ARMATURE, "ARMATURE", 0, "Armature", ""}, - {0, NULL, 0, NULL, NULL}}; - - func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for rendering."); - RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); - parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export."); - RNA_def_function_return(func, parm); + 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_preview_mesh", "rna_Object_create_preview_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied for preview."); + 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."); 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); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 8b5ad36f349..96ef796839b 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -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() ); } /***************************************************************************** diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index b7e3c86dd91..4e5536c8552 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -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} diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 0b8a7df1ae1..90876b36ee0 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1367,8 +1367,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 index 00000000000..4d80d3bff93 --- /dev/null +++ b/source/blender/python/intern/bpy_sys.c @@ -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 index 00000000000..a045ed0d537 --- /dev/null +++ b/source/blender/python/intern/bpy_sys.h @@ -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 */ + +/* PyObject *sys_Init( void ); */ + +#include + +PyObject *BPY_sys_module( void ); + + +#endif /* BPY_SYS_H */ -- cgit v1.2.3 From 6ede28a05ae7cfbf8159277f3618b763d1fbb2c2 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 1 Jul 2009 18:23:11 +0000 Subject: - started OBJ importer conversion - added Mesh.add_uv_layer, Object.add_vertex_group --- release/io/import_obj.py | 1280 +++++++++++++++++++++++ source/blender/makesrna/intern/rna_mesh_api.c | 14 + source/blender/makesrna/intern/rna_object.c | 6 +- source/blender/makesrna/intern/rna_object_api.c | 57 +- 4 files changed, 1350 insertions(+), 7 deletions(-) create mode 100644 release/io/import_obj.py diff --git a/release/io/import_obj.py b/release/io/import_obj.py new file mode 100644 index 00000000000..b81ada15f89 --- /dev/null +++ b/release/io/import_obj.py @@ -0,0 +1,1280 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 249 +Group: 'Import' +Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' +""" + +__author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone" +__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org'] +__version__= "2.11" + +__bpydoc__= """\ +This script imports a Wavefront OBJ files to Blender. + +Usage: +Run this script from "File->Import" menu and then load the desired OBJ file. +Note, This loads mesh objects and materials only, nurbs and curves are not supported. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2007 +# +# 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 ***** +# -------------------------------------------------------------------------- + +from Blender import Mesh, Draw, Window, Texture, Material, sys +import bpy +import BPyMesh +import BPyImage +import BPyMessages + +try: import os +except: os= False + +# Generic path functions +def stripFile(path): + '''Return directory, where the file is''' + lastSlash= max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path= path[:lastSlash] + return '%s%s' % (path, sys.sep) + +def stripPath(path): + '''Strips the slashes from the back of a string''' + return path.split('/')[-1].split('\\')[-1] + +def stripExt(name): # name is a string + '''Strips the prefix off the name before writing''' + index= name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name +# end path funcs + +def unpack_list(list_of_tuples): + l = [] + for t in list_of_tuples: + l.extend(t) + return l + +# same as above except that it adds 0 for triangle faces +def unpack_face_list(list_of_tuples): + l = [] + for t in list_of_tuples: + if len(t) == 3: + t += [0] + l.extend(t) + return l + + +def line_value(line_split): + ''' + Returns 1 string represneting the value for this line + None will be returned if theres only 1 word + ''' + length= len(line_split) + if length == 1: + return None + + elif length == 2: + return line_split[1] + + elif length > 2: + return ' '.join( line_split[1:] ) + +def obj_image_load(imagepath, DIR, IMAGE_SEARCH): + ''' + Mainly uses comprehensiveImageLoad + but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. + ''' + + if '_' in imagepath: + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + # Did the exporter rename the image? + image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + + # Return an image, placeholder if it dosnt exist + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) + return image + + +def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): + ''' + Create all the used materials in this obj, + assign colors and images to the materials from all referenced material libs + ''' + DIR= stripFile(filepath) + + #==================================================================================# + # This function sets textures defined in .mtl file # + #==================================================================================# + def load_material_image(blender_material, context_material_name, imagepath, type): + + texture= bpy.data.textures.new(type) + texture.setType('Image') + + # Absolute path - c:\.. etc would work here + image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) + has_data = image.has_data + texture.image = image + + # Adds textures for materials (rendering) + if type == 'Kd': + if has_data and image.depth == 32: + # Image has alpha + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) + texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + else: + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + # adds textures to faces (Textured/Alt-Z mode) + # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. + unique_material_images[context_material_name]= image, has_data # set the texface image + + elif type == 'Ka': + blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API + + elif type == 'Ks': + blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + + elif type == 'Bump': + blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) + elif type == 'D': + blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + # Todo, unset deffuse material alpha if it has an alpha channel + + elif type == 'refl': + blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) + + + # Add an MTL with the same name as the obj if no MTLs are spesified. + temp_mtl= stripExt(stripPath(filepath))+ '.mtl' + + if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: + material_libs.append( temp_mtl ) + del temp_mtl + + #Create new materials + for name in unique_materials: # .keys() + if name != None: + unique_materials[name]= bpy.data.materials.new(name) + unique_material_images[name]= None, False # assign None to all material images to start with, add to later. + + unique_materials[None]= None + unique_material_images[None]= None, False + + for libname in material_libs: + mtlpath= DIR + libname + if not sys.exists(mtlpath): + #print '\tError Missing MTL: "%s"' % mtlpath + pass + else: + #print '\t\tloading mtl: "%s"' % mtlpath + context_material= None + mtl= open(mtlpath, 'rU') + for line in mtl: #.xreadlines(): + if line.startswith('newmtl'): + context_material_name= line_value(line.split()) + if unique_materials.has_key(context_material_name): + context_material = unique_materials[ context_material_name ] + else: + context_material = None + + elif context_material: + # we need to make a material to assign properties to it. + line_split= line.split() + line_lower= line.lower().lstrip() + if line_lower.startswith('ka'): + context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('kd'): + context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ks'): + context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ns'): + context_material.setHardness( int((float(line_split[1])*0.51)) ) + elif line_lower.startswith('ni'): # Refraction index + context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 + elif line_lower.startswith('d') or line_lower.startswith('tr'): + context_material.setAlpha(float(line_split[1])) + elif line_lower.startswith('map_ka'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ka') + elif line_lower.startswith('map_ks'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ks') + elif line_lower.startswith('map_kd'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Kd') + elif line_lower.startswith('map_bump'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Bump') + elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'D') + + elif line_lower.startswith('refl'): # Reflectionmap + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'refl') + mtl.close() + + + + +def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + ''' + Takes vert_loc and faces, and seperates into multiple sets of + (verts_loc, faces, unique_materials, dataname) + This is done so objects do not overload the 16 material limit. + ''' + + filename = stripExt(stripPath(filepath)) + + if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + # use the filename for the object name since we arnt chopping up the mesh. + return [(verts_loc, faces, unique_materials, filename)] + + + def key_to_name(key): + # if the key is a tuple, join it to make a string + if type(key) == tuple: + return '%s_%s' % key + elif not key: + return filename # assume its a string. make sure this is true if the splitting code is changed + else: + return key + + # Return a key that makes the faces unique. + if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + def face_key(face): + return face[4] # object + + elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: + def face_key(face): + return face[2] # material + + else: # Both + def face_key(face): + return face[4], face[2] # object,material + + + face_split_dict= {} + + oldkey= -1 # initialize to a value that will never match the key + + for face in faces: + + key= face_key(face) + + if oldkey != key: + # Check the key has changed. + try: + verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] + except KeyError: + faces_split= [] + verts_split= [] + unique_materials_split= {} + vert_remap= [-1]*len(verts_loc) + + face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) + + oldkey= key + + face_vert_loc_indicies= face[0] + + # Remap verts to new vert list and add where needed + for enum, i in enumerate(face_vert_loc_indicies): + if vert_remap[i] == -1: + new_index= len(verts_split) + vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. + face_vert_loc_indicies[enum] = new_index # remap to the local index + verts_split.append( verts_loc[i] ) # add the vert to the local verts + + else: + face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index + + matname= face[2] + if matname and not unique_materials_split.has_key(matname): + unique_materials_split[matname] = unique_materials[matname] + + faces_split.append(face) + + + # remove one of the itemas and reorder + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()] + + +def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): + ''' + Takes all the data gathered and generates a mesh, adding the new object to new_objects + deals with fgons, sharp edges and assigning materials + ''' + if not has_ngons: + CREATE_FGONS= False + + if unique_smooth_groups: + sharp_edges= {} + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ]) + context_smooth_group_old= -1 + + # Split fgons into tri's + fgon_edges= {} # Used for storing fgon keys + if CREATE_EDGES: + edges= [] + + context_object= None + + # reverse loop through face indicies + for f_idx in xrange(len(faces)-1, -1, -1): + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= faces[f_idx] + + len_face_vert_loc_indicies = len(face_vert_loc_indicies) + + if len_face_vert_loc_indicies==1: + faces.pop(f_idx)# cant add single vert faces + + elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines + if CREATE_EDGES: + # generators are better in python 2.4+ but can't be used in 2.3 + # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) + edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] ) + + faces.pop(f_idx) + else: + + # Smooth Group + if unique_smooth_groups and context_smooth_group: + # Is a part of of a smooth group and is a face + if context_smooth_group_old is not context_smooth_group: + edge_dict= smooth_group_users[context_smooth_group] + context_smooth_group_old= context_smooth_group + + for i in xrange(len_face_vert_loc_indicies): + i1= face_vert_loc_indicies[i] + i2= face_vert_loc_indicies[i-1] + if i1>i2: i1,i2= i2,i1 + + try: + edge_dict[i1,i2]+= 1 + except KeyError: + edge_dict[i1,i2]= 1 + + # FGons into triangles + if has_ngons and len_face_vert_loc_indicies > 4: + + ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) + faces.extend(\ + [(\ + [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ + [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ + context_material,\ + context_smooth_group,\ + context_object)\ + for ngon in ngon_face_indices]\ + ) + + # edges to make fgons + if CREATE_FGONS: + edge_users= {} + for ngon in ngon_face_indices: + for i in (0,1,2): + i1= face_vert_loc_indicies[ngon[i ]] + i2= face_vert_loc_indicies[ngon[i-1]] + if i1>i2: i1,i2= i2,i1 + + try: + edge_users[i1,i2]+=1 + except KeyError: + edge_users[i1,i2]= 1 + + for key, users in edge_users.iteritems(): + if users>1: + fgon_edges[key]= None + + # remove all after 3, means we dont have to pop this one. + faces.pop(f_idx) + + + # Build sharp edges + if unique_smooth_groups: + for edge_dict in smooth_group_users.itervalues(): + for key, users in edge_dict.iteritems(): + if users==1: # This edge is on the boundry of a group + sharp_edges[key]= None + + + # map the material names to an index + material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys() + + materials= [None] * len(unique_materials) + + for name, index in material_mapping.iteritems(): + materials[index]= unique_materials[name] + + me= bpy.data.add_mesh(dataname) +# me= bpy.data.meshes.new(dataname) + + me.materials= materials[0:16] # make sure the list isnt too big. + #me.verts.extend([(0,0,0)]) # dummy vert + + me.add_geometry(len(verts_loc), 0, len(faces)) + + # verts_loc is a list of (x, y, z) tuples + me.verts.foreach_set("co", unpack_list(verts_loc)) +# me.verts.extend(verts_loc) + + # faces is a list of (vert_indices, texco_indices, ...) tuples + # XXX faces should not contain edges + # XXX no check for valid face indices + me.faces.foreach_set("verts", unpack_face_list([f[0] for f in faces])) +# face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) + + if verts_tex and me.faces: + me.add_uv_layer() +# me.faceUV= 1 + # TEXMODE= Mesh.FaceModes['TEX'] + + context_material_old= -1 # avoid a dict lookup + mat= 0 # rare case it may be un-initialized. + me_faces= me.faces +# ALPHA= Mesh.FaceTranspModes.ALPHA + + for i, face in enumerate(faces): + if len(face[0]) < 2: + pass #raise "bad face" + elif len(face[0])==2: + if CREATE_EDGES: + edges.append(face[0]) + else: +# face_index_map= face_mapping[i] + + # since we use foreach_set to add faces, all of them are added + if 1: +# if face_index_map!=None: # None means the face wasnt added + + blender_face = me.faces[i] +# blender_face= me_faces[face_index_map] + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= face + + + + if context_smooth_group: + blender_face.smooth= True + + if context_material: + if context_material_old is not context_material: + mat= material_mapping[context_material] + if mat>15: + mat= 15 + context_material_old= context_material + + blender_face.material_index= mat +# blender_face.mat= mat + + + if verts_tex: + + blender_tface= me.uv_layers[0].data[i] + + if context_material: + image, has_data= unique_material_images[context_material] + if image: # Can be none if the material dosnt have an image. + blender_tface.image= image +# blender_face.image= image + if has_data: +# if has_data and image.depth == 32: + blender_tface.transp = 'ALPHA' +# blender_face.transp |= ALPHA + + # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. + if len(face_vert_loc_indicies)==4: + if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: + face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] + else: # length of 3 + if face_vert_loc_indicies[2]==0: + face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] + # END EEEKADOODLE FIX + + # assign material, uv's and image + blender_tface.uv1= verts_tex[face_vert_tex_indicies[0]] + blender_tface.uv2= verts_tex[face_vert_tex_indicies[1]] + blender_tface.uv3= verts_tex[face_vert_tex_indicies[2]] + + if blender_face.verts[3] != 0: + blender_tface.uv4= verts_tex[face_vert_tex_indicies[3]] + +# for ii, uv in enumerate(blender_face.uv): +# uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] + del me_faces +# del ALPHA + + # Add edge faces. + me_edges= me.edges +# if CREATE_FGONS and fgon_edges: +# FGON= Mesh.EdgeFlags.FGON +# for ed in me.findEdges( fgon_edges.keys() ): +# if ed!=None: +# me_edges[ed].flag |= FGON +# del FGON + +# if unique_smooth_groups and sharp_edges: +# SHARP= Mesh.EdgeFlags.SHARP +# for ed in me.findEdges( sharp_edges.keys() ): +# if ed!=None: +# me_edges[ed].flag |= SHARP +# del SHARP + +# if CREATE_EDGES: +# me_edges.extend( edges ) + +# del me_edges + +# me.calcNormals() + + ob= bpy.data.add_object("MESH", "Mesh") + ob.data= me +# ob= scn.objects.new(me) + new_objects.append(ob) + +# # Create the vertex groups. No need to have the flag passed here since we test for the +# # content of the vertex_groups. If the user selects to NOT have vertex groups saved then +# # the following test will never run +# for group_name, group_indicies in vertex_groups.iteritems(): +# i= ob.add_vertex_group(group_name) +# # me.addVertGroup(group_name) +# me.assign_verts_to_group(group_index, group_indicies, len(group_indicies), 1.0, 'REPLACE') +# # me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE) + + +class Mesh(bpy.types.Mesh): + + def assign_verts_to_group(self, group_index, vert_indices, weight): + + +def create_nurbs(scn, context_nurbs, vert_loc, new_objects): + ''' + Add nurbs object to blender, only support one type at the moment + ''' + deg = context_nurbs.get('deg', (3,)) + curv_range = context_nurbs.get('curv_range', None) + curv_idx = context_nurbs.get('curv_idx', []) + parm_u = context_nurbs.get('parm_u', []) + parm_v = context_nurbs.get('parm_v', []) + name = context_nurbs.get('name', 'ObjNurb') + cstype = context_nurbs.get('cstype', None) + + if cstype == None: + print '\tWarning, cstype not found' + return + if cstype != 'bspline': + print '\tWarning, cstype is not supported (only bspline)' + return + if not curv_idx: + print '\tWarning, curv argument empty or not set' + return + if len(deg) > 1 or parm_v: + print '\tWarning, surfaces not supported' + return + + cu = bpy.data.curves.new(name, 'Curve') + cu.flag |= 1 # 3D curve + + nu = None + for pt in curv_idx: + + pt = vert_loc[pt] + pt = (pt[0], pt[1], pt[2], 1.0) + + if nu == None: + nu = cu.appendNurb(pt) + else: + nu.append(pt) + + nu.orderU = deg[0]+1 + + # get for endpoint flag from the weighting + if curv_range and len(parm_u) > deg[0]+1: + do_endpoints = True + for i in xrange(deg[0]+1): + + if abs(parm_u[i]-curv_range[0]) > 0.0001: + do_endpoints = False + break + + if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001: + do_endpoints = False + break + + else: + do_endpoints = False + + if do_endpoints: + nu.flagU |= 2 + + + # close + ''' + do_closed = False + if len(parm_u) > deg[0]+1: + for i in xrange(deg[0]+1): + #print curv_idx[i], curv_idx[-(i+1)] + + if curv_idx[i]==curv_idx[-(i+1)]: + do_closed = True + break + + if do_closed: + nu.flagU |= 1 + ''' + + ob = scn.objects.new(cu) + new_objects.append(ob) + + +def strip_slash(line_split): + if line_split[-1][-1]== '\\': + if len(line_split[-1])==1: + line_split.pop() # remove the \ item + else: + line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number + return True + return False + + + +def get_float_func(filepath): + ''' + find the float function for this obj file + - weather to replace commas or not + ''' + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + line = line.lstrip() + if line.startswith('v'): # vn vt v + if ',' in line: + return lambda f: float(f.replace(',', '.')) + elif '.' in line: + return float + + # incase all vert values were ints + return float + +def load_obj(filepath, + CLAMP_SIZE= 0.0, + CREATE_FGONS= True, + CREATE_SMOOTH_GROUPS= True, + CREATE_EDGES= True, + SPLIT_OBJECTS= True, + SPLIT_GROUPS= True, + SPLIT_MATERIALS= True, + ROTATE_X90= True, + IMAGE_SEARCH=True, + POLYGROUPS=False): + ''' + Called by the user interface or another script. + load_obj(path) - should give acceptable results. + This function passes the file and sends the data off + to be split into objects and then converted into mesh objects + ''' + print '\nimporting obj "%s"' % filepath + + if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: + POLYGROUPS = False + + time_main= sys.time() + + verts_loc= [] + verts_tex= [] + faces= [] # tuples of the faces + material_libs= [] # filanems to material libs this uses + vertex_groups = {} # when POLYGROUPS is true + + # Get the string to float conversion func for this file- is 'float' for almost all files. + float_func= get_float_func(filepath) + + # Context variables + context_material= None + context_smooth_group= None + context_object= None + context_vgroup = None + + # Nurbs + context_nurbs = {} + nurbs = [] + context_parm = '' # used by nurbs too but could be used elsewhere + + has_ngons= False + # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 + + # Until we can use sets + unique_materials= {} + unique_material_images= {} + unique_smooth_groups= {} + # unique_obects= {} - no use for this variable since the objects are stored in the face. + + # when there are faces that end with \ + # it means they are multiline- + # since we use xreadline we cant skip to the next line + # so we need to know weather + context_multi_line= '' + + print '\tparsing obj file "%s"...' % filepath, + time_sub= sys.time() + + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + line = line.lstrip() # rare cases there is white space at the start of the line + + if line.startswith('v '): + line_split= line.split() + # rotate X90: (x,-z,y) + verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) + + elif line.startswith('vn '): + pass + + elif line.startswith('vt '): + line_split= line.split() + verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) + + # Handel faces lines (as faces) and the second+ lines of fa multiline face here + # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) + elif line.startswith('f') or context_multi_line == 'f': + + if context_multi_line: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if strip_slash(line_split): + context_multi_line = 'f' + else: + context_multi_line = '' + + for v in line_split: + obj_vert= v.split('/') + + vert_loc_index= int(obj_vert[0])-1 + # Add the vertex to the current group + # *warning*, this wont work for files that have groups defined around verts + if POLYGROUPS and context_vgroup: + vertex_groups[context_vgroup].append(vert_loc_index) + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + if len(obj_vert)>1 and obj_vert[1]: + # formatting for faces with normals and textures us + # loc_index/tex_index/nor_index + + vert_tex_index= int(obj_vert[1])-1 + # Make relative negative vert indicies absolute + if vert_tex_index < 0: + vert_tex_index= len(verts_tex) + vert_tex_index + 1 + + face_vert_tex_indicies.append(vert_tex_index) + else: + # dummy + face_vert_tex_indicies.append(0) + + if len(face_vert_loc_indicies) > 4: + has_ngons= True + + elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'): + # very similar to the face load function above with some parts removed + + if context_multi_line: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if strip_slash(line_split): + context_multi_line = 'l' + else: + context_multi_line = '' + + isline= line.startswith('l') + + for v in line_split: + vert_loc_index= int(v)-1 + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + elif line.startswith('s'): + if CREATE_SMOOTH_GROUPS: + context_smooth_group= line_value(line.split()) + if context_smooth_group=='off': + context_smooth_group= None + elif context_smooth_group: # is not None + unique_smooth_groups[context_smooth_group]= None + + elif line.startswith('o'): + if SPLIT_OBJECTS: + context_object= line_value(line.split()) + # unique_obects[context_object]= None + + elif line.startswith('g'): + if SPLIT_GROUPS: + context_object= line_value(line.split()) + # print 'context_object', context_object + # unique_obects[context_object]= None + elif POLYGROUPS: + context_vgroup = line_value(line.split()) + if context_vgroup and context_vgroup != '(null)': + vertex_groups.setdefault(context_vgroup, []) + else: + context_vgroup = None # dont assign a vgroup + + elif line.startswith('usemtl'): + context_material= line_value(line.split()) + unique_materials[context_material]= None + elif line.startswith('mtllib'): # usemap or usemat + material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line + + + # Nurbs support + elif line.startswith('cstype '): + context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline' + elif line.startswith('curv ') or context_multi_line == 'curv': + line_split= line.split() + + curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline + + if not context_multi_line: + context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2]) + line_split[0:3] = [] # remove first 3 items + + if strip_slash(line_split): + context_multi_line = 'curv' + else: + context_multi_line = '' + + + for i in line_split: + vert_loc_index = int(i)-1 + + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + curv_idx.append(vert_loc_index) + + elif line.startswith('parm') or context_multi_line == 'parm': + line_split= line.split() + + if context_multi_line: + context_multi_line = '' + else: + context_parm = line_split[1] + line_split[0:2] = [] # remove first 2 + + if strip_slash(line_split): + context_multi_line = 'parm' + else: + context_multi_line = '' + + if context_parm.lower() == 'u': + context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] ) + elif context_parm.lower() == 'v': # surfaces not suported yet + context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] ) + # else: # may want to support other parm's ? + + elif line.startswith('deg '): + context_nurbs['deg']= [int(i) for i in line.split()[1:]] + elif line.startswith('end'): + # Add the nurbs curve + if context_object: + context_nurbs['name'] = context_object + nurbs.append(context_nurbs) + context_nurbs = {} + context_parm = '' + + ''' # How to use usemap? depricated? + elif line.startswith('usema'): # usemap or usemat + context_image= line_value(line.split()) + ''' + + file.close() + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + + print '\tloading materials and images...', + create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) + + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + if not ROTATE_X90: + verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] + + # deselect all + scn = bpy.data.scenes.active + scn.objects.selected = [] + new_objects= [] # put new objects here + + print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), + # Split the mesh by objects/materials, may + if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True + else: SPLIT_OB_OR_GROUP = False + + for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + # Create meshes from the data, warning 'vertex_groups' wont support splitting + create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) + + # nurbs support + for context_nurbs in nurbs: + create_nurbs(scn, context_nurbs, verts_loc, new_objects) + + + axis_min= [ 1000000000]*3 + axis_max= [-1000000000]*3 + + if CLAMP_SIZE: + # Get all object bounds + for ob in new_objects: + for v in ob.getBoundBox(): + for axis, value in enumerate(v): + if axis_min[axis] > value: axis_min[axis]= value + if axis_max[axis] < value: axis_max[axis]= value + + # Scale objects + max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) + scale= 1.0 + + while CLAMP_SIZE < max_axis * scale: + scale= scale/10.0 + + for ob in new_objects: + ob.setSize(scale, scale, scale) + + # Better rotate the vert locations + #if not ROTATE_X90: + # for ob in new_objects: + # ob.RotX = -1.570796326794896558 + + time_new= sys.time() + + print '%.4f sec' % (time_new-time_sub) + print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) + + +DEBUG= True + + +def load_obj_ui(filepath, BATCH_LOAD= False): + if BPyMessages.Error_NoFile(filepath): + return + + global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 + + CREATE_SMOOTH_GROUPS= Draw.Create(0) + CREATE_FGONS= Draw.Create(1) + CREATE_EDGES= Draw.Create(1) + SPLIT_OBJECTS= Draw.Create(0) + SPLIT_GROUPS= Draw.Create(0) + SPLIT_MATERIALS= Draw.Create(0) + CLAMP_SIZE= Draw.Create(10.0) + IMAGE_SEARCH= Draw.Create(1) + POLYGROUPS= Draw.Create(0) + KEEP_VERT_ORDER= Draw.Create(1) + ROTATE_X90= Draw.Create(1) + + + # Get USER Options + # Note, Works but not pretty, instead use a more complicated GUI + ''' + pup_block= [\ + 'Import...',\ + ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ + ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ + ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ + 'Separate objects from obj...',\ + ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ + ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ + ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ + 'Options...',\ + ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ + ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ + ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ + ] + + if not Draw.PupBlock('Import OBJ...', pup_block): + return + + if KEEP_VERT_ORDER.val: + SPLIT_OBJECTS.val = False + SPLIT_GROUPS.val = False + SPLIT_MATERIALS.val = False + ''' + + + + # BEGIN ALTERNATIVE UI ******************* + if True: + + EVENT_NONE = 0 + EVENT_EXIT = 1 + EVENT_REDRAW = 2 + EVENT_IMPORT = 3 + + GLOBALS = {} + GLOBALS['EVENT'] = EVENT_REDRAW + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + + def obj_ui_set_event(e,v): + GLOBALS['EVENT'] = e + + def do_split(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS + if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val: + KEEP_VERT_ORDER.val = 0 + POLYGROUPS.val = 0 + else: + KEEP_VERT_ORDER.val = 1 + + def do_vertorder(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER + if KEEP_VERT_ORDER.val: + SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 + else: + if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val): + KEEP_VERT_ORDER.val = 1 + + def do_polygroups(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS + if POLYGROUPS.val: + SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 + + def do_help(e,v): + url = __url__[0] + print 'Trying to open web browser with documentation at this address...' + print '\t' + url + + try: + import webbrowser + webbrowser.open(url) + except: + print '...could not open a browser window.' + + def obj_ui(): + ui_x, ui_y = GLOBALS['MOUSE'] + + # Center based on overall pup size + ui_x -= 165 + ui_y -= 90 + + global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 + + Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21) + Draw.BeginAlign() + CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges') + CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons') + CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges') + Draw.EndAlign() + + Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20) + Draw.BeginAlign() + SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split) + SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split) + SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split) + Draw.EndAlign() + + # Only used for user feedback + KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder) + + ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.') + + Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20) + CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)') + POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups) + IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)') + Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event) + Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event) + Draw.EndAlign() + + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT): + Draw.UIBlock(obj_ui, 0) + + if GLOBALS['EVENT'] != EVENT_IMPORT: + return + + # END ALTERNATIVE UI ********************* + + + + + + + + Window.WaitCursor(1) + + if BATCH_LOAD: # load the dir + try: + files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] + except: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|Could not open path ' + filepath) + return + + if not files: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|No files at path ' + filepath) + return + + for f in files: + scn= bpy.data.scenes.new( stripExt(f) ) + scn.makeCurrent() + + load_obj(sys.join(filepath, f),\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + ROTATE_X90.val,\ + IMAGE_SEARCH.val,\ + POLYGROUPS.val + ) + + else: # Normal load + load_obj(filepath,\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + ROTATE_X90.val,\ + IMAGE_SEARCH.val,\ + POLYGROUPS.val + ) + + Window.WaitCursor(0) + + +def load_obj_ui_batch(file): + load_obj_ui(file, True) + +DEBUG= False + +if __name__=='__main__' and not DEBUG: + if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: + Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') + else: + Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') + + # For testing compatibility +''' +else: + # DEBUG ONLY + TIME= sys.time() + DIR = '/fe/obj' + import os + print 'Searching for files' + def fileList(path): + for dirpath, dirnames, filenames in os.walk(path): + for filename in filenames: + yield os.path.join(dirpath, filename) + + files = [f for f in fileList(DIR) if f.lower().endswith('.obj')] + files.sort() + + for i, obj_file in enumerate(files): + if 0 < i < 20: + print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files) + newScn= bpy.data.scenes.new(os.path.basename(obj_file)) + newScn.makeCurrent() + load_obj(obj_file, False, IMAGE_SEARCH=0) + + print 'TOTAL TIME: %.6f' % (sys.time() - TIME) +''' +#load_obj('/test.obj') +#load_obj('/fe/obj/mba1.obj') + +# NOTES (all line numbers refer to 2.4x import_obj.py, not this file) +# check later: line 489 +# edge flags, edges, normals: lines 508-528 +# vertex groups: line 533 - cannot assign vertex groups diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 00d5bacfef0..ecc32b23249 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -232,6 +232,12 @@ static void rna_Mesh_add_faces(Mesh *mesh, int len) mesh->totface= totface; } +/* +static void rna_Mesh_add_faces(Mesh *mesh) +{ +} +*/ + static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) { if(verts) @@ -242,6 +248,11 @@ static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) rna_Mesh_add_faces(mesh, faces); } +static void rna_Mesh_add_uv_layer(Mesh *me) +{ + me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); +} + #else void RNA_api_mesh(StructRNA *srna) @@ -267,6 +278,9 @@ void RNA_api_mesh(StructRNA *srna) 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_uv_layer", "rna_Mesh_add_uv_layer"); + RNA_def_function_ui_description(func, "Add new UV layer to Mesh."); + /* func= RNA_def_function(srna, "add_geom", "rna_Mesh_add_geom"); RNA_def_function_ui_description(func, "Add geometry data to mesh."); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 4166eb9bc2c..e046f2ff73d 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -384,6 +384,7 @@ static void rna_GameObjectSettings_state_set(PointerRNA *ptr, const int *values) } } +/* static PointerRNA rna_DupliObject_object_get(PointerRNA *ptr) { DupliObject *dob= (DupliObject*)ptr->data; @@ -391,6 +392,7 @@ static PointerRNA rna_DupliObject_object_get(PointerRNA *ptr) RNA_pointer_create(&dob->ob->id, &RNA_Object, dob->ob, &newptr); return newptr; } +*/ #else @@ -1207,9 +1209,9 @@ static void rna_def_dupli_object(BlenderRNA *brna) /* 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_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_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."); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index b09acb51084..9d1a6a39d51 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -36,6 +36,10 @@ #include "DNA_object_types.h" +#include "BLO_sys_types.h" /* needed for intptr_t used in ED_mesh.h */ + +#include "ED_mesh.h" + /* parameter to rna_Object_create_mesh */ typedef enum CreateMeshType { CREATE_MESH_PREVIEW = 0, @@ -56,10 +60,6 @@ typedef enum CreateMeshType { #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) */ static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports, int type) { @@ -108,7 +108,7 @@ static void rna_Object_create_duplilist(Object *ob, bContext *C, ReportList *rep /* 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)); + BKE_reportf(reports, RPT_WARNING, "Object.dupli_list has not been freed."); free_object_duplilist(ob->duplilist); ob->duplilist= NULL; @@ -155,6 +155,47 @@ static void rna_Object_convert_to_triface(Object *ob, bContext *C, ReportList *r DAG_object_flush_update(sce, ob, OB_RECALC_DATA); } +static int rna_Object_add_vertex_group(Object *ob, char *group_name) +{ + bDeformGroup *defgroup= add_defgroup_name(ob, group_name); + return BLI_findindex(&ob->defbase, defgroup); +} + +/* +static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) +{ + if (ob->type != OB_MESH) { + BKE_report(reports, RPT_ERROR, "Object should be of MESH type."); + return; + } + + Mesh *me = (Mesh*)ob->data; + int group_index = get_defgroup_num(ob, group); + if (group_index == -1) { + BKE_report(reports, RPT_ERROR, "No deform groups assigned to mesh."); + return; + } + + if (assignmode != WEIGHT_REPLACE && assignmode != WEIGHT_ADD && assignmode != WEIGHT_SUBTRACT) { + BKE_report(reports, RPT_ERROR, "Bad assignment mode." ); + return; + } + + // makes a set of dVerts corresponding to the mVerts + if (!me->dvert) + create_dverts(&me->id); + + // loop list adding verts to group + for (i= 0; i < totindex; i++) { + if(i < 0 || i >= me->totvert) { + BKE_report(reports, RPT_ERROR, "Bad vertex index in list."); + return; + } + + add_vert_defnr(ob, group_index, i, weight, assignmode); + } +} +*/ #else @@ -190,6 +231,12 @@ void RNA_api_object(StructRNA *srna) 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); + + func= RNA_def_function(srna, "add_vertex_group", "rna_Object_add_vertex_group"); + RNA_def_function_ui_description(func, "Add vertex group to object."); + parm= RNA_def_string(func, "name", "Group", 0, "", "Vertex group name."); + parm= RNA_def_int(func, "group_index", 0, 0, 0, "", "Index of the created vertex group.", 0, 0); + RNA_def_function_return(func, parm); } #endif -- cgit v1.2.3 From 617851bf21ac5da10bfd171816187e1336cd4a69 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 2 Jul 2009 20:46:35 +0000 Subject: - added API functions: - Mesh.calc_normals - Object.add_vertex_to_group - Main.add_material - Main.add_texture - Material.add_texture - OBJ importer conversion in progress --- release/io/export_obj.py | 2 +- release/io/import_obj.py | 184 ++++++++++++---------- source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_internal.h | 1 + source/blender/makesrna/intern/rna_main_api.c | 30 +++- source/blender/makesrna/intern/rna_material.c | 2 + source/blender/makesrna/intern/rna_material_api.c | 126 +++++++++++++++ source/blender/makesrna/intern/rna_mesh_api.c | 8 + source/blender/makesrna/intern/rna_object_api.c | 33 +++- 9 files changed, 297 insertions(+), 91 deletions(-) create mode 100644 source/blender/makesrna/intern/rna_material_api.c diff --git a/release/io/export_obj.py b/release/io/export_obj.py index d139e872251..1ee685a52a3 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -464,7 +464,7 @@ def write(filename, objects, scene, # XXX # High Quality Normals if EXPORT_NORMALS and face_index_pairs: - pass + me.calc_normals() # if EXPORT_NORMALS_HQ: # BPyMesh.meshCalcNormals(me) # else: diff --git a/release/io/import_obj.py b/release/io/import_obj.py index b81ada15f89..e16780ce1d6 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -42,7 +42,7 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo from Blender import Mesh, Draw, Window, Texture, Material, sys import bpy -import BPyMesh +# import BPyMesh import BPyImage import BPyMessages @@ -130,9 +130,11 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ # This function sets textures defined in .mtl file # #==================================================================================# def load_material_image(blender_material, context_material_name, imagepath, type): - - texture= bpy.data.textures.new(type) - texture.setType('Image') + + texture= bpy.data.add_texture(type) + texture.type= 'IMAGE' +# texture= bpy.data.textures.new(type) +# texture.setType('Image') # Absolute path - c:\.. etc would work here image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) @@ -182,7 +184,8 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ #Create new materials for name in unique_materials: # .keys() if name != None: - unique_materials[name]= bpy.data.materials.new(name) + unique_materials[name]= bpy.data.add_material(name) +# unique_materials[name]= bpy.data.materials.new(name) unique_material_images[name]= None, False # assign None to all material images to start with, add to later. unique_materials[None]= None @@ -190,7 +193,8 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ for libname in material_libs: mtlpath= DIR + libname - if not sys.exists(mtlpath): + if not bpy.sys.exists(mtlpath): +# if not sys.exists(mtlpath): #print '\tError Missing MTL: "%s"' % mtlpath pass else: @@ -210,17 +214,23 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ line_split= line.split() line_lower= line.lower().lstrip() if line_lower.startswith('ka'): - context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + context_material.mirror_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) elif line_lower.startswith('kd'): - context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + context_material.diffuse_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) elif line_lower.startswith('ks'): - context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + context_material.specular_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) elif line_lower.startswith('ns'): - context_material.setHardness( int((float(line_split[1])*0.51)) ) + context_material.specular_hardness = int((float(line_split[1])*0.51)) +# context_material.setHardness( int((float(line_split[1])*0.51)) ) elif line_lower.startswith('ni'): # Refraction index - context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 + context_material.ior = max(1, min(float(line_split[1]), 3)) +# context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 elif line_lower.startswith('d') or line_lower.startswith('tr'): - context_material.setAlpha(float(line_split[1])) + context_material.alpha = float(line_split[1]) +# context_material.setAlpha(float(line_split[1])) elif line_lower.startswith('map_ka'): img_filepath= line_value(line.split()) if img_filepath: @@ -395,39 +405,39 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l edge_dict[i1,i2]= 1 # FGons into triangles - if has_ngons and len_face_vert_loc_indicies > 4: +# if has_ngons and len_face_vert_loc_indicies > 4: - ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) - faces.extend(\ - [(\ - [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ - [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ - context_material,\ - context_smooth_group,\ - context_object)\ - for ngon in ngon_face_indices]\ - ) +# ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) +# faces.extend(\ +# [(\ +# [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ +# [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ +# context_material,\ +# context_smooth_group,\ +# context_object)\ +# for ngon in ngon_face_indices]\ +# ) - # edges to make fgons - if CREATE_FGONS: - edge_users= {} - for ngon in ngon_face_indices: - for i in (0,1,2): - i1= face_vert_loc_indicies[ngon[i ]] - i2= face_vert_loc_indicies[ngon[i-1]] - if i1>i2: i1,i2= i2,i1 +# # edges to make fgons +# if CREATE_FGONS: +# edge_users= {} +# for ngon in ngon_face_indices: +# for i in (0,1,2): +# i1= face_vert_loc_indicies[ngon[i ]] +# i2= face_vert_loc_indicies[ngon[i-1]] +# if i1>i2: i1,i2= i2,i1 - try: - edge_users[i1,i2]+=1 - except KeyError: - edge_users[i1,i2]= 1 +# try: +# edge_users[i1,i2]+=1 +# except KeyError: +# edge_users[i1,i2]= 1 - for key, users in edge_users.iteritems(): - if users>1: - fgon_edges[key]= None +# for key, users in edge_users.iteritems(): +# if users>1: +# fgon_edges[key]= None - # remove all after 3, means we dont have to pop this one. - faces.pop(f_idx) +# # remove all after 3, means we dont have to pop this one. +# faces.pop(f_idx) # Build sharp edges @@ -564,33 +574,36 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # me_edges[ed].flag |= SHARP # del SHARP -# if CREATE_EDGES: + if CREATE_EDGES: + + me.add_geometry(0, len(edges)) + + # edges is (should be) a list of (a, b) tuples + me.edges.foreach_set("verts", unpack_list(edges)) # me_edges.extend( edges ) # del me_edges - + + me.calc_normals() # me.calcNormals() ob= bpy.data.add_object("MESH", "Mesh") ob.data= me + scn.add_object(ob) # ob= scn.objects.new(me) new_objects.append(ob) -# # Create the vertex groups. No need to have the flag passed here since we test for the -# # content of the vertex_groups. If the user selects to NOT have vertex groups saved then -# # the following test will never run -# for group_name, group_indicies in vertex_groups.iteritems(): -# i= ob.add_vertex_group(group_name) -# # me.addVertGroup(group_name) -# me.assign_verts_to_group(group_index, group_indicies, len(group_indicies), 1.0, 'REPLACE') -# # me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE) + # Create the vertex groups. No need to have the flag passed here since we test for the + # content of the vertex_groups. If the user selects to NOT have vertex groups saved then + # the following test will never run + for group_name, group_indicies in vertex_groups.iteritems(): + group= ob.add_vertex_group(group_name) +# me.addVertGroup(group_name) + for vertex_index in group_indicies: + ob.add_vertex_to_group(vertex_index, group, 1.0, 'REPLACE') +# me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE) -class Mesh(bpy.types.Mesh): - - def assign_verts_to_group(self, group_index, vert_indices, weight): - - def create_nurbs(scn, context_nurbs, vert_loc, new_objects): ''' Add nurbs object to blender, only support one type at the moment @@ -700,16 +713,16 @@ def get_float_func(filepath): return float def load_obj(filepath, - CLAMP_SIZE= 0.0, - CREATE_FGONS= True, - CREATE_SMOOTH_GROUPS= True, - CREATE_EDGES= True, - SPLIT_OBJECTS= True, - SPLIT_GROUPS= True, - SPLIT_MATERIALS= True, - ROTATE_X90= True, - IMAGE_SEARCH=True, - POLYGROUPS=False): + CLAMP_SIZE= 0.0, + CREATE_FGONS= True, + CREATE_SMOOTH_GROUPS= True, + CREATE_EDGES= True, + SPLIT_OBJECTS= True, + SPLIT_GROUPS= True, + SPLIT_MATERIALS= True, + ROTATE_X90= True, + IMAGE_SEARCH=True, + POLYGROUPS=False): ''' Called by the user interface or another script. load_obj(path) - should give acceptable results. @@ -997,30 +1010,30 @@ def load_obj(filepath, create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) # nurbs support - for context_nurbs in nurbs: - create_nurbs(scn, context_nurbs, verts_loc, new_objects) +# for context_nurbs in nurbs: +# create_nurbs(scn, context_nurbs, verts_loc, new_objects) axis_min= [ 1000000000]*3 axis_max= [-1000000000]*3 - if CLAMP_SIZE: - # Get all object bounds - for ob in new_objects: - for v in ob.getBoundBox(): - for axis, value in enumerate(v): - if axis_min[axis] > value: axis_min[axis]= value - if axis_max[axis] < value: axis_max[axis]= value +# if CLAMP_SIZE: +# # Get all object bounds +# for ob in new_objects: +# for v in ob.getBoundBox(): +# for axis, value in enumerate(v): +# if axis_min[axis] > value: axis_min[axis]= value +# if axis_max[axis] < value: axis_max[axis]= value - # Scale objects - max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) - scale= 1.0 +# # Scale objects +# max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) +# scale= 1.0 - while CLAMP_SIZE < max_axis * scale: - scale= scale/10.0 +# while CLAMP_SIZE < max_axis * scale: +# scale= scale/10.0 - for ob in new_objects: - ob.setSize(scale, scale, scale) +# for ob in new_objects: +# ob.setSize(scale, scale, scale) # Better rotate the vert locations #if not ROTATE_X90: @@ -1276,5 +1289,10 @@ else: # NOTES (all line numbers refer to 2.4x import_obj.py, not this file) # check later: line 489 -# edge flags, edges, normals: lines 508-528 -# vertex groups: line 533 - cannot assign vertex groups +# can convert now: edge flags, edges: lines 508-528 +# ngon (uses python module BPyMesh): 384-414 +# nurbs: 947- +# clamp size: cannot get bound box with RNA - neither I can write RNA struct function that returns it - +# again, RNA limitation +# warning: uses bpy.sys.exists +# get back to l 140 (here) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index e779f901b3c..8a9fdb8531d 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1911,7 +1911,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_lamp.c", NULL, RNA_def_lamp}, {"rna_lattice.c", NULL, RNA_def_lattice}, {"rna_main.c", "rna_main_api.c", RNA_def_main}, - {"rna_material.c", NULL, RNA_def_material}, + {"rna_material.c", "rna_material_api.c", RNA_def_material}, {"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh}, {"rna_meta.c", NULL, RNA_def_meta}, {"rna_modifier.c", NULL, RNA_def_modifier}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index f465e733d68..7bf33760011 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -193,6 +193,7 @@ 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); +void RNA_api_material(StructRNA *srna); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 08a3b7cee25..9dc32acff6f 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -40,6 +40,7 @@ #include "BKE_mesh.h" #include "BKE_library.h" #include "BKE_object.h" +#include "BKE_material.h" #include "DNA_mesh_types.h" @@ -68,7 +69,7 @@ static Object* rna_Main_add_object(Main *main, int type, char *name) } /* - WARNING: the following example shows when this function should not be called + NOTE: the following example shows when this function should _not_ be called ob = bpy.data.add_object() scene.add_object(ob) @@ -87,6 +88,20 @@ static void rna_Main_remove_object(Main *main, ReportList *reports, Object *ob) BKE_report(reports, RPT_ERROR, "Object must have zero users to be removed."); } +static Material *rna_Main_add_material(Main *main, char *name) +{ + return add_material(name); +} + +/* TODO: remove material? */ + +struct Tex *rna_Main_add_texture(Main *main, char *name) +{ + return add_texture(name); +} + +/* TODO: remove texture? */ + #else void RNA_api_main(StructRNA *srna) @@ -136,6 +151,19 @@ void RNA_api_main(StructRNA *srna) RNA_def_function_ui_description(func, "Remove a mesh if it has zero users."); parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "add_material", "rna_Main_add_material"); + RNA_def_function_ui_description(func, "Add a new material."); + parm= RNA_def_string(func, "name", "Material", 0, "", "New name for the datablock."); /* optional */ + parm= RNA_def_pointer(func, "material", "Material", "", "New material."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_texture", "rna_Main_add_texture"); + RNA_def_function_ui_description(func, "Add a new texture."); + parm= RNA_def_string(func, "name", "Tex", 0, "", "New name for the datablock."); /* optional */ + parm= RNA_def_pointer(func, "texture", "Texture", "", "New texture."); + RNA_def_function_return(func, parm); + } #endif diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 41f31594f6e..6de13dbd440 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1134,6 +1134,8 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_sss(brna); rna_def_material_mtex(brna); rna_def_material_strand(brna); + + RNA_api_material(srna); } void rna_def_mtex_common(StructRNA *srna, const char *begin, const char *activeget, const char *structname) diff --git a/source/blender/makesrna/intern/rna_material_api.c b/source/blender/makesrna/intern/rna_material_api.c new file mode 100644 index 00000000000..e2b47460fdb --- /dev/null +++ b/source/blender/makesrna/intern/rna_material_api.c @@ -0,0 +1,126 @@ +/** + * + * + * ***** 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 +#include + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_material_types.h" + +#ifdef RNA_RUNTIME + +#include "BKE_material.h" +#include "BKE_texture.h" + +/* + Adds material to the first free texture slot. + If all slots are busy, replaces the first. +*/ +static void rna_Material_add_texture(Material *ma, Tex *tex, int mapto, int texco) +{ + int i; + MTex *mtex; + int slot= -1; + + for (i= 0; i < MAX_MTEX; i++) { + if (!ma->mtex[i]) { + slot= i; + break; + } + } + + if (slot == -1) + slot= 0; + + if (ma->mtex[slot]) { + ma->mtex[slot]->tex->id.us--; + } + else { + ma->mtex[slot]= add_mtex(); + } + + mtex= ma->mtex[slot]; + + mtex->tex= tex; + id_us_plus(&tex->id); + + mtex->texco= mapto; + mtex->mapto= texco; +} + +#else + +void RNA_api_material(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + /* copied from rna_def_material_mtex (rna_material.c) */ + static EnumPropertyItem prop_texture_coordinates_items[] = { + {TEXCO_GLOB, "GLOBAL", 0, "Global", "Uses global coordinates for the texture coordinates."}, + {TEXCO_OBJECT, "OBJECT", 0, "Object", "Uses linked object's coordinates for texture coordinates."}, + {TEXCO_UV, "UV", 0, "UV", "Uses UV coordinates for texture coordinates."}, + {TEXCO_ORCO, "ORCO", 0, "Generated", "Uses the original undeformed coordinates of the object."}, + {TEXCO_STRAND, "STRAND", 0, "Strand", "Uses normalized strand texture coordinate (1D)."}, + {TEXCO_STICKY, "STICKY", 0, "Sticky", "Uses mesh's sticky coordinates for the texture coordinates."}, + {TEXCO_WINDOW, "WINDOW", 0, "Window", "Uses screen coordinates as texture coordinates."}, + {TEXCO_NORM, "NORMAL", 0, "Normal", "Uses normal vector as texture coordinates."}, + {TEXCO_REFL, "REFLECTION", 0, "Reflection", "Uses reflection vector as texture coordinates."}, + {TEXCO_STRESS, "STRESS", 0, "Stress", "Uses the difference of edge lengths compared to original coordinates of the mesh."}, + {TEXCO_TANGENT, "TANGENT", 0, "Tangent", "Uses the optional tangent vector as texture coordinates."}, + + {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem prop_texture_mapto_items[] = { + {MAP_COL, "COLOR", 0, "Color", "Causes the texture to affect basic color of the material"}, + {MAP_NORM, "NORMAL", 0, "Normal", "Causes the texture to affect the rendered normal"}, + {MAP_COLSPEC, "SPEC_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"}, + {MAP_COLMIR, "MIRROR", 0, "Mirror", "Causes the texture to affect the mirror color"}, + {MAP_REF, "REFLECTION", 0, "Reflection", "Causes the texture to affect the value of the materials reflectivity"}, + {MAP_SPEC, "SPECULARITY", 0, "Specularity", "Causes the texture to affect the value of specularity"}, + {MAP_EMIT, "EMIT", 0, "Emit", "Causes the texture to affect the emit value"}, + {MAP_ALPHA, "ALPHA", 0, "Alpha", "Causes the texture to affect the alpha value"}, + {MAP_HAR, "HARDNESS", 0, "Hardness", "Causes the texture to affect the hardness value"}, + {MAP_RAYMIRR, "RAY_MIRROR", 0, "Ray-Mirror", "Causes the texture to affect the ray-mirror value"}, + {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", "Causes the texture to affect the translucency value"}, + {MAP_AMB, "AMBIENT", 0, "Ambient", "Causes the texture to affect the value of ambient"}, + {MAP_DISPLACE, "DISPLACEMENT", 0, "Displacement", "Let the texture displace the surface"}, + {MAP_WARP, "WARP", 0, "Warp", "Let the texture warp texture coordinates of next channels"}, + {0, NULL, 0, NULL, NULL}}; + + func= RNA_def_function(srna, "add_texture", "rna_Material_add_texture"); + RNA_def_function_ui_description(func, "Add a texture to material's free texture slot."); + parm= RNA_def_pointer(func, "texture", "Texture", "", "Texture to add."); + parm= RNA_def_enum(func, "texture_coordinates", prop_texture_coordinates_items, TEXCO_UV, "", "Source of texture coordinate information."); /* optional */ + parm= RNA_def_enum(func, "map_to", prop_texture_mapto_items, MAP_COL, "", "Controls which material property the texture affects."); /* optional */ +} + +#endif + diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index ecc32b23249..b2157340207 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -253,6 +253,11 @@ static void rna_Mesh_add_uv_layer(Mesh *me) me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); } +static void rna_Mesh_calc_normals(Mesh *me) +{ + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); +} + #else void RNA_api_mesh(StructRNA *srna) @@ -281,6 +286,9 @@ void RNA_api_mesh(StructRNA *srna) func= RNA_def_function(srna, "add_uv_layer", "rna_Mesh_add_uv_layer"); RNA_def_function_ui_description(func, "Add new UV layer to Mesh."); + func= RNA_def_function(srna, "calc_normals", "rna_Mesh_calc_normals"); + RNA_def_function_ui_description(func, "Calculate vertex normals."); + /* func= RNA_def_function(srna, "add_geom", "rna_Mesh_add_geom"); RNA_def_function_ui_description(func, "Add geometry data to mesh."); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 9d1a6a39d51..02db7e83062 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -155,10 +155,15 @@ static void rna_Object_convert_to_triface(Object *ob, bContext *C, ReportList *r DAG_object_flush_update(sce, ob, OB_RECALC_DATA); } -static int rna_Object_add_vertex_group(Object *ob, char *group_name) +static bDeformGroup *rna_Object_add_vertex_group(Object *ob, char *group_name) { - bDeformGroup *defgroup= add_defgroup_name(ob, group_name); - return BLI_findindex(&ob->defbase, defgroup); + return add_defgroup_name(ob, group_name); +} + +static void rna_Object_add_vertex_to_group(Object *ob, int vertex_index, bDeformGroup *def, float weight, int assignmode) +{ + /* creates dverts if needed */ + add_vert_to_defgroup(ob, def, vertex_index, weight, assignmode); } /* @@ -210,6 +215,13 @@ void RNA_api_object(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem assign_mode_items[] = { + {WEIGHT_REPLACE, "REPLACE", 0, "Replace", "Replace."}, /* TODO: more meaningful descriptions */ + {WEIGHT_ADD, "ADD", 0, "Add", "Add."}, + {WEIGHT_SUBTRACT, "SUBTRACT", 0, "Subtract", "Subtract."}, + {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."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); @@ -234,9 +246,20 @@ void RNA_api_object(StructRNA *srna) func= RNA_def_function(srna, "add_vertex_group", "rna_Object_add_vertex_group"); RNA_def_function_ui_description(func, "Add vertex group to object."); - parm= RNA_def_string(func, "name", "Group", 0, "", "Vertex group name."); - parm= RNA_def_int(func, "group_index", 0, 0, 0, "", "Index of the created vertex group.", 0, 0); + parm= RNA_def_string(func, "name", "Group", 0, "", "Vertex group name."); /* optional */ + parm= RNA_def_pointer(func, "group", "VertexGroup", "", "New vertex group."); RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "add_vertex_to_group", "rna_Object_add_vertex_to_group"); + RNA_def_function_ui_description(func, "Add vertex to a vertex group."); + parm= RNA_def_int(func, "vertex_index", 0, 0, 0, "", "Vertex index.", 0, 0); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "group", "VertexGroup", "", "Vertex group to add vertex to."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight.", 0.0f, 1.0f); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode."); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif -- cgit v1.2.3 From 2a23fda9d55034e524be32bd8cb196ae4cd93920 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 3 Jul 2009 17:44:20 +0000 Subject: OBJ importer almost converted, except a few features (NURBS, NGON, FGON and sharp edges). Added to API: - Main.add_image - Material.z_transparency - two temporary properties: Image.depth and Image.has_data --- release/io/import_obj.py | 148 ++++++++++++++++++-------- source/blender/makesrna/intern/rna_image.c | 37 +++++++ source/blender/makesrna/intern/rna_main_api.c | 17 ++- source/blender/makesrna/intern/rna_material.c | 5 + 4 files changed, 159 insertions(+), 48 deletions(-) diff --git a/release/io/import_obj.py b/release/io/import_obj.py index e16780ce1d6..659d5207261 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -40,14 +40,16 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- -from Blender import Mesh, Draw, Window, Texture, Material, sys import bpy -# import BPyMesh -import BPyImage -import BPyMessages +import os -try: import os -except: os= False +# from Blender import Mesh, Draw, Window, Texture, Material, sys +# # import BPyMesh +# import BPyImage +# import BPyMessages + +# try: import os +# except: os= False # Generic path functions def stripFile(path): @@ -101,22 +103,44 @@ def line_value(line_split): elif length > 2: return ' '.join( line_split[1:] ) +# limited replacement for BPyImage.comprehensiveImageLoad +def load_image(imagepath, direc): + + if os.path.exists(imagepath): + return bpy.data.add_image(imagepath) + + im_base = os.path.basename(imagepath) + + tmp = os.path.join(direc, im_base) + if os.path.exists(tmp): + return bpy.data.add_image(tmp) + + # TODO comprehensiveImageLoad also searched in bpy.config.textureDir + def obj_image_load(imagepath, DIR, IMAGE_SEARCH): - ''' - Mainly uses comprehensiveImageLoad - but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. - ''' - + if '_' in imagepath: - image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) - if image: return image - # Did the exporter rename the image? - image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + image= load_image(imagepath.replace('_', ' '), DIR) if image: return image - - # Return an image, placeholder if it dosnt exist - image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) - return image + + return load_image(imagepath, DIR) + +# def obj_image_load(imagepath, DIR, IMAGE_SEARCH): +# ''' +# Mainly uses comprehensiveImageLoad +# but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. +# ''' + +# if '_' in imagepath: +# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) +# if image: return image +# # Did the exporter rename the image? +# image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) +# if image: return image + +# # Return an image, placeholder if it dosnt exist +# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) +# return image def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): @@ -139,46 +163,65 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ # Absolute path - c:\.. etc would work here image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) has_data = image.has_data - texture.image = image + + if image: + texture.image = image # Adds textures for materials (rendering) if type == 'Kd': if has_data and image.depth == 32: # Image has alpha - blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) - texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') - blender_material.mode |= Material.Modes.ZTRANSP + + # XXX bitmask won't work? + blender_material.add_texture(texture, "UV", ("COLOR", "ALPHA")) + texture.mipmap = True + texture.interpolation = True + texture.use_alpha = True + blender_material.z_transparency = True blender_material.alpha = 0.0 + +# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) +# texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') +# blender_material.mode |= Material.Modes.ZTRANSP +# blender_material.alpha = 0.0 else: - blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + blender_material.add_texture(texture, "UV", "COLOR") +# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) # adds textures to faces (Textured/Alt-Z mode) # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. unique_material_images[context_material_name]= image, has_data # set the texface image elif type == 'Ka': - blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API + blender_material.add_texture(texture, "UV", "AMBIENT") +# blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API elif type == 'Ks': - blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + blender_material.add_texture(texture, "UV", "SPECULAR") +# blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) elif type == 'Bump': - blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) + blender_material.add_texture(texture, "UV", "NORMAL") +# blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) elif type == 'D': - blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) - blender_material.mode |= Material.Modes.ZTRANSP + blender_material.add_texture(texture, "UV", "ALPHA") + blender_material.z_transparency = True blender_material.alpha = 0.0 +# blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) +# blender_material.mode |= Material.Modes.ZTRANSP +# blender_material.alpha = 0.0 # Todo, unset deffuse material alpha if it has an alpha channel elif type == 'refl': - blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) + blender_material.add_texture(texture, "UV", "REFLECTION") +# blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) # Add an MTL with the same name as the obj if no MTLs are spesified. temp_mtl= stripExt(stripPath(filepath))+ '.mtl' if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: - material_libs.append( temp_mtl ) + material_libs.append( temp_mtl ) del temp_mtl #Create new materials @@ -578,7 +621,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l me.add_geometry(0, len(edges)) - # edges is (should be) a list of (a, b) tuples + # edges should be a list of (a, b) tuples me.edges.foreach_set("verts", unpack_list(edges)) # me_edges.extend( edges ) @@ -713,6 +756,7 @@ def get_float_func(filepath): return float def load_obj(filepath, + context, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS= True, @@ -733,8 +777,9 @@ def load_obj(filepath, if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: POLYGROUPS = False - - time_main= sys.time() + + time_main= bpy.sys.time() +# time_main= sys.time() verts_loc= [] verts_tex= [] @@ -772,7 +817,8 @@ def load_obj(filepath, context_multi_line= '' print '\tparsing obj file "%s"...' % filepath, - time_sub= sys.time() + time_sub= bpy.sys.time() +# time_sub= sys.time() file= open(filepath, 'rU') for line in file: #.xreadlines(): @@ -980,15 +1026,17 @@ def load_obj(filepath, ''' file.close() - time_new= sys.time() + time_new= bpy.sys.time() +# time_new= sys.time() print '%.4f sec' % (time_new-time_sub) time_sub= time_new print '\tloading materials and images...', create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) - - time_new= sys.time() + + time_new= bpy.sys.time() +# time_new= sys.time() print '%.4f sec' % (time_new-time_sub) time_sub= time_new @@ -996,8 +1044,12 @@ def load_obj(filepath, verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] # deselect all - scn = bpy.data.scenes.active - scn.objects.selected = [] + if context.selected_objects: + bpy.ops.OBJECT_OT_select_all_toggle() + + scene = context.scene +# scn = bpy.data.scenes.active +# scn.objects.selected = [] new_objects= [] # put new objects here print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), @@ -1007,7 +1059,7 @@ def load_obj(filepath, for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): # Create meshes from the data, warning 'vertex_groups' wont support splitting - create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) + create_mesh(scene, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) # nurbs support # for context_nurbs in nurbs: @@ -1039,8 +1091,9 @@ def load_obj(filepath, #if not ROTATE_X90: # for ob in new_objects: # ob.RotX = -1.570796326794896558 - - time_new= sys.time() + + time_new= bpy.sys.time() +# time_new= sys.time() print '%.4f sec' % (time_new-time_sub) print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) @@ -1292,7 +1345,10 @@ else: # can convert now: edge flags, edges: lines 508-528 # ngon (uses python module BPyMesh): 384-414 # nurbs: 947- -# clamp size: cannot get bound box with RNA - neither I can write RNA struct function that returns it - -# again, RNA limitation -# warning: uses bpy.sys.exists +# NEXT clamp size: get bound box with RNA # get back to l 140 (here) +# search image in bpy.config.textureDir - load_image +# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load) +# bitmask won't work? - 132 +# uses operator bpy.ops.OBJECT_OT_select_all_toggle() to deselect all (not necessary?) +# uses bpy.sys.exists and bpy.sys.time() diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index c74e46c17da..fbef838d06c 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -66,6 +66,29 @@ static int rna_Image_dirty_get(PointerRNA *ptr) return 0; } +static int rna_Image_has_data_get(PointerRNA *ptr) +{ + Image *im= (Image*)ptr->data; + + if (im->ibufs.first) + return 1; + + return 0; +} + +static int rna_Image_depth_get(PointerRNA *ptr) +{ + Image *im= (Image*)ptr->data; + ImBuf *ibuf= BKE_image_get_ibuf(im, NULL); + + if (!ibuf) return 0; + + if (ibuf->rect_float) + return 128; + + return ibuf->depth; +} + #else static void rna_def_imageuser(BlenderRNA *brna) @@ -275,6 +298,20 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_V); RNA_def_property_ui_text(prop, "Clamp Y", "Disable texture repeating vertically."); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + + /* + Image.has_data and Image.depth are temporary, + Update import_obj.py when they are replaced (Arystan) + */ + prop= RNA_def_property(srna, "has_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Image_has_data_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Has data", "True if this image has data."); + + prop= RNA_def_property(srna, "depth", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_Image_depth_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Depth", "Image bit depth."); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); } void RNA_def_image(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 9dc32acff6f..17f3800e10e 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -33,6 +33,8 @@ #include "RNA_types.h" #include "DNA_object_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" #ifdef RNA_RUNTIME @@ -41,8 +43,7 @@ #include "BKE_library.h" #include "BKE_object.h" #include "BKE_material.h" - -#include "DNA_mesh_types.h" +#include "BKE_image.h" static Mesh *rna_Main_add_mesh(Main *main, char *name) { @@ -102,6 +103,11 @@ struct Tex *rna_Main_add_texture(Main *main, char *name) /* TODO: remove texture? */ +struct Image *rna_Main_add_image(Main *main, char *filename) +{ + return BKE_add_image_file(filename, 0); +} + #else void RNA_api_main(StructRNA *srna) @@ -164,6 +170,13 @@ void RNA_api_main(StructRNA *srna) parm= RNA_def_pointer(func, "texture", "Texture", "", "New texture."); RNA_def_function_return(func, parm); + func= RNA_def_function(srna, "add_image", "rna_Main_add_image"); + RNA_def_function_ui_description(func, "Add a new image."); + parm= RNA_def_string(func, "filename", "", 0, "", "Filename to load image from."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "image", "Image", "", "New image."); + RNA_def_function_return(func, parm); + } #endif diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 6de13dbd440..326c37d8597 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1082,6 +1082,11 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TANGENT_V); RNA_def_property_ui_text(prop, "Tangent Shading", "Use the material's tangent vector instead of the normal for shading - for anisotropic shading effects"); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); + + prop= RNA_def_property(srna, "z_transparency", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ZTRA); + RNA_def_property_ui_text(prop, "ZTransp", "Z-buffer transparency"); + RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); /* nested structs */ prop= RNA_def_property(srna, "raytrace_mirror", PROP_POINTER, PROP_NEVER_NULL); -- cgit v1.2.3 From ad0b2c87d5c86b56f073c81f25df5c3988911d14 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 7 Jul 2009 08:38:18 +0000 Subject: Integrated unit testing framework with scons on Linux. I needed this to make sure that BKE_copy_images works properly, probably will be useful in future. Using Check framework (http://check.sourceforge.net/doc/check.html/index.html). WITH_BF_UNIT_TEST option builds 'alltest' program under [BUILDDIR]/bin, which, when executed, runs unit tests, currently only 1. Example output: ---------------------------------------------------------------------- Running suite(s): Image 0%: Checks: 1, Failures: 1, Errors: 0 tests/alltest.c:74:F:Core:test_copy_images:0: Expected //bar/image.png to be translated to /tmp/bar/image.png, got /tmp/bar/image.pn. ---------------------------------------------------------------------- Spent lots of time (a couple of days actually :) to figure out how to link the test program with Blender libraries. As it turned out there are circular dependencies among Blender libraries. GCC by default doesn't expect circular dependencies - dependant libs should precede libs they depend on. The magical --start-group linker option helped to solve this (http://stephane.carrez.free.fr/doc/ld_2.html#IDX122). Also: - added bpy.util module. bpy.sys.* functions will move here later - added bpy.util.copy_images that uses BKE_copy_images - export_obj.py uses bpy.util.copy_images --- SConstruct | 11 ++- release/io/export_obj.py | 23 +++-- source/blender/blenkernel/BKE_image.h | 6 ++ source/blender/blenkernel/SConscript | 3 + source/blender/blenkernel/intern/image.c | 117 +++++++++++++++++++++++ source/blender/python/intern/bpy_interface.c | 3 + source/blender/python/intern/bpy_util.c | 133 ++++++++++++++++++++++++++- source/blender/python/intern/bpy_util.h | 2 + tools/btools.py | 6 +- 9 files changed, 290 insertions(+), 14 deletions(-) diff --git a/SConstruct b/SConstruct index b85bc799ea5..2d1daba98b6 100644 --- a/SConstruct +++ b/SConstruct @@ -407,7 +407,16 @@ if env['WITH_BF_PLAYER']: if 'blender' in B.targets or not env['WITH_BF_NOBLENDER']: #env.BlenderProg(B.root_build_dir, "blender", dobj , [], mainlist + thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') - env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist, [], thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') + blen = env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist, [], thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') + + build_data = {"lib": thestatlibs + thesyslibs, "libpath": thelibincs, "blen": blen} + + Export('env') + Export('build_data') + + BuildDir(B.root_build_dir+'/tests', 'tests', duplicate=0) + SConscript(B.root_build_dir+'/tests/SConscript') + if env['WITH_BF_PLAYER']: playerlist = B.create_blender_liblist(env, 'player') env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist, [], thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer') diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 1ee685a52a3..ee045053dd3 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -178,19 +178,22 @@ def copy_images(dest_dir): pass # Now copy images - copyCount = 0 +# 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 +# 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 + + paths= bpy.util.copy_images(uniqueImages.values(), dest_dir) print('\tCopied %d images' % copyCount) +# print('\tCopied %d images' % copyCount) # XXX not converted def test_nurbs_compat(ob): diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 816baa20467..f3f5266189a 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -40,6 +40,7 @@ struct ImBuf; struct Tex; struct anim; struct Scene; +struct ListBase; /* call from library */ void free_image(struct Image *me); @@ -154,6 +155,11 @@ struct Image *BKE_image_copy(struct Image *ima); /* merge source into dest, and free source */ void BKE_image_merge(struct Image *dest, struct Image *source); +/* ********************************** FOR EXPORTERS *********************** */ + +/* copy images into dest_dir */ +void BKE_copy_images(struct ListBase *images, char *dest_dir, struct ListBase *filenames); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index dbc990d0613..9aaea7e8aff 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -57,6 +57,9 @@ if env['BF_NO_ELBEEM']: if env['WITH_BF_LCMS']: defs.append('WITH_LCMS') + +if env['WITH_BF_UNIT_TEST']: + defs.append('WITH_UNIT_TEST') if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ef0984bf93d..039c2d07bce 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2109,3 +2109,120 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) } } +/* + Copy list of images to dest_dir. + + paths is optional, if given, image paths for each image will be written in it. + If an image file doesn't exist, NULL is added in paths. + + Logic: + + For each image if it's "below" current .blend file directory, + rebuild the same dir structure in dest_dir. + + For example //textures/foo/bar.png becomes + [dest_dir]/textures/foo/bar.png. + + If an image is not "below" current .blend file directory, disregard + it's path and copy it in the same directory where 3D file goes. + + For example //../foo/bar.png becomes [dest_dir]/bar.png. + + This logic will help ensure that all image paths are relative and + that a user gets his images in one place. It'll also provide + consistent behaviour across exporters. +*/ +void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) +{ + char path[FILE_MAX]; + char dir[FILE_MAX]; + char base[FILE_MAX]; + char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */ + char dest_path[FILE_MAX]; + int len; + Image *im; + LinkData *link; + + if (paths) { + memset(paths, 0, sizeof(*paths)); + } + + BLI_split_dirfile_basic(G.sce, blend_dir, NULL); + + link= images->first; + + while (link) { + im= link->data; + + BLI_strncpy(path, im->name, sizeof(path)); + + /* expand "//" in filename and get absolute path */ + BLI_convertstringcode(path, G.sce); + + /* in unit tests, we don't want to modify the filesystem */ +#ifndef WITH_UNIT_TEST + /* proceed only if image file exists */ + if (!BLI_exists(path)) { + + if (paths) { + LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); + ld->data= NULL; + BLI_addtail(paths, ld); + } + + continue; + } +#endif + + /* get the directory part */ + BLI_split_dirfile_basic(path, dir, base); + + len= strlen(blend_dir); + + /* if image is "below" current .blend file directory */ + if (!strncmp(path, blend_dir, len)) { + + /* if image is _in_ current .blend file directory */ + if (!strcmp(dir, blend_dir)) { + /* copy to dest_dir */ + BLI_join_dirfile(dest_path, dest_dir, base); + } + /* "below" */ + else { + char rel[FILE_MAX]; + + /* rel = image_path_dir - blend_dir */ + BLI_strncpy(rel, dir + len, sizeof(rel)); + + BLI_join_dirfile(dest_path, dest_dir, rel); + +#ifndef WITH_UNIT_TEST + /* build identical directory structure under dest_dir */ + BLI_make_existing_file(dest_path); +#endif + + BLI_join_dirfile(dest_path, dest_path, base); + } + + } + /* image is out of current directory */ + else { + /* copy to dest_dir */ + BLI_join_dirfile(dest_path, dest_dir, base); + } + +#ifndef WITH_UNIT_TEST + BLI_copy_fileops(path, dest_path); +#endif + + if (paths) { + LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); + len= strlen(dest_path) + 1; + ld->data= MEM_callocN(len, "PathLinkData"); + BLI_strncpy(ld->data, dest_path, len); + BLI_addtail(paths, ld); + } + + link= link->next; + } +} diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 96ef796839b..c895a41637d 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -92,6 +92,9 @@ 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, "util", BPY_util_module() ); + + /* XXX this will move to bpy.util */ PyModule_AddObject( mod, "sys", BPY_sys_module() ); } diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index bce73b903c0..5f235b91337 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -25,12 +25,17 @@ #include "DNA_listBase.h" #include "RNA_access.h" #include "bpy_util.h" -#include "BLI_dynstr.h" +#include "bpy_rna.h" + #include "MEM_guardedalloc.h" -#include "BKE_report.h" +#include "BLI_dynstr.h" +#include "BLI_listbase.h" +#include "BKE_report.h" +#include "BKE_image.h" #include "BKE_context.h" + bContext* __py_context = NULL; bContext* BPy_GetContext(void) { return __py_context; }; void BPy_SetContext(bContext *C) { __py_context= C; }; @@ -464,3 +469,127 @@ int BPy_errors_to_report(ReportList *reports) Py_DECREF(pystring); return 1; } + + +/* bpy.util module */ +static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args); + +struct PyMethodDef bpy_util_methods[] = { + {"copy_images", bpy_util_copy_images, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + +#if PY_VERSION_HEX >= 0x03000000 +static struct PyModuleDef bpy_util_module = { + PyModuleDef_HEAD_INIT, + "bpyutil", + NULL, + -1, + bpy_util_methods, + NULL, NULL, NULL, NULL +}; +#endif + +PyObject *BPY_util_module( void ) +{ + PyObject *submodule, *dict; + +#if PY_VERSION_HEX >= 0x03000000 + submodule= PyModule_Create(&bpy_util_module); +#else /* Py2.x */ + submodule= Py_InitModule3("bpyutil", bpy_util_methods, NULL); +#endif + + dict = PyModule_GetDict(submodule); + + return submodule; +} + +/* + copy_images(images, dest_dir) + return filenames +*/ +static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args) +{ + const char *dest_dir; + ListBase *images; + ListBase *paths; + LinkData *link; + PyObject *seq; + PyObject *ret; + PyObject *item; + int i; + int len; + + /* check args/types */ + if (!PyArg_ParseTuple(args, "Os", &seq, &dest_dir)) { + PyErr_SetString(PyExc_TypeError, "Invalid arguments."); + return NULL; + } + + /* expecting a sequence of Image objects */ + if (!PySequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, "Expected a sequence of images."); + return NULL; + } + + /* create image list */ + len= PySequence_Size(seq); + + if (!len) { + PyErr_SetString(PyExc_TypeError, "At least one image should be specified."); + return NULL; + } + + /* make sure all sequence items are Image */ + for(i= 0; i < len; i++) { + item= PySequence_GetItem(seq, i); + + if (!BPy_StructRNA_Check(item) || ((BPy_StructRNA*)item)->ptr.type != &RNA_Image) { + PyErr_SetString(PyExc_TypeError, "Expected a sequence of Image objects."); + return NULL; + } + } + + images= MEM_callocN(sizeof(*images), "ListBase of images"); + + for(i= 0; i < len; i++) { + BPy_StructRNA* srna; + + item= PySequence_GetItem(seq, i); + srna= (BPy_StructRNA*)item; + + link= MEM_callocN(sizeof(LinkData), "LinkData image"); + link->data= srna->ptr.data; + BLI_addtail(images, link); + + Py_DECREF(item); + } + + paths= MEM_callocN(sizeof(*paths), "ListBase of image paths"); + + /* call BKE_copy_images */ + BKE_copy_images(images, dest_dir, paths); + + /* convert filenames */ + ret= PyList_New(0); + len= BLI_countlist(paths); + + for(link= paths->first, i= 0; link; link++, i++) { + if (link->data) { + item= PyUnicode_FromString(link->data); + PyList_Append(ret, item); + Py_DECREF(item); + } + else { + PyList_Append(ret, Py_None); + } + } + + /* free memory */ + BLI_freelistN(images); + BLI_freelistN(paths); + + /* return filenames */ + return ret; +} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 6429af67eb0..89d27ba8325 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -81,4 +81,6 @@ int BPy_errors_to_report(struct ReportList *reports); struct bContext *BPy_GetContext(void); void BPy_SetContext(struct bContext *C); +PyObject *BPY_util_module(void); + #endif diff --git a/tools/btools.py b/tools/btools.py index 9603022deaa..f4d79b1bb24 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -65,6 +65,8 @@ def validate_arguments(args, bc): 'WITH_BF_DOCS', 'BF_NUMJOBS', 'BF_MSVS', + + 'WITH_BF_UNIT_TEST' ] # Have options here that scons expects to be lists @@ -356,7 +358,9 @@ def read_opts(cfg, args): ('BF_CONFIG', 'SCons python config file used to set default options', 'user_config.py'), ('BF_NUMJOBS', 'Number of build processes to spawn', '1'), - ('BF_MSVS', 'Generate MSVS project files and solution', False) + ('BF_MSVS', 'Generate MSVS project files and solution', False), + + (BoolVariable('WITH_BF_UNIT_TEST', 'Build unit tests', False)) ) # end of opts.AddOptions() -- cgit v1.2.3 From f7438ff77a206049cb11873e15360215064c1961 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 7 Jul 2009 19:13:05 +0000 Subject: - slowly starting FBX exporter conversion - added Bone.matrix and Bone.armature_matrix --- release/io/export_fbx.py | 3112 +++++++++++++++++++++++++ release/io/export_obj.py | 1 + source/blender/makesrna/intern/rna_armature.c | 10 + source/blender/makesrna/intern/rna_pose_api.c | 56 + 4 files changed, 3179 insertions(+) create mode 100644 release/io/export_fbx.py create mode 100644 source/blender/makesrna/intern/rna_pose_api.c diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py new file mode 100644 index 00000000000..cea9f500533 --- /dev/null +++ b/release/io/export_fbx.py @@ -0,0 +1,3112 @@ +#!BPY +""" +Name: 'Autodesk FBX (.fbx)...' +Blender: 249 +Group: 'Export' +Tooltip: 'Selection to an ASCII Autodesk FBX ' +""" +__author__ = "Campbell Barton" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.2" + +__bpydoc__ = """\ +This script is an exporter to the FBX file format. + +http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx +""" +# -------------------------------------------------------------------------- +# FBX Export v0.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 os + +try: + import time + # import os # only needed for batch export, nbot used yet +except: + time = None # use this to check if they have python modules installed + +# for python 2.3 support +try: + set() +except: + try: + from sets import Set as set + except: + set = None # so it complains you dont have a ! + +# # os is only needed for batch 'own dir' option +# try: +# import os +# except: +# os = None + +import Blender +import bpy +from Blender.Mathutils import Matrix, Vector, RotationMatrix + +import BPyObject +import BPyMesh +import BPySys +import BPyMessages + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' +##v = range(255) +##for c in valid: v.remove(ord(c)) +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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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]) +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name +del v, i + + +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, textures): + if not dest_dir.endswith(os.sep): + dest_dir += os.sep + + image_paths = set() + for tex in textures: + image_paths.add(Blender.sys.expandpath(tex.filename)) + + # Now copy images + copyCount = 0 + for image_path in image_paths: + if Blender.sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not Blender.sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + try: + copy_file(image_path, dest_image_path) + copyCount+=1 + except: + print '\t\tWarning, file failed to copy, skipping.' + + print '\tCopied %d images' % copyCount + +mtx4_identity = Matrix() + +# testing +mtx_x90 = RotationMatrix( 90, 3, 'x') # used +#mtx_x90n = RotationMatrix(-90, 3, 'x') +#mtx_y90 = RotationMatrix( 90, 3, 'y') +#mtx_y90n = RotationMatrix(-90, 3, 'y') +#mtx_z90 = RotationMatrix( 90, 3, 'z') +#mtx_z90n = RotationMatrix(-90, 3, 'z') + +#mtx4_x90 = RotationMatrix( 90, 4, 'x') +mtx4_x90n = RotationMatrix(-90, 4, 'x') # used +#mtx4_y90 = RotationMatrix( 90, 4, 'y') +mtx4_y90n = RotationMatrix(-90, 4, 'y') # used +mtx4_z90 = RotationMatrix( 90, 4, 'z') # used +mtx4_z90n = RotationMatrix(-90, 4, 'z') # used + +def strip_path(p): + return p.split('\\')[-1].split('/')[-1] + +# Used to add the scene name into the filename without using odd chars +sane_name_mapping_ob = {} +sane_name_mapping_mat = {} +sane_name_mapping_tex = {} +sane_name_mapping_take = {} +sane_name_mapping_group = {} + +# Make sure reserved names are not used +sane_name_mapping_ob['Scene'] = 'Scene_' +sane_name_mapping_ob['blend_root'] = 'blend_root_' + +def increment_string(t): + name = t + num = '' + while name and name[-1].isdigit(): + num = name[-1] + num + name = name[:-1] + if num: return '%s%d' % (name, int(num)+1) + else: return name + '_0' + + + +# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. +def sane_name(data, dct): + #if not data: return None + + if type(data)==tuple: # materials are paired up with images + data, other = data + use_other = True + else: + other = None + use_other = False + + if data: name = data.name + else: name = None + orig_name = name + + if other: + orig_name_other = other.name + name = '%s #%s' % (name, orig_name_other) + else: + orig_name_other = None + + # dont cache, only ever call once for each data type now, + # so as to avoid namespace collision between types - like with objects <-> bones + #try: return dct[name] + #except: pass + + if not name: + name = 'unnamed' # blank string, ASKING FOR TROUBLE! + else: + #name = BPySys.cleanName(name) + name = cleanName(name) # use our own + + while name in dct.itervalues(): name = increment_string(name) + + if use_other: # even if other is None - orig_name_other will be a string or None + dct[orig_name, orig_name_other] = name + else: + dct[orig_name] = name + + return name + +def sane_obname(data): return sane_name(data, sane_name_mapping_ob) +def sane_matname(data): return sane_name(data, sane_name_mapping_mat) +def sane_texname(data): return sane_name(data, sane_name_mapping_tex) +def sane_takename(data): return sane_name(data, sane_name_mapping_take) +def sane_groupname(data): return sane_name(data, sane_name_mapping_group) + +def derived_paths(fname_orig, basepath, FORCE_CWD=False): + ''' + fname_orig - blender path, can be relative + basepath - fname_rel will be relative to this + FORCE_CWD - dont use the basepath, just add a ./ to the filename. + use when we know the file will be in the basepath. + ''' + fname = Blender.sys.expandpath(fname_orig) + fname_strip = strip_path(fname) + if FORCE_CWD: fname_rel = '.' + os.sep + fname_strip + else: fname_rel = Blender.sys.relpath(fname, basepath) + if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] + return fname, fname_strip, fname_rel + + +def mat4x4str(mat): + return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) + +def meshNormalizedWeights(me): + try: # account for old bad BPyMesh + groupNames, vWeightList = BPyMesh.meshWeight2List(me) + except: + return [],[] + + if not groupNames: + return [],[] + + for i, vWeights in enumerate(vWeightList): + tot = 0.0 + for w in vWeights: + tot+=w + + if tot: + for j, w in enumerate(vWeights): + vWeights[j] = w/tot + + return groupNames, vWeightList + +header_comment = \ +'''; FBX 6.1.0 project file +; Created by Blender FBX Exporter +; for support mail: ideasman42@gmail.com +; ---------------------------------------------------- + +''' + +# This func can be called with just the filename +def write(filename, batch_objects = None, \ + context = None, + EXP_OBS_SELECTED = True, + EXP_MESH = True, + EXP_MESH_APPLY_MOD = True, + EXP_MESH_HQ_NORMALS = False, + EXP_ARMATURE = True, + EXP_LAMP = True, + EXP_CAMERA = True, + EXP_EMPTY = True, + EXP_IMAGE_COPY = False, + GLOBAL_MATRIX = Matrix(), + ANIM_ENABLE = True, + ANIM_OPTIMIZE = True, + ANIM_OPTIMIZE_PRECISSION = 6, + ANIM_ACTION_ALL = False, + BATCH_ENABLE = False, + BATCH_GROUP = True, + BATCH_SCENE = False, + BATCH_FILE_PREFIX = '', + BATCH_OWN_DIR = False + ): + + # ----------------- Batch support! + if BATCH_ENABLE: + if os == None: BATCH_OWN_DIR = False + + fbxpath = filename + + # get the path component of filename + tmp_exists = bpy.sys.exists(fbxpath) +# tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: # a file, we want a path + while fbxpath and fbxpath[-1] not in ('/', '\\'): + fbxpath = fbxpath[:-1] + if not filename: + # XXX + print('Error%t|Directory does not exist!') +# Draw.PupMenu('Error%t|Directory does not exist!') + return + + tmp_exists = bpy.sys.exists(fbxpath) +# tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: + # XXX + print('Error%t|Directory does not exist!') +# Draw.PupMenu('Error%t|Directory does not exist!') + return + + if not fbxpath.endswith(os.sep): + fbxpath += os.sep + del tmp_exists + + + if BATCH_GROUP: + data_seq = bpy.data.groups + else: + data_seq = bpy.data.scenes + + # call this function within a loop with BATCH_ENABLE == False + orig_sce = context.scene +# orig_sce = bpy.data.scenes.active + + + new_fbxpath = fbxpath # own dir option modifies, we need to keep an original + for data in data_seq: # scene or group + newname = BATCH_FILE_PREFIX + cleanName(data.name) +# newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) + + + if BATCH_OWN_DIR: + new_fbxpath = fbxpath + newname + os.sep + # path may alredy exist + # TODO - might exist but be a file. unlikely but should probably account for it. + + if bpy.sys.exists(new_fbxpath) == 0: +# if Blender.sys.exists(new_fbxpath) == 0: + os.mkdir(new_fbxpath) + + + filename = new_fbxpath + newname + '.fbx' + + print '\nBatch exporting %s as...\n\t"%s"' % (data, filename) + + # XXX don't know what to do with this, probably do the same? (Arystan) + if BATCH_GROUP: #group + # group, so objects update properly, add a dummy scene. + sce = bpy.data.scenes.new() + sce.Layers = (1<<20) -1 + bpy.data.scenes.active = sce + for ob_base in data.objects: + sce.objects.link(ob_base) + + sce.update(1) + + # TODO - BUMMER! Armatures not in the group wont animate the mesh + + else:# scene + + + data_seq.active = data + + + # Call self with modified args + # Dont pass batch options since we alredy usedt them + write(filename, data.objects, + context, + False, + EXP_MESH, + EXP_MESH_APPLY_MOD, + EXP_MESH_HQ_NORMALS, + EXP_ARMATURE, + EXP_LAMP, + EXP_CAMERA, + EXP_EMPTY, + EXP_IMAGE_COPY, + GLOBAL_MATRIX, + ANIM_ENABLE, + ANIM_OPTIMIZE, + ANIM_OPTIMIZE_PRECISSION, + ANIM_ACTION_ALL + ) + + if BATCH_GROUP: + # remove temp group scene + bpy.data.remove_scene(sce) +# bpy.data.scenes.unlink(sce) + + bpy.data.scenes.active = orig_sce + + return # so the script wont run after we have batch exported. + + # end batch support + + # Use this for working out paths relative to the export location + basepath = Blender.sys.dirname(filename) + + # ---------------------------------------------- + # storage classes + class my_bone_class: + __slots__ =(\ + 'blenName',\ + 'blenBone',\ + 'blenMeshes',\ + 'restMatrix',\ + 'parent',\ + 'blenName',\ + 'fbxName',\ + 'fbxArm',\ + '__pose_bone',\ + '__anim_poselist') + + def __init__(self, blenBone, fbxArm): + + # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace + self.fbxName = sane_obname(blenBone) + + self.blenName = blenBone.name + self.blenBone = blenBone + self.blenMeshes = {} # fbxMeshObName : mesh + self.fbxArm = fbxArm + self.restMatrix = blenBone.armature_matrix + # self.restMatrix = blenBone.matrix['ARMATURESPACE'] + + # not used yet + # self.restMatrixInv = self.restMatrix.copy().invert() + # self.restMatrixLocal = None # set later, need parent matrix + + self.parent = None + + # not public + pose = fbxArm.blenObject.pose +# pose = fbxArm.blenObject.getPose() + self.__pose_bone = pose.bones[self.blenName] + + # store a list if matricies here, (poseMatrix, head, tail) + # {frame:posematrix, frame:posematrix, ...} + self.__anim_poselist = {} + + ''' + def calcRestMatrixLocal(self): + if self.parent: + self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() + else: + self.restMatrixLocal = self.restMatrix.copy() + ''' + def setPoseFrame(self, f): + # cache pose info here, frame must be set beforehand + + # Didnt end up needing head or tail, if we do - here it is. + ''' + self.__anim_poselist[f] = (\ + self.__pose_bone.poseMatrix.copy(),\ + self.__pose_bone.head.copy(),\ + self.__pose_bone.tail.copy() ) + ''' + + self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() + + # get pose from frame. + def getPoseMatrix(self, f):# ---------------------------------------------- + return self.__anim_poselist[f] + ''' + def getPoseHead(self, f): + #return self.__pose_bone.head.copy() + return self.__anim_poselist[f][1].copy() + def getPoseTail(self, f): + #return self.__pose_bone.tail.copy() + return self.__anim_poselist[f][2].copy() + ''' + # end + + def getAnimParRelMatrix(self, frame): + #arm_mat = self.fbxArm.matrixWorld + #arm_mat = self.fbxArm.parRelMatrix() + if not self.parent: + #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore + return mtx4_z90 * self.getPoseMatrix(frame) + else: + #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() + return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() + + # we need thes because cameras and lights modified rotations + def getAnimParRelMatrixRot(self, frame): + return self.getAnimParRelMatrix(frame) + + def flushAnimData(self): + self.__anim_poselist.clear() + + + class my_object_generic: + # Other settings can be applied for each type - mesh, armature etc. + def __init__(self, ob, matrixWorld = None): + self.fbxName = sane_obname(ob) + self.blenObject = ob + self.fbxGroupNames = [] + self.fbxParent = None # set later on IF the parent is in the selection. + if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX + else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + self.__anim_poselist = {} # we should only access this + + def parRelMatrix(self): + if self.fbxParent: + return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() + else: + return self.matrixWorld + + def setPoseFrame(self, f): + self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + + def getAnimParRelMatrix(self, frame): + if self.fbxParent: + #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX + return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() + else: + return self.__anim_poselist[frame] * GLOBAL_MATRIX + + def getAnimParRelMatrixRot(self, frame): + type = self.blenObject.type + if self.fbxParent: + matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() + else: + matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() + + # Lamps need to be rotated + if type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + elif ob and type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + + return matrix_rot + + # ---------------------------------------------- + + + + + + print '\nFBX export starting...', filename + start_time = Blender.sys.time() + try: + file = open(filename, 'w') + except: + return False + + sce = bpy.data.scenes.active + world = sce.world + + + # ---------------------------- Write the header first + file.write(header_comment) + if time: + curtime = time.localtime()[0:6] + else: + curtime = (0,0,0,0,0,0) + # + file.write(\ +'''FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 6100 + CreationTimeStamp: { + Version: 1000 + Year: %.4i + Month: %.2i + Day: %.2i + Hour: %.2i + Minute: %.2i + Second: %.2i + Millisecond: 0 + } + Creator: "FBX SDK/FBX Plugins build 20070228" + OtherFlags: { + FlagPLE: 0 + } +}''' % (curtime)) + + file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) + file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + + pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way + + # --------------- funcs for exporting + def object_tx(ob, loc, matrix, matrix_mod = None): + ''' + Matrix mod is so armature objects can modify their bone matricies + ''' + if isinstance(ob, Blender.Types.BoneType): + + # we know we have a matrix + # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) + matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + + parent = ob.parent + if parent: + #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) + par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + matrix = matrix * par_matrix.copy().invert() + + matrix_rot = matrix.rotationPart() + + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + rot = tuple(matrix_rot.toEuler()) + + else: + # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore + #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX + if ob and not matrix: raise "error: this should never happen!" + + matrix_rot = matrix + #if matrix: + # matrix = matrix_scale * matrix + + if matrix: + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + + matrix_rot = matrix.rotationPart() + # Lamps need to be rotated + if ob and ob.type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + rot = tuple(matrix_rot.toEuler()) + elif ob and ob.type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + rot = tuple(matrix_rot.toEuler()) + else: + rot = tuple(matrix_rot.toEuler()) + else: + if not loc: + loc = 0,0,0 + scale = 1,1,1 + rot = 0,0,0 + + return loc, rot, scale, matrix, matrix_rot + + def write_object_tx(ob, loc, matrix, matrix_mod= None): + ''' + We have loc to set the location if non blender objects that have a location + + matrix_mod is only used for bones at the moment + ''' + loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) + + file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) + file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) + return loc, rot, scale, matrix, matrix_rot + + def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): + # if the type is 0 its an empty otherwise its a mesh + # only difference at the moment is one has a color + file.write(''' + Properties60: { + Property: "QuaternionInterpolate", "bool", "",0 + Property: "Visibility", "Visibility", "A+",1''') + + loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) + + # Rotation order, note, for FBX files Iv loaded normal order is 1 + # setting to zero. + # eEULER_XYZ = 0 + # eEULER_XZY + # eEULER_YZX + # eEULER_YXZ + # eEULER_ZXY + # eEULER_ZYX + + file.write(''' + Property: "RotationOffset", "Vector3D", "",0,0,0 + Property: "RotationPivot", "Vector3D", "",0,0,0 + Property: "ScalingOffset", "Vector3D", "",0,0,0 + Property: "ScalingPivot", "Vector3D", "",0,0,0 + Property: "TranslationActive", "bool", "",0 + Property: "TranslationMin", "Vector3D", "",0,0,0 + Property: "TranslationMax", "Vector3D", "",0,0,0 + Property: "TranslationMinX", "bool", "",0 + Property: "TranslationMinY", "bool", "",0 + Property: "TranslationMinZ", "bool", "",0 + Property: "TranslationMaxX", "bool", "",0 + Property: "TranslationMaxY", "bool", "",0 + Property: "TranslationMaxZ", "bool", "",0 + Property: "RotationOrder", "enum", "",0 + Property: "RotationSpaceForLimitOnly", "bool", "",0 + Property: "AxisLen", "double", "",10 + Property: "PreRotation", "Vector3D", "",0,0,0 + Property: "PostRotation", "Vector3D", "",0,0,0 + Property: "RotationActive", "bool", "",0 + Property: "RotationMin", "Vector3D", "",0,0,0 + Property: "RotationMax", "Vector3D", "",0,0,0 + Property: "RotationMinX", "bool", "",0 + Property: "RotationMinY", "bool", "",0 + Property: "RotationMinZ", "bool", "",0 + Property: "RotationMaxX", "bool", "",0 + Property: "RotationMaxY", "bool", "",0 + Property: "RotationMaxZ", "bool", "",0 + Property: "RotationStiffnessX", "double", "",0 + Property: "RotationStiffnessY", "double", "",0 + Property: "RotationStiffnessZ", "double", "",0 + Property: "MinDampRangeX", "double", "",0 + Property: "MinDampRangeY", "double", "",0 + Property: "MinDampRangeZ", "double", "",0 + Property: "MaxDampRangeX", "double", "",0 + Property: "MaxDampRangeY", "double", "",0 + Property: "MaxDampRangeZ", "double", "",0 + Property: "MinDampStrengthX", "double", "",0 + Property: "MinDampStrengthY", "double", "",0 + Property: "MinDampStrengthZ", "double", "",0 + Property: "MaxDampStrengthX", "double", "",0 + Property: "MaxDampStrengthY", "double", "",0 + Property: "MaxDampStrengthZ", "double", "",0 + Property: "PreferedAngleX", "double", "",0 + Property: "PreferedAngleY", "double", "",0 + Property: "PreferedAngleZ", "double", "",0 + Property: "InheritType", "enum", "",0 + Property: "ScalingActive", "bool", "",0 + Property: "ScalingMin", "Vector3D", "",1,1,1 + Property: "ScalingMax", "Vector3D", "",1,1,1 + Property: "ScalingMinX", "bool", "",0 + Property: "ScalingMinY", "bool", "",0 + Property: "ScalingMinZ", "bool", "",0 + Property: "ScalingMaxX", "bool", "",0 + Property: "ScalingMaxY", "bool", "",0 + Property: "ScalingMaxZ", "bool", "",0 + Property: "GeometricTranslation", "Vector3D", "",0,0,0 + Property: "GeometricRotation", "Vector3D", "",0,0,0 + Property: "GeometricScaling", "Vector3D", "",1,1,1 + Property: "LookAtProperty", "object", "" + Property: "UpVectorProperty", "object", "" + Property: "Show", "bool", "",1 + Property: "NegativePercentShapeSupport", "bool", "",1 + Property: "DefaultAttributeIndex", "int", "",0''') + if ob and type(ob) != Blender.Types.BoneType: + # Only mesh objects have color + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Size", "double", "",100') + file.write('\n\t\t\tProperty: "Look", "enum", "",1') + + return loc, rot, scale, matrix, matrix_rot + + + # -------------------------------------------- Armatures + #def write_bone(bone, name, matrix_mod): + def write_bone(my_bone): + file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) + file.write('\n\t\tVersion: 232') + + #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] + poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore + pose_items.append( (my_bone.fbxName, poseMatrix) ) + + + # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + file.write('\n\t\t\tProperty: "Size", "double", "",1') + + #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) + + """ + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + """ + + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) + + #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') + file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Skeleton"') + file.write('\n\t}') + + def write_camera_switch(): + file.write(''' + Model: "Model::Camera Switcher", "CameraSwitcher" { + Version: 232''') + + write_object_props() + file.write(''' + Property: "Color", "Color", "A",0.8,0.8,0.8 + Property: "Camera Index", "Integer", "A+",100 + } + MultiLayer: 0 + MultiTake: 1 + Hidden: "True" + Shading: W + Culling: "CullingOff" + Version: 101 + Name: "Model::Camera Switcher" + CameraId: 0 + CameraName: 100 + CameraIndexName: + }''') + + def write_camera_dummy(name, loc, near, far, proj_type, up): + file.write('\n\tModel: "Model::%s", "Camera" {' % name ) + file.write('\n\t\tVersion: 232') + write_object_props(None, loc) + + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",320') + file.write('\n\t\t\tProperty: "AspectH", "double", "",200') + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tHidden: "True"') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %i,%i,%i' % up) + file.write('\n\t\tLookAt: 0,0,0') + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_camera_default(): + # This sucks but to match FBX converter its easier to + # write the cameras though they are not needed. + write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) + write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) + + def write_camera(my_cam): + ''' + Write a blender camera + ''' + render = sce.render + width = render.sizeX + height = render.sizeY + aspect = float(width)/height + + data = my_cam.blenObject.data + + file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) + file.write('\n\t\tVersion: 232') + loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) + + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) + file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) + + '''Camera aspect ratio modes. + 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. + 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. + 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. + 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. + 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. + + Definition at line 234 of file kfbxcamera.h. ''' + + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') + + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) ) + file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) ) + + #file.write('\n\t\tUp: 0,0,0' ) + #file.write('\n\t\tLookAt: 0,0,0' ) + + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_light(my_light): + light = my_light.blenObject.data + file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) + file.write('\n\t\tVersion: 232') + + write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) + + # Why are these values here twice?????? - oh well, follow the holy sdk's output + + # Blender light types match FBX's, funny coincidence, we just need to + # be sure that all unsupported types are made into a point light + #ePOINT, + #eDIRECTIONAL + #eSPOT + light_type = light.type + if light_type > 2: light_type = 1 # hemi and area lights become directional + + mode = light.mode + if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: + do_shadow = 1 + else: + do_shadow = 0 + + if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): + do_light = 0 + else: + do_light = 1 + + scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case + + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') + file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) + file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) + file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Light"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t}') + + # matrixOnly is not used at the moment + def write_null(my_null = None, fbxName = None, matrixOnly = None): + # ob can be null + if not fbxName: fbxName = my_null.fbxName + + file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) + file.write('\n\t\tVersion: 232') + + # only use this for the root matrix at the moment + if matrixOnly: + poseMatrix = write_object_props(None, None, matrixOnly)[3] + + else: # all other Null's + if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] + else: poseMatrix = write_object_props()[3] + + pose_items.append((fbxName, poseMatrix)) + + file.write(''' + } + MultiLayer: 0 + MultiTake: 1 + Shading: Y + Culling: "CullingOff" + TypeFlags: "Null" + }''') + + # Material Settings + if world: world_amb = world.getAmb() + else: world_amb = (0,0,0) # Default value + + def write_material(matname, mat): + file.write('\n\tMaterial: "Material::%s", "" {' % matname) + + # Todo, add more material Properties. + if mat: + mat_cold = tuple(mat.rgbCol) + mat_cols = tuple(mat.specCol) + #mat_colm = tuple(mat.mirCol) # we wont use the mirror color + mat_colamb = tuple([c for c in world_amb]) + + mat_dif = mat.ref + mat_amb = mat.amb + mat_hard = (float(mat.hard)-1)/5.10 + mat_spec = mat.spec/2.0 + mat_alpha = mat.alpha + mat_emit = mat.emit + mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS + if mat_shadeless: + mat_shader = 'Lambert' + else: + if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: + mat_shader = 'Lambert' + else: + mat_shader = 'Phong' + else: + mat_cols = mat_cold = 0.8, 0.8, 0.8 + mat_colamb = 0.0,0.0,0.0 + # mat_colm + mat_dif = 1.0 + mat_amb = 0.5 + mat_hard = 20.0 + mat_spec = 0.2 + mat_alpha = 1.0 + mat_emit = 0.0 + mat_shadeless = False + mat_shader = 'Phong' + + file.write('\n\t\tVersion: 102') + file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) + file.write('\n\t\tMultiLayer: 0') + + file.write('\n\t\tProperties60: {') + file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) + file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') + file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender + file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_emit) + + file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) + file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) + file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) + file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_dif) + file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') + file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') + file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) + file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) + file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') + file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') + file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) + file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) + file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) + file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') + + file.write('\n\t\t}') + file.write('\n\t}') + + def write_video(texname, tex): + # Same as texture really! + file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) + + file.write(''' + Type: "Clip" + Properties60: { + Property: "FrameRate", "double", "",0 + Property: "LastFrame", "int", "",0 + Property: "Width", "int", "",0 + Property: "Height", "int", "",0''') + if tex: + fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + else: + fname = fname_strip = fname_rel = '' + + file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) + + + file.write(''' + Property: "StartFrame", "int", "",0 + Property: "StopFrame", "int", "",0 + Property: "PlaySpeed", "double", "",1 + Property: "Offset", "KTime", "",0 + Property: "InterlaceMode", "enum", "",0 + Property: "FreeRunning", "bool", "",0 + Property: "Loop", "bool", "",0 + Property: "AccessMode", "enum", "",0 + } + UseMipMap: 0''') + + file.write('\n\t\tFilename: "%s"' % fname_strip) + if fname_strip: fname_strip = '/' + fname_strip + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative + file.write('\n\t}') + + + def write_texture(texname, tex, num): + # if tex == None then this is a dummy tex + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) + file.write('\n\t\tType: "TextureVideoClip"') + file.write('\n\t\tVersion: 202') + # TODO, rare case _empty_ exists as a name. + file.write('\n\t\tTextureName: "Texture::%s"' % texname) + + file.write(''' + Properties60: { + Property: "Translation", "Vector", "A+",0,0,0 + Property: "Rotation", "Vector", "A+",0,0,0 + Property: "Scaling", "Vector", "A+",1,1,1''') + file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) + + + # WrapModeU/V 0==rep, 1==clamp, TODO add support + file.write(''' + Property: "TextureTypeUse", "enum", "",0 + Property: "CurrentTextureBlendMode", "enum", "",1 + Property: "UseMaterial", "bool", "",0 + Property: "UseMipMap", "bool", "",0 + Property: "CurrentMappingType", "enum", "",0 + Property: "UVSwap", "bool", "",0''') + + file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) + file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) + + file.write(''' + Property: "TextureRotationPivot", "Vector3D", "",0,0,0 + Property: "TextureScalingPivot", "Vector3D", "",0,0,0 + Property: "VideoProperty", "object", "" + }''') + + file.write('\n\t\tMedia: "Video::%s"' % texname) + + if tex: + fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + else: + fname = fname_strip = fname_rel = '' + + file.write('\n\t\tFileName: "%s"' % fname_strip) + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command + + file.write(''' + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + }''') + + def write_deformer_skin(obname): + ''' + Each mesh has its own deformer + ''' + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Skin" + Properties60: { + } + Link_DeformAcuracy: 50 + }''') + + # in the example was 'Bip01 L Thigh_2' + def write_sub_deformer_skin(my_mesh, my_bone, weights): + + ''' + Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers + So the SubDeformer needs the mesh-object name as a prefix to make it unique + + Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, + a but silly but dosnt really matter + ''' + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) + + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Cluster" + Properties60: { + Property: "SrcModel", "object", "" + Property: "SrcModelReference", "object", "" + } + UserData: "", ""''') + + # Support for bone parents + if my_mesh.fbxBoneParent: + if my_mesh.fbxBoneParent == my_bone: + # TODO - this is a bit lazy, we could have a simple write loop + # for this case because all weights are 1.0 but for now this is ok + # Parent Bones arent used all that much anyway. + vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))] + else: + # This bone is not a parent of this mesh object, no weights + vgroup_data = [] + + else: + # Normal weight painted mesh + if my_bone.blenName in weights[0]: + # Before we used normalized wright list + #vgroup_data = me.getVertsFromGroup(bone.name, 1) + group_index = weights[0].index(my_bone.blenName) + vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] + else: + vgroup_data = [] + + file.write('\n\t\tIndexes: ') + + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%i' % vg[0]) + i=0 + else: + if i==23: + file.write('\n\t\t') + i=0 + file.write(',%i' % vg[0]) + i+=1 + + file.write('\n\t\tWeights: ') + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%.8f' % vg[1]) + i=0 + else: + if i==38: + file.write('\n\t\t') + i=0 + file.write(',%.8f' % vg[1]) + i+=1 + + if my_mesh.fbxParent: + # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + else: + # Yes! this is it... - but dosnt work when the mesh is a. + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + + #m = mtx4_z90 * my_bone.restMatrix + matstr = mat4x4str(m) + matstr_i = mat4x4str(m.invert()) + + file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ + file.write('\n\t\tTransformLink: %s' % matstr) + file.write('\n\t}') + + def write_mesh(my_mesh): + + me = my_mesh.blenData + + # if there are non NULL materials on this mesh + if my_mesh.blenMaterials: do_materials = True + else: do_materials = False + + if my_mesh.blenTextures: do_textures = True + else: do_textures = False + + do_uvs = me.faceUV + + + file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) + file.write('\n\t\tVersion: 232') # newline is added in write_object_props + + poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3] + pose_items.append((my_mesh.fbxName, poseMatrix)) + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + + + # Write the Real Mesh data here + file.write('\n\t\tVertices: ') + i=-1 + + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) + i+=1 + + file.write('\n\t\tPolygonVertexIndex: ') + i=-1 + for f in me.faces: + fi = [v.index for v in f] + # flip the last index, odd but it looks like + # this is how fbx tells one face from another + fi[-1] = -(fi[-1]+1) + fi = tuple(fi) + if i==-1: + if len(f) == 3: file.write('%i,%i,%i' % fi ) + else: file.write('%i,%i,%i,%i' % fi ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + if len(f) == 3: file.write(',%i,%i,%i' % fi ) + else: file.write(',%i,%i,%i,%i' % fi ) + i+=1 + + file.write('\n\t\tEdges: ') + i=-1 + for ed in me.edges: + if i==-1: + file.write('%i,%i' % (ed.v1.index, ed.v2.index)) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) + i+=1 + + file.write('\n\t\tGeometryVersion: 124') + + file.write(''' + LayerElementNormal: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByVertice" + ReferenceInformationType: "Direct" + Normals: ''') + + i=-1 + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + i+=1 + file.write('\n\t\t}') + + # Write Face Smoothing + file.write(''' + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygon" + ReferenceInformationType: "Direct" + Smoothing: ''') + + i=-1 + for f in me.faces: + if i==-1: + file.write('%i' % f.smooth); i=0 + else: + if i==54: + file.write('\n '); i=0 + file.write(',%i' % f.smooth) + i+=1 + + file.write('\n\t\t}') + + # Write Edge Smoothing + file.write(''' + LayerElementSmoothing: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: ''') + + SHARP = Blender.Mesh.EdgeFlags.SHARP + i=-1 + for ed in me.edges: + if i==-1: + file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 + else: + if i==54: + file.write('\n '); i=0 + file.write(',%i' % ((ed.flag&SHARP)!=0)) + i+=1 + + file.write('\n\t\t}') + del SHARP + + + # Write VertexColor Layers + # note, no programs seem to use this info :/ + collayers = [] + if me.vertexColors: + collayers = me.getColorLayerNames() + collayer_orig = me.activeColorLayer + for colindex, collayer in enumerate(collayers): + me.activeColorLayer = collayer + file.write('\n\t\tLayerElementColor: %i {' % colindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % collayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + Colors: ''') + + i = -1 + ii = 0 # Count how many Colors we write + + for f in me.faces: + for col in f.col: + if i==-1: + file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) + i=0 + else: + if i==7: + file.write('\n\t\t\t\t') + i=0 + file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) + i+=1 + ii+=1 # One more Color + + file.write('\n\t\t\tColorIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + + + # Write UV and texture layers. + uvlayers = [] + if do_uvs: + uvlayers = me.getUVLayerNames() + uvlayer_orig = me.activeUVLayer + for uvindex, uvlayer in enumerate(uvlayers): + me.activeUVLayer = uvlayer + file.write('\n\t\tLayerElementUV: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: ''') + + i = -1 + ii = 0 # Count how many UVs we write + + for f in me.faces: + for uv in f.uv: + if i==-1: + file.write('%.6f,%.6f' % tuple(uv)) + i=0 + else: + if i==7: + file.write('\n ') + i=0 + file.write(',%.6f,%.6f' % tuple(uv)) + i+=1 + ii+=1 # One more UV + + file.write('\n\t\t\tUVIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + if do_textures: + file.write('\n\t\tLayerElementTexture: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + if len(my_mesh.blenTextures) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tBlendMode: "Translucent"') + file.write('\n\t\t\tTextureAlpha: 1') + file.write('\n\t\t\tTextureId: ') + + if len(my_mesh.blenTextures) == 1: + file.write('0') + else: + texture_mapping_local = {None:-1} + + i = 0 # 1 for dummy + for tex in my_mesh.blenTextures: + if tex: # None is set above + texture_mapping_local[tex] = i + i+=1 + + i=-1 + for f in me.faces: + img_key = f.image + + if i==-1: + i=0 + file.write( '%s' % texture_mapping_local[img_key]) + else: + if i==55: + file.write('\n ') + i=0 + + file.write(',%s' % texture_mapping_local[img_key]) + i+=1 + + else: + file.write(''' + LayerElementTexture: 0 { + Version: 101 + Name: "" + MappingInformationType: "NoMappingInformation" + ReferenceInformationType: "IndexToDirect" + BlendMode: "Translucent" + TextureAlpha: 1 + TextureId: ''') + file.write('\n\t\t}') + + me.activeUVLayer = uvlayer_orig + + # Done with UV/textures. + + if do_materials: + file.write('\n\t\tLayerElementMaterial: 0 {') + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: ""') + + if len(my_mesh.blenMaterials) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tMaterials: ') + + if len(my_mesh.blenMaterials) == 1: + file.write('0') + else: + # Build a material mapping for this + material_mapping_local = {} # local-mat & tex : global index. + + for j, mat_tex_pair in enumerate(my_mesh.blenMaterials): + material_mapping_local[mat_tex_pair] = j + + len_material_mapping_local = len(material_mapping_local) + + mats = my_mesh.blenMaterialList + + i=-1 + for f in me.faces: + try: mat = mats[f.mat] + except:mat = None + + if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ + else: tex = None + + if i==-1: + i=0 + file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + + file.write(',%s' % (material_mapping_local[mat, tex])) + i+=1 + + file.write('\n\t\t}') + + file.write(''' + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + }''') + + if do_materials: + file.write(''' + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + }''') + + # Always write this + if do_textures: + file.write(''' + LayerElement: { + Type: "LayerElementTexture" + TypedIndex: 0 + }''') + + if me.vertexColors: + file.write(''' + LayerElement: { + Type: "LayerElementColor" + TypedIndex: 0 + }''') + + if do_uvs: # same as me.faceUV + file.write(''' + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + }''') + + + file.write('\n\t\t}') + + if len(uvlayers) > 1: + for i in xrange(1, len(uvlayers)): + + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementUV"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + if do_textures: + + file.write(''' + LayerElement: { + Type: "LayerElementTexture"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + file.write('\n\t\t}') + + if len(collayers) > 1: + # Take into account any UV layers + layer_offset = 0 + if uvlayers: layer_offset = len(uvlayers)-1 + + for i in xrange(layer_offset, len(collayers)+layer_offset): + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementColor"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + file.write('\n\t\t}') + file.write('\n\t}') + + def write_group(name): + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) + + file.write(''' + Properties60: { + Property: "MultiLayer", "bool", "",0 + Property: "Pickable", "bool", "",1 + Property: "Transformable", "bool", "",1 + Property: "Show", "bool", "",1 + } + MultiLayer: 0 + }''') + + + # add meshes here to clear because they are not used anywhere. + meshes_to_clear = [] + + ob_meshes = [] + ob_lights = [] + ob_cameras = [] + # in fbx we export bones as children of the mesh + # armatures not a part of a mesh, will be added to ob_arms + ob_bones = [] + ob_arms = [] + ob_null = [] # emptys + + # List of types that have blender objects (not bones) + ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] + + groups = [] # blender groups, only add ones that have objects in the selections + materials = {} # (mat, image) keys, should be a set() + textures = {} # should be a set() + + tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error + + # if EXP_OBS_SELECTED is false, use sceens objects + if not batch_objects: + if EXP_OBS_SELECTED: tmp_objects = sce.objects.context + else: tmp_objects = sce.objects + else: + tmp_objects = batch_objects + + if EXP_ARMATURE: + # This is needed so applying modifiers dosnt apply the armature deformation, its also needed + # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. + # set every armature to its rest, backup the original values so we done mess up the scene + ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] + + for arm in bpy.data.armatures: + arm.restPosition = True + + if ob_arms_orig_rest: + for ob_base in bpy.data.objects: + #if ob_base.type == 'Armature': + ob_base.makeDisplayList() + + # This causes the makeDisplayList command to effect the mesh + Blender.Set('curframe', Blender.Get('curframe')) + + + for ob_base in tmp_objects: + for ob, mtx in BPyObject.getDerivedObjects(ob_base): + #for ob in [ob_base,]: + tmp_ob_type = ob.type + if tmp_ob_type == 'Camera': + if EXP_CAMERA: + ob_cameras.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Lamp': + if EXP_LAMP: + ob_lights.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Armature': + if EXP_ARMATURE: + # TODO - armatures dont work in dupligroups! + if ob not in ob_arms: ob_arms.append(ob) + # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" + elif tmp_ob_type == 'Empty': + if EXP_EMPTY: + ob_null.append(my_object_generic(ob, mtx)) + elif EXP_MESH: + origData = True + if tmp_ob_type != 'Mesh': + me = bpy.data.meshes.new() + try: me.getFromObject(ob) + except: me = None + if me: + meshes_to_clear.append( me ) + mats = me.materials + origData = False + else: + # Mesh Type! + if EXP_MESH_APPLY_MOD: + me = bpy.data.meshes.new() + me.getFromObject(ob) + + # so we keep the vert groups + if EXP_ARMATURE: + orig_mesh = ob.getData(mesh=1) + if orig_mesh.getVertGroupNames(): + ob.copy().link(me) + # If new mesh has no vgroups we can try add if verts are teh same + if not me.getVertGroupNames(): # vgroups were not kept by the modifier + if len(me.verts) == len(orig_mesh.verts): + groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) + BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + + # print ob, me, me.getVertGroupNames() + meshes_to_clear.append( me ) + origData = False + mats = me.materials + else: + me = ob.getData(mesh=1) + mats = me.materials + + # Support object colors + tmp_colbits = ob.colbits + if tmp_colbits: + tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. + for i in xrange(16): + if tmp_colbits & (1< fbxObject mapping + # this is needed for groups as well as fbxParenting + bpy.data.objects.tag = False + tmp_obmapping = {} + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + ob_base.blenObject.tag = True + tmp_obmapping[ob_base.blenObject] = ob_base + + # Build Groups from objects we export + for blenGroup in bpy.data.groups: + fbxGroupName = None + for ob in blenGroup.objects: + if ob.tag: + if fbxGroupName == None: + fbxGroupName = sane_groupname(blenGroup) + groups.append((fbxGroupName, blenGroup)) + + tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames + + groups.sort() # not really needed + + # Assign parents using this mapping + for ob_generic in ob_all_typegroups: + for my_ob in ob_generic: + parent = my_ob.blenObject.parent + if parent and parent.tag: # does it exist and is it in the mapping + my_ob.fbxParent = tmp_obmapping[parent] + + + del tmp_obmapping + # Finished finding groups we use + + + materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.iterkeys()] + textures = [(sane_texname(tex), tex) for tex in textures.iterkeys() if tex] + materials.sort() # sort by name + textures.sort() + + camera_count = 8 + file.write(''' + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: %i''' % (\ + 1+1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones)+\ + bone_deformer_count+\ + len(materials)+\ + (len(textures)*2))) # add 1 for the root model 1 for global settings + + del bone_deformer_count + + file.write(''' + ObjectType: "Model" { + Count: %i + }''' % (\ + 1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones))) # add 1 for the root model + + file.write(''' + ObjectType: "Geometry" { + Count: %i + }''' % len(ob_meshes)) + + if materials: + file.write(''' + ObjectType: "Material" { + Count: %i + }''' % len(materials)) + + if textures: + file.write(''' + ObjectType: "Texture" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + file.write(''' + ObjectType: "Video" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + + tmp = 0 + # Add deformer nodes + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + tmp+=1 + + # Add subdeformers + for my_bone in ob_bones: + tmp += len(my_bone.blenMeshes) + + if tmp: + file.write(''' + ObjectType: "Deformer" { + Count: %i + }''' % tmp) + del tmp + + # we could avoid writing this possibly but for now just write it + + file.write(''' + ObjectType: "Pose" { + Count: 1 + }''') + + if groups: + file.write(''' + ObjectType: "GroupSelection" { + Count: %i + }''' % len(groups)) + + file.write(''' + ObjectType: "GlobalSettings" { + Count: 1 + } +}''') + + file.write(''' + +; Object properties +;------------------------------------------------------------------ + +Objects: {''') + + # To comply with other FBX FILES + write_camera_switch() + + # Write the null object + write_null(None, 'blend_root')# , GLOBAL_MATRIX) + + for my_null in ob_null: + write_null(my_null) + + for my_arm in ob_arms: + write_null(my_arm) + + for my_cam in ob_cameras: + write_camera(my_cam) + + for my_light in ob_lights: + write_light(my_light) + + for my_mesh in ob_meshes: + write_mesh(my_mesh) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + write_bone(my_bone) + + write_camera_default() + + for matname, (mat, tex) in materials: + write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard) + + # each texture uses a video, odd + for texname, tex in textures: + write_video(texname, tex) + i = 0 + for texname, tex in textures: + write_texture(texname, tex, i) + i+=1 + + for groupname, group in groups: + write_group(groupname) + + # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. + + # Write armature modifiers + # TODO - add another MODEL? - because of this skin definition. + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + write_deformer_skin(my_mesh.fbxName) + + # Get normalized weights for temorary use + if my_mesh.fbxBoneParent: + weights = None + else: + weights = meshNormalizedWeights(my_mesh.blenData) + + #for bonename, bone, obname, bone_mesh, armob in ob_bones: + for my_bone in ob_bones: + if me in my_bone.blenMeshes.itervalues(): + write_sub_deformer_skin(my_mesh, my_bone, weights) + + # Write pose's really weired, only needed when an armature and mesh are used together + # each by themselves dont need pose data. for now only pose meshes and bones + + file.write(''' + Pose: "Pose::BIND_POSES", "BindPose" { + Type: "BindPose" + Version: 100 + Properties60: { + } + NbPoseNodes: ''') + file.write(str(len(pose_items))) + + + for fbxName, matrix in pose_items: + file.write('\n\t\tPoseNode: {') + file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) + if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) + else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) + file.write('\n\t\t}') + + file.write('\n\t}') + + + # Finish Writing Objects + # Write global settings + file.write(''' + GlobalSettings: { + Version: 1000 + Properties60: { + Property: "UpAxis", "int", "",1 + Property: "UpAxisSign", "int", "",1 + Property: "FrontAxis", "int", "",2 + Property: "FrontAxisSign", "int", "",1 + Property: "CoordAxis", "int", "",0 + Property: "CoordAxisSign", "int", "",1 + Property: "UnitScaleFactor", "double", "",100 + } + } +''') + file.write('}') + + file.write(''' + +; Object relations +;------------------------------------------------------------------ + +Relations: {''') + + file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') + + for my_null in ob_null: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) + + for my_arm in ob_arms: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) + + for my_mesh in ob_meshes: + file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) + + # TODO - limbs can have the same name for multiple armatures, should prefix. + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) + + for my_cam in ob_cameras: + file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) + + for my_light in ob_lights: + file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) + + file.write(''' + Model: "Model::Producer Perspective", "Camera" { + } + Model: "Model::Producer Top", "Camera" { + } + Model: "Model::Producer Bottom", "Camera" { + } + Model: "Model::Producer Front", "Camera" { + } + Model: "Model::Producer Back", "Camera" { + } + Model: "Model::Producer Right", "Camera" { + } + Model: "Model::Producer Left", "Camera" { + } + Model: "Model::Camera Switcher", "CameraSwitcher" { + }''') + + for matname, (mat, tex) in materials: + file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) + + if textures: + for texname, tex in textures: + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) + for texname, tex in textures: + file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) + + # deformers - modifiers + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName + # is this bone effecting a mesh? + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) + + # This should be at the end + # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') + + for groupname, group in groups: + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) + + file.write('\n}') + file.write(''' + +; Object connections +;------------------------------------------------------------------ + +Connections: {''') + + # NOTE - The FBX SDK dosnt care about the order but some importers DO! + # for instance, defining the material->mesh connection + # before the mesh->blend_root crashes cinema4d + + + # write the fake root node + file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') + + for ob_generic in ob_all_typegroups: # all blender 'Object's we support + for my_ob in ob_generic: + if my_ob.fbxParent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) + else: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) + + if materials: + for my_mesh in ob_meshes: + # Connect all materials to all objects, not good form but ok for now. + for mat, tex in my_mesh.blenMaterials: + if mat: mat_name = mat.name + else: mat_name = None + + if tex: tex_name = tex.name + else: tex_name = None + + file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName)) + + if textures: + for my_mesh in ob_meshes: + if my_mesh.blenTextures: + # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) + for tex in my_mesh.blenTextures: + if tex: + file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) + + for texname, tex in textures: + file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) + + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) + + # limbs -> deformers + # for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) + + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + # Always parent to armature now + if my_bone.parent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) + else: + # the armature object is written as an empty and all root level bones connect to it + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) + + # groups + if groups: + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + for fbxGroupName in ob_base.fbxGroupNames: + file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) + + for my_arm in ob_arms: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) + + file.write('\n}') + + + # Needed for scene footer as well as animation + render = sce.render + + # from the FBX sdk + #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) + def fbx_time(t): + # 0.5 + val is the same as rounding. + return int(0.5 + ((t/fps) * 46186158000)) + + fps = float(render.fps) + start = render.sFrame + end = render.eFrame + if end < start: start, end = end, start + if start==end: ANIM_ENABLE = False + + # animations for these object types + ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms + + if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: + + frame_orig = Blender.Get('curframe') + + if ANIM_OPTIMIZE: + ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION + + # default action, when no actions are avaioable + tmp_actions = [None] # None is the default action + blenActionDefault = None + action_lastcompat = None + + if ANIM_ACTION_ALL: + bpy.data.actions.tag = False + tmp_actions = list(bpy.data.actions) + + + # find which actions are compatible with the armatures + # blenActions is not yet initialized so do it now. + tmp_act_count = 0 + for my_arm in ob_arms: + + # get the default name + if not blenActionDefault: + blenActionDefault = my_arm.blenAction + + arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) + + for action in tmp_actions: + + action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) + + if action_chan_names: # at least one channel matches. + my_arm.blenActionList.append(action) + action.tag = True + tmp_act_count += 1 + + # incase there is no actions applied to armatures + action_lastcompat = action + + if tmp_act_count: + # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. + if not blenActionDefault: + blenActionDefault = action_lastcompat + + del action_lastcompat + + file.write(''' +;Takes and animation section +;---------------------------------------------------- + +Takes: {''') + + if blenActionDefault: + file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) + else: + file.write('\n\tCurrent: "Default Take"') + + for blenAction in tmp_actions: + # we have tagged all actious that are used be selected armatures + if blenAction: + if blenAction.tag: + print '\taction: "%s" exporting...' % blenAction.name + else: + print '\taction: "%s" has no armature using it, skipping' % blenAction.name + continue + + if blenAction == None: + # Warning, this only accounts for tmp_actions being [None] + file.write('\n\tTake: "Default Take" {') + act_start = start + act_end = end + else: + # use existing name + if blenAction == blenActionDefault: # have we alredy got the name + file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) + else: + file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) + + tmp = blenAction.getFrameNumbers() + if tmp: + act_start = min(tmp) + act_end = max(tmp) + del tmp + else: + # Fallback on this, theres not much else we can do? :/ + # when an action has no length + act_start = start + act_end = end + + # Set the action active + for my_bone in ob_arms: + if blenAction in my_bone.blenActionList: + ob.action = blenAction + # print '\t\tSetting Action!', blenAction + # sce.update(1) + + file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed + file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + + file.write(''' + + ;Models animation + ;----------------------------------------------------''') + + + # set pose data for all bones + # do this here incase the action changes + ''' + for my_bone in ob_bones: + my_bone.flushAnimData() + ''' + i = act_start + while i <= act_end: + Blender.Set('curframe', i) + for ob_generic in ob_anim_lists: + for my_ob in ob_generic: + #Blender.Window.RedrawAll() + if ob_generic == ob_meshes and my_ob.fbxArm: + # We cant animate armature meshes! + pass + else: + my_ob.setPoseFrame(i) + + i+=1 + + + #for bonename, bone, obname, me, armob in ob_bones: + for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): + + for my_ob in ob_generic: + + if ob_generic == ob_meshes and my_ob.fbxArm: + # do nothing, + pass + else: + + file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed + file.write('\n\t\t\tVersion: 1.1') + file.write('\n\t\t\tChannel: "Transform" {') + + context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] + + # ---------------- + # ---------------- + for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale + + if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='S': context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='R': + # Was.... + # elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] + # + # ...but we need to use the previous euler for compatible conversion. + context_bone_anim_vecs = [] + prev_eul = None + for mtx in context_bone_anim_mats: + if prev_eul: prev_eul = mtx[1].toEuler(prev_eul) + else: prev_eul = mtx[1].toEuler() + context_bone_anim_vecs.append(prev_eul) + + file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation + + for i in xrange(3): + # Loop on each axis of the bone + file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation + file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) + file.write('\n\t\t\t\t\t\tKeyVer: 4005') + + if not ANIM_OPTIMIZE: + # Just write all frames, simple but in-eficient + file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) + file.write('\n\t\t\t\t\t\tKey: ') + frame = act_start + while frame <= act_end: + if frame!=act_start: + file.write(',') + + # Curve types are 'C,n' for constant, 'L' for linear + # C,n is for bezier? - linear is best for now so we can do simple keyframe removal + file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + frame+=1 + else: + # remove unneeded keys, j is the frame, needed when some frames are removed. + context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + + # last frame to fisrt frame, missing 1 frame on either side. + # removeing in a backwards loop is faster + #for j in xrange( (act_end-act_start)-1, 0, -1 ): + # j = (act_end-act_start)-1 + j = len(context_bone_anim_keys)-2 + while j > 0 and len(context_bone_anim_keys) > 2: + # print j, len(context_bone_anim_keys) + # Is this key the same as the ones next to it? + + # co-linear horizontal... + if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ + abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + + del context_bone_anim_keys[j] + + else: + frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1]) + frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range + frame_range_fac2 = 1.0 - frame_range_fac1 + + if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + del context_bone_anim_keys[j] + else: + j-=1 + + # keep the index below the list length + if j > len(context_bone_anim_keys)-2: + j = len(context_bone_anim_keys)-2 + + if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: + # This axis has no moton, its okay to skip KeyCount and Keys in this case + pass + else: + # We only need to write these if there is at least one + file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) + file.write('\n\t\t\t\t\t\tKey: ') + for val, frame in context_bone_anim_keys: + if frame != context_bone_anim_keys[0][1]: # not the first + file.write(',') + # frame is alredy one less then blenders frame + file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + + if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') + elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') + elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + + file.write('\n\t\t\t\t\t}') + file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) + file.write('\n\t\t\t\t}') + + # --------------- + + file.write('\n\t\t\t}') + file.write('\n\t\t}') + + # end the take + file.write('\n\t}') + + # end action loop. set original actions + # do this after every loop incase actions effect eachother. + for my_bone in ob_arms: + my_bone.blenObject.action = my_bone.blenAction + + file.write('\n}') + + Blender.Set('curframe', frame_orig) + + else: + # no animation + file.write('\n;Takes and animation section') + file.write('\n;----------------------------------------------------') + file.write('\n') + file.write('\nTakes: {') + file.write('\n\tCurrent: ""') + file.write('\n}') + + + # write meshes animation + #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: + + + # Clear mesh data Only when writing with modifiers applied + for me in meshes_to_clear: + me.verts = None + + + + # --------------------------- Footer + if world: + has_mist = world.mode & 1 + mist_intense, mist_start, mist_end, mist_height = world.mist + world_hor = world.hor + else: + has_mist = mist_intense = mist_start = mist_end = mist_height = 0 + world_hor = 0,0,0 + + file.write('\n;Version 5 settings') + file.write('\n;------------------------------------------------------------------') + file.write('\n') + file.write('\nVersion5: {') + file.write('\n\tAmbientRenderSettings: {') + file.write('\n\t\tVersion: 101') + file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) + file.write('\n\t}') + file.write('\n\tFogOptions: {') + file.write('\n\t\tFlogEnable: %i' % has_mist) + file.write('\n\t\tFogMode: 0') + file.write('\n\t\tFogDensity: %.3f' % mist_intense) + file.write('\n\t\tFogStart: %.3f' % mist_start) + file.write('\n\t\tFogEnd: %.3f' % mist_end) + file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) + file.write('\n\t}') + file.write('\n\tSettings: {') + file.write('\n\t\tFrameRate: "%i"' % int(fps)) + file.write('\n\t\tTimeFormat: 1') + file.write('\n\t\tSnapOnFrames: 0') + file.write('\n\t\tReferenceTimeIndex: -1') + file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) + file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) + file.write('\n\t}') + file.write('\n\tRendererSetting: {') + file.write('\n\t\tDefaultCamera: "Producer Perspective"') + file.write('\n\t\tDefaultViewingMode: 0') + file.write('\n\t}') + file.write('\n}') + file.write('\n') + + # Incase sombody imports this, clean up by clearing global dicts + sane_name_mapping_ob.clear() + sane_name_mapping_mat.clear() + sane_name_mapping_tex.clear() + + ob_arms[:] = [] + ob_bones[:] = [] + ob_cameras[:] = [] + ob_lights[:] = [] + ob_meshes[:] = [] + ob_null[:] = [] + + + # copy images if enabled + if EXP_IMAGE_COPY: + copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) + + print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) + return True + + +# -------------------------------------------- +# UI Function - not a part of the exporter. +# this is to seperate the user interface from the rest of the exporter. +from Blender import Draw, Window +EVENT_NONE = 0 +EVENT_EXIT = 1 +EVENT_REDRAW = 2 +EVENT_FILESEL = 3 + +GLOBALS = {} + +# export opts + +def do_redraw(e,v): GLOBALS['EVENT'] = e + +# toggle between these 2, only allow one on at once +def do_obs_sel(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 0 + GLOBALS['EXP_OBS_SELECTED'].val = 1 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_batch_type_grp(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 1 + GLOBALS['BATCH_SCENE'].val = 0 + +def do_batch_type_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 0 + GLOBALS['BATCH_SCENE'].val = 1 + +def do_anim_act_all(e,v): + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + +def do_anim_act_cur(e,v): + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: + Draw.PupMenu('Warning%t|Cant use this with batch export group option') + else: + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 0 + GLOBALS['ANIM_ACTION_ALL'][1].val = 1 + +def fbx_ui_exit(e,v): + GLOBALS['EVENT'] = e + +def do_help(e,v): + url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' + print 'Trying to open web browser with documentation at this address...' + print '\t' + url + + try: + import webbrowser + webbrowser.open(url) + except: + Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation") + print '...could not open a browser window.' + + + +# run when export is pressed +#def fbx_ui_write(e,v): +def fbx_ui_write(filename, context): + + # Dont allow overwriting files when saving normally + if not GLOBALS['BATCH_ENABLE'].val: + if not BPyMessages.Warning_SaveOver(filename): + return + + GLOBALS['EVENT'] = EVENT_EXIT + + # Keep the order the same as above for simplicity + # the [] is a dummy arg used for objects + + Blender.Window.WaitCursor(1) + + # Make the matrix + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val + if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + ret = write(\ + filename, None,\ + context, + GLOBALS['EXP_OBS_SELECTED'].val,\ + GLOBALS['EXP_MESH'].val,\ + GLOBALS['EXP_MESH_APPLY_MOD'].val,\ + GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ + GLOBALS['EXP_ARMATURE'].val,\ + GLOBALS['EXP_LAMP'].val,\ + GLOBALS['EXP_CAMERA'].val,\ + GLOBALS['EXP_EMPTY'].val,\ + GLOBALS['EXP_IMAGE_COPY'].val,\ + GLOBAL_MATRIX,\ + GLOBALS['ANIM_ENABLE'].val,\ + GLOBALS['ANIM_OPTIMIZE'].val,\ + GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ + GLOBALS['ANIM_ACTION_ALL'][0].val,\ + GLOBALS['BATCH_ENABLE'].val,\ + GLOBALS['BATCH_GROUP'].val,\ + GLOBALS['BATCH_SCENE'].val,\ + GLOBALS['BATCH_FILE_PREFIX'].val,\ + GLOBALS['BATCH_OWN_DIR'].val,\ + ) + + Blender.Window.WaitCursor(0) + GLOBALS.clear() + + if ret == False: + Draw.PupMenu('Error%t|Path cannot be written to!') + + +def fbx_ui(): + # Only to center the UI + x,y = GLOBALS['MOUSE'] + x-=180; y-=0 # offset... just to get it centered + + Draw.Label('Export Objects...', x+20,y+165, 200, 20) + + if not GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) + GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') + GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') + GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') + GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') + Draw.EndAlign() + + y -= 35 + + Draw.BeginAlign() + GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') + GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') + GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') + GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') + GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) + Draw.EndAlign() + + if GLOBALS['EXP_MESH'].val: + # below mesh but + Draw.BeginAlign() + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) + Draw.EndAlign() + + GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) + + + Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) + + GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) + if GLOBALS['ANIM_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) + if GLOBALS['ANIM_OPTIMIZE'].val: + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 1, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) + GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) + Draw.EndAlign() + + + Draw.Label('Export Batch...', x+20,y-60, 300, 20) + GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) + + if GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) + GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) + + # Own dir requires OS module + if os: + GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + else: + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + + + Draw.EndAlign() + + #y+=80 + + ''' + Draw.BeginAlign() + GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') + Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) + ''' + # Until batch is added + # + + + #Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) + Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) + + #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) + #Draw.EndAlign() + + # exit when mouse out of the view? + # GLOBALS['EVENT'] = EVENT_EXIT + +#def write_ui(filename): +def write_ui(): + + # globals + GLOBALS['EVENT'] = EVENT_REDRAW + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + GLOBALS['FILENAME'] = '' + ''' + # IF called from the fileselector + if filename == None: + GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) + else: + GLOBALS['FILENAME'].val = filename + ''' + GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity + GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) + + GLOBALS['EXP_MESH'] = Draw.Create(1) + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) + GLOBALS['EXP_ARMATURE'] = Draw.Create(1) + GLOBALS['EXP_LAMP'] = Draw.Create(1) + GLOBALS['EXP_CAMERA'] = Draw.Create(1) + GLOBALS['EXP_EMPTY'] = Draw.Create(1) + GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) + # animation opts + GLOBALS['ANIM_ENABLE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(4) # decimal places + GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action + + # batch export options + GLOBALS['BATCH_ENABLE'] = Draw.Create(0) + GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. + GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above + GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) + GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) + # done setting globals + + # Used by the user interface + GLOBALS['_SCALE'] = Draw.Create(1.0) + GLOBALS['_XROT90'] = Draw.Create(True) + GLOBALS['_YROT90'] = Draw.Create(False) + GLOBALS['_ZROT90'] = Draw.Create(False) + + # best not do move the cursor + # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] != EVENT_EXIT: + + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: + #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + + if GLOBALS['EVENT'] == EVENT_FILESEL: + if GLOBALS['BATCH_ENABLE'].val: + txt = 'Batch FBX Dir' + name = Blender.sys.expandpath('//') + else: + txt = 'Export FBX' + name = Blender.sys.makename(ext='.fbx') + + Blender.Window.FileSelector(fbx_ui_write, txt, name) + #fbx_ui_write('/test.fbx') + break + + Draw.UIBlock(fbx_ui, 0) + + + # GLOBALS.clear() +#test = [write_ui] +if __name__ == '__main__': + # Cant call the file selector first because of a bug in the interface that crashes it. + # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) + #write('/scratch/test.fbx') + #write_ui('/scratch/test.fbx') + + if not set: + Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.') + else: + write_ui() + +# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) +# +# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print +# - get rid of cleanName somehow +# - new scene creation, activation: lines 327-342, 368 + +# TODO + +# bpy.data.remove_scene: line 366 diff --git a/release/io/export_obj.py b/release/io/export_obj.py index ee045053dd3..26e6e248a45 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -962,3 +962,4 @@ if __name__ == "__main__": # - NURBS - needs API additions # - all scenes export # - normals calculation +# - get rid of cleanName somehow diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index caa970eff57..dc519e9ec6e 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -609,6 +609,16 @@ static void rna_def_bone(BlenderRNA *brna) prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Selected", ""); + + prop= RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "bone_mat"); + RNA_def_property_array(prop, 9); + RNA_def_property_ui_text(prop, "Bone Matrix", "3x3 bone matrix."); + + prop= RNA_def_property(srna, "armature_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "arm_mat"); + RNA_def_property_array(prop, 16); + RNA_def_property_ui_text(prop, "Bone Armature Matrix", "4x4 bone matrix relative to armature."); } static void rna_def_edit_bone(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c new file mode 100644 index 00000000000..c0bf3339f4f --- /dev/null +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -0,0 +1,56 @@ +/** + * + * + * ***** 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 +#include +#include +#include + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_object_types.h" + +/* #include "BLO_sys_types.h" */ + +#ifdef RNA_RUNTIME + +/* #include "DNA_anim_types.h" */ +#include "DNA_action_types.h" /* bPose */ + +#else + +void RNA_api_pose(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + +} + +#endif + -- cgit v1.2.3 From 797c6a2295f47f1c3a71f9094c710316cdf2ecf3 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 10 Jul 2009 14:46:52 +0000 Subject: - RNA-wrapped Bone props: head, armature_head, tail, armature_tail. - more FBX conversion --- release/io/export_fbx.py | 131 +++++++++++++++++--------- release/io/export_obj.py | 12 +-- source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_armature.c | 23 ++++- 4 files changed, 116 insertions(+), 52 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index cea9f500533..59480c4d455 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -210,10 +210,14 @@ def derived_paths(fname_orig, basepath, FORCE_CWD=False): FORCE_CWD - dont use the basepath, just add a ./ to the filename. use when we know the file will be in the basepath. ''' - fname = Blender.sys.expandpath(fname_orig) + fname = bpy.sys.expandpath(fname_orig) +# fname = Blender.sys.expandpath(fname_orig) fname_strip = strip_path(fname) - if FORCE_CWD: fname_rel = '.' + os.sep + fname_strip - else: fname_rel = Blender.sys.relpath(fname, basepath) + if FORCE_CWD: + fname_rel = '.' + os.sep + fname_strip + else: + fname_rel = bpy.sys.relpath(fname, basepath) +# fname_rel = Blender.sys.relpath(fname, basepath) if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] return fname, fname_strip, fname_rel @@ -414,7 +418,7 @@ def write(filename, batch_objects = None, \ self.blenMeshes = {} # fbxMeshObName : mesh self.fbxArm = fbxArm self.restMatrix = blenBone.armature_matrix - # self.restMatrix = blenBone.matrix['ARMATURESPACE'] +# self.restMatrix = blenBone.matrix['ARMATURESPACE'] # not used yet # self.restMatrixInv = self.restMatrix.copy().invert() @@ -532,13 +536,15 @@ def write(filename, batch_objects = None, \ print '\nFBX export starting...', filename - start_time = Blender.sys.time() + start_time = bpy.sys.time() +# start_time = Blender.sys.time() try: file = open(filename, 'w') except: return False - - sce = bpy.data.scenes.active + + sce = context.scene +# sce = bpy.data.scenes.active world = sce.world @@ -570,7 +576,8 @@ def write(filename, batch_objects = None, \ }''' % (curtime)) file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) - file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + file.write('\nCreator: "Blender3D version 2.5"') +# file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way @@ -579,16 +586,19 @@ def write(filename, batch_objects = None, \ ''' Matrix mod is so armature objects can modify their bone matricies ''' - if isinstance(ob, Blender.Types.BoneType): + if isinstance(ob, bpy.types.Bone): +# if isinstance(ob, Blender.Types.BoneType): # we know we have a matrix # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) - matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + matrix = mtx4_z90 * ob.armature_matrix # dont apply armature matrix anymore +# matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore parent = ob.parent if parent: #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) - par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + par_matrix = mtx4_z90 * parent.armature_matrix # dont apply armature matrix anymore +# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore matrix = matrix * par_matrix.copy().invert() matrix_rot = matrix.rotationPart() @@ -755,8 +765,9 @@ def write(filename, batch_objects = None, \ ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) """ - file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ - (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % + (my_bone.blenBone.armature_head - my_bone.blenBone.armature_tail).length) +# (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') @@ -895,9 +906,12 @@ def write(filename, batch_objects = None, \ ''' Write a blender camera ''' - render = sce.render - width = render.sizeX - height = render.sizeY + render = sce.render_data + width = render.resolution_x + height = render.resolution_y +# render = sce.render +# width = render.sizeX +# height = render.sizeY aspect = float(width)/height data = my_cam.blenObject.data @@ -911,8 +925,10 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') - file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? - file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units? +# file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto +# file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') @@ -944,8 +960,10 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') - file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) - file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clip_start) +# file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clip_end) +# file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) @@ -1018,16 +1036,20 @@ def write(filename, batch_objects = None, \ #ePOINT, #eDIRECTIONAL #eSPOT - light_type = light.type + light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 4} + light_type = light_type_items[light.type] +# light_type = light.type if light_type > 2: light_type = 1 # hemi and area lights become directional - - mode = light.mode - if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: + +# mode = light.mode + if light.shadow_method == 'RAY_SHADOW' or light.shadow_method == 'BUFFER_SHADOW': +# if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: do_shadow = 1 else: do_shadow = 0 - - if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): + + if light.only_shadow or (not light.diffuse and not light.specular): +# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): do_light = 0 else: do_light = 1 @@ -1042,11 +1064,16 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 - file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + if light.type == 'SPOT': + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spot_size * scale)) +# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') - file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) + file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.color)) +# file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 - file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) +# + # duplication? see ^ (Arystan) +# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) @@ -1055,7 +1082,8 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') - file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) + file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.distance) +# file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') @@ -1101,7 +1129,8 @@ def write(filename, batch_objects = None, \ }''') # Material Settings - if world: world_amb = world.getAmb() + if world: world_amb = tuple(world.ambient_color) +# if world: world_amb = world.getAmb() else: world_amb = (0,0,0) # Default value def write_material(matname, mat): @@ -1109,22 +1138,31 @@ def write(filename, batch_objects = None, \ # Todo, add more material Properties. if mat: - mat_cold = tuple(mat.rgbCol) - mat_cols = tuple(mat.specCol) + mat_cold = tuple(mat.diffuse_color) +# mat_cold = tuple(mat.rgbCol) + mat_cols = tuple(mat.specular_color) +# mat_cols = tuple(mat.specCol) #mat_colm = tuple(mat.mirCol) # we wont use the mirror color - mat_colamb = tuple([c for c in world_amb]) - - mat_dif = mat.ref - mat_amb = mat.amb - mat_hard = (float(mat.hard)-1)/5.10 - mat_spec = mat.spec/2.0 + mat_colamb = world_amb +# mat_colamb = tuple([c for c in world_amb]) + + mat_dif = mat.diffuse_reflection +# mat_dif = mat.ref + mat_amb = mat.ambient +# mat_amb = mat.amb + mat_hard = (float(mat.specular_hardness)-1)/5.10 +# mat_hard = (float(mat.hard)-1)/5.10 + mat_spec = mat.specular_reflection/2.0 +# mat_spec = mat.spec/2.0 mat_alpha = mat.alpha mat_emit = mat.emit - mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS + mat_shadeless = mat.shadeless +# mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS if mat_shadeless: mat_shader = 'Lambert' else: - if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: + if mat.diffuse_shader == 'LAMBERT': +# if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: mat_shader = 'Lambert' else: mat_shader = 'Phong' @@ -3102,11 +3140,16 @@ if __name__ == '__main__': write_ui() # NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) -# # - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print # - get rid of cleanName somehow -# - new scene creation, activation: lines 327-342, 368 +# - isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 # TODO -# bpy.data.remove_scene: line 366 +# - bpy.data.remove_scene: line 366 +# - bpy.sys.time move to bpy.sys.util? +# - new scene creation, activation: lines 327-342, 368 +# - uses bpy.sys.expandpath, *.relpath - replace at least relpath + +# SMALL or COSMETICAL +# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version') diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 26e6e248a45..51d0403cdae 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -389,16 +389,13 @@ def write(filename, objects, scene, if ob_main.dupli_type != 'NONE': obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list] - # XXX + # XXX debug print 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): @@ -418,7 +415,10 @@ def write(filename, objects, scene, else: me = ob.data.create_copy() - me.transform(ob_mat) + if EXPORT_ROTX90: + me.transform(ob_mat * mat_xrot90) + else: + me.transform(ob_mat) # # Will work for non meshes now! :) # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) @@ -961,5 +961,5 @@ if __name__ == "__main__": # - duplis - only tested dupliverts # - NURBS - needs API additions # - all scenes export -# - normals calculation +# + normals calculation # - get rid of cleanName somehow diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 8a9fdb8531d..fb2d052e241 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1920,7 +1920,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_object_force.c", NULL, RNA_def_object_force}, {"rna_packedfile.c", NULL, RNA_def_packedfile}, {"rna_particle.c", NULL, RNA_def_particle}, - {"rna_pose.c", NULL, RNA_def_pose}, + {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, {"rna_property.c", NULL, RNA_def_gameproperty}, {"rna_scene.c", "rna_scene_api.c", RNA_def_scene}, {"rna_screen.c", NULL, RNA_def_screen}, diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index dc519e9ec6e..7d8391132b1 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -610,6 +610,7 @@ static void rna_def_bone(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); RNA_def_property_ui_text(prop, "Selected", ""); + /* XXX better matrix descriptions possible (Arystan) */ prop= RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "bone_mat"); RNA_def_property_array(prop, 9); @@ -618,7 +619,27 @@ static void rna_def_bone(BlenderRNA *brna) prop= RNA_def_property(srna, "armature_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "arm_mat"); RNA_def_property_array(prop, 16); - RNA_def_property_ui_text(prop, "Bone Armature Matrix", "4x4 bone matrix relative to armature."); + RNA_def_property_ui_text(prop, "Bone Armature-Relative Matrix", "4x4 bone matrix relative to armature."); + + prop= RNA_def_property(srna, "tail", PROP_FLOAT, PROP_VECTOR); + RNA_def_property_float_sdna(prop, NULL, "tail"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Tail", "Location of tail end of the bone."); + + prop= RNA_def_property(srna, "armature_tail", PROP_FLOAT, PROP_VECTOR); + RNA_def_property_float_sdna(prop, NULL, "arm_tail"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Armature-Relative Tail", "Location of tail end of the bone relative to armature."); + + prop= RNA_def_property(srna, "head", PROP_FLOAT, PROP_VECTOR); + RNA_def_property_float_sdna(prop, NULL, "head"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Head", "Location of head end of the bone."); + + prop= RNA_def_property(srna, "armature_head", PROP_FLOAT, PROP_VECTOR); + RNA_def_property_float_sdna(prop, NULL, "arm_head"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Armature-Relative Head", "Location of head end of the bone relative to armature."); } static void rna_def_edit_bone(BlenderRNA *brna) -- cgit v1.2.3 From f221d9128ddf593f7977251ed4214cfe682d7c40 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 11 Jul 2009 11:58:50 +0000 Subject: Added Scene.set_frame RNA function to get immediate scene update. Changing Scene.current_frame doesn't work in this case because it adds a notifier. Also added RNA_property_update call in pyrna_struct_setattro so that notifiers are added when a property changes. --- release/io/export_fbx.py | 6 ++-- release/scripts/export_fbx.py | 3 +- source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_action.c | 2 ++ source/blender/makesrna/intern/rna_action_api.c | 48 +++++++++++++++++++++++++ source/blender/makesrna/intern/rna_pose_api.c | 2 -- source/blender/makesrna/intern/rna_scene_api.c | 16 +++++++++ source/blender/python/intern/bpy_rna.c | 7 +++- 8 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 source/blender/makesrna/intern/rna_action_api.c diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 59480c4d455..62c8e0daaaf 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -2500,7 +2500,8 @@ Connections: {''') if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: - frame_orig = Blender.Get('curframe') + frame_orig = sce.current_frame +# frame_orig = Blender.Get('curframe') if ANIM_OPTIMIZE: ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION @@ -2613,7 +2614,8 @@ Takes: {''') ''' i = act_start while i <= act_end: - Blender.Set('curframe', i) + sce.set_frame(i) +# Blender.Set('curframe', i) for ob_generic in ob_anim_lists: for my_ob in ob_generic: #Blender.Window.RedrawAll() diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py index 4115140a852..bac4c6cbcc4 100644 --- a/release/scripts/export_fbx.py +++ b/release/scripts/export_fbx.py @@ -2445,7 +2445,8 @@ Connections: {''') if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: - frame_orig = Blender.Get('curframe') + frame_orig = sce.current_frame +# frame_orig = Blender.Get('curframe') if ANIM_OPTIMIZE: ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index d7c9ffe9800..7a8dfe78ca1 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1897,7 +1897,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_rna.c", NULL, RNA_def_rna}, {"rna_ID.c", NULL, RNA_def_ID}, {"rna_texture.c", NULL, RNA_def_texture}, - {"rna_action.c", NULL, RNA_def_action}, + {"rna_action.c", "rna_action_api.c", RNA_def_action}, {"rna_animation.c", NULL, RNA_def_animation}, {"rna_actuator.c", NULL, RNA_def_actuator}, {"rna_armature.c", NULL, RNA_def_armature}, diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 3639d6d3fff..bc59e06a978 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -100,6 +100,8 @@ void rna_def_action(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "markers", NULL); RNA_def_property_struct_type(prop, "TimelineMarker"); RNA_def_property_ui_text(prop, "Pose Markers", "Markers specific to this Action, for labeling poses."); + + RNA_api_action(srna); } /* --------- */ diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c new file mode 100644 index 00000000000..a758a2c56d0 --- /dev/null +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -0,0 +1,48 @@ +/** + * ***** 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 +#include +#include +#include + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_action_types.h" + +#ifdef RNA_RUNTIME + +#else + +void RNA_api_action(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + +} + +#endif diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index c0bf3339f4f..9ac7713b2e9 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -1,6 +1,4 @@ /** - * - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index a38622b48ae..f3cbb630df5 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -33,6 +33,7 @@ #include "RNA_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #ifdef RNA_RUNTIME @@ -67,6 +68,15 @@ static void rna_Scene_remove_object(Scene *sce, ReportList *reports, Object *ob) ED_base_object_free_and_unlink(sce, base); } +static void rna_Scene_set_frame(Scene *sce, bContext *C, int frame) +{ + sce->r.cfra= frame; + CLAMP(sce->r.cfra, MINAFRAME, MAXFRAME); + scene_update_for_newframe(sce, (1<<20) - 1); + + WM_event_add_notifier(C, NC_SCENE|ND_FRAME, sce); +} + #else void RNA_api_scene(StructRNA *srna) @@ -85,6 +95,12 @@ void RNA_api_scene(StructRNA *srna) 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); + + func= RNA_def_function(srna, "set_frame", "rna_Scene_set_frame"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Set scene frame updating all objects immediately."); + parm= RNA_def_int(func, "frame", 0, MINAFRAME, MAXFRAME, "", "Frame number to set.", MINAFRAME, MAXFRAME); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ef504b6fbd8..9619d6fbbbb 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1311,6 +1311,7 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje { char *name = _PyUnicode_AsString(pyname); PropertyRNA *prop = RNA_struct_find_property(&self->ptr, name); + int ret; if (prop==NULL) { if (!BPy_StructRNA_CheckExact(self) && PyObject_GenericSetAttr((PyObject *)self, pyname, value) >= 0) { @@ -1328,7 +1329,11 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje } /* pyrna_py_to_prop sets its own exceptions */ - return pyrna_py_to_prop(&self->ptr, prop, NULL, value); + ret= pyrna_py_to_prop(&self->ptr, prop, NULL, value); + + RNA_property_update(BPy_GetContext(), &self->ptr, prop); + + return ret; } static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) -- cgit v1.2.3 From 870a9d61042d8badb02673678dd1ed32a6ee994d Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 11 Jul 2009 16:11:26 +0000 Subject: RNA functions can now return dynamic arrays (float, int/boolean). RNA handles freeing memory. Example code: http://pastebin.mozilla.org/662154. --- source/blender/makesrna/RNA_types.h | 3 +++ source/blender/makesrna/intern/makesrna.c | 24 +++++++++++++++++++++--- source/blender/makesrna/intern/rna_access.c | 7 ++++++- source/blender/makesrna/intern/rna_action_api.c | 15 +++++++++++++++ source/blender/makesrna/intern/rna_define.c | 2 ++ source/blender/python/SConscript | 2 +- source/blender/python/intern/bpy_rna.c | 6 ++++++ 7 files changed, 54 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index dc2a2a1a1de..ed6f12681cc 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -106,6 +106,9 @@ typedef enum PropertyFlag { /* pointers */ PROP_ID_REFCOUNT = 64, + /* arrays */ + PROP_DYNAMIC_ARRAY = 32768, + /* internal flags */ PROP_BUILTIN = 128, PROP_EXPORT = 256, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 7a8dfe78ca1..5462c005bcf 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1200,6 +1200,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA fprintf(f, "\tchar *_data"); if(func->ret) fprintf(f, ", *_retdata"); fprintf(f, ";\n"); + if(func->ret && (func->ret->flag & PROP_DYNAMIC_ARRAY)) fprintf(f, "\tint _ret_array_length;\n"); fprintf(f, "\t\n"); /* assign self */ @@ -1254,6 +1255,12 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA fprintf(f, "reports"); } + if(func->ret && (func->ret->flag & PROP_DYNAMIC_ARRAY)) { + if(!first) fprintf(f, ", "); + first= 0; + fprintf(f, "&_ret_array_length"); + } + dparm= dfunc->cont.properties.first; for(; dparm; dparm= dparm->next) { if(dparm->prop==func->ret) @@ -1271,6 +1278,10 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA dparm= rna_find_parameter_def(func->ret); ptrstr= dparm->prop->type == PROP_POINTER || dparm->prop->arraylength > 0 ? "*" : ""; fprintf(f, "\t*((%s%s%s*)_retdata)= %s;\n", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, func->ret->identifier); + + if(func->ret && (func->ret->flag & PROP_DYNAMIC_ARRAY)) { + fprintf(f, "\t_parms->func->ret->arraylength= _ret_array_length;\n"); + } } } @@ -1476,9 +1487,9 @@ static void rna_generate_static_parameter_prototypes(BlenderRNA *brna, StructRNA /* return type */ for(dparm= dfunc->cont.properties.first; dparm; dparm= dparm->next) { if(dparm->prop==func->ret) { - if(dparm->prop->arraylength) - fprintf(f, "XXX no array return types yet"); /* XXX not supported */ - else if(dparm->prop->type == PROP_POINTER) + if(dparm->prop->arraylength && !(dparm->prop->flag & PROP_DYNAMIC_ARRAY)) + fprintf(f, "\"XXX array return types only allowed with PROP_DYNAMIC_ARRAY flag.\""); /* XXX not supported */ + else if(dparm->prop->type == PROP_POINTER || (dparm->prop->flag & PROP_DYNAMIC_ARRAY)) fprintf(f, "%s%s *", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop)); else fprintf(f, "%s%s ", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop)); @@ -1515,6 +1526,13 @@ static void rna_generate_static_parameter_prototypes(BlenderRNA *brna, StructRNA fprintf(f, "ReportList *reports"); } + /* dynamic array length paramter */ + if(func->ret && (func->ret->flag & PROP_DYNAMIC_ARRAY)) { + if(!first) fprintf(f, ", "); + first= 0; + fprintf(f, "int *array_length"); + } + /* defined parameters */ for(dparm= dfunc->cont.properties.first; dparm; dparm= dparm->next) { if(dparm->prop==func->ret) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index f20df81d6ad..b312b0b8e51 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2799,8 +2799,13 @@ void RNA_parameter_list_free(ParameterList *parms) parm= parms->func->cont.properties.first; for(tot= 0; parm; parm= parm->next) { - if(parm->type == PROP_COLLECTION) + if(parm->type == PROP_COLLECTION) { BLI_freelistN((ListBase*)((char*)parms->data+tot)); + } + else if(parm->flag & PROP_DYNAMIC_ARRAY) { + /* for dynamic arrays, data is a pointer to an array */ + MEM_freeN(*(char**)parms->data+tot); + } tot+= rna_parameter_size(parm); } diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c index a758a2c56d0..b989d2d66a9 100644 --- a/source/blender/makesrna/intern/rna_action_api.c +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -36,6 +36,16 @@ #ifdef RNA_RUNTIME +int *rna_Action_get_frames(bAction *act, int *ret_length) +{ + *ret_length= 3; + int *ret= MEM_callocN(*ret_length * sizeof(int), "action frames"); + ret[0] = 1; + ret[1] = 2; + ret[2] = 3; + return ret; +} + #else void RNA_api_action(StructRNA *srna) @@ -43,6 +53,11 @@ void RNA_api_action(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; + func= RNA_def_function(srna, "get_frames", "rna_Action_get_frames"); + RNA_def_function_ui_description(func, "Get action frames."); /* XXX describe better */ + parm= RNA_def_int_array(func, "frames", 1, NULL, 0, 0, "", "", 0, 0); + RNA_def_property_flag(parm, PROP_DYNAMIC_ARRAY); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 07515d3ad56..d0a2de515ed 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -2220,6 +2220,8 @@ int rna_parameter_size(PropertyRNA *parm) PropertyType ptype= parm->type; int len= parm->arraylength; + if (parm->flag & PROP_DYNAMIC_ARRAY) return sizeof(void*); + if(len > 0) { switch (ptype) { case PROP_BOOLEAN: diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 73dc171fc3e..0ef6689de7e 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('intern/*.c') -incs = '. ../editors/include ../makesdna ../makesrna ../blenlib ../blenkernel ../nodes' +incs = '. ../editors/include ../makesdna ../makesrna ../makesrna/intern ../blenlib ../blenkernel ../nodes' incs += ' ../imbuf ../blenloader ../render/extern/include ../windowmanager' incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include' incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 9619d6fbbbb..fe68436c07f 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -44,6 +44,8 @@ #include "DNA_scene_types.h" #include "ED_keyframing.h" +#include "rna_internal_types.h" /* PropertyRNA */ + #define USE_MATHUTILS #ifdef USE_MATHUTILS @@ -1792,6 +1794,10 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) /* resolve the array from a new pytype */ ret = PyTuple_New(len); + /* for return values, data is a pointer to an array, not first element pointer */ + if (prop->flag & PROP_DYNAMIC_ARRAY) + data = *((char**)data); + switch (type) { case PROP_BOOLEAN: for(a=0; a Date: Sun, 12 Jul 2009 06:59:57 +0000 Subject: Added Action.get_frame_range returning a (min, max) pair or (0, 0) if there are no keys. --- release/io/export_fbx.py | 23 +++++++------ source/blender/makesrna/intern/rna_action_api.c | 45 ++++++++++++++++++++----- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 62c8e0daaaf..063a52b2f7d 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -2577,17 +2577,18 @@ Takes: {''') file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) else: file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) - - tmp = blenAction.getFrameNumbers() - if tmp: - act_start = min(tmp) - act_end = max(tmp) - del tmp - else: - # Fallback on this, theres not much else we can do? :/ - # when an action has no length - act_start = start - act_end = end + + act_start, act_end = blenAction.get_frame_range() +# tmp = blenAction.getFrameNumbers() +# if tmp: +# act_start = min(tmp) +# act_end = max(tmp) +# del tmp +# else: +# # Fallback on this, theres not much else we can do? :/ +# # when an action has no length +# act_start = start +# act_end = end # Set the action active for my_bone in ob_arms: diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c index b989d2d66a9..9f63d44f8ef 100644 --- a/source/blender/makesrna/intern/rna_action_api.c +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -36,13 +36,40 @@ #ifdef RNA_RUNTIME -int *rna_Action_get_frames(bAction *act, int *ret_length) +#include "DNA_anim_types.h" +#include "DNA_curve_types.h" + +/* return frame range of all curves (min, max) or (0, 0) if there are no keys */ +int *rna_Action_get_frame_range(bAction *act, int *ret_length) { - *ret_length= 3; - int *ret= MEM_callocN(*ret_length * sizeof(int), "action frames"); - ret[0] = 1; - ret[1] = 2; - ret[2] = 3; + FCurve *cu; + int *ret; + + *ret_length= 2; + ret= MEM_callocN(*ret_length * sizeof(int), "rna_Action_get_frame_range"); + + ret[0]= 0; + ret[1]= 0; + + for (cu= act->curves.first; cu; cu= cu->next) { + int verts= cu->totvert; + BezTriple *bezt= cu->bezt; + while (verts) { + int frame= (int)bezt->vec[1][0]; + + if (cu == act->curves.first && verts == cu->totvert) + ret[0]= ret[1]= frame; + + if (frame < ret[0]) + ret[0]= frame; + if (frame > ret[1]) + ret[1]= frame; + + bezt++; + verts--; + } + } + return ret; } @@ -53,9 +80,9 @@ void RNA_api_action(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func= RNA_def_function(srna, "get_frames", "rna_Action_get_frames"); - RNA_def_function_ui_description(func, "Get action frames."); /* XXX describe better */ - parm= RNA_def_int_array(func, "frames", 1, NULL, 0, 0, "", "", 0, 0); + func= RNA_def_function(srna, "get_frame_range", "rna_Action_get_frame_range"); + RNA_def_function_ui_description(func, "Get action frame range as a (min, max) tuple."); + parm= RNA_def_int_array(func, "frame_range", 1, NULL, 0, 0, "", "Action frame range.", 0, 0); RNA_def_property_flag(parm, PROP_DYNAMIC_ARRAY); RNA_def_function_return(func, parm); } -- cgit v1.2.3 From ffa5636a8b348d47d08b76644ec567d90cc9d3c5 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sun, 12 Jul 2009 07:20:49 +0000 Subject: Reusing existing blenkernel function calc_action_range for Action.get_frame_range. --- source/blender/makesrna/intern/rna_action_api.c | 29 +++++-------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c index 9f63d44f8ef..2b51a424fcf 100644 --- a/source/blender/makesrna/intern/rna_action_api.c +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -39,36 +39,19 @@ #include "DNA_anim_types.h" #include "DNA_curve_types.h" -/* return frame range of all curves (min, max) or (0, 0) if there are no keys */ +/* return frame range of all curves (min, max) or (0, 1) if there are no keys */ int *rna_Action_get_frame_range(bAction *act, int *ret_length) { - FCurve *cu; int *ret; + float start, end; + + calc_action_range(act, &start, &end, 1); *ret_length= 2; ret= MEM_callocN(*ret_length * sizeof(int), "rna_Action_get_frame_range"); - ret[0]= 0; - ret[1]= 0; - - for (cu= act->curves.first; cu; cu= cu->next) { - int verts= cu->totvert; - BezTriple *bezt= cu->bezt; - while (verts) { - int frame= (int)bezt->vec[1][0]; - - if (cu == act->curves.first && verts == cu->totvert) - ret[0]= ret[1]= frame; - - if (frame < ret[0]) - ret[0]= frame; - if (frame > ret[1]) - ret[1]= frame; - - bezt++; - verts--; - } - } + ret[0]= (int)start; + ret[1]= (int)end; return ret; } -- cgit v1.2.3 From fb150e12c560acd1418c106dbbe94f757731db09 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 13 Jul 2009 11:04:18 +0000 Subject: - FBX exporter conversion continued - added (uncommented actually) PoseChannel.pose_matrix - added Object.dag_update that calls DAG_object_flush_update. I'm not sure if it's needed, but FBX exporter uses it. --- release/io/export_fbx.py | 174 +++++++++++++++++------- source/blender/makesrna/intern/rna_object_api.c | 25 +++- source/blender/makesrna/intern/rna_pose.c | 9 +- 3 files changed, 147 insertions(+), 61 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 063a52b2f7d..0a6588c380b 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -37,12 +37,13 @@ http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx # -------------------------------------------------------------------------- import os +import time -try: - import time - # import os # only needed for batch export, nbot used yet -except: - time = None # use this to check if they have python modules installed +# try: +# import time +# # import os # only needed for batch export, nbot used yet +# except: +# time = None # use this to check if they have python modules installed # for python 2.3 support try: @@ -114,10 +115,41 @@ def copy_images(dest_dir, textures): print '\tCopied %d images' % copyCount -mtx4_identity = Matrix() +def BPyObject_getObjectArmature(ob): + ''' + This returns the first armature the mesh uses. + remember there can be more then 1 armature but most people dont do that. + ''' + if ob.type != 'MESH': + return None + + arm = ob.parent + if arm and arm.type == 'ARMATURE' and ob.parent_type == 'ARMATURE': + return arm + + for m in ob.modifiers: + if m.type== 'ARMATURE': + arm = m.object + if arm: + return arm + + return None + +# I guess FBX uses degrees instead of radians (Arystan). +# Call this function just before writing to FBX. +def eulerRadToDeg(eul): + ret = Mathutils.Euler() + + ret.x = 180 / math.pi * eul.x + ret.y = 180 / math.pi * eul.y + ret.z = 180 / math.pi * eul.z + + return ret + +mtx4_identity = Mathutils.Matrix() # testing -mtx_x90 = RotationMatrix( 90, 3, 'x') # used +mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'x') # used #mtx_x90n = RotationMatrix(-90, 3, 'x') #mtx_y90 = RotationMatrix( 90, 3, 'y') #mtx_y90n = RotationMatrix(-90, 3, 'y') @@ -125,14 +157,14 @@ mtx_x90 = RotationMatrix( 90, 3, 'x') # used #mtx_z90n = RotationMatrix(-90, 3, 'z') #mtx4_x90 = RotationMatrix( 90, 4, 'x') -mtx4_x90n = RotationMatrix(-90, 4, 'x') # used +mtx4_x90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'x') # used #mtx4_y90 = RotationMatrix( 90, 4, 'y') -mtx4_y90n = RotationMatrix(-90, 4, 'y') # used -mtx4_z90 = RotationMatrix( 90, 4, 'z') # used -mtx4_z90n = RotationMatrix(-90, 4, 'z') # used +mtx4_y90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'y') # used +mtx4_z90 = Mathutils.RotationMatrix( math.pi/2, 4, 'z') # used +mtx4_z90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'z') # used -def strip_path(p): - return p.split('\\')[-1].split('/')[-1] +# def strip_path(p): +# return p.split('\\')[-1].split('/')[-1] # Used to add the scene name into the filename without using odd chars sane_name_mapping_ob = {} @@ -212,7 +244,8 @@ def derived_paths(fname_orig, basepath, FORCE_CWD=False): ''' fname = bpy.sys.expandpath(fname_orig) # fname = Blender.sys.expandpath(fname_orig) - fname_strip = strip_path(fname) + fname_strip = os.path.basename(fname) +# fname_strip = strip_path(fname) if FORCE_CWD: fname_rel = '.' + os.sep + fname_strip else: @@ -265,7 +298,7 @@ def write(filename, batch_objects = None, \ EXP_CAMERA = True, EXP_EMPTY = True, EXP_IMAGE_COPY = False, - GLOBAL_MATRIX = Matrix(), + GLOBAL_MATRIX = Mathutils.Matrix(), ANIM_ENABLE = True, ANIM_OPTIMIZE = True, ANIM_OPTIMIZE_PRECISSION = 6, @@ -288,9 +321,11 @@ def write(filename, batch_objects = None, \ # tmp_exists = Blender.sys.exists(fbxpath) if tmp_exists != 2: # a file, we want a path - while fbxpath and fbxpath[-1] not in ('/', '\\'): - fbxpath = fbxpath[:-1] - if not filename: + fbxpath = os.path.dirname(fbxpath) +# while fbxpath and fbxpath[-1] not in ('/', '\\'): +# fbxpath = fbxpath[:-1] + if not fbxpath: +# if not filename: # XXX print('Error%t|Directory does not exist!') # Draw.PupMenu('Error%t|Directory does not exist!') @@ -391,7 +426,9 @@ def write(filename, batch_objects = None, \ # end batch support # Use this for working out paths relative to the export location - basepath = Blender.sys.dirname(filename) + basepath = os.path.dirname(filename) or '.' + basepath += os.sep +# basepath = Blender.sys.dirname(filename) # ---------------------------------------------- # storage classes @@ -429,7 +466,8 @@ def write(filename, batch_objects = None, \ # not public pose = fbxArm.blenObject.pose # pose = fbxArm.blenObject.getPose() - self.__pose_bone = pose.bones[self.blenName] + self.__pose_bone = pose.pose_channels[self.blenName] +# self.__pose_bone = pose.bones[self.blenName] # store a list if matricies here, (poseMatrix, head, tail) # {frame:posematrix, frame:posematrix, ...} @@ -452,8 +490,9 @@ def write(filename, batch_objects = None, \ self.__pose_bone.head.copy(),\ self.__pose_bone.tail.copy() ) ''' - - self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() + + self.__anim_poselist[f] = self.__pose_bone.pose_matrix.copy() +# self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() # get pose from frame. def getPoseMatrix(self, f):# ---------------------------------------------- @@ -521,11 +560,12 @@ def write(filename, batch_objects = None, \ matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() # Lamps need to be rotated - if type =='Lamp': + if type =='LAMP': matrix_rot = mtx_x90 * matrix_rot - elif ob and type =='Camera': + elif type =='CAMERA': +# elif ob and type =='Camera': y = Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) return matrix_rot @@ -627,7 +667,7 @@ def write(filename, batch_objects = None, \ rot = tuple(matrix_rot.toEuler()) elif ob and ob.type =='Camera': y = Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) rot = tuple(matrix_rot.toEuler()) else: rot = tuple(matrix_rot.toEuler()) @@ -648,7 +688,8 @@ def write(filename, batch_objects = None, \ loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) - file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % eulerRadToDeg(rot)) +# file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) return loc, rot, scale, matrix, matrix_rot @@ -735,7 +776,8 @@ def write(filename, batch_objects = None, \ Property: "Show", "bool", "",1 Property: "NegativePercentShapeSupport", "bool", "",1 Property: "DefaultAttributeIndex", "int", "",0''') - if ob and type(ob) != Blender.Types.BoneType: + if ob and not isinstance(ob, bpy.types.Bone): +# if ob and type(ob) != Blender.Types.BoneType: # Only mesh objects have color file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') file.write('\n\t\t\tProperty: "Size", "double", "",100') @@ -1214,7 +1256,8 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t}') file.write('\n\t}') - + + # tex is an Image (Arystan) def write_video(texname, tex): # Same as texture really! file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) @@ -1276,9 +1319,11 @@ def write(filename, batch_objects = None, \ Property: "UseMipMap", "bool", "",0 Property: "CurrentMappingType", "enum", "",0 Property: "UVSwap", "bool", "",0''') - - file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) - file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) + + file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clamp_x) +# file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) + file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clamp_y) +# file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) file.write(''' Property: "TextureRotationPivot", "Vector3D", "",0,0,0 @@ -1915,13 +1960,16 @@ def write(filename, batch_objects = None, \ else: # Mesh Type! if EXP_MESH_APPLY_MOD: - me = bpy.data.meshes.new() - me.getFromObject(ob) +# me = bpy.data.meshes.new() + me = ob.create_mesh('PREVIEW') +# me.getFromObject(ob) # so we keep the vert groups if EXP_ARMATURE: - orig_mesh = ob.getData(mesh=1) - if orig_mesh.getVertGroupNames(): + orig_mesh = ob.data +# orig_mesh = ob.getData(mesh=1) + if len(ob.vertex_groups): +# if orig_mesh.getVertGroupNames(): ob.copy().link(me) # If new mesh has no vgroups we can try add if verts are teh same if not me.getVertGroupNames(): # vgroups were not kept by the modifier @@ -1980,7 +2028,7 @@ def write(filename, batch_objects = None, \ materials[None, None] = None if EXP_ARMATURE: - armob = BPyObject.getObjectArmature(ob) + armob = BPyObject_getObjectArmature(ob) blenParentBoneName = None # parent bone - special case @@ -2014,14 +2062,17 @@ def write(filename, batch_objects = None, \ if EXP_ARMATURE: # now we have the meshes, restore the rest arm position for i, arm in enumerate(bpy.data.armatures): - arm.restPosition = ob_arms_orig_rest[i] + arm.rest_position = ob_arms_orig_rest[i] +# arm.restPosition = ob_arms_orig_rest[i] if ob_arms_orig_rest: for ob_base in bpy.data.objects: if ob_base.type == 'Armature': - ob_base.makeDisplayList() + ob_base.dag_update() +# ob_base.makeDisplayList() # This causes the makeDisplayList command to effect the mesh - Blender.Set('curframe', Blender.Get('curframe')) + sce.set_frame(sce.current_frame) +# Blender.Set('curframe', Blender.Get('curframe')) del tmp_ob_type, tmp_objects @@ -2032,7 +2083,11 @@ def write(filename, batch_objects = None, \ my_arm.fbxBones = [] my_arm.blenData = ob.data - my_arm.blenAction = ob.action + if ob.animation_data: + my_arm.blenAction = ob.animation_data.action + else: + my_arm.blenAction = None +# my_arm.blenAction = ob.action my_arm.blenActionList = [] # fbxName, blenderObject, my_bones, blenderActions @@ -2087,7 +2142,8 @@ def write(filename, batch_objects = None, \ # Build blenObject -> fbxObject mapping # this is needed for groups as well as fbxParenting - bpy.data.objects.tag = False + for ob in bpy.data.objects: ob.tag = False +# bpy.data.objects.tag = False tmp_obmapping = {} for ob_generic in ob_all_typegroups: for ob_base in ob_generic: @@ -2512,7 +2568,8 @@ Connections: {''') action_lastcompat = None if ANIM_ACTION_ALL: - bpy.data.actions.tag = False + for a in bpy.data.actions: a.tag = False +# bpy.data.actions.tag = False tmp_actions = list(bpy.data.actions) @@ -2528,8 +2585,9 @@ Connections: {''') arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) for action in tmp_actions: - - action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) + + action_chan_names = arm_bone_names.intersection( set([g.name for g in action.groups]) ) +# action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) if action_chan_names: # at least one channel matches. my_arm.blenActionList.append(action) @@ -2661,7 +2719,8 @@ Takes: {''') for mtx in context_bone_anim_mats: if prev_eul: prev_eul = mtx[1].toEuler(prev_eul) else: prev_eul = mtx[1].toEuler() - context_bone_anim_vecs.append(prev_eul) + context_bone_anim_vecs.append(eulerRadToDeg(prev_eul)) +# context_bone_anim_vecs.append(prev_eul) file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation @@ -2752,8 +2811,9 @@ Takes: {''') my_bone.blenObject.action = my_bone.blenAction file.write('\n}') - - Blender.Set('curframe', frame_orig) + + sce.set_frame(frame_orig) +# Blender.Set('curframe', frame_orig) else: # no animation @@ -2771,15 +2831,23 @@ Takes: {''') # Clear mesh data Only when writing with modifiers applied for me in meshes_to_clear: - me.verts = None + bpy.data.remove_mesh(me) +# me.verts = None # --------------------------- Footer if world: - has_mist = world.mode & 1 - mist_intense, mist_start, mist_end, mist_height = world.mist - world_hor = world.hor + m = world.mist + has_mist = m.enabled +# has_mist = world.mode & 1 + mist_intense = m.intensity + mist_start = m.start + mist_end = m.depth + mist_height = m.height +# mist_intense, mist_start, mist_end, mist_height = world.mist + world_hor = world.horizon_color +# world_hor = world.hor else: has_mist = mist_intense = mist_start = mist_end = mist_height = 0 world_hor = 0,0,0 @@ -3146,6 +3214,8 @@ if __name__ == '__main__': # - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print # - get rid of cleanName somehow # - isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 +# - get rid of BPyObject_getObjectArmature, move it in RNA? +# - BATCH_ENABLE and BATCH_GROUP options: line 327 # TODO diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 02db7e83062..bf1fb6d2b6a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -166,6 +166,11 @@ static void rna_Object_add_vertex_to_group(Object *ob, int vertex_index, bDeform add_vert_to_defgroup(ob, def, vertex_index, weight, assignmode); } +static void rna_Object_dag_update(Object *ob, bContext *C) +{ + DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA); +} + /* static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) { @@ -222,6 +227,7 @@ void RNA_api_object(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + /* mesh */ 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."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); @@ -230,6 +236,13 @@ void RNA_api_object(StructRNA *srna) 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, "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); + + /* duplis */ 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); @@ -238,12 +251,7 @@ void RNA_api_object(StructRNA *srna) 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); - + /* vertex groups */ func= RNA_def_function(srna, "add_vertex_group", "rna_Object_add_vertex_group"); RNA_def_function_ui_description(func, "Add vertex group to object."); parm= RNA_def_string(func, "name", "Group", 0, "", "Vertex group name."); /* optional */ @@ -260,6 +268,11 @@ void RNA_api_object(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode."); RNA_def_property_flag(parm, PROP_REQUIRED); + + /* DAG */ + func= RNA_def_function(srna, "dag_update", "rna_Object_dag_update"); + RNA_def_function_ui_description(func, "DAG update."); /* XXX describe better */ + RNA_def_function_flag(func, FUNC_USE_CONTEXT); } #endif diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index b8863540bdf..2561322b9a2 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -181,15 +181,18 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints.");*/ /* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */ -/* prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_struct_type(prop, "pose_mat"); + prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, "pose_mat"); + RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Pose Matrix", "Final 4x4 matrix for this channel."); + /* prop= RNA_def_property(srna, "constraint_inverse_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_struct_type(prop, "constinv"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Constraint Inverse Matrix", "4x4 matrix, defines transform from final position to unconstrained position."); */ + RNA_def_property_ui_text(prop, "Constraint Inverse Matrix", "4x4 matrix, defines transform from final position to unconstrained position."); + */ prop= RNA_def_property(srna, "pose_head", PROP_FLOAT, PROP_VECTOR); RNA_def_property_clear_flag(prop, PROP_EDITABLE); -- cgit v1.2.3 From 73ad2d320cca8c34d7901630dd8c6223ba4cd4a3 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 16 Jul 2009 08:20:15 +0000 Subject: More FBX exporter conversion. Experimenting with cross-compiling my branch with MinGW on Linux: - tweaked config/linuxcross.py, source/blender/makesdna/intern/SConscript and tools/Blender.py So far linking fails. --- config/linuxcross-config.py | 47 +++++-- release/io/export_fbx.py | 196 +++++++++++++++++++++++------- release/io/export_obj.py | 8 +- source/blender/makesdna/intern/SConscript | 2 +- source/blender/makesrna/intern/rna_pose.c | 2 +- tools/Blender.py | 6 +- 6 files changed, 198 insertions(+), 63 deletions(-) diff --git a/config/linuxcross-config.py b/config/linuxcross-config.py index 5e5c44ecd69..5253110be66 100644 --- a/config/linuxcross-config.py +++ b/config/linuxcross-config.py @@ -2,13 +2,13 @@ LCGDIR = '#../lib/windows' LIBDIR = '${LCGDIR}' BF_PYTHON = LIBDIR + '/python' -BF_PYTHON_VERSION = '2.5' +BF_PYTHON_VERSION = '2.6' BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' -BF_PYTHON_LIB = 'python25' +BF_PYTHON_LIB = 'python26' BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' -WITH_BF_OPENAL = True +WITH_BF_OPENAL = False # XXX (Arystan) WITH_BF_STATICOPENAL = False BF_OPENAL = LIBDIR + '/openal' BF_OPENAL_INC = '${BF_OPENAL}/include' @@ -17,6 +17,12 @@ BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' # Warning, this static lib configuration is untested! users of this OS please confirm. BF_OPENAL_LIB_STATIC = '${BF_OPENAL}/lib/libopenal.a' +# copied from win32-mingw-config.py (Arystan) +WITH_BF_FFMPEG = False +BF_FFMPEG_LIB = 'avformat swscale avcodec avutil avdevice xvidcore x264' +BF_FFMPEG_LIBPATH = LIBDIR + '/gcc/ffmpeg/lib' +BF_FFMPEG_INC = LIBDIR + '/gcc/ffmpeg/include' + # Warning, this static lib configuration is untested! users of this OS please confirm. BF_CXX = '/usr' WITH_BF_STATICCXX = False @@ -33,7 +39,7 @@ BF_PTHREADS_INC = '${BF_PTHREADS}/include' BF_PTHREADS_LIB = 'pthreadGC2' BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib' -WITH_BF_OPENEXR = True +WITH_BF_OPENEXR = False WITH_BF_STATICOPENEXR = False BF_OPENEXR = LIBDIR + '/gcc/openexr' BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR' @@ -58,6 +64,8 @@ BF_PNG_LIBPATH = '${BF_PNG}/lib' BF_TIFF = LIBDIR + '/tiff' BF_TIFF_INC = '${BF_TIFF}/include' +BF_TIFF_LIB = 'libtiff' +BF_TIFF_LIBPATH = '${BF_TIFF}/lib' WITH_BF_ZLIB = True BF_ZLIB = LIBDIR + '/zlib' @@ -69,16 +77,26 @@ WITH_BF_INTERNATIONAL = True BF_GETTEXT = LIBDIR + '/gettext' BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gnu_gettext' +BF_GETTEXT_LIB = 'gettextlib' +# BF_GETTEXT_LIB = 'gnu_gettext' BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' WITH_BF_GAMEENGINE = False +WITH_BF_ODE = True +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + WITH_BF_BULLET = True BF_BULLET = '#extern/bullet2/src' BF_BULLET_INC = '${BF_BULLET}' BF_BULLET_LIB = 'extern_bullet' +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + BF_WINTAB = LIBDIR + '/wintab' BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE' @@ -100,9 +118,12 @@ BF_ICONV_LIBPATH = '${BF_ICONV}/lib' # Mesa Libs should go here if your using them as well.... WITH_BF_STATICOPENGL = False -BF_OPENGL = 'C:\\MingW' -BF_OPENGL_INC = '${BF_OPENGL}/include' -BF_OPENGL_LIBINC = '${BF_OPENGL}/lib' +BF_OPENGL = '' +# BF_OPENGL = 'C:\\MingW' +BF_OPENGL_INC = '' +# BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIBINC = '' +# BF_OPENGL_LIBINC = '${BF_OPENGL}/lib' BF_OPENGL_LIB = 'opengl32 glu32' BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a', '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a', @@ -111,9 +132,13 @@ BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a' CC = 'i586-mingw32msvc-gcc' CXX = 'i586-mingw32msvc-g++' +# Custom built MinGW (Arystan) +# CC = 'i586-pc-mingw32-gcc' +# CXX = 'i586-pc-mingw32-g++' + CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ] -CPPFLAGS = [ '-DXP_UNIX', '-DWIN32', '-DFREE_WINDOWS' ] +CPPFLAGS = [ '-DXP_UNIX', '-DWIN32', '-DFREE_WINDOWS', '-DLINUX_CROSS' ] CXXFLAGS = ['-pipe', '-mwindows', '-funsigned-char', '-fno-strict-aliasing' ] REL_CFLAGS = [ '-O2' ] REL_CCFLAGS = [ '-O2' ] @@ -122,7 +147,7 @@ C_WARN = [ '-Wall' , '-Wno-char-subscripts', '-Wdeclaration-after-statement' ] CC_WARN = [ '-Wall' ] -LLIBS = [ '-ldxguid', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz'] #'-lutil', '-lc', '-lm', '-ldl', '-lpthread' ] +LLIBS = [ '-ldxguid', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++'] #'-lutil', '-lc', '-lm', '-ldl', '-lpthread' ] BF_DEBUG = False BF_DEBUG_CCFLAGS= [] @@ -134,3 +159,5 @@ BF_PROFILE_LINKFLAGS = ['-pg'] BF_BUILDDIR = '../build/linuxcross' BF_INSTALLDIR='../install/linuxcross' BF_DOCDIR='../install/doc' + +# LINKFLAGS = ['-Wl,--start-group'] diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 0a6588c380b..c4f56b472dc 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -60,9 +60,10 @@ except: # except: # os = None -import Blender +# import Blender import bpy -from Blender.Mathutils import Matrix, Vector, RotationMatrix +import Mathutils +# from Blender.Mathutils import Matrix, Vector, RotationMatrix import BPyObject import BPyMesh @@ -258,9 +259,48 @@ def derived_paths(fname_orig, basepath, FORCE_CWD=False): def mat4x4str(mat): return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) +# XXX not used +# duplicated in OBJ exporter +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 + +# ob must be OB_MESH +def BPyMesh_meshWeight2List(ob): + ''' Takes a mesh and return its group names and a list of lists, one list per vertex. + aligning the each vert list with the group names, each list contains float value for the weight. + These 2 lists can be modified and then used with list2MeshWeight to apply the changes. + ''' + + me = ob.data + + # Clear the vert group. + groupNames= [g.name for g in ob.vertex_groups] + len_groupNames= len(groupNames) + + if not len_groupNames: + # no verts? return a vert aligned empty list + return [[] for i in xrange(len(me.verts))], [] + else: + vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))] + + for i, v in enumerate(me.verts): + for g in v.groups: + vWeightList[i][g.group] = g.weight + + return groupNames, vWeightList + + def meshNormalizedWeights(me): try: # account for old bad BPyMesh - groupNames, vWeightList = BPyMesh.meshWeight2List(me) + groupNames, vWeightList = BPyMesh_meshWeight2List(me) +# groupNames, vWeightList = BPyMesh.meshWeight2List(me) except: return [],[] @@ -564,7 +604,7 @@ def write(filename, batch_objects = None, \ matrix_rot = mtx_x90 * matrix_rot elif type =='CAMERA': # elif ob and type =='Camera': - y = Vector(0,1,0) * matrix_rot + y = Mathutils.Vector(0,1,0) * matrix_rot matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) return matrix_rot @@ -666,7 +706,7 @@ def write(filename, batch_objects = None, \ matrix_rot = mtx_x90 * matrix_rot rot = tuple(matrix_rot.toEuler()) elif ob and ob.type =='Camera': - y = Vector(0,1,0) * matrix_rot + y = Mathutils.Vector(0,1,0) * matrix_rot matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) rot = tuple(matrix_rot.toEuler()) else: @@ -1052,8 +1092,8 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tTypeFlags: "Camera"') file.write('\n\t\tGeometryVersion: 124') file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) - file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) ) - file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) ) + file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,1,0) * matrix_rot) ) + file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,0,-1)*matrix_rot) ) #file.write('\n\t\tUp: 0,0,0' ) #file.write('\n\t\tLookAt: 0,0,0' ) @@ -1458,7 +1498,8 @@ def write(filename, batch_objects = None, \ if my_mesh.blenTextures: do_textures = True else: do_textures = False - do_uvs = me.faceUV + do_uvs = len(me.uv_layers) > 0 +# do_uvs = me.faceUV file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) @@ -1490,20 +1531,24 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tPolygonVertexIndex: ') i=-1 for f in me.faces: - fi = [v.index for v in f] + fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3] +# fi = [v.index for v in f] + # flip the last index, odd but it looks like # this is how fbx tells one face from another fi[-1] = -(fi[-1]+1) fi = tuple(fi) if i==-1: - if len(f) == 3: file.write('%i,%i,%i' % fi ) + if len(fi) == 3: file.write('%i,%i,%i' % fi ) +# if len(f) == 3: file.write('%i,%i,%i' % fi ) else: file.write('%i,%i,%i,%i' % fi ) i=0 else: if i==13: file.write('\n\t\t') i=0 - if len(f) == 3: file.write(',%i,%i,%i' % fi ) + if len(fi) == 3: file.write(',%i,%i,%i' % fi ) +# if len(f) == 3: file.write(',%i,%i,%i' % fi ) else: file.write(',%i,%i,%i,%i' % fi ) i+=1 @@ -1511,13 +1556,15 @@ def write(filename, batch_objects = None, \ i=-1 for ed in me.edges: if i==-1: - file.write('%i,%i' % (ed.v1.index, ed.v2.index)) + file.write('%i,%i' % (ed.verts[0], ed.verts[1])) +# file.write('%i,%i' % (ed.v1.index, ed.v2.index)) i=0 else: if i==13: file.write('\n\t\t') i=0 - file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) + file.write(',%i,%i' % (ed.verts[0], ed.verts[1])) +# file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) i+=1 file.write('\n\t\tGeometryVersion: 124') @@ -1533,11 +1580,13 @@ def write(filename, batch_objects = None, \ i=-1 for v in me.verts: if i==-1: - file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + file.write('%.15f,%.15f,%.15f' % tuple(v.normal)); i=0 +# file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 else: if i==2: file.write('\n '); i=0 - file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + file.write(',%.15f,%.15f,%.15f' % tuple(v.normal)) +# file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) i+=1 file.write('\n\t\t}') @@ -1571,32 +1620,49 @@ def write(filename, batch_objects = None, \ ReferenceInformationType: "Direct" Smoothing: ''') - SHARP = Blender.Mesh.EdgeFlags.SHARP +# SHARP = Blender.Mesh.EdgeFlags.SHARP i=-1 for ed in me.edges: if i==-1: - file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 + file.write('%i' % (ed.sharp)); i=0 +# file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 else: if i==54: file.write('\n '); i=0 - file.write(',%i' % ((ed.flag&SHARP)!=0)) + file.write(',%i' % (ed.sharp)) +# file.write(',%i' % ((ed.flag&SHARP)!=0)) i+=1 file.write('\n\t\t}') - del SHARP - +# del SHARP + + # small utility function + # returns a slice of data depending on number of face verts + # data is either a MeshTextureFace or MeshColor + def face_data(data, face): + if f.verts[3] == 0: + totvert = 3 + else: + totvert = 4 + + return data[:totvert] + # Write VertexColor Layers # note, no programs seem to use this info :/ collayers = [] - if me.vertexColors: - collayers = me.getColorLayerNames() - collayer_orig = me.activeColorLayer + if len(me.vertex_colors): +# if me.vertexColors: + collayers = me.vertex_colors +# collayers = me.getColorLayerNames() + collayer_orig = me.active_vertex_color +# collayer_orig = me.activeColorLayer for colindex, collayer in enumerate(collayers): - me.activeColorLayer = collayer +# me.activeColorLayer = collayer file.write('\n\t\tLayerElementColor: %i {' % colindex) file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % collayer) + file.write('\n\t\t\tName: "%s"' % collayer.name) +# file.write('\n\t\t\tName: "%s"' % collayer) file.write(''' MappingInformationType: "ByPolygonVertex" @@ -1605,19 +1671,37 @@ def write(filename, batch_objects = None, \ i = -1 ii = 0 # Count how many Colors we write - - for f in me.faces: - for col in f.col: + + for f, cf in zip(me.faces, collayer.data): + colors = [cf.color1, cf.color2, cf.color3, cf.color4] + + # determine number of verts + colors = face_data(colors, f) + + for col in colors: if i==-1: - file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) + file.write('%.4f,%.4f,%.4f,1' % tuple(col)) i=0 else: if i==7: file.write('\n\t\t\t\t') i=0 - file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) + file.write(',%.4f,%.4f,%.4f,1' % tuple(col)) i+=1 ii+=1 # One more Color + +# for f in me.faces: +# for col in f.col: +# if i==-1: +# file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) +# i=0 +# else: +# if i==7: +# file.write('\n\t\t\t\t') +# i=0 +# file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) +# i+=1 +# ii+=1 # One more Color file.write('\n\t\t\tColorIndex: ') i = -1 @@ -1639,13 +1723,17 @@ def write(filename, batch_objects = None, \ # Write UV and texture layers. uvlayers = [] if do_uvs: - uvlayers = me.getUVLayerNames() - uvlayer_orig = me.activeUVLayer - for uvindex, uvlayer in enumerate(uvlayers): - me.activeUVLayer = uvlayer + uvlayers = me.uv_textures +# uvlayers = me.getUVLayerNames() + uvlayer_orig = me.active_uv_texture +# uvlayer_orig = me.activeUVLayer + for uvindex, uvlayer in enumerate(me.uv_textures): +# for uvindex, uvlayer in enumerate(uvlayers): +# me.activeUVLayer = uvlayer file.write('\n\t\tLayerElementUV: %i {' % uvindex) file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer) + file.write('\n\t\t\tName: "%s"' % uvlayer.name) +# file.write('\n\t\t\tName: "%s"' % uvlayer) file.write(''' MappingInformationType: "ByPolygonVertex" @@ -1655,8 +1743,13 @@ def write(filename, batch_objects = None, \ i = -1 ii = 0 # Count how many UVs we write - for f in me.faces: - for uv in f.uv: + for f, uf in zip(me.faces, uvlayer.data): +# for f in me.faces: + uvs = [uf.uv1, uf.uv2, uf.uv3, uf.uv4] + uvs = face_data(uvs, f) + + for uv in uvs: +# for uv in f.uv: if i==-1: file.write('%.6f,%.6f' % tuple(uv)) i=0 @@ -1686,7 +1779,8 @@ def write(filename, batch_objects = None, \ if do_textures: file.write('\n\t\tLayerElementTexture: %i {' % uvindex) file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer) + file.write('\n\t\t\tName: "%s"' % uvlayer.name) +# file.write('\n\t\t\tName: "%s"' % uvlayer) if len(my_mesh.blenTextures) == 1: file.write('\n\t\t\tMappingInformationType: "AllSame"') @@ -1710,7 +1804,8 @@ def write(filename, batch_objects = None, \ i+=1 i=-1 - for f in me.faces: + for f in uvlayer.data: +# for f in me.faces: img_key = f.image if i==-1: @@ -1736,7 +1831,7 @@ def write(filename, batch_objects = None, \ TextureId: ''') file.write('\n\t\t}') - me.activeUVLayer = uvlayer_orig +# me.activeUVLayer = uvlayer_orig # Done with UV/textures. @@ -1765,13 +1860,21 @@ def write(filename, batch_objects = None, \ len_material_mapping_local = len(material_mapping_local) mats = my_mesh.blenMaterialList + + if me.active_uv_texture: + uv_faces = me.active_uv_texture.data + else: + uv_faces = [None] * len(me.faces) i=-1 - for f in me.faces: - try: mat = mats[f.mat] + for f, uf in zip(me.faces, uv_faces) +# for f in me.faces: + try: mat = mats[f.material_index] +# try: mat = mats[f.mat] except:mat = None - if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ + if do_uvs: tex = uf.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ +# if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ else: tex = None if i==-1: @@ -1810,7 +1913,8 @@ def write(filename, batch_objects = None, \ TypedIndex: 0 }''') - if me.vertexColors: + if me.vertex_colors: +# if me.vertexColors: file.write(''' LayerElement: { Type: "LayerElementColor" @@ -2331,7 +2435,8 @@ Objects: {''') if my_mesh.fbxBoneParent: weights = None else: - weights = meshNormalizedWeights(my_mesh.blenData) + weights = meshNormalizedWeights(my_mesh.blenObject) +# weights = meshNormalizedWeights(my_mesh.blenData) #for bonename, bone, obname, bone_mesh, armob in ob_bones: for my_bone in ob_bones: @@ -3216,6 +3321,7 @@ if __name__ == '__main__': # - isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 # - get rid of BPyObject_getObjectArmature, move it in RNA? # - BATCH_ENABLE and BATCH_GROUP options: line 327 +# - implement all BPyMesh_* used here with RNA # TODO diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 466fb2f2362..70be6bb541b 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -434,7 +434,7 @@ def write(filename, objects, scene, # continue if EXPORT_UV: - faceuv = len(me.uv_layers) > 0 + faceuv = len(me.uv_textures) > 0 else: faceuv = False @@ -508,7 +508,7 @@ def write(filename, objects, scene, pass elif faceuv: # XXX update - tface = me.active_uv_layer.data + tface = me.active_uv_texture.data # exception only raised if Python 2.3 or lower... try: @@ -570,7 +570,7 @@ def write(filename, objects, scene, 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 + uv_layer = me.active_uv_texture for f, f_index in face_index_pairs: tface = uv_layer.data[f_index] @@ -652,7 +652,7 @@ def write(filename, objects, scene, # f_mat = min(f.mat, len(materialNames)-1) if faceuv: - tface = me.active_uv_layer.data[face_index_pairs[f_index][1]] + tface = me.active_uv_texture.data[face_index_pairs[f_index][1]] f_image = tface.image f_uv= [tface.uv1, tface.uv2, tface.uv3] diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript index 1c716019e80..9089718da83 100644 --- a/source/blender/makesdna/intern/SConscript +++ b/source/blender/makesdna/intern/SConscript @@ -61,6 +61,6 @@ if env['OURPLATFORM'] != 'linuxcross': else: dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET") else: - dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET") + dna.Command ('dna.c', '', 'wine ' + root_build_dir+os.sep+"makesdna.exe $TARGET") obj = ['intern/dna.c', 'intern/dna_genfile.c'] Return ('obj') diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 2561322b9a2..12822024654 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -182,7 +182,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) /* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */ prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_float_sdna(prop, "pose_mat"); + RNA_def_property_float_sdna(prop, NULL, "pose_mat"); RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Pose Matrix", "Final 4x4 matrix for this channel."); diff --git a/tools/Blender.py b/tools/Blender.py index 164a9d097e6..8866df2c0ae 100644 --- a/tools/Blender.py +++ b/tools/Blender.py @@ -112,7 +112,6 @@ def setup_staticlibs(lenv): #here libs for static linking ] libincs = [ - '/usr/lib', lenv['BF_OPENGL_LIBPATH'], lenv['BF_JPEG_LIBPATH'], lenv['BF_PNG_LIBPATH'], @@ -120,6 +119,9 @@ def setup_staticlibs(lenv): lenv['BF_ICONV_LIBPATH'] ] + if lenv['OURPLATFORM'] != 'linuxcross': + libincs = ['/usr/lib'] + libincs + libincs += Split(lenv['BF_FREETYPE_LIBPATH']) if lenv['WITH_BF_PYTHON']: libincs += Split(lenv['BF_PYTHON_LIBPATH']) @@ -223,7 +225,7 @@ def buildinfo(lenv, build_type): obj = [] if lenv['BF_BUILDINFO']: - if sys.platform=='win32': + if sys.platform=='win32' or lenv['OURPLATFORM']=='linuxcross': build_info_file = open("source/creator/winbuildinfo.h", 'w') build_info_file.write("char *build_date=\"%s\";\n"%build_date) build_info_file.write("char *build_time=\"%s\";\n"%build_time) -- cgit v1.2.3 From aede14d4e08b953e0e300c9992776f191e9fd94d Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 16 Jul 2009 13:19:43 +0000 Subject: - replaced Object.create_mesh body with 2.4x API's Mesh.createFromObject code to also support curves, surfaces and metaballs. - replaced Object.dag_update with Object.make_display_list, which copies old API's Object.makeDisplayList --- release/io/export_fbx.py | 47 +++-- release/io/export_obj.py | 9 +- source/blender/makesrna/intern/rna_object_api.c | 233 +++++++++++++++++++----- 3 files changed, 224 insertions(+), 65 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index c4f56b472dc..d74e6246104 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -2019,41 +2019,60 @@ def write(filename, batch_objects = None, \ # This is needed so applying modifiers dosnt apply the armature deformation, its also needed # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. # set every armature to its rest, backup the original values so we done mess up the scene - ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] + ob_arms_orig_rest = [arm.rest_position for arm in bpy.data.armatures] +# ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] for arm in bpy.data.armatures: - arm.restPosition = True + arm.rest_position = True +# arm.restPosition = True if ob_arms_orig_rest: for ob_base in bpy.data.objects: #if ob_base.type == 'Armature': - ob_base.makeDisplayList() + ob_base.make_display_list() +# ob_base.makeDisplayList() # This causes the makeDisplayList command to effect the mesh - Blender.Set('curframe', Blender.Get('curframe')) + sce.set_frame(sce.current_frame) +# Blender.Set('curframe', Blender.Get('curframe')) for ob_base in tmp_objects: - for ob, mtx in BPyObject.getDerivedObjects(ob_base): - #for ob in [ob_base,]: + + # ignore dupli children + if ob_base.parent and ob_base.parent.dupli_type != 'NONE': + continue + + obs = [(ob_base, ob_base.matrix)] + if ob_base.dupli_type != 'NONE': + ob_base.create_dupli_list() + obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list] + + for ob, mtx in obs: +# for ob, mtx in BPyObject.getDerivedObjects(ob_base): tmp_ob_type = ob.type - if tmp_ob_type == 'Camera': + if tmp_ob_type == 'CAMERA': +# if tmp_ob_type == 'Camera': if EXP_CAMERA: ob_cameras.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'Lamp': + elif tmp_ob_type == 'LAMP': +# elif tmp_ob_type == 'Lamp': if EXP_LAMP: ob_lights.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'Armature': + elif tmp_ob_type == 'ARMATURE': +# elif tmp_ob_type == 'Armature': if EXP_ARMATURE: # TODO - armatures dont work in dupligroups! if ob not in ob_arms: ob_arms.append(ob) # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" - elif tmp_ob_type == 'Empty': + elif tmp_ob_type == 'EMPTY': +# elif tmp_ob_type == 'Empty': if EXP_EMPTY: ob_null.append(my_object_generic(ob, mtx)) elif EXP_MESH: origData = True - if tmp_ob_type != 'Mesh': + if tmp_ob_type != 'MESH': +# if tmp_ob_type != 'Mesh': me = bpy.data.meshes.new() try: me.getFromObject(ob) except: me = None @@ -2171,8 +2190,9 @@ def write(filename, batch_objects = None, \ if ob_arms_orig_rest: for ob_base in bpy.data.objects: - if ob_base.type == 'Armature': - ob_base.dag_update() + if ob_base.type == 'ARMATURE': +# if ob_base.type == 'Armature': + ob_base.make_display_list() # ob_base.makeDisplayList() # This causes the makeDisplayList command to effect the mesh sce.set_frame(sce.current_frame) @@ -3322,6 +3342,7 @@ if __name__ == '__main__': # - get rid of BPyObject_getObjectArmature, move it in RNA? # - BATCH_ENABLE and BATCH_GROUP options: line 327 # - implement all BPyMesh_* used here with RNA +# - getDerivedObjects is not fully replicated with .dupli* funcs # TODO diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 70be6bb541b..251fdfcf113 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -380,11 +380,6 @@ def write(filename, objects, scene, # 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 @@ -393,6 +388,10 @@ def write(filename, objects, scene, obs = [] if ob_main.dupli_type != 'NONE': + # XXX + print('creating dupli_list on', ob_main.name) + ob_main.create_dupli_list() + obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list] # XXX debug print diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index bf1fb6d2b6a..bae651bf806 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -40,62 +40,190 @@ #include "ED_mesh.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_main.h" +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_object.h" +#include "BKE_mesh.h" #include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" #include "BKE_anim.h" -#include "BKE_report.h" #include "BKE_depsgraph.h" +#include "BKE_displist.h" +#include "BKE_font.h" +#include "BKE_mball.h" + +#include "BLI_arithb.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" +#include "DNA_curve_types.h" -#include "BLI_arithb.h" +#include "MEM_guardedalloc.h" -/* copied from init_render_mesh (render code) */ -static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports, int type) +/* copied from Mesh_getFromObject and adapted to RNA interface */ +/* settings: 0 - preview, 1 - render */ +static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports, int apply_modifiers, int settings) { - /* 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); + Mesh *tmpmesh; + Curve *tmpcu = NULL; + Object *tmpobj = NULL; + int render = settings, i; + int cage = !apply_modifiers; + Scene *sce = CTX_data_scene(C); + + /* perform the mesh extraction based on type */ + switch (ob->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + + /* copies object and modifiers (but not the data) */ + tmpobj= copy_object(ob); + tmpcu = (Curve *)tmpobj->data; + tmpcu->id.us--; + + /* if getting the original caged mesh, delete object modifiers */ + if( cage ) + object_free_modifiers(tmpobj); + + /* copies the data */ + tmpobj->data = copy_curve( (Curve *) ob->data ); + +#if 0 + /* copy_curve() sets disp.first null, so currently not need */ + { + Curve *cu; + cu = (Curve *)tmpobj->data; + if( cu->disp.first ) + MEM_freeN( cu->disp.first ); + cu->disp.first = NULL; + } - /* TODO: other types */ - if(ob->type != OB_MESH) { - BKE_report(reports, RPT_ERROR, "Object should be of type MESH."); - return NULL; - } +#endif - if (type == CREATE_MESH_PREVIEW) { - dm= mesh_create_derived_view(sce, ob, mask); - } - else { - dm= mesh_create_derived_render(sce, ob, mask); - } + /* get updated display list, and convert to a mesh */ + makeDispListCurveTypes( sce, tmpobj, 0 ); + nurbs_to_mesh( tmpobj ); + + /* nurbs_to_mesh changes the type to a mesh, check it worked */ + if (tmpobj->type != OB_MESH) { + free_libblock_us( &G.main->object, tmpobj ); + BKE_report(reports, RPT_ERROR, "cant convert curve to mesh. Does the curve have any segments?"); + return NULL; + } + tmpmesh = tmpobj->data; + free_libblock_us( &G.main->object, tmpobj ); + break; + + case OB_MBALL: + /* metaballs don't have modifiers, so just convert to mesh */ + ob = find_basis_mball( sce, ob ); + tmpmesh = add_mesh("Mesh"); + mball_to_mesh( &ob->disp, tmpmesh ); + break; + + case OB_MESH: + /* copies object and modifiers (but not the data) */ + if (cage) { + /* copies the data */ + tmpmesh = copy_mesh( ob->data ); + /* if not getting the original caged mesh, get final derived mesh */ + } else { + /* Make a dummy mesh, saves copying */ + DerivedMesh *dm; + /* 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 */ + + /* Write the display mesh into the dummy mesh */ + if (render) + dm = mesh_create_derived_render( sce, ob, mask ); + else + dm = mesh_create_derived_view( sce, ob, mask ); + + tmpmesh = add_mesh( "Mesh" ); + DM_to_mesh( dm, tmpmesh ); + dm->release( dm ); + } + + break; + default: + BKE_report(reports, RPT_ERROR, "Object does not have geometry data"); + return NULL; + } + + /* Copy materials to new mesh */ + switch (ob->type) { + case OB_SURF: + tmpmesh->totcol = tmpcu->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpcu->mat ) { + for( i = tmpcu->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + if (ob->colbits & 1<mat[i] = ob->mat[i]; + else + tmpmesh->mat[i] = tmpcu->mat[i]; + + if (tmpmesh->mat[i]) + tmpmesh->mat[i]->id.us++; + } + } + break; + +#if 0 + /* Crashes when assigning the new material, not sure why */ + case OB_MBALL: + tmpmb = (MetaBall *)ob->data; + tmpmesh->totcol = tmpmb->totcol; + + /* free old material list (if it exists) and adjust user counts */ + if( tmpmb->mat ) { + for( i = tmpmb->totcol; i-- > 0; ) { + tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */ + if (tmpmesh->mat[i]) { + tmpmb->mat[i]->id.us++; + } + } + } + break; +#endif - if(!dm) { - /* TODO: report */ - return NULL; - } + case OB_MESH: + if (!cage) { + Mesh *origmesh= ob->data; + tmpmesh->flag= origmesh->flag; + tmpmesh->mat = MEM_dupallocN(origmesh->mat); + tmpmesh->totcol = origmesh->totcol; + tmpmesh->smoothresh= origmesh->smoothresh; + if( origmesh->mat ) { + for( i = origmesh->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + if (ob->colbits & 1<mat[i] = ob->mat[i]; + else + tmpmesh->mat[i] = origmesh->mat[i]; + if (tmpmesh->mat[i]) + tmpmesh->mat[i]->id.us++; + } + } + } + break; + } /* end copy materials */ - me= add_mesh("tmp_render_mesh"); - me->id.us--; /* we don't assign it to anything */ - DM_to_mesh(dm, me); - dm->release(dm); + /* we don't assign it to anything */ + tmpmesh->id.us--; + + /* make sure materials get updated in objects */ + test_object_materials( ( ID * ) tmpmesh ); - return me; + return tmpmesh; } /* When no longer needed, duplilist should be freed with Object.free_duplilist */ @@ -166,9 +294,18 @@ static void rna_Object_add_vertex_to_group(Object *ob, int vertex_index, bDeform add_vert_to_defgroup(ob, def, vertex_index, weight, assignmode); } -static void rna_Object_dag_update(Object *ob, bContext *C) +/* copied from old API Object.makeDisplayList (Object.c) */ +static void rna_Object_make_display_list(Object *ob, bContext *C) { - DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA); + Scene *sce= CTX_data_scene(C); + + if (ob->type == OB_FONT) { + Curve *cu = ob->data; + freedisplist(&cu->disp); + BKE_text_to_curve(sce, ob, CU_LEFT); + } + + DAG_object_flush_update(sce, ob, OB_RECALC_DATA); } /* @@ -215,8 +352,8 @@ void RNA_api_object(StructRNA *srna) PropertyRNA *parm; static EnumPropertyItem mesh_type_items[] = { - {CREATE_MESH_PREVIEW, "PREVIEW", 0, "Preview", "Apply preview settings."}, - {CREATE_MESH_RENDER, "RENDER", 0, "Render", "Apply render settings."}, + {0, "PREVIEW", 0, "Preview", "Apply modifier preview settings."}, + {1, "RENDER", 0, "Render", "Apply modifier render settings."}, {0, NULL, 0, NULL, NULL} }; @@ -229,9 +366,11 @@ void RNA_api_object(StructRNA *srna) /* mesh */ 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."); + RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied."); 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_boolean(func, "apply_modifiers", 0, "", "Apply modifiers."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "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); @@ -270,8 +409,8 @@ void RNA_api_object(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); /* DAG */ - func= RNA_def_function(srna, "dag_update", "rna_Object_dag_update"); - RNA_def_function_ui_description(func, "DAG update."); /* XXX describe better */ + func= RNA_def_function(srna, "make_display_list", "rna_Object_make_display_list"); + RNA_def_function_ui_description(func, "Update object's display data."); /* XXX describe better */ RNA_def_function_flag(func, FUNC_USE_CONTEXT); } -- cgit v1.2.3 From 140f2b154f0a68cfe0ff6c42de8102883cd0958a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 16 Jul 2009 19:07:54 +0000 Subject: Reverted BF_GETTEXT_LIB in config/linuxcross-config.py to previous value. Cross-compiling works! Started a wiki page describing the process here: http://wiki.blender.org/index.php/User:Kazanbas/Cross-compiling_Blender_2.5_on_Linux TODO: - make scons copy DLLs to install directory - deal with python: which version, what to install, etc. - package up into .msi? --- config/linuxcross-config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/linuxcross-config.py b/config/linuxcross-config.py index 5253110be66..8bc1391db6d 100644 --- a/config/linuxcross-config.py +++ b/config/linuxcross-config.py @@ -77,7 +77,7 @@ WITH_BF_INTERNATIONAL = True BF_GETTEXT = LIBDIR + '/gettext' BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gettextlib' +BF_GETTEXT_LIB = 'gnu_gettext' # BF_GETTEXT_LIB = 'gnu_gettext' BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' -- cgit v1.2.3 From 122104b3bb1a69549b0bd016c29aa01dc71f3704 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 17 Jul 2009 10:09:07 +0000 Subject: FBX exporter conversion almost done. Unit tests: - add a check that BKE_copy_images produces NULL filepath for images having type other than IMA_TYPE_IMAGE - also expect NULL filepath for images having empty filename Enhanced BKE_copy_images so the tests pass. --- release/io/export_fbx.py | 136 ++++++++++++++++-------- source/blender/blenkernel/intern/image.c | 26 ++--- source/blender/makesrna/intern/rna_object_api.c | 2 +- source/blender/python/intern/bpy_util.c | 3 +- 4 files changed, 104 insertions(+), 63 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index d74e6246104..c19a914d22e 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -297,6 +297,29 @@ def BPyMesh_meshWeight2List(ob): return groupNames, vWeightList +def BPyMesh_meshWeight2Dict(me, ob): + ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex. + using the group as a key and a float value for the weight. + These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. + ''' + + vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist. + + # Clear the vert group. + groupNames= [g.name for g in ob.vertex_groups] +# groupNames= me.getVertGroupNames() + + for group in groupNames: + for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. + vWeightDict[vert_index][group]= weight + + # removed this because me may be copying teh vertex groups. + #for group in groupNames: + # me.removeVertGroup(group) + + return groupNames, vWeightDict + + def meshNormalizedWeights(me): try: # account for old bad BPyMesh groupNames, vWeightList = BPyMesh_meshWeight2List(me) @@ -1498,7 +1521,7 @@ def write(filename, batch_objects = None, \ if my_mesh.blenTextures: do_textures = True else: do_textures = False - do_uvs = len(me.uv_layers) > 0 + do_uvs = len(me.uv_textures) > 0 # do_uvs = me.faceUV @@ -2073,8 +2096,9 @@ def write(filename, batch_objects = None, \ origData = True if tmp_ob_type != 'MESH': # if tmp_ob_type != 'Mesh': - me = bpy.data.meshes.new() - try: me.getFromObject(ob) +# me = bpy.data.meshes.new() + try: me = ob.create_mesh(True, 'PREVIEW') +# try: me.getFromObject(ob) except: me = None if me: meshes_to_clear.append( me ) @@ -2084,65 +2108,70 @@ def write(filename, batch_objects = None, \ # Mesh Type! if EXP_MESH_APPLY_MOD: # me = bpy.data.meshes.new() - me = ob.create_mesh('PREVIEW') + me = ob.create_mesh(True, 'PREVIEW') # me.getFromObject(ob) # so we keep the vert groups - if EXP_ARMATURE: - orig_mesh = ob.data +# if EXP_ARMATURE: # orig_mesh = ob.getData(mesh=1) - if len(ob.vertex_groups): # if orig_mesh.getVertGroupNames(): - ob.copy().link(me) - # If new mesh has no vgroups we can try add if verts are teh same - if not me.getVertGroupNames(): # vgroups were not kept by the modifier - if len(me.verts) == len(orig_mesh.verts): - groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) - BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) +# ob.copy().link(me) +# # If new mesh has no vgroups we can try add if verts are teh same +# if not me.getVertGroupNames(): # vgroups were not kept by the modifier +# if len(me.verts) == len(orig_mesh.verts): +# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) +# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) # print ob, me, me.getVertGroupNames() meshes_to_clear.append( me ) origData = False mats = me.materials else: - me = ob.getData(mesh=1) + me = ob.data +# me = ob.getData(mesh=1) mats = me.materials - # Support object colors - tmp_colbits = ob.colbits - if tmp_colbits: - tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. - for i in xrange(16): - if tmp_colbits & (1< 0: +# if me.faceUV: + uvlayer_orig = me.active_uv_texture +# uvlayer_orig = me.activeUVLayer + for uvlayer in me.uv_textures: +# for uvlayer in me.getUVLayerNames(): +# me.activeUVLayer = uvlayer + for f, uf in zip(me.faces, uvlayer.data): +# for f in me.faces: + tex = uf.image +# tex = f.image textures[tex] = texture_mapping_local[tex] = None - try: mat = mats[f.mat] + try: mat = mats[f.material_index] +# try: mat = mats[f.mat] except: mat = None materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5 - me.activeUVLayer = uvlayer_orig +# me.activeUVLayer = uvlayer_orig else: for mat in mats: # 2.44 use mat.lib too for uniqueness @@ -2155,9 +2184,12 @@ def write(filename, batch_objects = None, \ blenParentBoneName = None # parent bone - special case - if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE: + if (not armob) and ob.parent and ob.parent.type == 'ARMATURE' and \ + ob.parent_type == 'BONE': +# if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE: armob = ob.parent - blenParentBoneName = ob.parentbonename + blenParentBoneName = ob.parent_bone +# blenParentBoneName = ob.parentbonename if armob and armob not in ob_arms: @@ -2181,7 +2213,11 @@ def write(filename, batch_objects = None, \ my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later ob_meshes.append( my_mesh ) - + + # not forgetting to free dupli_list + if ob_base.dupli_list: ob_base.free_dupli_list() + + if EXP_ARMATURE: # now we have the meshes, restore the rest arm position for i, arm in enumerate(bpy.data.armatures): @@ -2217,7 +2253,8 @@ def write(filename, batch_objects = None, \ # fbxName, blenderObject, my_bones, blenderActions #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, []) - for bone in my_arm.blenData.bones.values(): + for bone in my_arm.blenData.bones: +# for bone in my_arm.blenData.bones.values(): my_bone = my_bone_class(bone, my_arm) my_arm.fbxBones.append( my_bone ) ob_bones.append( my_bone ) @@ -2662,7 +2699,8 @@ Connections: {''') # Needed for scene footer as well as animation - render = sce.render + render = sce.render_data +# render = sce.render # from the FBX sdk #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) @@ -2671,8 +2709,10 @@ Connections: {''') return int(0.5 + ((t/fps) * 46186158000)) fps = float(render.fps) - start = render.sFrame - end = render.eFrame + start = sce.start_frame +# start = render.sFrame + end = sce.end_frame +# end = render.eFrame if end < start: start, end = end, start if start==end: ANIM_ENABLE = False @@ -2959,8 +2999,6 @@ Takes: {''') bpy.data.remove_mesh(me) # me.verts = None - - # --------------------------- Footer if world: m = world.mist @@ -3025,7 +3063,8 @@ Takes: {''') if EXP_IMAGE_COPY: copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) - print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) + print 'export finished in %.4f sec.' % (bpy.sys.time() - start_time) +# print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) return True @@ -3338,11 +3377,14 @@ if __name__ == '__main__': # NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) # - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print # - get rid of cleanName somehow -# - isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 +# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 # - get rid of BPyObject_getObjectArmature, move it in RNA? # - BATCH_ENABLE and BATCH_GROUP options: line 327 # - implement all BPyMesh_* used here with RNA # - getDerivedObjects is not fully replicated with .dupli* funcs +# - talk to Campbell, this code won't work? lines 1867-1875 +# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893 +# - no hq normals: 1900-1901 # TODO diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 495dd3ec523..833d5ac1a90 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2120,6 +2120,7 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) Copy list of images to dest_dir. paths is optional, if given, image paths for each image will be written in it. + It will also contain NULLs for images that cannot be copied. If an image file doesn't exist, NULL is added in paths. Logic: @@ -2161,6 +2162,13 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) while (link) { im= link->data; + LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); + ld->data= NULL; + BLI_addtail(paths, ld); + + if (!strcmp(im->name, "") || im->type != IMA_TYPE_IMAGE) + goto next; + BLI_strncpy(path, im->name, sizeof(path)); /* expand "//" in filename and get absolute path */ @@ -2169,16 +2177,8 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) /* in unit tests, we don't want to modify the filesystem */ #ifndef WITH_UNIT_TEST /* proceed only if image file exists */ - if (!BLI_exists(path)) { - - if (paths) { - LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); - ld->data= NULL; - BLI_addtail(paths, ld); - } - - continue; - } + if (!BLI_exists(path)) + goto next; #endif /* get the directory part */ @@ -2219,17 +2219,17 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) } #ifndef WITH_UNIT_TEST - BLI_copy_fileops(path, dest_path); + if (BLI_copy_fileops(path, dest_path) != 0) + goto next; #endif if (paths) { - LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); len= strlen(dest_path) + 1; ld->data= MEM_callocN(len, "PathLinkData"); BLI_strncpy(ld->data, dest_path, len); - BLI_addtail(paths, ld); } + next: link= link->next; } } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index bae651bf806..27a0ceb21c1 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -370,7 +370,7 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers."); RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Mesh settings to apply."); + parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier 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); diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 3295bdd91c0..c5fd030cdd6 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -583,9 +583,8 @@ static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args) /* convert filenames */ ret= PyList_New(0); - len= BLI_countlist(paths); - for(link= paths->first, i= 0; link; link++, i++) { + for(link= paths->first; link; link= link->next) { if (link->data) { item= PyUnicode_FromString(link->data); PyList_Append(ret, item); -- cgit v1.2.3 From 00e219d8e97afcf3767a6d2b28a6d05bcc984279 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 22 Jul 2009 13:35:02 +0000 Subject: FBX exporter: - made an operator with props for UI. UI is still "raw" - ran 2to3 on export_fbx.py to make it python 3-compatible Next: testing/fixing. --- release/io/export_fbx.py | 189 +++++++++++++++++------- release/io/export_obj.py | 1 + release/io/export_ply.py | 2 +- source/blender/makesrna/intern/rna_object_api.c | 2 +- 4 files changed, 138 insertions(+), 56 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 64a8870bb3d..a861436d132 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -38,6 +38,7 @@ http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx import os import time +import math # math.pi # try: # import time @@ -65,10 +66,10 @@ import bpy import Mathutils # from Blender.Mathutils import Matrix, Vector, RotationMatrix -import BPyObject -import BPyMesh -import BPySys -import BPyMessages +# import BPyObject +# import BPyMesh +# import BPySys +# import BPyMessages ## This was used to make V, but faster not to do all that ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' @@ -79,7 +80,7 @@ invalid = ''.join([chr(i) for i in v]) def cleanName(name): for ch in invalid: name = name.replace(ch, '_') return name -del v, i +# del v, i def copy_file(source, dest): @@ -107,14 +108,14 @@ def copy_images(dest_dir, textures): # Make a name for the target path. dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] if not Blender.sys.exists(dest_image_path): # Image isnt alredy there - print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + print('\tCopying "%s" > "%s"' % (image_path, dest_image_path)) try: copy_file(image_path, dest_image_path) copyCount+=1 except: - print '\t\tWarning, file failed to copy, skipping.' + print('\t\tWarning, file failed to copy, skipping.') - print '\tCopied %d images' % copyCount + print('\tCopied %d images' % copyCount) def BPyObject_getObjectArmature(ob): ''' @@ -141,9 +142,9 @@ def BPyObject_getObjectArmature(ob): def eulerRadToDeg(eul): ret = Mathutils.Euler() - ret.x = 180 / math.pi * eul.x - ret.y = 180 / math.pi * eul.y - ret.z = 180 / math.pi * eul.z + ret.x = 180 / math.pi * eul[0] + ret.y = 180 / math.pi * eul[1] + ret.z = 180 / math.pi * eul[2] return ret @@ -221,7 +222,7 @@ def sane_name(data, dct): #name = BPySys.cleanName(name) name = cleanName(name) # use our own - while name in dct.itervalues(): name = increment_string(name) + while name in iter(dct.values()): name = increment_string(name) if use_other: # even if other is None - orig_name_other will be a string or None dct[orig_name, orig_name_other] = name @@ -286,9 +287,9 @@ def BPyMesh_meshWeight2List(ob): if not len_groupNames: # no verts? return a vert aligned empty list - return [[] for i in xrange(len(me.verts))], [] + return [[] for i in range(len(me.verts))], [] else: - vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))] + vWeightList= [[0.0]*len_groupNames for i in range(len(me.verts))] for i, v in enumerate(me.verts): for g in v.groups: @@ -303,7 +304,7 @@ def BPyMesh_meshWeight2Dict(me, ob): These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. ''' - vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist. + vWeightDict= [dict() for i in range(len(me.verts))] # Sync with vertlist. # Clear the vert group. groupNames= [g.name for g in ob.vertex_groups] @@ -368,7 +369,6 @@ def write(filename, batch_objects = None, \ ANIM_ACTION_ALL = False, BATCH_ENABLE = False, BATCH_GROUP = True, - BATCH_SCENE = False, BATCH_FILE_PREFIX = '', BATCH_OWN_DIR = False ): @@ -436,7 +436,7 @@ def write(filename, batch_objects = None, \ filename = new_fbxpath + newname + '.fbx' - print '\nBatch exporting %s as...\n\t"%s"' % (data, filename) + print('\nBatch exporting %s as...\n\t"%s"' % (data, filename)) # XXX don't know what to do with this, probably do the same? (Arystan) if BATCH_GROUP: #group @@ -596,7 +596,8 @@ def write(filename, batch_objects = None, \ self.fbxGroupNames = [] self.fbxParent = None # set later on IF the parent is in the selection. if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX - else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + else: self.matrixWorld = ob.matrix * GLOBAL_MATRIX +# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX self.__anim_poselist = {} # we should only access this def parRelMatrix(self): @@ -606,7 +607,8 @@ def write(filename, batch_objects = None, \ return self.matrixWorld def setPoseFrame(self, f): - self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + self.__anim_poselist[f] = self.blenObject.matrix.copy() +# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() def getAnimParRelMatrix(self, frame): if self.fbxParent: @@ -638,7 +640,7 @@ def write(filename, batch_objects = None, \ - print '\nFBX export starting...', filename + print('\nFBX export starting...', filename) start_time = bpy.sys.time() # start_time = Blender.sys.time() try: @@ -713,7 +715,7 @@ def write(filename, batch_objects = None, \ else: # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX - if ob and not matrix: raise "error: this should never happen!" + if ob and not matrix: raise Exception("error: this should never happen!") matrix_rot = matrix #if matrix: @@ -751,7 +753,7 @@ def write(filename, batch_objects = None, \ loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) - file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % eulerRadToDeg(rot)) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple(eulerRadToDeg(rot))) # file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) return loc, rot, scale, matrix, matrix_rot @@ -1453,7 +1455,7 @@ def write(filename, batch_objects = None, \ # TODO - this is a bit lazy, we could have a simple write loop # for this case because all weights are 1.0 but for now this is ok # Parent Bones arent used all that much anyway. - vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))] + vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.verts))] else: # This bone is not a parent of this mesh object, no weights vgroup_data = [] @@ -1728,7 +1730,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tColorIndex: ') i = -1 - for j in xrange(ii): + for j in range(ii): if i == -1: file.write('%i' % j) i=0 @@ -1786,7 +1788,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tUVIndex: ') i = -1 - for j in xrange(ii): + for j in range(ii): if i == -1: file.write('%i' % j) i=0 @@ -1890,7 +1892,7 @@ def write(filename, batch_objects = None, \ uv_faces = [None] * len(me.faces) i=-1 - for f, uf in zip(me.faces, uv_faces) + for f, uf in zip(me.faces, uv_faces): # for f in me.faces: try: mat = mats[f.material_index] # try: mat = mats[f.mat] @@ -1955,7 +1957,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t}') if len(uvlayers) > 1: - for i in xrange(1, len(uvlayers)): + for i in range(1, len(uvlayers)): file.write('\n\t\tLayer: %i {' % i) file.write('\n\t\t\tVersion: 100') @@ -1983,7 +1985,7 @@ def write(filename, batch_objects = None, \ layer_offset = 0 if uvlayers: layer_offset = len(uvlayers)-1 - for i in xrange(layer_offset, len(collayers)+layer_offset): + for i in range(layer_offset, len(collayers)+layer_offset): file.write('\n\t\tLayer: %i {' % i) file.write('\n\t\t\tVersion: 100') @@ -2033,7 +2035,8 @@ def write(filename, batch_objects = None, \ # if EXP_OBS_SELECTED is false, use sceens objects if not batch_objects: - if EXP_OBS_SELECTED: tmp_objects = sce.objects.context + if EXP_OBS_SELECTED: tmp_objects = context.selected_objects +# if EXP_OBS_SELECTED: tmp_objects = sce.objects.context else: tmp_objects = sce.objects else: tmp_objects = batch_objects @@ -2201,9 +2204,9 @@ def write(filename, batch_objects = None, \ my_mesh = my_object_generic(ob, mtx) my_mesh.blenData = me my_mesh.origData = origData - my_mesh.blenMaterials = material_mapping_local.keys() + my_mesh.blenMaterials = list(material_mapping_local.keys()) my_mesh.blenMaterialList = mats - my_mesh.blenTextures = texture_mapping_local.keys() + my_mesh.blenTextures = list(texture_mapping_local.keys()) # if only 1 null texture then empty the list if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None: @@ -2336,8 +2339,8 @@ def write(filename, batch_objects = None, \ # Finished finding groups we use - materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.iterkeys()] - textures = [(sane_texname(tex), tex) for tex in textures.iterkeys() if tex] + materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.keys()] + textures = [(sane_texname(tex), tex) for tex in textures.keys() if tex] materials.sort() # sort by name textures.sort() @@ -2497,7 +2500,7 @@ Objects: {''') #for bonename, bone, obname, bone_mesh, armob in ob_bones: for my_bone in ob_bones: - if me in my_bone.blenMeshes.itervalues(): + if me in iter(my_bone.blenMeshes.values()): write_sub_deformer_skin(my_mesh, my_bone, weights) # Write pose's really weired, only needed when an armature and mesh are used together @@ -2784,9 +2787,9 @@ Takes: {''') # we have tagged all actious that are used be selected armatures if blenAction: if blenAction.tag: - print '\taction: "%s" exporting...' % blenAction.name + print('\taction: "%s" exporting...' % blenAction.name) else: - print '\taction: "%s" has no armature using it, skipping' % blenAction.name + print('\taction: "%s" has no armature using it, skipping' % blenAction.name) continue if blenAction == None: @@ -2866,7 +2869,7 @@ Takes: {''') file.write('\n\t\t\tVersion: 1.1') file.write('\n\t\t\tChannel: "Transform" {') - context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] + context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end+1) ] # ---------------- # ---------------- @@ -2889,7 +2892,7 @@ Takes: {''') file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation - for i in xrange(3): + for i in range(3): # Loop on each axis of the bone file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) @@ -3064,7 +3067,7 @@ Takes: {''') # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) bpy.util.copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) - print 'export finished in %.4f sec.' % (bpy.sys.time() - start_time) + print('export finished in %.4f sec.' % (bpy.sys.time() - start_time)) # print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) return True @@ -3072,7 +3075,7 @@ Takes: {''') # -------------------------------------------- # UI Function - not a part of the exporter. # this is to seperate the user interface from the rest of the exporter. -from Blender import Draw, Window +# from Blender import Draw, Window EVENT_NONE = 0 EVENT_EXIT = 1 EVENT_REDRAW = 2 @@ -3123,15 +3126,15 @@ def fbx_ui_exit(e,v): def do_help(e,v): url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' - print 'Trying to open web browser with documentation at this address...' - print '\t' + url + print('Trying to open web browser with documentation at this address...') + print('\t' + url) try: import webbrowser webbrowser.open(url) except: Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation") - print '...could not open a browser window.' + print('...could not open a browser window.') @@ -3358,17 +3361,95 @@ def write_ui(): # GLOBALS.clear() -#test = [write_ui] -if __name__ == '__main__': - # Cant call the file selector first because of a bug in the interface that crashes it. - # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) - #write('/scratch/test.fbx') - #write_ui('/scratch/test.fbx') - - if not set: - Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.') - else: - write_ui() + +class EXPORT_OT_fbx(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "export.fbx" + __label__ = "Export FBX" + + # 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=""), + bpy.props.BoolProperty(attr="EXP_OBS_SELECTED", name="Selected Objects", description="Export selected objects on visible layers", default=True), +# bpy.props.BoolProperty(attr="EXP_OBS_SCENE", name="Scene Objects", description="Export all objects in this scene", default=True), + bpy.props.FloatProperty(attr="_SCALE", name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0), + bpy.props.BoolProperty(attr="_XROT90", name="Rot X90", description="Rotate all objects 90 degrese about the X axis", default=True), + bpy.props.BoolProperty(attr="_YROT90", name="Rot Y90", description="Rotate all objects 90 degrese about the Y axis", default=False), + bpy.props.BoolProperty(attr="_ZROT90", name="Rot Z90", description="Rotate all objects 90 degrese about the Z axis", default=False), + bpy.props.BoolProperty(attr="EXP_EMPTY", name="Empties", description="Export empty objects", default=True), + bpy.props.BoolProperty(attr="EXP_CAMERA", name="Cameras", description="Export camera objects", default=True), + bpy.props.BoolProperty(attr="EXP_LAMP", name="Lamps", description="Export lamp objects", default=True), + bpy.props.BoolProperty(attr="EXP_ARMATURE", name="Armatures", description="Export armature objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH", name="Meshes", description="Export mesh objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH_APPLY_MOD", name="Modifiers", description="Apply modifiers to mesh objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH_HQ_NORMALS", name="HQ Normals", description="Generate high quality normals", default=True), + bpy.props.BoolProperty(attr="EXP_IMAGE_COPY", name="Copy Image Files", description="Copy image files to the destination path", default=False), + # armature animation + bpy.props.BoolProperty(attr="ANIM_ENABLE", name="Enable Animation", description="Export keyframe animation", default=True), + bpy.props.BoolProperty(attr="ANIM_OPTIMIZE", name="Optimize Keyframes", description="Remove double keyframes", default=True), + bpy.props.FloatProperty(attr="ANIM_OPTIMIZE_PRECISSION", name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0), +# bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True), + bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures", default=False), + # batch + bpy.props.BoolProperty(attr="BATCH_ENABLE", name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False), + bpy.props.BoolProperty(attr="BATCH_GROUP", name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False), + bpy.props.BoolProperty(attr="BATCH_OWN_DIR", name="Own Dir", description="Create a dir for each exported file", default=True), + bpy.props.StringProperty(attr="BATCH_FILE_PREFIX", name="Prefix", description="Prefix each file with this name", maxlen= 1024, default=""), + ] + + def poll(self, context): + print("Poll") + return context.active_object != None + + def execute(self, context): + if not self.filename: + raise Exception("filename not set") + + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self._SCALE + if self._XROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if self._YROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if self._ZROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + write(self.filename, + None, # XXX + context, + self.EXP_OBS_SELECTED, + self.EXP_MESH, + self.EXP_MESH_APPLY_MOD, + self.EXP_MESH_HQ_NORMALS, + self.EXP_ARMATURE, + self.EXP_LAMP, + self.EXP_CAMERA, + self.EXP_EMPTY, + self.EXP_IMAGE_COPY, + GLOBAL_MATRIX, + self.ANIM_ENABLE, + self.ANIM_OPTIMIZE, + self.ANIM_OPTIMIZE_PRECISSION, + self.ANIM_ACTION_ALL, + self.BATCH_ENABLE, + self.BATCH_GROUP, + self.BATCH_FILE_PREFIX, + self.BATCH_OWN_DIR) + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + + +bpy.ops.add(EXPORT_OT_fbx) + +# if __name__ == "__main__": +# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply") + # NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) # - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 251fdfcf113..bf3aa4ae819 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -891,6 +891,7 @@ class EXPORT_OT_obj(bpy.types.Operator): * multiple scene export (only active scene is written) * particles ''' + __idname__ = "export.obj" __label__ = 'Export OBJ' # List of operator properties, the attributes will be assigned diff --git a/release/io/export_ply.py b/release/io/export_ply.py index 2028358ff3b..8cbb2d5605a 100644 --- a/release/io/export_ply.py +++ b/release/io/export_ply.py @@ -238,7 +238,7 @@ def write(filename, scene, ob, \ class EXPORT_OT_ply(bpy.types.Operator): ''' - Operator documentatuon text, will be used for the operator tooltip and python docs. + Operator documentation text, will be used for the operator tooltip and python docs. ''' __idname__ = "export.ply" __label__ = "Export PLY" diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 27a0ceb21c1..bc031c4e5f2 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -368,7 +368,7 @@ void RNA_api_object(StructRNA *srna) func= RNA_def_function(srna, "create_mesh", "rna_Object_create_mesh"); RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied."); RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS); - RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers."); + parm= RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers."); RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply."); RNA_def_property_flag(parm, PROP_REQUIRED); -- cgit v1.2.3 From c96041628e141b7bfc1da28be09510e7e0e5cd0a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 23 Jul 2009 12:55:26 +0000 Subject: API: - replaced BKE_copy_images with BKE_export_image, now it handles only one image at a time, this is better since for exporters it is easier to export one image at a time writing new image path to a file - exposing BKE_export_image in RNA as Image.export, interestingly, RNA allowed me to define a function with PROP_STRING return type although it doesn't free memory, will fix that in the next commit - removed bpy.util.copy_images Unit tests: - re-wrote a test for BKE_export_image, it's more compact now - moved unit tests to the creator module to avoid another executable, now running tests with `blender --test` - as before, unit tests are built only if WITH_BF_UNIT_TEST is non 0 --- SConstruct | 8 -- release/io/export_fbx.py | 35 +++++--- source/blender/blenkernel/BKE_image.h | 5 +- source/blender/blenkernel/intern/image.c | 130 ++++++++++++--------------- source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_image.c | 2 + source/blender/python/intern/bpy_interface.c | 2 +- source/blender/python/intern/bpy_util.c | 123 ------------------------- source/creator/SConscript | 11 ++- source/creator/creator.c | 6 ++ source/creator/tests/alltest.c | 114 +++++++++++++++++++++++ tools/Blender.py | 2 + tools/btools.py | 6 +- 13 files changed, 222 insertions(+), 224 deletions(-) create mode 100644 source/creator/tests/alltest.c diff --git a/SConstruct b/SConstruct index 2d1daba98b6..c1b4f8da174 100644 --- a/SConstruct +++ b/SConstruct @@ -409,14 +409,6 @@ if 'blender' in B.targets or not env['WITH_BF_NOBLENDER']: #env.BlenderProg(B.root_build_dir, "blender", dobj , [], mainlist + thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') blen = env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist, [], thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') - build_data = {"lib": thestatlibs + thesyslibs, "libpath": thelibincs, "blen": blen} - - Export('env') - Export('build_data') - - BuildDir(B.root_build_dir+'/tests', 'tests', duplicate=0) - SConscript(B.root_build_dir+'/tests/SConscript') - if env['WITH_BF_PLAYER']: playerlist = B.create_blender_liblist(env, 'player') env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist, [], thestatlibs + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer') diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index a861436d132..f98cefb076e 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -356,7 +356,7 @@ def write(filename, batch_objects = None, \ EXP_OBS_SELECTED = True, EXP_MESH = True, EXP_MESH_APPLY_MOD = True, - EXP_MESH_HQ_NORMALS = False, +# EXP_MESH_HQ_NORMALS = False, EXP_ARMATURE = True, EXP_LAMP = True, EXP_CAMERA = True, @@ -464,7 +464,7 @@ def write(filename, batch_objects = None, \ False, EXP_MESH, EXP_MESH_APPLY_MOD, - EXP_MESH_HQ_NORMALS, +# EXP_MESH_HQ_NORMALS, EXP_ARMATURE, EXP_LAMP, EXP_CAMERA, @@ -2306,19 +2306,25 @@ def write(filename, batch_objects = None, \ # Build blenObject -> fbxObject mapping # this is needed for groups as well as fbxParenting - for ob in bpy.data.objects: ob.tag = False +# for ob in bpy.data.objects: ob.tag = False # bpy.data.objects.tag = False + + # using a list of object names for tagging (Arystan) + tagged_objects = [] + tmp_obmapping = {} for ob_generic in ob_all_typegroups: for ob_base in ob_generic: - ob_base.blenObject.tag = True + tagged_objects.append(ob_base.blenObject.name) +# ob_base.blenObject.tag = True tmp_obmapping[ob_base.blenObject] = ob_base # Build Groups from objects we export for blenGroup in bpy.data.groups: fbxGroupName = None for ob in blenGroup.objects: - if ob.tag: + if ob.name in tagged_objects: +# if ob.tag: if fbxGroupName == None: fbxGroupName = sane_groupname(blenGroup) groups.append((fbxGroupName, blenGroup)) @@ -2331,7 +2337,8 @@ def write(filename, batch_objects = None, \ for ob_generic in ob_all_typegroups: for my_ob in ob_generic: parent = my_ob.blenObject.parent - if parent and parent.tag: # does it exist and is it in the mapping + if parent and parent.name in tagged_objects: # does it exist and is it in the mapping +# if parent and parent.tag: # does it exist and is it in the mapping my_ob.fbxParent = tmp_obmapping[parent] @@ -2734,9 +2741,11 @@ Connections: {''') tmp_actions = [None] # None is the default action blenActionDefault = None action_lastcompat = None + + # instead of tagging + tagged_actions = [] if ANIM_ACTION_ALL: - for a in bpy.data.actions: a.tag = False # bpy.data.actions.tag = False tmp_actions = list(bpy.data.actions) @@ -2759,7 +2768,8 @@ Connections: {''') if action_chan_names: # at least one channel matches. my_arm.blenActionList.append(action) - action.tag = True + tagged_actions.append(action.name) +# action.tag = True tmp_act_count += 1 # incase there is no actions applied to armatures @@ -2786,7 +2796,8 @@ Takes: {''') for blenAction in tmp_actions: # we have tagged all actious that are used be selected armatures if blenAction: - if blenAction.tag: + if blenAction.name in tagged_actions: +# if blenAction.tag: print('\taction: "%s" exporting...' % blenAction.name) else: print('\taction: "%s" has no armature using it, skipping' % blenAction.name) @@ -3065,7 +3076,7 @@ Takes: {''') # copy images if enabled if EXP_IMAGE_COPY: # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) - bpy.util.copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) + bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath) print('export finished in %.4f sec.' % (bpy.sys.time() - start_time)) # print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) @@ -3393,7 +3404,7 @@ class EXPORT_OT_fbx(bpy.types.Operator): bpy.props.BoolProperty(attr="ANIM_OPTIMIZE", name="Optimize Keyframes", description="Remove double keyframes", default=True), bpy.props.FloatProperty(attr="ANIM_OPTIMIZE_PRECISSION", name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0), # bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True), - bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures", default=False), + bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures, if false, use current action", default=False), # batch bpy.props.BoolProperty(attr="BATCH_ENABLE", name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False), bpy.props.BoolProperty(attr="BATCH_GROUP", name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False), @@ -3421,7 +3432,7 @@ class EXPORT_OT_fbx(bpy.types.Operator): self.EXP_OBS_SELECTED, self.EXP_MESH, self.EXP_MESH_APPLY_MOD, - self.EXP_MESH_HQ_NORMALS, +# self.EXP_MESH_HQ_NORMALS, self.EXP_ARMATURE, self.EXP_LAMP, self.EXP_CAMERA, diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index f3f5266189a..052f7738f2b 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -155,10 +155,9 @@ struct Image *BKE_image_copy(struct Image *ima); /* merge source into dest, and free source */ void BKE_image_merge(struct Image *dest, struct Image *source); -/* ********************************** FOR EXPORTERS *********************** */ +/* copy image file to a directory rebuilding subdirectory structure */ +int BKE_export_image(struct Image *im, const char *dest_dir, char *out_path, int out_path_len); -/* copy images into dest_dir */ -void BKE_copy_images(struct ListBase *images, char *dest_dir, struct ListBase *filenames); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 833d5ac1a90..a469752602e 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2117,30 +2117,27 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) } /* - Copy list of images to dest_dir. - - paths is optional, if given, image paths for each image will be written in it. - It will also contain NULLs for images that cannot be copied. - If an image file doesn't exist, NULL is added in paths. + Copy an image to destination directory rebuilding subdirectory structure if needed. + Target image path is written to out_path. + Returns 1 on success, 0 otherwise. Logic: - For each image if it's "below" current .blend file directory, - rebuild the same dir structure in dest_dir. + - if an image is "below" current .blend file directory, rebuild the same dir structure in dest_dir - For example //textures/foo/bar.png becomes - [dest_dir]/textures/foo/bar.png. + For example //textures/foo/bar.png becomes [dest_dir]/textures/foo/bar.png. - If an image is not "below" current .blend file directory, disregard - it's path and copy it in the same directory where 3D file goes. + - if an image is not "below" current .blend file directory, disregard it's path and copy it in the + same directory where 3D file goes. For example //../foo/bar.png becomes [dest_dir]/bar.png. This logic will help ensure that all image paths are relative and that a user gets his images in one place. It'll also provide consistent behaviour across exporters. -*/ -void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) + + */ +int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_path_len) { char path[FILE_MAX]; char dir[FILE_MAX]; @@ -2148,88 +2145,77 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths) char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */ char dest_path[FILE_MAX]; int len; - Image *im; - LinkData *link; - if (paths) { - memset(paths, 0, sizeof(*paths)); - } + out_path[0]= 0; BLI_split_dirfile_basic(G.sce, blend_dir, NULL); - - link= images->first; - - while (link) { - im= link->data; - - LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData"); - ld->data= NULL; - BLI_addtail(paths, ld); - if (!strcmp(im->name, "") || im->type != IMA_TYPE_IMAGE) - goto next; + if (!strcmp(im->name, "") || im->type != IMA_TYPE_IMAGE) { + if (G.f & G_DEBUG) printf("invalid image type\n"); + return 0; + } - BLI_strncpy(path, im->name, sizeof(path)); + BLI_strncpy(path, im->name, sizeof(path)); - /* expand "//" in filename and get absolute path */ - BLI_convertstringcode(path, G.sce); + /* expand "//" in filename and get absolute path */ + BLI_convertstringcode(path, G.sce); - /* in unit tests, we don't want to modify the filesystem */ + /* in unit tests, we don't want to modify the filesystem */ #ifndef WITH_UNIT_TEST - /* proceed only if image file exists */ - if (!BLI_exists(path)) - goto next; + /* proceed only if image file exists */ + if (!BLI_exists(path)) { + if (G.f & G_DEBUG) printf("%s doesn't exist\n", path); + goto next; + } #endif - /* get the directory part */ - BLI_split_dirfile_basic(path, dir, base); + /* get the directory part */ + BLI_split_dirfile_basic(path, dir, base); - len= strlen(blend_dir); + len= strlen(blend_dir); - /* if image is "below" current .blend file directory */ - if (!strncmp(path, blend_dir, len)) { + /* if image is "below" current .blend file directory */ + if (!strncmp(path, blend_dir, len)) { - /* if image is _in_ current .blend file directory */ - if (!strcmp(dir, blend_dir)) { - /* copy to dest_dir */ - BLI_join_dirfile(dest_path, dest_dir, base); - } - /* "below" */ - else { - char rel[FILE_MAX]; + /* if image is _in_ current .blend file directory */ + if (!strcmp(dir, blend_dir)) { + /* copy to dest_dir */ + BLI_join_dirfile(dest_path, dest_dir, base); + } + /* "below" */ + else { + char rel[FILE_MAX]; - /* rel = image_path_dir - blend_dir */ - BLI_strncpy(rel, dir + len, sizeof(rel)); + /* rel = image_path_dir - blend_dir */ + BLI_strncpy(rel, dir + len, sizeof(rel)); - BLI_join_dirfile(dest_path, dest_dir, rel); + BLI_join_dirfile(dest_path, dest_dir, rel); #ifndef WITH_UNIT_TEST - /* build identical directory structure under dest_dir */ - BLI_make_existing_file(dest_path); + /* build identical directory structure under dest_dir */ + BLI_make_existing_file(dest_path); #endif - BLI_join_dirfile(dest_path, dest_path, base); - } - - } - /* image is out of current directory */ - else { - /* copy to dest_dir */ - BLI_join_dirfile(dest_path, dest_dir, base); + BLI_join_dirfile(dest_path, dest_path, base); } + + } + /* image is out of current directory */ + else { + /* copy to dest_dir */ + BLI_join_dirfile(dest_path, dest_dir, base); + } #ifndef WITH_UNIT_TEST - if (BLI_copy_fileops(path, dest_path) != 0) - goto next; + if (G.f & G_DEBUG) printf("copying %s to %s\n", path, dest_path); + + if (BLI_copy_fileops(path, dest_path) != 0) { + if (G.f & G_DEBUG) printf("couldn't copy %s to %s\n", path, dest_path); + return 0; + } #endif - if (paths) { - len= strlen(dest_path) + 1; - ld->data= MEM_callocN(len, "PathLinkData"); - BLI_strncpy(ld->data, dest_path, len); - } + BLI_strncpy(out_path, dest_path, out_path_len); - next: - link= link->next; - } + return 1; } diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 63ce5786ae3..03d8edde4b3 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1936,7 +1936,7 @@ RNAProcessItem PROCESS_ITEMS[]= { {"rna_fcurve.c", NULL, RNA_def_fcurve}, {"rna_fluidsim.c", NULL, RNA_def_fluidsim}, {"rna_group.c", NULL, RNA_def_group}, - {"rna_image.c", NULL, RNA_def_image}, + {"rna_image.c", "rna_image_api.c", RNA_def_image}, {"rna_key.c", NULL, RNA_def_key}, {"rna_lamp.c", NULL, RNA_def_lamp}, {"rna_lattice.c", NULL, RNA_def_lattice}, diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index fbef838d06c..5366296a6b8 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -312,6 +312,8 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_int_funcs(prop, "rna_Image_depth_get", NULL, NULL); RNA_def_property_ui_text(prop, "Depth", "Image bit depth."); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + RNA_api_image(srna); } void RNA_def_image(BlenderRNA *brna) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index f045e977394..4ab79dcf074 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -93,7 +93,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, "util", BPY_util_module() ); + /* PyModule_AddObject( mod, "util", BPY_util_module() ); */ /* XXX this will move to bpy.util */ PyModule_AddObject( mod, "sys", BPY_sys_module() ); diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index dc3132814b4..89a68ba576c 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -488,126 +488,3 @@ int BPy_errors_to_report(ReportList *reports) Py_DECREF(pystring); return 1; } - - -/* bpy.util module */ -static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args); - -struct PyMethodDef bpy_util_methods[] = { - {"copy_images", bpy_util_copy_images, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -#if PY_VERSION_HEX >= 0x03000000 -static struct PyModuleDef bpy_util_module = { - PyModuleDef_HEAD_INIT, - "bpyutil", - NULL, - -1, - bpy_util_methods, - NULL, NULL, NULL, NULL -}; -#endif - -PyObject *BPY_util_module( void ) -{ - PyObject *submodule, *dict; - -#if PY_VERSION_HEX >= 0x03000000 - submodule= PyModule_Create(&bpy_util_module); -#else /* Py2.x */ - submodule= Py_InitModule3("bpyutil", bpy_util_methods, NULL); -#endif - - dict = PyModule_GetDict(submodule); - - return submodule; -} - -/* - copy_images(images, dest_dir) - return filenames -*/ -static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args) -{ - const char *dest_dir; - ListBase *images; - ListBase *paths; - LinkData *link; - PyObject *seq; - PyObject *ret; - PyObject *item; - int i; - int len; - - /* check args/types */ - if (!PyArg_ParseTuple(args, "Os", &seq, &dest_dir)) { - PyErr_SetString(PyExc_TypeError, "Invalid arguments."); - return NULL; - } - - /* expecting a sequence of Image objects */ - if (!PySequence_Check(seq)) { - PyErr_SetString(PyExc_TypeError, "Expected a sequence of images."); - return NULL; - } - - /* create image list */ - len= PySequence_Size(seq); - - if (!len) { - PyErr_SetString(PyExc_TypeError, "At least one image should be specified."); - return NULL; - } - - /* make sure all sequence items are Image */ - for(i= 0; i < len; i++) { - item= PySequence_GetItem(seq, i); - - if (!BPy_StructRNA_Check(item) || ((BPy_StructRNA*)item)->ptr.type != &RNA_Image) { - PyErr_SetString(PyExc_TypeError, "Expected a sequence of Image objects."); - return NULL; - } - } - - images= MEM_callocN(sizeof(*images), "ListBase of images"); - - for(i= 0; i < len; i++) { - BPy_StructRNA* srna; - - item= PySequence_GetItem(seq, i); - srna= (BPy_StructRNA*)item; - - link= MEM_callocN(sizeof(LinkData), "LinkData image"); - link->data= srna->ptr.data; - BLI_addtail(images, link); - - Py_DECREF(item); - } - - paths= MEM_callocN(sizeof(*paths), "ListBase of image paths"); - - /* call BKE_copy_images */ - BKE_copy_images(images, dest_dir, paths); - - /* convert filenames */ - ret= PyList_New(0); - - for(link= paths->first; link; link= link->next) { - if (link->data) { - item= PyUnicode_FromString(link->data); - PyList_Append(ret, item); - Py_DECREF(item); - } - else { - PyList_Append(ret, Py_None); - } - } - - /* free memory */ - BLI_freelistN(images); - BLI_freelistN(paths); - - /* return filenames */ - return ret; -} diff --git a/source/creator/SConscript b/source/creator/SConscript index 75e7494ebb5..82059c846e6 100644 --- a/source/creator/SConscript +++ b/source/creator/SConscript @@ -1,7 +1,10 @@ #!/usr/bin/python Import ('env') -sources = 'creator.c' +sources = ['creator.c'] + +if env['WITH_BF_UNIT_TEST']: + sources += env.Glob('tests/*.c') incs = '#/intern/guardedalloc ../blender/blenlib ../blender/blenkernel' incs += ' ../blender/editors/include ../blender/blenloader ../blender/imbuf' @@ -11,6 +14,10 @@ incs += ' ../kernel/gen_system #/extern/glew/include ../blender/gpu' incs += ' ' + env['BF_OPENGL_INC'] defs = [] + +if env['WITH_BF_UNIT_TEST']: + defs.append('WITH_UNIT_TEST') + if env['WITH_BF_QUICKTIME']: incs += ' ' + env['BF_QUICKTIME_INC'] defs.append('WITH_QUICKTIME') @@ -32,4 +39,4 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') -env.BlenderLib ( libname = 'bf_creator', sources = Split(sources), includes = Split(incs), defines = defs, libtype='core', priority = 0 ) +env.BlenderLib ( libname = 'bf_creator', sources = sources, includes = Split(incs), defines = defs, libtype='core', priority = 0 ) diff --git a/source/creator/creator.c b/source/creator/creator.c index 8e0152b5e63..3a2a0ff32bc 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -338,6 +338,12 @@ int main(int argc, char **argv) exit(0); } +#ifdef WITH_UNIT_TEST + if (!strcmp(argv[a], "--test")) { + exit(run_tests()); + } +#endif + /* end argument processing after -- */ if (!strcmp( argv[a], "--")){ a = argc; diff --git a/source/creator/tests/alltest.c b/source/creator/tests/alltest.c new file mode 100644 index 00000000000..2173ecd224f --- /dev/null +++ b/source/creator/tests/alltest.c @@ -0,0 +1,114 @@ +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BKE_blender.h" +#include "BKE_image.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" + +#include "BLI_listbase.h" + +#include "DNA_image_types.h" + +char bprogname[FILE_MAXDIR+FILE_MAXFILE]; +char btempdir[FILE_MAXDIR+FILE_MAXFILE]; + +typedef struct ImageTestData { + char *path; /* image filename */ + char *expect_path; /* file path that we expect */ + int type; /* image type */ + int ret; /* expected function return value */ +} ImageTestData; + +/* check that BKE_copy_images manipulates paths correctly */ +START_TEST(test_copy_images) +{ + char *dest_dir[] = {"/tmp/", "/tmp", NULL}; + char **dir; + ImageTestData *test; + + /* XXX Windows not tested */ +#ifdef WIN32 + static ImageTestData test_data[] = { + {"//bar/image.png", "C:\\Temp\\bar\\image.png"}, + /* TODO add more */ + {NULL, NULL}, + }; + + BLI_strncpy(G.sce, "C:\\Temp\untitled.blend", sizeof(G.sce)); +#else + /* + XXX are these paths possible in image->name?: + + ./foo/image.png + ../foo/image.png + + if so, BKE_copy_images currently doesn't support them! + */ + static ImageTestData test_data[] = { + {"//bar/image.png", "/tmp/bar/image.png", IMA_TYPE_IMAGE, 1}, + {"/foo/bar/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, + {"//image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, + {"//../../../foo/bar/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, + {"//./foo/bar/image.png", "/tmp/foo/bar/image.png", IMA_TYPE_IMAGE, 1}, + {"/tmp/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, + {"//textures/test/foo/bar/image.png", "/tmp/textures/test/foo/bar/image.png", IMA_TYPE_IMAGE, 1}, + {"//textures/test/foo/bar/image.png", "", IMA_TYPE_MULTILAYER, 0}, + {"", "", IMA_TYPE_IMAGE, 0}, + {NULL, NULL}, + }; + + /* substitute G.sce */ + BLI_strncpy(G.sce, "/tmp/foo/bar/untitled.blend", sizeof(G.sce)); +#endif + + for (dir = dest_dir; *dir; dir++) { + for (test= &test_data[0]; test->path; test++) { + Image image; + char path[FILE_MAX]; + int ret; + + BLI_strncpy(image.name, test->path, sizeof(image.name)); + image.type= test->type; + + ret= BKE_export_image(&image, *dest_dir, path, sizeof(path)); + + /* check if we got correct output */ + fail_if(ret != test->ret, "For image with filename %s and type %d, expected %d as return value got %d.", + test->path, test->type, test->ret, ret); + fail_if(strcmp(path, test->expect_path), "For image with filename %s and type %d, expected path '%s' got '%s'.", + test->path, test->type, test->expect_path, path); + } + } +} +END_TEST + +static Suite *image_suite(void) +{ + Suite *s = suite_create("Image"); + + /* Core test case */ + TCase *tc_core = tcase_create("Core"); + tcase_add_test(tc_core, test_copy_images); + suite_add_tcase(s, tc_core); + + return s; +} + +int run_tests() +{ + int totfail; + Suite *s = image_suite(); + SRunner *sr = srunner_create(s); + + /* run tests */ + srunner_run_all(sr, CK_VERBOSE); + + totfail= srunner_ntests_failed(sr); + srunner_free(sr); + + return !totfail ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tools/Blender.py b/tools/Blender.py index 8d213166a4b..c3ba9b2e76d 100644 --- a/tools/Blender.py +++ b/tools/Blender.py @@ -161,6 +161,8 @@ def setup_syslibs(lenv): ] syslibs += Split(lenv['BF_FREETYPE_LIB']) + if lenv['WITH_BF_UNIT_TEST']: + syslibs.append(lenv['BF_CHECK_LIB']) if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']: if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'): syslibs.append(lenv['BF_PYTHON_LIB']+'_d') diff --git a/tools/btools.py b/tools/btools.py index f4d79b1bb24..521596eca97 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -66,7 +66,8 @@ def validate_arguments(args, bc): 'BF_NUMJOBS', 'BF_MSVS', - 'WITH_BF_UNIT_TEST' + 'WITH_BF_UNIT_TEST', + 'BF_CHECK_LIB', ] # Have options here that scons expects to be lists @@ -360,7 +361,8 @@ def read_opts(cfg, args): ('BF_NUMJOBS', 'Number of build processes to spawn', '1'), ('BF_MSVS', 'Generate MSVS project files and solution', False), - (BoolVariable('WITH_BF_UNIT_TEST', 'Build unit tests', False)) + (BoolVariable('WITH_BF_UNIT_TEST', 'Build unit tests', False)), + ('BF_CHECK_LIB', 'Check unit testing framework library', 'check'), ) # end of opts.AddOptions() -- cgit v1.2.3 From d8f4ab2d599956fa4511d4cb8a6b68e613cf239f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 23 Jul 2009 15:57:30 +0000 Subject: API: - freeing strings returned by RNA struct functions in RNA_parameter_list_free Unit tests: - check that BKE_export_image actually creates a file. This test is becoming dangerous: it creates and deletes files under /tmp. Having written this complicated test function I now realize it's much easier to write tests in a scripted language, which gives more freedom in expressions and need not be compiled. --- release/io/export_fbx.py | 56 ++++++++++------- source/blender/blenkernel/intern/image.c | 23 ++++--- source/blender/makesrna/intern/rna_access.c | 9 ++- source/blender/python/intern/bpy_rna.c | 3 +- source/creator/tests/alltest.c | 93 ++++++++++++++++++++++++----- 5 files changed, 129 insertions(+), 55 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index f98cefb076e..b7caf2b24dc 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -237,24 +237,24 @@ def sane_texname(data): return sane_name(data, sane_name_mapping_tex) def sane_takename(data): return sane_name(data, sane_name_mapping_take) def sane_groupname(data): return sane_name(data, sane_name_mapping_group) -def derived_paths(fname_orig, basepath, FORCE_CWD=False): - ''' - fname_orig - blender path, can be relative - basepath - fname_rel will be relative to this - FORCE_CWD - dont use the basepath, just add a ./ to the filename. - use when we know the file will be in the basepath. - ''' - fname = bpy.sys.expandpath(fname_orig) -# fname = Blender.sys.expandpath(fname_orig) - fname_strip = os.path.basename(fname) -# fname_strip = strip_path(fname) - if FORCE_CWD: - fname_rel = '.' + os.sep + fname_strip - else: - fname_rel = bpy.sys.relpath(fname, basepath) -# fname_rel = Blender.sys.relpath(fname, basepath) - if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] - return fname, fname_strip, fname_rel +# def derived_paths(fname_orig, basepath, FORCE_CWD=False): +# ''' +# fname_orig - blender path, can be relative +# basepath - fname_rel will be relative to this +# FORCE_CWD - dont use the basepath, just add a ./ to the filename. +# use when we know the file will be in the basepath. +# ''' +# fname = bpy.sys.expandpath(fname_orig) +# # fname = Blender.sys.expandpath(fname_orig) +# fname_strip = os.path.basename(fname) +# # fname_strip = strip_path(fname) +# if FORCE_CWD: +# fname_rel = '.' + os.sep + fname_strip +# else: +# fname_rel = bpy.sys.relpath(fname, basepath) +# # fname_rel = Blender.sys.relpath(fname, basepath) +# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] +# return fname, fname_strip, fname_rel def mat4x4str(mat): @@ -1324,6 +1324,8 @@ def write(filename, batch_objects = None, \ # tex is an Image (Arystan) def write_video(texname, tex): + if not EXP_IMAGE_COPY: return + # Same as texture really! file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) @@ -1335,7 +1337,10 @@ def write(filename, batch_objects = None, \ Property: "Width", "int", "",0 Property: "Height", "int", "",0''') if tex: - fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + abspath = tex.export(basepath) + fname_rel = os.path.relpath(abspath, basepath) + fname_strip = os.path.basename(abspath) +# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: fname = fname_strip = fname_rel = '' @@ -1361,6 +1366,8 @@ def write(filename, batch_objects = None, \ def write_texture(texname, tex, num): + if not EXP_IMAGE_COPY: return + # if tex == None then this is a dummy tex file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) file.write('\n\t\tType: "TextureVideoClip"') @@ -1399,7 +1406,10 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tMedia: "Video::%s"' % texname) if tex: - fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + abspath = tex.export(basepath) + fname_rel = os.path.relpath(abspath, basepath) + fname_strip = os.path.basename(abspath) +# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: fname = fname_strip = fname_rel = '' @@ -3074,9 +3084,9 @@ Takes: {''') # copy images if enabled - if EXP_IMAGE_COPY: -# copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) - bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath) +# if EXP_IMAGE_COPY: +# # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) +# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath) print('export finished in %.4f sec.' % (bpy.sys.time() - start_time)) # print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a469752602e..f0b29f766ec 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2160,14 +2160,11 @@ int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_pa /* expand "//" in filename and get absolute path */ BLI_convertstringcode(path, G.sce); - /* in unit tests, we don't want to modify the filesystem */ -#ifndef WITH_UNIT_TEST /* proceed only if image file exists */ if (!BLI_exists(path)) { if (G.f & G_DEBUG) printf("%s doesn't exist\n", path); - goto next; + return 0; } -#endif /* get the directory part */ BLI_split_dirfile_basic(path, dir, base); @@ -2191,10 +2188,8 @@ int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_pa BLI_join_dirfile(dest_path, dest_dir, rel); -#ifndef WITH_UNIT_TEST /* build identical directory structure under dest_dir */ - BLI_make_existing_file(dest_path); -#endif + BLI_recurdir_fileops(dest_path); BLI_join_dirfile(dest_path, dest_path, base); } @@ -2206,14 +2201,18 @@ int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_pa BLI_join_dirfile(dest_path, dest_dir, base); } -#ifndef WITH_UNIT_TEST if (G.f & G_DEBUG) printf("copying %s to %s\n", path, dest_path); - if (BLI_copy_fileops(path, dest_path) != 0) { - if (G.f & G_DEBUG) printf("couldn't copy %s to %s\n", path, dest_path); - return 0; + /* only copy if paths differ */ + if (strcmp(path, dest_path)) { + if (BLI_copy_fileops(path, dest_path) != 0) { + if (G.f & G_DEBUG) printf("couldn't copy %s to %s\n", path, dest_path); + return 0; + } + } + else if (G.f & G_DEBUG){ + printf("%s and %s are the same file\n", path, dest_path); } -#endif BLI_strncpy(out_path, dest_path, out_path_len); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 9c133605f96..c9bf97fd274 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2820,9 +2820,12 @@ void RNA_parameter_list_free(ParameterList *parms) if(parm->type == PROP_COLLECTION) { BLI_freelistN((ListBase*)((char*)parms->data+tot)); } - else if(parm->flag & PROP_DYNAMIC_ARRAY) { - /* for dynamic arrays, data is a pointer to an array */ - MEM_freeN(*(char**)parms->data+tot); + else if(parm == parms->func->ret) { + /* for dynamic arrays and strings, data is a pointer to an array */ + char *ptr= *(char**)((char*)parms->data+tot); + if((parm->flag & PROP_DYNAMIC_ARRAY || parm->type == PROP_STRING) && ptr) { + MEM_freeN(ptr); + } } tot+= rna_parameter_size(parm); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c7767c6c08e..780c58e2877 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1844,7 +1844,8 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) break; case PROP_STRING: { - ret = PyUnicode_FromString( *(char**)data ); + char *ptr = *(char**)data; + ret = ptr ? PyUnicode_FromString( ptr ) : Py_None; break; } case PROP_ENUM: diff --git a/source/creator/tests/alltest.c b/source/creator/tests/alltest.c index 2173ecd224f..8bb2b1a9bb0 100644 --- a/source/creator/tests/alltest.c +++ b/source/creator/tests/alltest.c @@ -10,6 +10,9 @@ #include "BKE_global.h" #include "BLI_listbase.h" +#include "BLI_util.h" +#include "BLI_fileops.h" +#include "BLI_string.h" #include "DNA_image_types.h" @@ -21,12 +24,31 @@ typedef struct ImageTestData { char *expect_path; /* file path that we expect */ int type; /* image type */ int ret; /* expected function return value */ + int create_file; /* whether the file should be created */ } ImageTestData; +/* recursively deletes a directory only if it is under /tmp */ +static void delete_only_tmp(char *path, int dir) { +#ifdef WIN32 +#else + if (!strncmp(path, "/tmp/", 5) && BLI_exists(path)) { + BLI_delete(path, dir, 1); + } +#endif +} + +static void touch_only_tmp(char *path) { +#ifdef WIN32 +#else + if (!strncmp(path, "/tmp/", 5)) { + BLI_touch(path); + } +#endif +} + /* check that BKE_copy_images manipulates paths correctly */ START_TEST(test_copy_images) { - char *dest_dir[] = {"/tmp/", "/tmp", NULL}; char **dir; ImageTestData *test; @@ -49,38 +71,77 @@ START_TEST(test_copy_images) if so, BKE_copy_images currently doesn't support them! */ static ImageTestData test_data[] = { - {"//bar/image.png", "/tmp/bar/image.png", IMA_TYPE_IMAGE, 1}, - {"/foo/bar/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, - {"//image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, - {"//../../../foo/bar/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, - {"//./foo/bar/image.png", "/tmp/foo/bar/image.png", IMA_TYPE_IMAGE, 1}, - {"/tmp/image.png", "/tmp/image.png", IMA_TYPE_IMAGE, 1}, - {"//textures/test/foo/bar/image.png", "/tmp/textures/test/foo/bar/image.png", IMA_TYPE_IMAGE, 1}, - {"//textures/test/foo/bar/image.png", "", IMA_TYPE_MULTILAYER, 0}, - {"", "", IMA_TYPE_IMAGE, 0}, + {"//bar/image.png", "/tmp/blender/dest/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"//image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"//textures/test/foo/bar/image.png", "/tmp/blender/dest/textures/test/foo/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"//textures/test/foo/bar/image.png", "", IMA_TYPE_MULTILAYER, 0, 1}, + {"//./foo/bar/image.png", "/tmp/blender/dest/foo/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"//../foo/bar/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"/tmp/blender/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, + /* expecting it to return 1 when src and dest are the same file */ + {"/tmp/blender/foo/bar/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, + {"/tmp/blender/dest/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, + /* expecting empty path and 0 return value for non-existing files */ + {"/tmp/blender/src/file-not-created", "", IMA_TYPE_IMAGE, 0, 0}, + {"", "", IMA_TYPE_IMAGE, 0, 0}, {NULL, NULL}, }; + char *dest_dir[] = {"/tmp/blender/dest/", "/tmp/blender/dest", NULL}; + const char *blend_dir = "/tmp/blender/src"; + /* substitute G.sce */ - BLI_strncpy(G.sce, "/tmp/foo/bar/untitled.blend", sizeof(G.sce)); + BLI_snprintf(G.sce, sizeof(G.sce), "%s/untitled.blend", blend_dir); #endif + /* only delete files/directories under /tmp/ ! */ + delete_only_tmp(blend_dir, 1); + + for (dir = dest_dir; *dir; dir++) { + delete_only_tmp(*dir, 1); + } + + /* create files */ + BLI_recurdir_fileops(blend_dir); + + /* create fake empty source files */ + for (test= &test_data[0]; test->path; test++) { + char dir[FILE_MAX]; + char path[FILE_MAX]; + + if (!test->create_file) continue; + + /* expand "//" */ + BLI_strncpy(path, test->path, sizeof(path)); + BLI_convertstringcode(path, G.sce); + + /* create a directory */ + BLI_split_dirfile_basic(path, dir, NULL); + BLI_recurdir_fileops(dir); + + /* create a file */ + touch_only_tmp(path); + } + for (dir = dest_dir; *dir; dir++) { for (test= &test_data[0]; test->path; test++) { Image image; char path[FILE_MAX]; + char part[200]; int ret; BLI_strncpy(image.name, test->path, sizeof(image.name)); image.type= test->type; - ret= BKE_export_image(&image, *dest_dir, path, sizeof(path)); + ret= BKE_export_image(&image, *dir, path, sizeof(path)); /* check if we got correct output */ - fail_if(ret != test->ret, "For image with filename %s and type %d, expected %d as return value got %d.", - test->path, test->type, test->ret, ret); - fail_if(strcmp(path, test->expect_path), "For image with filename %s and type %d, expected path '%s' got '%s'.", - test->path, test->type, test->expect_path, path); + BLI_snprintf(part, sizeof(part), "For image with filename %s and type %d", test->path, test->type); + fail_if(ret != test->ret, "%s, expected %d as return value got %d.", part, test->ret, ret); + fail_if(strcmp(path, test->expect_path), "%s, expected path %s got \"%s\".", part, test->expect_path, path); + if (test->ret == ret && ret == 1) { + fail_if(!BLI_exists(test->expect_path), "%s, expected %s to be created.", part, test->expect_path); + } } } } -- cgit v1.2.3 From d63d703842f62916f6242ac7c9331edd4943dc5e Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 24 Jul 2009 14:26:47 +0000 Subject: - added operator for OBJ importer plus some python 3 conversions --- release/io/export_obj.py | 9 +- release/io/import_obj.py | 144 ++++++++++++++++++++++-------- source/blender/makesrna/intern/rna_pose.c | 7 +- 3 files changed, 112 insertions(+), 48 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index bf3aa4ae819..4d67903c343 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -200,19 +200,16 @@ def copy_images(dest_dir): # XXX not converted def test_nurbs_compat(ob): - if ob.type != 'CURVE': + if ob.type != 'Curve': return False - for nu in ob.data.curves: + for nu in ob.data: 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 diff --git a/release/io/import_obj.py b/release/io/import_obj.py index 659d5207261..a4778ac7790 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -57,7 +57,8 @@ def stripFile(path): lastSlash= max(path.rfind('\\'), path.rfind('/')) if lastSlash != -1: path= path[:lastSlash] - return '%s%s' % (path, sys.sep) + return '%s%s' % (path, os.sep) +# return '%s%s' % (path, sys.sep) def stripPath(path): '''Strips the slashes from the back of a string''' @@ -219,8 +220,9 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ # Add an MTL with the same name as the obj if no MTLs are spesified. temp_mtl= stripExt(stripPath(filepath))+ '.mtl' - - if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: + + if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs: +# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: material_libs.append( temp_mtl ) del temp_mtl @@ -236,7 +238,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ for libname in material_libs: mtlpath= DIR + libname - if not bpy.sys.exists(mtlpath): + if not os.path.exists(mtlpath): # if not sys.exists(mtlpath): #print '\tError Missing MTL: "%s"' % mtlpath pass @@ -247,7 +249,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ for line in mtl: #.xreadlines(): if line.startswith('newmtl'): context_material_name= line_value(line.split()) - if unique_materials.has_key(context_material_name): + if context_material_name in unique_materials: context_material = unique_materials[ context_material_name ] else: context_material = None @@ -377,14 +379,14 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index matname= face[2] - if matname and not unique_materials_split.has_key(matname): + if matname and matname not in unique_materials_split: unique_materials_split[matname] = unique_materials[matname] faces_split.append(face) # remove one of the itemas and reorder - return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()] + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.items()] def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): @@ -397,7 +399,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l if unique_smooth_groups: sharp_edges= {} - smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ]) + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.keys() ]) context_smooth_group_old= -1 # Split fgons into tri's @@ -408,7 +410,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l context_object= None # reverse loop through face indicies - for f_idx in xrange(len(faces)-1, -1, -1): + for f_idx in range(len(faces)-1, -1, -1): face_vert_loc_indicies,\ face_vert_tex_indicies,\ @@ -425,7 +427,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l if CREATE_EDGES: # generators are better in python 2.4+ but can't be used in 2.3 # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) - edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] ) + edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in range(len_face_vert_loc_indicies-1)] ) faces.pop(f_idx) else: @@ -437,7 +439,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l edge_dict= smooth_group_users[context_smooth_group] context_smooth_group_old= context_smooth_group - for i in xrange(len_face_vert_loc_indicies): + for i in range(len_face_vert_loc_indicies): i1= face_vert_loc_indicies[i] i2= face_vert_loc_indicies[i-1] if i1>i2: i1,i2= i2,i1 @@ -485,8 +487,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # Build sharp edges if unique_smooth_groups: - for edge_dict in smooth_group_users.itervalues(): - for key, users in edge_dict.iteritems(): + for edge_dict in smooth_group_users.values(): + for key, users in edge_dict.items(): if users==1: # This edge is on the boundry of a group sharp_edges[key]= None @@ -496,7 +498,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l materials= [None] * len(unique_materials) - for name, index in material_mapping.iteritems(): + for name, index in material_mapping.items(): materials[index]= unique_materials[name] me= bpy.data.add_mesh(dataname) @@ -639,7 +641,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # Create the vertex groups. No need to have the flag passed here since we test for the # content of the vertex_groups. If the user selects to NOT have vertex groups saved then # the following test will never run - for group_name, group_indicies in vertex_groups.iteritems(): + for group_name, group_indicies in vertex_groups.items(): group= ob.add_vertex_group(group_name) # me.addVertGroup(group_name) for vertex_index in group_indicies: @@ -660,16 +662,16 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects): cstype = context_nurbs.get('cstype', None) if cstype == None: - print '\tWarning, cstype not found' + print('\tWarning, cstype not found') return if cstype != 'bspline': - print '\tWarning, cstype is not supported (only bspline)' + print('\tWarning, cstype is not supported (only bspline)') return if not curv_idx: - print '\tWarning, curv argument empty or not set' + print('\tWarning, curv argument empty or not set') return if len(deg) > 1 or parm_v: - print '\tWarning, surfaces not supported' + print('\tWarning, surfaces not supported') return cu = bpy.data.curves.new(name, 'Curve') @@ -691,7 +693,7 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects): # get for endpoint flag from the weighting if curv_range and len(parm_u) > deg[0]+1: do_endpoints = True - for i in xrange(deg[0]+1): + for i in range(deg[0]+1): if abs(parm_u[i]-curv_range[0]) > 0.0001: do_endpoints = False @@ -773,7 +775,7 @@ def load_obj(filepath, This function passes the file and sends the data off to be split into objects and then converted into mesh objects ''' - print '\nimporting obj "%s"' % filepath + print('\nimporting obj "%s"' % filepath) if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: POLYGROUPS = False @@ -816,7 +818,7 @@ def load_obj(filepath, # so we need to know weather context_multi_line= '' - print '\tparsing obj file "%s"...' % filepath, + print('\tparsing obj file "%s"...' % filepath, end=' ') time_sub= bpy.sys.time() # time_sub= sys.time() @@ -1028,31 +1030,31 @@ def load_obj(filepath, file.close() time_new= bpy.sys.time() # time_new= sys.time() - print '%.4f sec' % (time_new-time_sub) + print('%.4f sec' % (time_new-time_sub)) time_sub= time_new - print '\tloading materials and images...', + print('\tloading materials and images...', end=' ') create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) time_new= bpy.sys.time() # time_new= sys.time() - print '%.4f sec' % (time_new-time_sub) + print('%.4f sec' % (time_new-time_sub)) time_sub= time_new if not ROTATE_X90: verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] # deselect all - if context.selected_objects: - bpy.ops.OBJECT_OT_select_all_toggle() +# if context.selected_objects: +# bpy.ops.OBJECT_OT_select_all_toggle() scene = context.scene # scn = bpy.data.scenes.active # scn.objects.selected = [] new_objects= [] # put new objects here - print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), + print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), end=' ') # Split the mesh by objects/materials, may if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True else: SPLIT_OB_OR_GROUP = False @@ -1095,8 +1097,8 @@ def load_obj(filepath, time_new= bpy.sys.time() # time_new= sys.time() - print '%.4f sec' % (time_new-time_sub) - print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) + print('%.4f sec' % (time_new-time_sub)) + print('finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main))) DEBUG= True @@ -1189,14 +1191,14 @@ def load_obj_ui(filepath, BATCH_LOAD= False): def do_help(e,v): url = __url__[0] - print 'Trying to open web browser with documentation at this address...' - print '\t' + url + print('Trying to open web browser with documentation at this address...') + print('\t' + url) try: import webbrowser webbrowser.open(url) except: - print '...could not open a browser window.' + print('...could not open a browser window.') def obj_ui(): ui_x, ui_y = GLOBALS['MOUSE'] @@ -1306,11 +1308,11 @@ def load_obj_ui_batch(file): DEBUG= False -if __name__=='__main__' and not DEBUG: - if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: - Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') - else: - Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') +# if __name__=='__main__' and not DEBUG: +# if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: +# Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') +# else: +# Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') # For testing compatibility ''' @@ -1340,6 +1342,70 @@ else: #load_obj('/test.obj') #load_obj('/fe/obj/mba1.obj') + + +class IMPORT_OT_obj(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "import.obj" + __label__ = "Import 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= ""), + + bpy.props.BoolProperty(attr="CREATE_SMOOTH_GROUPS", name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True), + bpy.props.BoolProperty(attr="CREATE_FGONS", name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True), + bpy.props.BoolProperty(attr="CREATE_EDGES", name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True), + bpy.props.BoolProperty(attr="SPLIT_OBJECTS", name="Object", description="Import OBJ Objects into Blender Objects", default= True), + bpy.props.BoolProperty(attr="SPLIT_GROUPS", name="Group", description="Import OBJ Groups into Blender Objects", default= True), + bpy.props.BoolProperty(attr="SPLIT_MATERIALS", name="Material", description="Import each material into a seperate mesh (Avoids > 16 per mesh error)", default= True), + # old comment: only used for user feedback + # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj + # bpy.props.BoolProperty(attr="KEEP_VERT_ORDER", name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True), + bpy.props.BoolProperty(attr="ROTATE_X90", name="-X90", description="Rotate X 90.", default= True), + bpy.props.FloatProperty(attr="CLAMP_SIZE", name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.01, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0), + bpy.props.BoolProperty(attr="POLYGROUPS", name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True), + bpy.props.BoolProperty(attr="IMAGE_SEARCH", name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True), + ] + + def poll(self, context): + print("Poll") + return context.active_object != None + + def execute(self, context): + # print("Selected: " + context.active_object.name) + + if not self.filename: + raise Exception("filename not set") + + load_obj(self.filename, + context, + self.CLAMP_SIZE, + self.CREATE_FGONS, + self.CREATE_SMOOTH_GROUPS, + self.CREATE_EDGES, + self.SPLIT_OBJECTS, + self.SPLIT_GROUPS, + self.SPLIT_MATERIALS, + self.ROTATE_X90, + self.IMAGE_SEARCH, + self.POLYGROUPS) + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + + +bpy.ops.add(IMPORT_OT_obj) + + # NOTES (all line numbers refer to 2.4x import_obj.py, not this file) # check later: line 489 # can convert now: edge flags, edges: lines 508-528 @@ -1351,4 +1417,4 @@ else: # replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load) # bitmask won't work? - 132 # uses operator bpy.ops.OBJECT_OT_select_all_toggle() to deselect all (not necessary?) -# uses bpy.sys.exists and bpy.sys.time() +# uses bpy.sys.time() diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index c6f4f430983..ce803aae78a 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -332,10 +332,11 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE|ND_TRANSFORM, "rna_Pose_update"); /* These three matrix properties await an implementation of the PROP_MATRIX subtype, which currently doesn't exist. */ -/* prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_struct_type(prop, "chan_mat"); + prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "chan_mat"); + RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints.");*/ + RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints."); /* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */ prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); -- cgit v1.2.3 From d1e42cc5f85a6665e85a388763696fd291b86db8 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 24 Jul 2009 15:27:59 +0000 Subject: Forgot to add rna_image_api.c. --- source/blender/makesrna/intern/rna_image_api.c | 73 ++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 source/blender/makesrna/intern/rna_image_api.c diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c new file mode 100644 index 00000000000..42ee2b64c7a --- /dev/null +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -0,0 +1,73 @@ +/** + * + * + * ***** 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 +#include +#include +#include + +#include "RNA_define.h" +#include "RNA_types.h" + +#include "DNA_object_types.h" + +#ifdef RNA_RUNTIME + +#include "BKE_utildefines.h" +#include "BKE_image.h" + +static char *rna_Image_export(Image *image, char *dest_dir) +{ + int length = FILE_MAX; + char *path= MEM_callocN(length, "image file path"); + + if (!BKE_export_image(image, dest_dir, path, length)) { + MEM_freeN(path); + return NULL; + } + + return path; +} + +#else + +void RNA_api_image(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "export", "rna_Image_export"); + RNA_def_function_ui_description(func, "Copy image file to a directory rebuilding subdirectory structure."); + parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "path", "", 0, "", "Absolute file path of copied image."); + RNA_def_function_return(func, parm); +} + +#endif + -- cgit v1.2.3 From 4086ca58e275816a49950f6ac0cbffa6cb36a8ad Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 3 Aug 2009 12:02:40 +0000 Subject: - re-wrote image exporting function renaming it from BKE_export_image to BKE_get_image_export_path because now it doesn't copy files but only manipulates paths. It produces both ablsolute and relative paths. COLLADA exporter can now use it. - re-wrote unit test for it, this is now more compact and readable - RNA API Image.get_export_path takes a boolean arg to indicate whether a relative or absolute path should be returned. Python scripts can now use it. --- source/blender/blenkernel/BKE_image.h | 3 +- source/blender/blenkernel/intern/image.c | 77 +++++------ source/blender/makesrna/intern/rna_image_api.c | 12 +- source/creator/tests/alltest.c | 181 +++++++++++++------------ 4 files changed, 136 insertions(+), 137 deletions(-) diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 052f7738f2b..56c58cdc6bf 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -156,8 +156,7 @@ struct Image *BKE_image_copy(struct Image *ima); void BKE_image_merge(struct Image *dest, struct Image *source); /* copy image file to a directory rebuilding subdirectory structure */ -int BKE_export_image(struct Image *im, const char *dest_dir, char *out_path, int out_path_len); - +int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, int abs_size, char *rel, int rel_size); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f0b29f766ec..276d79b7e32 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2117,41 +2117,51 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr) } /* - Copy an image to destination directory rebuilding subdirectory structure if needed. - Target image path is written to out_path. - Returns 1 on success, 0 otherwise. + Produce image export path. + + Fails returning 0 if image filename is empty or if destination path + matches image path (i.e. both are the same file). + + Trailing slash in dest_dir is optional. Logic: - - if an image is "below" current .blend file directory, rebuild the same dir structure in dest_dir + - if an image is "below" current .blend file directory, rebuild the + same dir structure in dest_dir - For example //textures/foo/bar.png becomes [dest_dir]/textures/foo/bar.png. + For example //textures/foo/bar.png becomes + [dest_dir]/textures/foo/bar.png. - - if an image is not "below" current .blend file directory, disregard it's path and copy it in the - same directory where 3D file goes. + - if an image is not "below" current .blend file directory, + disregard it's path and copy it in the same directory where 3D file + goes. For example //../foo/bar.png becomes [dest_dir]/bar.png. This logic will help ensure that all image paths are relative and that a user gets his images in one place. It'll also provide consistent behaviour across exporters. - */ -int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_path_len) +int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, int abs_size, char *rel, int rel_size) { char path[FILE_MAX]; char dir[FILE_MAX]; char base[FILE_MAX]; char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */ char dest_path[FILE_MAX]; + char rel_dir[FILE_MAX]; int len; - out_path[0]= 0; + if (abs) + abs[0]= 0; + + if (rel) + rel[0]= 0; BLI_split_dirfile_basic(G.sce, blend_dir, NULL); - if (!strcmp(im->name, "") || im->type != IMA_TYPE_IMAGE) { - if (G.f & G_DEBUG) printf("invalid image type\n"); + if (!strlen(im->name)) { + if (G.f & G_DEBUG) printf("Invalid image type.\n"); return 0; } @@ -2160,61 +2170,48 @@ int BKE_export_image(Image *im, const char *dest_dir, char *out_path, int out_pa /* expand "//" in filename and get absolute path */ BLI_convertstringcode(path, G.sce); - /* proceed only if image file exists */ - if (!BLI_exists(path)) { - if (G.f & G_DEBUG) printf("%s doesn't exist\n", path); - return 0; - } - /* get the directory part */ BLI_split_dirfile_basic(path, dir, base); len= strlen(blend_dir); + rel_dir[0] = 0; + /* if image is "below" current .blend file directory */ if (!strncmp(path, blend_dir, len)) { /* if image is _in_ current .blend file directory */ if (!strcmp(dir, blend_dir)) { - /* copy to dest_dir */ BLI_join_dirfile(dest_path, dest_dir, base); } /* "below" */ else { - char rel[FILE_MAX]; - /* rel = image_path_dir - blend_dir */ - BLI_strncpy(rel, dir + len, sizeof(rel)); - - BLI_join_dirfile(dest_path, dest_dir, rel); - - /* build identical directory structure under dest_dir */ - BLI_recurdir_fileops(dest_path); + BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir)); + BLI_join_dirfile(dest_path, dest_dir, rel_dir); BLI_join_dirfile(dest_path, dest_path, base); } } /* image is out of current directory */ else { - /* copy to dest_dir */ BLI_join_dirfile(dest_path, dest_dir, base); } - if (G.f & G_DEBUG) printf("copying %s to %s\n", path, dest_path); - - /* only copy if paths differ */ - if (strcmp(path, dest_path)) { - if (BLI_copy_fileops(path, dest_path) != 0) { - if (G.f & G_DEBUG) printf("couldn't copy %s to %s\n", path, dest_path); - return 0; - } - } - else if (G.f & G_DEBUG){ - printf("%s and %s are the same file\n", path, dest_path); + /* only return 1 if paths differ */ + if (!strcmp(path, dest_path)) { + if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path); + return 0; } - BLI_strncpy(out_path, dest_path, out_path_len); + if (abs) + BLI_strncpy(abs, dest_path, abs_size); + + if (rel) { + strncat(rel, rel_dir, rel_size); + strncat(rel, base, rel_size); + } return 1; } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 42ee2b64c7a..20770ef2957 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -41,12 +41,12 @@ #include "BKE_utildefines.h" #include "BKE_image.h" -static char *rna_Image_export(Image *image, char *dest_dir) +static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel) { int length = FILE_MAX; char *path= MEM_callocN(length, "image file path"); - if (!BKE_export_image(image, dest_dir, path, length)) { + if (!BKE_get_image_export_path(image, dest_dir, rel ? NULL : path, length, rel ? path : NULL, length )) { MEM_freeN(path); return NULL; } @@ -61,11 +61,13 @@ void RNA_api_image(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func= RNA_def_function(srna, "export", "rna_Image_export"); - RNA_def_function_ui_description(func, "Copy image file to a directory rebuilding subdirectory structure."); + func= RNA_def_function(srna, "export", "rna_Image_get_export_path"); + RNA_def_function_ui_description(func, "Produce image export path."); parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory."); RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "path", "", 0, "", "Absolute file path of copied image."); + parm= RNA_def_boolean(func, "get_rel_path", 1, "", "Return relative path if True."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_string(func, "path", "", 0, "", "Absolute export path."); RNA_def_function_return(func, parm); } diff --git a/source/creator/tests/alltest.c b/source/creator/tests/alltest.c index 8bb2b1a9bb0..99e0d2f5b26 100644 --- a/source/creator/tests/alltest.c +++ b/source/creator/tests/alltest.c @@ -19,48 +19,26 @@ char bprogname[FILE_MAXDIR+FILE_MAXFILE]; char btempdir[FILE_MAXDIR+FILE_MAXFILE]; +typedef struct ImageTestResult { + char *path; + char *rel; + int ret; +} ImageTestResult; + typedef struct ImageTestData { char *path; /* image filename */ - char *expect_path; /* file path that we expect */ - int type; /* image type */ - int ret; /* expected function return value */ - int create_file; /* whether the file should be created */ + ImageTestResult result[10]; } ImageTestData; -/* recursively deletes a directory only if it is under /tmp */ -static void delete_only_tmp(char *path, int dir) { -#ifdef WIN32 -#else - if (!strncmp(path, "/tmp/", 5) && BLI_exists(path)) { - BLI_delete(path, dir, 1); - } -#endif -} - -static void touch_only_tmp(char *path) { -#ifdef WIN32 -#else - if (!strncmp(path, "/tmp/", 5)) { - BLI_touch(path); - } -#endif -} - /* check that BKE_copy_images manipulates paths correctly */ START_TEST(test_copy_images) { char **dir; ImageTestData *test; + int i,j; - /* XXX Windows not tested */ #ifdef WIN32 - static ImageTestData test_data[] = { - {"//bar/image.png", "C:\\Temp\\bar\\image.png"}, - /* TODO add more */ - {NULL, NULL}, - }; - - BLI_strncpy(G.sce, "C:\\Temp\untitled.blend", sizeof(G.sce)); + /* TBD... */ #else /* XXX are these paths possible in image->name?: @@ -70,77 +48,100 @@ START_TEST(test_copy_images) if so, BKE_copy_images currently doesn't support them! */ + + const char *blend_dir = "/home/user/foo"; + char *dest_dir[] = {"/home/user/", "/home/user", "/home/user/export/", "/home/user/foo/", NULL}; + static ImageTestData test_data[] = { - {"//bar/image.png", "/tmp/blender/dest/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"//image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"//textures/test/foo/bar/image.png", "/tmp/blender/dest/textures/test/foo/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"//textures/test/foo/bar/image.png", "", IMA_TYPE_MULTILAYER, 0, 1}, - {"//./foo/bar/image.png", "/tmp/blender/dest/foo/bar/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"//../foo/bar/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"/tmp/blender/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, - /* expecting it to return 1 when src and dest are the same file */ - {"/tmp/blender/foo/bar/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, - {"/tmp/blender/dest/image.png", "/tmp/blender/dest/image.png", IMA_TYPE_IMAGE, 1, 1}, - /* expecting empty path and 0 return value for non-existing files */ - {"/tmp/blender/src/file-not-created", "", IMA_TYPE_IMAGE, 0, 0}, - {"", "", IMA_TYPE_IMAGE, 0, 0}, - {NULL, NULL}, - }; - char *dest_dir[] = {"/tmp/blender/dest/", "/tmp/blender/dest", NULL}; - const char *blend_dir = "/tmp/blender/src"; + /* image path | [expected output path | corresponding relative path | expected return value] */ + + /* relative, 0 level deep */ + {"//image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"", "", 0},}}, + + /* relative, 1 level deep */ + {"//bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/export/bar/image.png", "bar/image.png", 1}, + {"", "", 0},}}, + + /* relative, 2 level deep */ + {"//bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, + {"", "", 0},}}, + + /* absolute, not under .blend dir */ + {"/home/user/bar/image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"/home/user/foo/image.png", "image.png", 1},}}, + + /* absolute, under .blend dir, 0 level deep */ + {"/home/user/foo/image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"", "", 0},}}, + + /* absolute, under .blend dir, 1 level deep */ + {"/home/user/foo/bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/export/bar/image.png", "bar/image.png", 1}, + {"", "", 0},}}, + + /* absolute, under .blend dir, 2 level deep */ + {"/home/user/foo/bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, + {"", "", 0},}}, + + /* empty image path, don't let these pass! */ + {"", {{"", 0}, + {"", 0}, + {"", 0}}}, + + {NULL}, + }; /* substitute G.sce */ BLI_snprintf(G.sce, sizeof(G.sce), "%s/untitled.blend", blend_dir); #endif - /* only delete files/directories under /tmp/ ! */ - delete_only_tmp(blend_dir, 1); - - for (dir = dest_dir; *dir; dir++) { - delete_only_tmp(*dir, 1); - } - - /* create files */ - BLI_recurdir_fileops(blend_dir); - - /* create fake empty source files */ - for (test= &test_data[0]; test->path; test++) { - char dir[FILE_MAX]; - char path[FILE_MAX]; - - if (!test->create_file) continue; - - /* expand "//" */ - BLI_strncpy(path, test->path, sizeof(path)); - BLI_convertstringcode(path, G.sce); - - /* create a directory */ - BLI_split_dirfile_basic(path, dir, NULL); - BLI_recurdir_fileops(dir); - - /* create a file */ - touch_only_tmp(path); - } - - for (dir = dest_dir; *dir; dir++) { + for (dir= dest_dir, i= 0; *dir; dir++, i++) { for (test= &test_data[0]; test->path; test++) { Image image; char path[FILE_MAX]; + char rel[FILE_MAX]; char part[200]; int ret; BLI_strncpy(image.name, test->path, sizeof(image.name)); - image.type= test->type; - ret= BKE_export_image(&image, *dir, path, sizeof(path)); + /* passing NULL as abs path or rel path or both shouldn't break it */ + int abs_rel_null[][2]= {{0, 0}, {1, 0}, {0, 1}, {1, 1}, {-1}}; + + for (j= 0; abs_rel_null[j][0] != -1; j++) { + + int *is_null= abs_rel_null[j]; + + ret= BKE_get_image_export_path(&image, *dir, + is_null[0] ? NULL : path, sizeof(path), + is_null[1] ? NULL : rel, sizeof(rel)); + + BLI_snprintf(part, sizeof(part), "For image at %s (output abs path is %s, rel path is %s)", + test->path, is_null[0] ? "NULL" : "non-NULL", is_null[1] ? "NULL" : "non-NULL"); + + /* we should get what we expect */ + ImageTestResult *res= &test->result[i]; + fail_if(ret != res->ret, "%s, expected to return %d got %d.", part, res->ret, ret); - /* check if we got correct output */ - BLI_snprintf(part, sizeof(part), "For image with filename %s and type %d", test->path, test->type); - fail_if(ret != test->ret, "%s, expected %d as return value got %d.", part, test->ret, ret); - fail_if(strcmp(path, test->expect_path), "%s, expected path %s got \"%s\".", part, test->expect_path, path); - if (test->ret == ret && ret == 1) { - fail_if(!BLI_exists(test->expect_path), "%s, expected %s to be created.", part, test->expect_path); + if (!is_null[0] && res->path) + fail_if(strcmp(path, res->path), "%s, expected absolute path \"%s\" got \"%s\".", part, res->path, path); + if (!is_null[1] && res->rel) + fail_if(strcmp(rel, res->rel), "%s, expected relative path \"%s\" got \"%s\".", part, res->rel, rel); } } } @@ -149,10 +150,10 @@ END_TEST static Suite *image_suite(void) { - Suite *s = suite_create("Image"); + Suite *s= suite_create("Image"); /* Core test case */ - TCase *tc_core = tcase_create("Core"); + TCase *tc_core= tcase_create("Core"); tcase_add_test(tc_core, test_copy_images); suite_add_tcase(s, tc_core); @@ -162,8 +163,8 @@ static Suite *image_suite(void) int run_tests() { int totfail; - Suite *s = image_suite(); - SRunner *sr = srunner_create(s); + Suite *s= image_suite(); + SRunner *sr= srunner_create(s); /* run tests */ srunner_run_all(sr, CK_VERBOSE); -- cgit v1.2.3 From 7586990ace3a988e720397f47bf95b7bc9d7124b Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 5 Aug 2009 07:59:49 +0000 Subject: - modified BKE_get_image_export_path so that it writes relative path if src file = dest file returning 2 in this case - modified unit tests for ^ firstly - incorporated Image.get_export_path into FBX exporter script --- release/io/export_fbx.py | 22 +++++++++++++++------- source/blender/blenkernel/intern/image.c | 12 ++++++------ source/blender/makesrna/intern/rna_image_api.c | 5 +++++ source/creator/tests/alltest.c | 12 ++++++------ 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index a81dea4d909..c50b60fd97e 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -39,6 +39,7 @@ http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx import os import time import math # math.pi +import shutil # for file copying # try: # import time @@ -1324,8 +1325,6 @@ def write(filename, batch_objects = None, \ # tex is an Image (Arystan) def write_video(texname, tex): - if not EXP_IMAGE_COPY: return - # Same as texture really! file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) @@ -1337,9 +1336,15 @@ def write(filename, batch_objects = None, \ Property: "Width", "int", "",0 Property: "Height", "int", "",0''') if tex: - abspath = tex.export(basepath) - fname_rel = os.path.relpath(abspath, basepath) - fname_strip = os.path.basename(abspath) + src = bpy.sys.expandpath(tex.filename) + fname_rel = tex.get_export_path(basepath, True) + fname_abs = tex.get_export_path(basepath, False) + fname_strip = os.path.basename(fname_rel) + + if EXP_IMAGE_COPY: + if !os.path.exists(fname_abs): + shutil.copy(src, fname_abs) + # fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: fname = fname_strip = fname_rel = '' @@ -1404,11 +1409,14 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tMedia: "Video::%s"' % texname) if tex: - fname_rel = tex.get_export_path(relpath, True) + src = bpy.sys.expandpath(tex.filename) + fname_rel = tex.get_export_path(basepath, True) + fname_abs = tex.get_export_path(basepath, False) fname_strip = os.path.basename(fname_rel) if EXP_IMAGE_COPY: - + if !os.path.exists(fname_abs): + shutil.copy(src, fname_abs) # fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index b66213ffbc2..4a355640d8b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2206,12 +2206,6 @@ int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, BLI_join_dirfile(dest_path, dest_dir, base); } - /* only return 1 if paths differ */ - if (!strcmp(path, dest_path)) { - if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path); - return 0; - } - if (abs) BLI_strncpy(abs, dest_path, abs_size); @@ -2220,5 +2214,11 @@ int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, strncat(rel, base, rel_size); } + /* return 2 if src=dest */ + if (!strcmp(path, dest_path)) { + if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path); + return 2; + } + return 1; } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 20770ef2957..af059b435b3 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -41,6 +41,11 @@ #include "BKE_utildefines.h" #include "BKE_image.h" +/* + User should check if returned path exists before copying a file there. + + TODO: it would be better to return a (abs, rel) tuple. +*/ static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel) { int length = FILE_MAX; diff --git a/source/creator/tests/alltest.c b/source/creator/tests/alltest.c index 99e0d2f5b26..89a58a08dfd 100644 --- a/source/creator/tests/alltest.c +++ b/source/creator/tests/alltest.c @@ -60,19 +60,19 @@ START_TEST(test_copy_images) {"//image.png", {{"/home/user/image.png", "image.png", 1}, {"/home/user/image.png", "image.png", 1}, {"/home/user/export/image.png", "image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/image.png", "image.png", 2},}}, /* relative, 1 level deep */ {"//bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, {"/home/user/bar/image.png", "bar/image.png", 1}, {"/home/user/export/bar/image.png", "bar/image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, /* relative, 2 level deep */ {"//bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, /* absolute, not under .blend dir */ {"/home/user/bar/image.png", {{"/home/user/image.png", "image.png", 1}, @@ -84,19 +84,19 @@ START_TEST(test_copy_images) {"/home/user/foo/image.png", {{"/home/user/image.png", "image.png", 1}, {"/home/user/image.png", "image.png", 1}, {"/home/user/export/image.png", "image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/image.png", "image.png", 2},}}, /* absolute, under .blend dir, 1 level deep */ {"/home/user/foo/bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, {"/home/user/bar/image.png", "bar/image.png", 1}, {"/home/user/export/bar/image.png", "bar/image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, /* absolute, under .blend dir, 2 level deep */ {"/home/user/foo/bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, - {"", "", 0},}}, + {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, /* empty image path, don't let these pass! */ {"", {{"", 0}, -- cgit v1.2.3 From bf90970eca5471b86d900daffb2f8eebdf85a673 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 5 Aug 2009 09:49:59 +0000 Subject: - OBJ exporter now copies images - added OBJ, FBX scripts to File -> Export, File -> Import menus --- release/io/export_fbx.py | 33 +++++++++++------------- release/io/export_obj.py | 65 +++++++++++++++++++++++++++++------------------- release/ui/space_info.py | 3 +++ 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index c50b60fd97e..ad9b3caa13a 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -1323,6 +1323,19 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t}') file.write('\n\t}') + def copy_image(image): + + rel = image.get_export_path(basepath, True) + base = os.path.basename(fname_rel) + + if EXP_IMAGE_COPY: + src = bpy.sys.expandpath(image.filename) + absp = image.get_export_path(basepath, False) + if not os.path.exists(absp): + shutil.copy(src, absp) + + return (rel, base) + # tex is an Image (Arystan) def write_video(texname, tex): # Same as texture really! @@ -1336,15 +1349,7 @@ def write(filename, batch_objects = None, \ Property: "Width", "int", "",0 Property: "Height", "int", "",0''') if tex: - src = bpy.sys.expandpath(tex.filename) - fname_rel = tex.get_export_path(basepath, True) - fname_abs = tex.get_export_path(basepath, False) - fname_strip = os.path.basename(fname_rel) - - if EXP_IMAGE_COPY: - if !os.path.exists(fname_abs): - shutil.copy(src, fname_abs) - + fname_rel, fname_strip = copy_image(tex) # fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: fname = fname_strip = fname_rel = '' @@ -1409,15 +1414,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tMedia: "Video::%s"' % texname) if tex: - src = bpy.sys.expandpath(tex.filename) - fname_rel = tex.get_export_path(basepath, True) - fname_abs = tex.get_export_path(basepath, False) - fname_strip = os.path.basename(fname_rel) - - if EXP_IMAGE_COPY: - if !os.path.exists(fname_abs): - shutil.copy(src, fname_abs) - + fname_rel, fname_strip = copy_image(tex) # fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: fname = fname_strip = fname_rel = '' diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 4d67903c343..1209e10afe3 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -47,7 +47,7 @@ will be exported as mesh data. # import math and other in functions that use them for the sake of fast Blender startup # import math -import os # os.sep +import os import bpy import Mathutils @@ -83,13 +83,26 @@ def BPySys_cleanName(name): # A Dict of Materials # (material.name, image.name):matname_imagename # matname_imagename has gaps removed. -MTL_DICT = {} +MTL_DICT = {} -def write_mtl(scene, filename): +def write_mtl(scene, filename, copy_images): world = scene.world worldAmb = world.ambient_color + dest_dir = os.path.dirname(filename) + + def copy_image(image): + rel = image.get_export_path(dest_dir, True) + + if copy_images: + abspath = image.get_export_path(dest_dir, False) + if not os.path.exists(abs_path): + shutil.copy(bpy.sys.expandpath(image.filename), abs_path) + + return rel + + file = open(filename, "w") # XXX # file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) @@ -129,13 +142,17 @@ def write_mtl(scene, filename): # 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 + # write relative image path + rel = copy_image(img) + file.write('map_Kd %s\n' % rel) # Diffuse mapping image +# 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] + filename = copy_image(mtex.texture.image) +# filename = mtex.texture.image.filename.split('\\')[-1].split('/')[-1] file.write('map_Kd %s\n' % filename) # Diffuse mapping image break except: @@ -146,6 +163,7 @@ def write_mtl(scene, filename): file.close() +# XXX not used def copy_file(source, dest): file = open(source, 'rb') data = file.read() @@ -156,6 +174,7 @@ def copy_file(source, dest): file.close() +# XXX not used def copy_images(dest_dir): if dest_dir[-1] != os.sep: dest_dir += os.sep @@ -181,7 +200,7 @@ def copy_images(dest_dir): pass # Now copy images -# copyCount = 0 + copyCount = 0 # for bImage in uniqueImages.values(): # image_path = bpy.sys.expandpath(bImage.filename) @@ -193,7 +212,7 @@ def copy_images(dest_dir): # copy_file(image_path, dest_image_path) # copyCount+=1 - paths= bpy.util.copy_images(uniqueImages.values(), dest_dir) +# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir) print('\tCopied %d images' % copyCount) # print('\tCopied %d images' % copyCount) @@ -412,16 +431,11 @@ def write(filename, objects, scene, if ob.type != 'MESH': continue - if EXPORT_APPLY_MODIFIERS: - me = ob.create_mesh('PREVIEW') - else: - me = ob.data.create_copy() + me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') if EXPORT_ROTX90: - print(ob_mat * mat_xrot90) me.transform(ob_mat * mat_xrot90) else: - print(ob_mat) me.transform(ob_mat) # # Will work for non meshes now! :) @@ -597,7 +611,7 @@ def write(filename, objects, scene, # file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) - del uv, uvkey, uv_dict, f_index, uv_index +# del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping # NORMAL, Smooth/Non smoothed. @@ -783,16 +797,17 @@ def write(filename, objects, scene, # 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) + write_mtl(scene, mtlfilename, EXPORT_COPY_IMAGES) +# if EXPORT_COPY_IMAGES: +# dest_dir = os.path.basename(filename) +# # 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) @@ -898,7 +913,7 @@ class EXPORT_OT_obj(bpy.types.Operator): 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_selection", name="Selection Only", description="", default= False), 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), diff --git a/release/ui/space_info.py b/release/ui/space_info.py index 855ce0b4f8f..3ec3bce3d91 100644 --- a/release/ui/space_info.py +++ b/release/ui/space_info.py @@ -74,6 +74,7 @@ class INFO_MT_file_import(bpy.types.Menu): def draw(self, context): layout = self.layout + layout.itemO("import.obj", text="OBJ") class INFO_MT_file_export(bpy.types.Menu): __space_type__ = "USER_PREFERENCES" @@ -82,6 +83,8 @@ class INFO_MT_file_export(bpy.types.Menu): def draw(self, context): layout = self.layout + layout.itemO("export.fbx", text="FBX") + layout.itemO("export.obj", text="OBJ") layout.itemO("export.ply", text="PLY") class INFO_MT_file_external_data(bpy.types.Menu): -- cgit v1.2.3 From 59abddc2024080b3d243d14710d3fb3340766737 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 5 Aug 2009 12:01:42 +0000 Subject: - added Mesh.add_material function - tweaked OBJ importer. It reads primitive files (cube, cone, etc.) --- release/io/import_obj.py | 23 ++++++++++------- source/blender/makesrna/intern/rna_mesh_api.c | 37 ++++++++++++++++++++------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/release/io/import_obj.py b/release/io/import_obj.py index a4778ac7790..2a5d92969af 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -83,9 +83,11 @@ def unpack_list(list_of_tuples): def unpack_face_list(list_of_tuples): l = [] for t in list_of_tuples: - if len(t) == 3: - t += [0] - l.extend(t) + face = [i for i in t] + if len(face) > 4: + raise RuntimeError("More than 4 vertices per face.") + if len(face) == 3: face.append(0) + l.extend(face) return l @@ -163,7 +165,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ # Absolute path - c:\.. etc would work here image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) - has_data = image.has_data + has_data = image.has_data if image else False if image: texture.image = image @@ -503,8 +505,11 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l me= bpy.data.add_mesh(dataname) # me= bpy.data.meshes.new(dataname) - - me.materials= materials[0:16] # make sure the list isnt too big. + + # make sure the list isnt too big + for material in materials[0:16]: + me.add_material(material) +# me.materials= materials[0:16] # make sure the list isnt too big. #me.verts.extend([(0,0,0)]) # dummy vert me.add_geometry(len(verts_loc), 0, len(faces)) @@ -569,7 +574,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l if verts_tex: - blender_tface= me.uv_layers[0].data[i] + blender_tface= me.uv_textures[0].data[i] if context_material: image, has_data= unique_material_images[context_material] @@ -621,7 +626,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l if CREATE_EDGES: - me.add_geometry(0, len(edges)) + me.add_geometry(0, len(edges), 0) # edges should be a list of (a, b) tuples me.edges.foreach_set("verts", unpack_list(edges)) @@ -629,7 +634,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # del me_edges - me.calc_normals() + me.update() # me.calcNormals() ob= bpy.data.add_object("MESH", "Mesh") diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 9a527948b0f..b50cc678f4f 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -258,6 +258,29 @@ static void rna_Mesh_calc_normals(Mesh *me) mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); } +static void rna_Mesh_add_material(Mesh *me, Material *ma) +{ + int i; + int totcol = me->totcol + 1; + Material **mat; + + /* don't add if mesh already has it */ + for (i = 0; i < me->totcol; i++) + if (me->mat[i] == ma) + return; + + mat= MEM_callocN(sizeof(void*) * totcol, "newmatar"); + + if (me->totcol) memcpy(mat, me->mat, sizeof(void*) * me->totcol); + if (me->mat) MEM_freeN(me->mat); + + me->mat = mat; + me->mat[me->totcol++] = ma; + ma->id.us++; + + test_object_materials((ID*)me); +} + #else void RNA_api_mesh(StructRNA *srna) @@ -289,17 +312,13 @@ void RNA_api_mesh(StructRNA *srna) func= RNA_def_function(srna, "calc_normals", "rna_Mesh_calc_normals"); RNA_def_function_ui_description(func, "Calculate vertex normals."); - /* - 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); + + func= RNA_def_function(srna, "add_material", "rna_Mesh_add_material"); + RNA_def_function_ui_description(func, "Add a new material to Mesh."); + parm= RNA_def_pointer(func, "material", "Material", "", "Material to add."); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif -- cgit v1.2.3 From 01eedc504656b065dc9d17751016913906afe4d5 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 6 Aug 2009 12:22:50 +0000 Subject: - OBJ importer now reads most of the test files. Had to copy BPyMesh.ngon function to OBJ import code - added MeshEdge.fgon property, not using it yet - fixed in bpy_rna.c to correctly read arrays returned from RNA functions --- release/io/export_fbx.py | 2 +- release/io/export_obj.py | 5 +- release/io/import_obj.py | 311 ++++++++++++++++++++----- source/blender/makesrna/intern/rna_image_api.c | 2 +- source/blender/makesrna/intern/rna_mesh.c | 5 + source/blender/python/intern/bpy_rna.c | 4 + 6 files changed, 273 insertions(+), 56 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index ad9b3caa13a..5bb169a9849 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -1326,7 +1326,7 @@ def write(filename, batch_objects = None, \ def copy_image(image): rel = image.get_export_path(basepath, True) - base = os.path.basename(fname_rel) + base = os.path.basename(rel) if EXP_IMAGE_COPY: src = bpy.sys.expandpath(image.filename) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index 1209e10afe3..fa07c5408a7 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -120,7 +120,10 @@ def write_mtl(scene, filename, copy_images): 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 + if hasattr(mat, "ior"): + file.write('Ni %.6f\n' % mat.ior) # Refraction index + else: + file.write('Ni %.6f\n' % 1.0) 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. diff --git a/release/io/import_obj.py b/release/io/import_obj.py index 2a5d92969af..f064561a512 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -40,9 +40,12 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- -import bpy import os +import bpy +import Mathutils +import Geometry + # from Blender import Mesh, Draw, Window, Texture, Material, sys # # import BPyMesh # import BPyImage @@ -84,12 +87,196 @@ def unpack_face_list(list_of_tuples): l = [] for t in list_of_tuples: face = [i for i in t] - if len(face) > 4: - raise RuntimeError("More than 4 vertices per face.") - if len(face) == 3: face.append(0) + if len(face) != 3 and len(face) != 4: + raise RuntimeError("{0} vertices in face.".format(len(face))) + if len(face) == 3: + face.append(0) l.extend(face) return l +def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True): + ''' + Takes a polyline of indices (fgon) + and returns a list of face indicie lists. + Designed to be used for importers that need indices for an fgon to create from existing verts. + + from_data: either a mesh, or a list/tuple of vectors. + indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. + PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. + ''' + + if not set: # Need sets for this, otherwise do a normal fill. + PREF_FIX_LOOPS= False + + Vector= Mathutils.Vector + if not indices: + return [] + + # return [] + def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) + def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length + + def vert_treplet(v, i): + return v, rvec(v), i, mlen(v) + + def ed_key_mlen(v1, v2): + if v1[3] > v2[3]: + return v2[1], v1[1] + else: + return v1[1], v2[1] + + + if not PREF_FIX_LOOPS: + ''' + Normal single concave loop filling + ''' + if type(from_data) in (tuple, list): + verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] + else: + verts= [from_data.verts[i].co for ii, i in enumerate(indices)] + + for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): + if verts[i][1]==verts[i-1][0]: + verts.pop(i-1) + + fill= Geometry.PolyFill([verts]) + + else: + ''' + Seperate this loop into multiple loops be finding edges that are used twice + This is used by lightwave LWO files a lot + ''' + + if type(from_data) in (tuple, list): + verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] + else: + verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] + + edges= [(i, i-1) for i in range(len(verts))] + if edges: + edges[0]= (0,len(verts)-1) + + if not verts: + return [] + + + edges_used= set() + edges_doubles= set() + # We need to check if any edges are used twice location based. + for ed in edges: + edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) + if edkey in edges_used: + edges_doubles.add(edkey) + else: + edges_used.add(edkey) + + # Store a list of unconnected loop segments split by double edges. + # will join later + loop_segments= [] + + v_prev= verts[0] + context_loop= [v_prev] + loop_segments= [context_loop] + + for v in verts: + if v!=v_prev: + # Are we crossing an edge we removed? + if ed_key_mlen(v, v_prev) in edges_doubles: + context_loop= [v] + loop_segments.append(context_loop) + else: + if context_loop and context_loop[-1][1]==v[1]: + #raise "as" + pass + else: + context_loop.append(v) + + v_prev= v + # Now join loop segments + + def join_seg(s1,s2): + if s2[-1][1]==s1[0][1]: # + s1,s2= s2,s1 + elif s1[-1][1]==s2[0][1]: + pass + else: + return False + + # If were stuill here s1 and s2 are 2 segments in the same polyline + s1.pop() # remove the last vert from s1 + s1.extend(s2) # add segment 2 to segment 1 + + if s1[0][1]==s1[-1][1]: # remove endpoints double + s1.pop() + + s2[:]= [] # Empty this segment s2 so we dont use it again. + return True + + joining_segments= True + while joining_segments: + joining_segments= False + segcount= len(loop_segments) + + for j in range(segcount-1, -1, -1): #reversed(range(segcount)): + seg_j= loop_segments[j] + if seg_j: + for k in range(j-1, -1, -1): # reversed(range(j)): + if not seg_j: + break + seg_k= loop_segments[k] + + if seg_k and join_seg(seg_j, seg_k): + joining_segments= True + + loop_list= loop_segments + + for verts in loop_list: + while verts and verts[0][1]==verts[-1][1]: + verts.pop() + + loop_list= [verts for verts in loop_list if len(verts)>2] + # DONE DEALING WITH LOOP FIXING + + + # vert mapping + vert_map= [None]*len(indices) + ii=0 + for verts in loop_list: + if len(verts)>2: + for i, vert in enumerate(verts): + vert_map[i+ii]= vert[2] + ii+=len(verts) + + fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) + #draw_loops(loop_list) + #raise 'done loop' + # map to original indicies + fill= [[vert_map[i] for i in reversed(f)] for f in fill] + + + if not fill: + print('Warning Cannot scanfill, fallback on a triangle fan.') + fill= [ [0, i-1, i] for i in range(2, len(indices)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in fill: + if flip != None: + break + for i, vi in enumerate(fi): + if vi==0 and fi[i-1]==1: + flip= False + break + elif vi==1 and fi[i-1]==0: + flip= True + break + + if not flip: + for i, fi in enumerate(fill): + fill[i]= tuple([ii for ii in reversed(fi)]) + + return fill def line_value(line_split): ''' @@ -388,7 +575,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, # remove one of the itemas and reorder - return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.items()] + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())] def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): @@ -401,7 +588,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l if unique_smooth_groups: sharp_edges= {} - smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.keys() ]) + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ]) context_smooth_group_old= -1 # Split fgons into tri's @@ -452,45 +639,45 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l edge_dict[i1,i2]= 1 # FGons into triangles -# if has_ngons and len_face_vert_loc_indicies > 4: + if has_ngons and len_face_vert_loc_indicies > 4: -# ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) -# faces.extend(\ -# [(\ -# [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ -# [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ -# context_material,\ -# context_smooth_group,\ -# context_object)\ -# for ngon in ngon_face_indices]\ -# ) + ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies) + faces.extend(\ + [(\ + [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ + [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ + context_material,\ + context_smooth_group,\ + context_object)\ + for ngon in ngon_face_indices]\ + ) -# # edges to make fgons -# if CREATE_FGONS: -# edge_users= {} -# for ngon in ngon_face_indices: -# for i in (0,1,2): -# i1= face_vert_loc_indicies[ngon[i ]] -# i2= face_vert_loc_indicies[ngon[i-1]] -# if i1>i2: i1,i2= i2,i1 + # edges to make fgons + if CREATE_FGONS: + edge_users= {} + for ngon in ngon_face_indices: + for i in (0,1,2): + i1= face_vert_loc_indicies[ngon[i ]] + i2= face_vert_loc_indicies[ngon[i-1]] + if i1>i2: i1,i2= i2,i1 -# try: -# edge_users[i1,i2]+=1 -# except KeyError: -# edge_users[i1,i2]= 1 + try: + edge_users[i1,i2]+=1 + except KeyError: + edge_users[i1,i2]= 1 -# for key, users in edge_users.iteritems(): -# if users>1: -# fgon_edges[key]= None + for key, users in edge_users.items(): + if users>1: + fgon_edges[key]= None -# # remove all after 3, means we dont have to pop this one. -# faces.pop(f_idx) + # remove all after 3, means we dont have to pop this one. + faces.pop(f_idx) # Build sharp edges if unique_smooth_groups: - for edge_dict in smooth_group_users.values(): - for key, users in edge_dict.items(): + for edge_dict in list(smooth_group_users.values()): + for key, users in list(edge_dict.items()): if users==1: # This edge is on the boundry of a group sharp_edges[key]= None @@ -500,7 +687,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l materials= [None] * len(unique_materials) - for name, index in material_mapping.items(): + for name, index in list(material_mapping.items()): materials[index]= unique_materials[name] me= bpy.data.add_mesh(dataname) @@ -607,36 +794,54 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] del me_faces # del ALPHA + + if CREATE_EDGES: + + me.add_geometry(0, len(edges), 0) + + # edges should be a list of (a, b) tuples + me.edges.foreach_set("verts", unpack_list(edges)) +# me_edges.extend( edges ) + +# del me_edges # Add edge faces. - me_edges= me.edges +# me_edges= me.edges + + def edges_match(e1, e2): + return (e1[0] == e2[0] and e1[1] == e2[1]) or (e1[0] == e2[1] and e1[1] == e2[0]) + + # XXX slow +# if CREATE_FGONS and fgon_edges: +# for fgon_edge in fgon_edges.keys(): +# for ed in me.edges: +# if edges_match(fgon_edge, ed.verts): +# ed.fgon = True + # if CREATE_FGONS and fgon_edges: # FGON= Mesh.EdgeFlags.FGON # for ed in me.findEdges( fgon_edges.keys() ): # if ed!=None: # me_edges[ed].flag |= FGON # del FGON - + + # XXX slow +# if unique_smooth_groups and sharp_edges: +# for sharp_edge in sharp_edges.keys(): +# for ed in me.edges: +# if edges_match(sharp_edge, ed.verts): +# ed.sharp = True + # if unique_smooth_groups and sharp_edges: # SHARP= Mesh.EdgeFlags.SHARP # for ed in me.findEdges( sharp_edges.keys() ): # if ed!=None: # me_edges[ed].flag |= SHARP # del SHARP - - if CREATE_EDGES: - - me.add_geometry(0, len(edges), 0) - - # edges should be a list of (a, b) tuples - me.edges.foreach_set("verts", unpack_list(edges)) -# me_edges.extend( edges ) - -# del me_edges me.update() # me.calcNormals() - + ob= bpy.data.add_object("MESH", "Mesh") ob.data= me scn.add_object(ob) @@ -823,7 +1028,7 @@ def load_obj(filepath, # so we need to know weather context_multi_line= '' - print('\tparsing obj file "%s"...' % filepath, end=' ') + print('\tparsing obj file "%s"...' % filepath) time_sub= bpy.sys.time() # time_sub= sys.time() @@ -1039,7 +1244,7 @@ def load_obj(filepath, time_sub= time_new - print('\tloading materials and images...', end=' ') + print('\tloading materials and images...') create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) time_new= bpy.sys.time() @@ -1059,7 +1264,7 @@ def load_obj(filepath, # scn.objects.selected = [] new_objects= [] # put new objects here - print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), end=' ') + print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) )) # Split the mesh by objects/materials, may if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True else: SPLIT_OB_OR_GROUP = False diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index af059b435b3..ccc9846600d 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -66,7 +66,7 @@ void RNA_api_image(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func= RNA_def_function(srna, "export", "rna_Image_get_export_path"); + func= RNA_def_function(srna, "get_export_path", "rna_Image_get_export_path"); RNA_def_function_ui_description(func, "Produce image export path."); parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory."); RNA_def_property_flag(parm, PROP_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index dba5a0622c3..dc953f80804 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -877,6 +877,11 @@ static void rna_def_medge(BlenderRNA *brna) 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"); + + prop= RNA_def_property(srna, "fgon", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FGON); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Fgon", "Fgon edge"); } static void rna_def_mface(BlenderRNA *brna) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 27bfb89b963..ded07d545ef 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1801,6 +1801,10 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) /* resolve the array from a new pytype */ ret = PyTuple_New(len); + /* for return values, data is a pointer to an array, not first element pointer */ + if (prop->flag & PROP_DYNAMIC_ARRAY) + data = *((char**)data) + switch (type) { case PROP_BOOLEAN: for(a=0; a Date: Fri, 7 Aug 2009 13:00:39 +0000 Subject: bpyrna: interpret a tuple of enum items (e1, e2, ...) as a bitmask (e1 | e2 | ...). --- source/blender/python/intern/bpy_rna.c | 63 +++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ded07d545ef..54d7b812fe1 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -33,6 +33,7 @@ #include "RNA_access.h" #include "RNA_define.h" /* for defining our own rna */ +#include "rna_internal_types.h" #include "MEM_guardedalloc.h" #include "BKE_utildefines.h" @@ -241,6 +242,27 @@ static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) return result; } +static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix) +{ + char *param= _PyUnicode_AsString(item); + + if (param==NULL) { + char *enum_str= pyrna_enum_as_string(ptr, prop); + PyErr_Format(PyExc_TypeError, "%.200s expected a string enum type in (%.200s)", error_prefix, enum_str); + MEM_freeN(enum_str); + return 0; + } else { + if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, val)) { + char *enum_str= pyrna_enum_as_string(ptr, prop); + PyErr_Format(PyExc_TypeError, "%.200s enum \"%.200s\" not found in (%.200s)", error_prefix, param, enum_str); + MEM_freeN(enum_str); + return 0; + } + } + + return 1; +} + PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) { PyObject *ret; @@ -641,25 +663,34 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v } case PROP_ENUM: { - char *param = _PyUnicode_AsString(value); - - if (param==NULL) { + int val, i; + + if (PyUnicode_Check(value)) { + if (!pyrna_string_to_enum(value, ptr, prop, &val, error_prefix)) + return -1; + } + else if (PyTuple_Check(value)) { + /* tuple of enum items, concatenate all values with OR */ + val= 0; + for (i= 0; i < PyTuple_Size(value); i++) { + int tmpval; + + /* PyTuple_GET_ITEM returns a borrowed reference */ + if (!pyrna_string_to_enum(PyTuple_GET_ITEM(value, i), ptr, prop, &tmpval, error_prefix)) + return -1; + + val |= tmpval; + } + } + else { char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_TypeError, "%.200s expected a string enum type in (%.200s)", error_prefix, enum_str); + PyErr_Format(PyExc_TypeError, "%.200s expected a string enum or a tuple of strings in (%.200s)", error_prefix, enum_str); MEM_freeN(enum_str); return -1; - } else { - int val; - if (RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, &val)) { - if(data) *((int*)data)= val; - else RNA_property_enum_set(ptr, prop, val); - } else { - char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_TypeError, "%.200s enum \"%.200s\" not found in (%.200s)", error_prefix, param, enum_str); - MEM_freeN(enum_str); - return -1; - } } + + if(data) *((int*)data)= val; + else RNA_property_enum_set(ptr, prop, val); break; } @@ -1803,7 +1834,7 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) /* for return values, data is a pointer to an array, not first element pointer */ if (prop->flag & PROP_DYNAMIC_ARRAY) - data = *((char**)data) + data = *(char**)(char*)data; switch (type) { case PROP_BOOLEAN: -- cgit v1.2.3 From 8fa528cef8faa4f5ce2f6ff4f6e2f5b08709d08e Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 8 Aug 2009 11:33:34 +0000 Subject: Added Object.find_armature() to find armature connected to object. Previously this was BPyObject.getObjectArmature() --- release/io/export_fbx.py | 48 ++----------------------- source/blender/editors/include/ED_mesh.h | 3 ++ source/blender/makesrna/intern/rna_object_api.c | 30 ++++++++++++++++ 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 5bb169a9849..2a3ea5fc30e 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -118,26 +118,6 @@ def copy_images(dest_dir, textures): print('\tCopied %d images' % copyCount) -def BPyObject_getObjectArmature(ob): - ''' - This returns the first armature the mesh uses. - remember there can be more then 1 armature but most people dont do that. - ''' - if ob.type != 'MESH': - return None - - arm = ob.parent - if arm and arm.type == 'ARMATURE' and ob.parent_type == 'ARMATURE': - return arm - - for m in ob.modifiers: - if m.type== 'ARMATURE': - arm = m.object - if arm: - return arm - - return None - # I guess FBX uses degrees instead of radians (Arystan). # Call this function just before writing to FBX. def eulerRadToDeg(eul): @@ -298,30 +278,6 @@ def BPyMesh_meshWeight2List(ob): return groupNames, vWeightList - -def BPyMesh_meshWeight2Dict(me, ob): - ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex. - using the group as a key and a float value for the weight. - These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. - ''' - - vWeightDict= [dict() for i in range(len(me.verts))] # Sync with vertlist. - - # Clear the vert group. - groupNames= [g.name for g in ob.vertex_groups] -# groupNames= me.getVertGroupNames() - - for group in groupNames: - for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. - vWeightDict[vert_index][group]= weight - - # removed this because me may be copying teh vertex groups. - #for group in groupNames: - # me.removeVertGroup(group) - - return groupNames, vWeightDict - - def meshNormalizedWeights(me): try: # account for old bad BPyMesh groupNames, vWeightList = BPyMesh_meshWeight2List(me) @@ -2199,7 +2155,7 @@ def write(filename, batch_objects = None, \ materials[None, None] = None if EXP_ARMATURE: - armob = BPyObject_getObjectArmature(ob) + armob = ob.find_armature() blenParentBoneName = None # parent bone - special case @@ -3482,7 +3438,7 @@ bpy.ops.add(EXPORT_OT_fbx) # - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print # - get rid of cleanName somehow # + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 -# - get rid of BPyObject_getObjectArmature, move it in RNA? +# + get rid of BPyObject_getObjectArmature, move it in RNA? # - BATCH_ENABLE and BATCH_GROUP options: line 327 # - implement all BPyMesh_* used here with RNA # - getDerivedObjects is not fully replicated with .dupli* funcs diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 0face00f82b..cceebeadc96 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -154,6 +154,9 @@ void EM_reveal_mesh(struct EditMesh *em); void EM_select_by_material(struct EditMesh *em, int index); void EM_deselect_by_material(struct EditMesh *em, int index); +/* editmesh_tools.c */ +void convert_to_triface(struct EditMesh *em, int direction); + /* editface.c */ struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 881c2bdf549..8192801d9fb 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -63,6 +63,7 @@ #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" #include "DNA_curve_types.h" +#include "DNA_modifier_types.h" #include "MEM_guardedalloc.h" @@ -309,6 +310,29 @@ static void rna_Object_make_display_list(Object *ob, bContext *C) DAG_object_flush_update(sce, ob, OB_RECALC_DATA); } +static Object *rna_Object_find_armature(Object *ob) +{ + Object *ob_arm = NULL; + + if (ob->type != OB_MESH) return NULL; + + if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { + ob_arm = ob->parent; + } + else { + ModifierData *mod = (ModifierData*)ob->modifiers.first; + while (mod) { + if (mod->type == eModifierType_Armature) { + ob_arm = ((ArmatureModifierData*)mod)->object; + } + + mod = mod->next; + } + } + + return ob_arm; +} + /* static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) { @@ -409,6 +433,12 @@ void RNA_api_object(StructRNA *srna) parm= RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode."); RNA_def_property_flag(parm, PROP_REQUIRED); + /* Armature */ + func= RNA_def_function(srna, "find_armature", "rna_Object_find_armature"); + RNA_def_function_ui_description(func, "Find armature influencing this object as a parent or via a modifier."); + parm= RNA_def_pointer(func, "ob_arm", "Object", "", "Armature object influencing this object or NULL."); + RNA_def_function_return(func, parm); + /* DAG */ func= RNA_def_function(srna, "make_display_list", "rna_Object_make_display_list"); RNA_def_function_ui_description(func, "Update object's display data."); /* XXX describe better */ -- cgit v1.2.3 From d1f22f6ce324e465697765221f2f4edf6af65147 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sat, 8 Aug 2009 11:44:56 +0000 Subject: Copied 3DS, X3D scripts to release/io naming them after [import|export]_[format].py scheme. --- release/io/export_3ds.py | 1025 ++++++++++++++++++++++++++++++++++++++++++++ release/io/export_x3d.py | 1051 ++++++++++++++++++++++++++++++++++++++++++++++ release/io/import_3ds.py | 1007 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3083 insertions(+) create mode 100644 release/io/export_3ds.py create mode 100644 release/io/export_x3d.py create mode 100644 release/io/import_3ds.py diff --git a/release/io/export_3ds.py b/release/io/export_3ds.py new file mode 100644 index 00000000000..69b4d00b4d8 --- /dev/null +++ b/release/io/export_3ds.py @@ -0,0 +1,1025 @@ +#!BPY +# coding: utf-8 +""" +Name: '3D Studio (.3ds)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to 3DS file format (.3ds).' +""" + +__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__ = "0.90a" +__bpydoc__ = """\ + +3ds Exporter + +This script Exports a 3ds file. + +Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information +from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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 ***** +# -------------------------------------------------------------------------- + + +###################################################### +# Importing modules +###################################################### + +import Blender +import bpy +from BPyMesh import getMeshFromObject +from BPyObject import getDerivedObjects +try: + import struct +except: + struct = None + +# So 3ds max can open files, limit names to 12 in length +# this is verry annoying for filenames! +name_unique = [] +name_mapping = {} +def sane_name(name): + name_fixed = name_mapping.get(name) + if name_fixed != None: + return name_fixed + + if len(name) > 12: + new_name = name[:12] + else: + new_name = name + + i = 0 + + while new_name in name_unique: + new_name = new_name[:-4] + '.%.3d' % i + i+=1 + + name_unique.append(new_name) + name_mapping[name] = new_name + return new_name + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will export +#----- Primary Chunk, at the beginning of each file +PRIMARY= long("0x4D4D",16) + +#------ Main Chunks +OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long("0x0002",16); #This gives the version of the .3ds file +KFDATA = long("0xB000",16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +MATNAME = long("0xA000",16); # This holds the material name +MATAMBIENT = long("0xA010",16); # Ambient color of the object/material +MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material +MATSPECULAR = long("0xA030",16); # SPecular color of the object/material +MATSHINESS = long("0xA040",16); # ?? +MATMAP = long("0xA200",16); # This is a header for a new material +MATMAPFILE = long("0xA300",16); # This holds the file name of the texture + +RGB1= long("0x0011",16) +RGB2= long("0x0012",16) + +#>------ sub defines of OBJECT +OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object +OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object +OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long("0x4110",16); # The objects vertices +OBJECT_FACES = long("0x4120",16); # The objects faces +OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long("0x4140",16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix + +#>------ sub defines of KFDATA +KFDATA_KFHDR = long("0xB00A",16); +KFDATA_KFSEG = long("0xB008",16); +KFDATA_KFCURTIME = long("0xB009",16); +KFDATA_OBJECT_NODE_TAG = long("0xB002",16); + +#>------ sub defines of OBJECT_NODE_TAG +OBJECT_NODE_ID = long("0xB030",16); +OBJECT_NODE_HDR = long("0xB010",16); +OBJECT_PIVOT = long("0xB013",16); +OBJECT_INSTANCE_NAME = long("0xB011",16); +POS_TRACK_TAG = long("0xB020",16); +ROT_TRACK_TAG = long("0xB021",16); +SCL_TRACK_TAG = long("0xB022",16); + +def uv_key(uv): + return round(uv.x, 6), round(uv.y, 6) + +# size defines: +SZ_SHORT = 2 +SZ_INT = 4 +SZ_FLOAT = 4 + +class _3ds_short(object): + '''Class representing a short (2-byte integer) for a 3ds file. + *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' + __slots__ = 'value' + def __init__(self, val=0): + self.value=val + + def get_size(self): + return SZ_SHORT + + def write(self,file): + file.write(struct.pack("= mat_ls_len: + mat_index = f.mat = 0 + mat = mat_ls[mat_index] + if mat: mat_name = mat.name + else: mat_name = None + # else there alredy set to none + + img = f.image + if img: img_name = img.name + else: img_name = None + + materialDict.setdefault((mat_name, img_name), (mat, img) ) + + + else: + for mat in mat_ls: + if mat: # material may be None so check its not. + materialDict.setdefault((mat.name, None), (mat, None) ) + + # Why 0 Why! + for f in data.faces: + if f.mat >= mat_ls_len: + f.mat = 0 + + # Make material chunks for all materials used in the meshes: + for mat_and_image in materialDict.itervalues(): + object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) + + # Give all objects a unique ID and build a dictionary from object name to object id: + """ + name_to_id = {} + for ob, data in mesh_objects: + name_to_id[ob.name]= len(name_to_id) + #for ob in empty_objects: + # name_to_id[ob.name]= len(name_to_id) + """ + + # Create object chunks for all meshes: + i = 0 + for ob, blender_mesh in mesh_objects: + # create a new object chunk + object_chunk = _3ds_chunk(OBJECT) + + # set the object name + object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) + + # make a mesh chunk out of the mesh: + object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) + object_info.add_subchunk(object_chunk) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # make a kf object node for the object: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + ''' + blender_mesh.verts = None + i+=i + + # Create chunks for all empties: + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + for ob in empty_objects: + # Empties only require a kf object node: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + pass + ''' + + # Add main object info chunk to primary chunk: + primary.add_subchunk(object_info) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # Add main keyframe data chunk to primary chunk: + primary.add_subchunk(kfdata) + ''' + + # At this point, the chunk hierarchy is completely built. + + # Check the size: + primary.get_size() + # Open the file for writing: + file = open( filename, 'wb' ) + + # Recursively write the chunks to file: + primary.write(file) + + # Close the file: + file.close() + + # Debugging only: report the exporting time: + Blender.Window.WaitCursor(0) + print "3ds export time: %.2f" % (Blender.sys.time() - time1) + + # Debugging only: dump the chunk hierarchy: + #primary.dump() + + +if __name__=='__main__': + if struct: + Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) + else: + Blender.Draw.PupMenu("Error%t|This script requires a full python installation") +# save_3ds('/test_b.3ds') diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py new file mode 100644 index 00000000000..b12ff67d8a6 --- /dev/null +++ b/release/io/export_x3d.py @@ -0,0 +1,1051 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'X3D Extensible 3D (.x3d)...' +Blender: 245 +Group: 'Export' +Tooltip: 'Export selection to Extensible 3D file (.x3d)' +""" + +__author__ = ("Bart", "Campbell Barton") +__email__ = ["Bart, bart:neeneenee*de"] +__url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml"] +__version__ = "2006/01/17" +__bpydoc__ = """\ +This script exports to X3D format. + +Usage: + +Run this script from "File->Export" menu. A pop-up will ask whether you +want to export only selected or all relevant objects. + +Known issues:
+ Doesn't handle multiple materials (don't use material indices);
+ Doesn't handle multiple UV textures on a single mesh (create a mesh for each texture);
+ Can't get the texture array associated with material * not the UV ones; +""" + + +# $Id$ +# +#------------------------------------------------------------------------ +# X3D exporter for blender 2.36 or above +# +# ***** 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 ***** +# + +#################################### +# Library dependancies +#################################### + +import Blender +from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh +from Blender.Scene import Render +import math +import BPyObject +import BPyMesh + +# +DEG2RAD=0.017453292519943295 +MATWORLD= Blender.Mathutils.RotationMatrix(-90, 4, 'x') + +#################################### +# Global Variables +#################################### + +filename = Blender.Get('filename') +_safeOverwrite = True + +extension = '' + +########################################################## +# Functions for writing output file +########################################################## + +class x3d_class: + + def __init__(self, filename): + #--- public you can change these --- + self.writingcolor = 0 + self.writingtexture = 0 + self.writingcoords = 0 + self.proto = 1 + self.matonly = 0 + self.share = 0 + self.billnode = 0 + self.halonode = 0 + self.collnode = 0 + self.tilenode = 0 + self.verbose=2 # level of verbosity in console 0-none, 1-some, 2-most + self.cp=3 # decimals for material color values 0.000 - 1.000 + self.vp=3 # decimals for vertex coordinate values 0.000 - n.000 + self.tp=3 # decimals for texture coordinate values 0.000 - 1.000 + self.it=3 + + #--- class private don't touch --- + self.texNames={} # dictionary of textureNames + self.matNames={} # dictionary of materiaNames + self.meshNames={} # dictionary of meshNames + self.indentLevel=0 # keeps track of current indenting + self.filename=filename + self.file = None + if filename.lower().endswith('.x3dz'): + try: + import gzip + self.file = gzip.open(filename, "w") + except: + print "failed to import compression modules, exporting uncompressed" + self.filename = filename[:-1] # remove trailing z + + if self.file == None: + self.file = open(self.filename, "w") + + self.bNav=0 + self.nodeID=0 + self.namesReserved=[ "Anchor","Appearance","Arc2D","ArcClose2D","AudioClip","Background","Billboard", + "BooleanFilter","BooleanSequencer","BooleanToggle","BooleanTrigger","Box","Circle2D", + "Collision","Color","ColorInterpolator","ColorRGBA","component","Cone","connect", + "Contour2D","ContourPolyline2D","Coordinate","CoordinateDouble","CoordinateInterpolator", + "CoordinateInterpolator2D","Cylinder","CylinderSensor","DirectionalLight","Disk2D", + "ElevationGrid","EspduTransform","EXPORT","ExternProtoDeclare","Extrusion","field", + "fieldValue","FillProperties","Fog","FontStyle","GeoCoordinate","GeoElevationGrid", + "GeoLocationLocation","GeoLOD","GeoMetadata","GeoOrigin","GeoPositionInterpolator", + "GeoTouchSensor","GeoViewpoint","Group","HAnimDisplacer","HAnimHumanoid","HAnimJoint", + "HAnimSegment","HAnimSite","head","ImageTexture","IMPORT","IndexedFaceSet", + "IndexedLineSet","IndexedTriangleFanSet","IndexedTriangleSet","IndexedTriangleStripSet", + "Inline","IntegerSequencer","IntegerTrigger","IS","KeySensor","LineProperties","LineSet", + "LoadSensor","LOD","Material","meta","MetadataDouble","MetadataFloat","MetadataInteger", + "MetadataSet","MetadataString","MovieTexture","MultiTexture","MultiTextureCoordinate", + "MultiTextureTransform","NavigationInfo","Normal","NormalInterpolator","NurbsCurve", + "NurbsCurve2D","NurbsOrientationInterpolator","NurbsPatchSurface", + "NurbsPositionInterpolator","NurbsSet","NurbsSurfaceInterpolator","NurbsSweptSurface", + "NurbsSwungSurface","NurbsTextureCoordinate","NurbsTrimmedSurface","OrientationInterpolator", + "PixelTexture","PlaneSensor","PointLight","PointSet","Polyline2D","Polypoint2D", + "PositionInterpolator","PositionInterpolator2D","ProtoBody","ProtoDeclare","ProtoInstance", + "ProtoInterface","ProximitySensor","ReceiverPdu","Rectangle2D","ROUTE","ScalarInterpolator", + "Scene","Script","Shape","SignalPdu","Sound","Sphere","SphereSensor","SpotLight","StaticGroup", + "StringSensor","Switch","Text","TextureBackground","TextureCoordinate","TextureCoordinateGenerator", + "TextureTransform","TimeSensor","TimeTrigger","TouchSensor","Transform","TransmitterPdu", + "TriangleFanSet","TriangleSet","TriangleSet2D","TriangleStripSet","Viewpoint","VisibilitySensor", + "WorldInfo","X3D","XvlShell","VertexShader","FragmentShader","MultiShaderAppearance","ShaderAppearance" ] + self.namesStandard=[ "Empty","Empty.000","Empty.001","Empty.002","Empty.003","Empty.004","Empty.005", + "Empty.006","Empty.007","Empty.008","Empty.009","Empty.010","Empty.011","Empty.012", + "Scene.001","Scene.002","Scene.003","Scene.004","Scene.005","Scene.06","Scene.013", + "Scene.006","Scene.007","Scene.008","Scene.009","Scene.010","Scene.011","Scene.012", + "World","World.000","World.001","World.002","World.003","World.004","World.005" ] + self.namesFog=[ "","LINEAR","EXPONENTIAL","" ] + +########################################################## +# Writing nodes routines +########################################################## + + def writeHeader(self): + #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '<').replace('>', '>') + bfile = self.filename.replace('<', '<').replace('>', '>') # use outfile name + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\t\n" % sys.basename(bfile)) + self.file.write("\t\n" % Blender.Get('version')) + self.file.write("\t\n") + self.file.write("\n") + self.file.write("\n") + + # This functionality is poorly defined, disabling for now - campbell + ''' + def writeInline(self): + inlines = Blender.Scene.Get() + allinlines = len(inlines) + if scene != inlines[0]: + return + else: + for i in xrange(allinlines): + nameinline=inlines[i].name + if (nameinline not in self.namesStandard) and (i > 0): + self.file.write("" % nameinline) + self.file.write("\n\n") + + + def writeScript(self): + textEditor = Blender.Text.Get() + alltext = len(textEditor) + for i in xrange(alltext): + nametext = textEditor[i].name + nlines = textEditor[i].getNLines() + if (self.proto == 1): + if (nametext == "proto" or nametext == "proto.js" or nametext == "proto.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in xrange(nalllines): + self.writeIndented(alllines[j] + "\n") + elif (self.proto == 0): + if (nametext == "route" or nametext == "route.js" or nametext == "route.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in xrange(nalllines): + self.writeIndented(alllines[j] + "\n") + self.writeIndented("\n") + ''' + + def writeViewpoint(self, ob, mat, scene): + context = scene.render + ratio = float(context.imageSizeY())/float(context.imageSizeX()) + lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180) + lens = min(lens, math.pi) + + # get the camera location, subtract 90 degress from X to orient like X3D does + # mat = ob.matrixWorld - mat is now passed! + + loc = self.rotatePointForVRML(mat.translationPart()) + rot = mat.toEuler() + rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD) + nRot = self.rotatePointForVRML( rot ) + # convert to Quaternion and to Angle Axis + Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2]) + Q1 = self.multiplyQuaternions(Q[0], Q[1]) + Qf = self.multiplyQuaternions(Q1, Q[2]) + angleAxis = self.quaternionToAngleAxis(Qf) + self.file.write("\n\n" % (lens)) + + def writeFog(self, world): + if world: + mtype = world.getMistype() + mparam = world.getMist() + grd = world.getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + else: + return + if (mtype == 1 or mtype == 2): + self.file.write("\n\n" % round(mparam[2],self.cp)) + else: + return + + def writeNavigationInfo(self, scene): + self.file.write('\n') + + def writeSpotLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + # compute cutoff and beamwidth + intensity=min(lamp.energy/1.75,1.0) + beamWidth=((lamp.spotSize*math.pi)/180.0)*.37; + cutOffAngle=beamWidth*1.3 + + dx,dy,dz=self.computeDirection(mtx) + # note -dx seems to equal om[3][0] + # note -dz seems to equal om[3][1] + # note dy seems to equal om[3][2] + + #location=(ob.matrixWorld*MATWORLD).translationPart() # now passed + location=(mtx*MATWORLD).translationPart() + + radius = lamp.dist*math.cos(beamWidth) + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + + + def writeDirectionalLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + intensity=min(lamp.energy/1.75,1.0) + (dx,dy,dz)=self.computeDirection(mtx) + self.file.write("\n\n" % (round(dx,4),round(dy,4),round(dz,4))) + + def writePointLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + # location=(ob.matrixWorld*MATWORLD).translationPart() # now passed + location= (mtx*MATWORLD).translationPart() + + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + ''' + def writeNode(self, ob, mtx): + obname=str(ob.name) + if obname in self.namesStandard: + return + else: + dx,dy,dz = self.computeDirection(mtx) + # location=(ob.matrixWorld*MATWORLD).translationPart() + location=(mtx*MATWORLD).translationPart() + self.writeIndented("<%s\n" % obname,1) + self.writeIndented("direction=\"%s %s %s\"\n" % (round(dx,3),round(dy,3),round(dz,3))) + self.writeIndented("location=\"%s %s %s\"\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + self.writeIndented("/>\n",-1) + self.writeIndented("\n") + ''' + def secureName(self, name): + name = name + str(self.nodeID) + self.nodeID=self.nodeID+1 + if len(name) <= 3: + newname = "_" + str(self.nodeID) + return "%s" % (newname) + else: + for bad in ['"','#',"'",',','.','[','\\',']','{','}']: + name=name.replace(bad,'_') + if name in self.namesReserved: + newname = name[0:3] + "_" + str(self.nodeID) + return "%s" % (newname) + elif name[0].isdigit(): + newname = "_" + name + str(self.nodeID) + return "%s" % (newname) + else: + newname = name + return "%s" % (newname) + + def writeIndexedFaceSet(self, ob, mesh, mtx, world, EXPORT_TRI = False): + imageMap={} # set of used images + sided={} # 'one':cnt , 'two':cnt + vColors={} # 'multi':1 + meshName = self.cleanStr(ob.name) + + meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not + if len(mesh.faces) == 0: return + mode = 0 + if mesh.faceUV: + for face in mesh.faces: + mode |= face.mode + + if mode & Mesh.FaceModes.HALO and self.halonode == 0: + self.writeIndented("\n",1) + self.halonode = 1 + elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: + self.writeIndented("\n",1) + self.billnode = 1 + elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0: + self.matonly = 1 + elif mode & Mesh.FaceModes.TILES and self.tilenode == 0: + self.tilenode = 1 + elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0: + self.writeIndented("\n",1) + self.collnode = 1 + + nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) + + if nIFSCnt > 1: + self.writeIndented("\n" % ("G_", meshName),1) + + if sided.has_key('two') and sided['two'] > 0: + bTwoSided=1 + else: + bTwoSided=0 + + # mtx = ob.matrixWorld * MATWORLD # mtx is now passed + mtx = mtx * MATWORLD + + loc= mtx.translationPart() + sca= mtx.scalePart() + quat = mtx.toQuat() + rot= quat.axis + + # self.writeIndented('\n' % (rot[0], rot[1], rot[2], rot[3])) + self.writeIndented('\n' % \ + (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) ) + + self.writeIndented("\n",1) + maters=mesh.materials + hasImageTexture=0 + issmooth=0 + + if len(maters) > 0 or mesh.faceUV: + self.writeIndented("\n", 1) + # right now this script can only handle a single material per mesh. + if len(maters) >= 1: + mat=maters[0] + matFlags = mat.getMode() + if not matFlags & Blender.Material.Modes['TEXFACE']: + self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) + if len(maters) > 1: + print "Warning: mesh named %s has multiple materials" % meshName + print "Warning: only one material per object handled" + + #-- textures + if mesh.faceUV: + for face in mesh.faces: + if (hasImageTexture == 0) and (face.image): + self.writeImageTexture(face.image) + hasImageTexture=1 # keep track of face texture + if self.tilenode == 1: + self.writeIndented("\n" % (face.image.xrep, face.image.yrep)) + self.tilenode = 0 + self.writeIndented("\n", -1) + + #-- IndexedFaceSet or IndexedLineSet + + # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5 + ifStyle="IndexedFaceSet" + # look up mesh name, use it if available + if self.meshNames.has_key(meshME): + self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1) + self.meshNames[meshME]+=1 + else: + if int(mesh.users) > 1: + self.writeIndented("<%s DEF=\"ME_%s\" " % (ifStyle, meshME), 1) + self.meshNames[meshME]=1 + else: + self.writeIndented("<%s " % ifStyle, 1) + + if bTwoSided == 1: + self.file.write("solid=\"false\" ") + else: + self.file.write("solid=\"true\" ") + + for face in mesh.faces: + if face.smooth: + issmooth=1 + break + if issmooth==1: + creaseAngle=(mesh.degr)*(math.pi/180.0) + self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) + + #--- output textureCoordinates if UV texture used + if mesh.faceUV: + if self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + elif hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + #--- output coordinates + self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) + + self.writingcoords = 1 + self.writingtexture = 1 + self.writingcolor = 1 + self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) + + #--- output textureCoordinates if UV texture used + if mesh.faceUV: + if hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + elif self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + #--- output vertexColors + self.matonly = 0 + self.share = 0 + + self.writingcoords = 0 + self.writingtexture = 0 + self.writingcolor = 0 + #--- output closing braces + self.writeIndented("\n" % ifStyle, -1) + self.writeIndented("\n", -1) + self.writeIndented("\n", -1) + + if self.halonode == 1: + self.writeIndented("\n", -1) + self.halonode = 0 + + if self.billnode == 1: + self.writeIndented("\n", -1) + self.billnode = 0 + + if self.collnode == 1: + self.writeIndented("\n", -1) + self.collnode = 0 + + if nIFSCnt > 1: + self.writeIndented("\n", -1) + + self.file.write("\n") + + def writeCoordinates(self, ob, mesh, meshName, EXPORT_TRI = False): + # create vertex list and pre rotate -90 degrees X for VRML + + if self.writingcoords == 0: + self.file.write('coordIndex="') + for face in mesh.faces: + fv = face.v + + if len(face)==3: + self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + else: + if EXPORT_TRI: + self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index)) + else: + self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index)) + + self.file.write("\">\n") + else: + #-- vertices + # mesh.transform(ob.matrixWorld) + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeTextureCoordinates(self, mesh): + texCoordList=[] + texIndexList=[] + j=0 + + for face in mesh.faces: + for uv in face.uv: + texIndexList.append(j) + texCoordList.append(uv) + j=j+1 + texIndexList.append(-1) + if self.writingtexture == 0: + self.file.write("\n\t\t\ttexCoordIndex=\"") + texIndxStr="" + for i in xrange(len(texIndexList)): + texIndxStr = texIndxStr + "%d, " % texIndexList[i] + if texIndexList[i]==-1: + self.file.write(texIndxStr) + texIndxStr="" + self.file.write("\"\n\t\t\t") + else: + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeFaceColors(self, mesh): + if self.writingcolor == 0: + self.file.write("colorPerVertex=\"false\" ") + else: + self.writeIndented(" 2: + print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b) + aColor = self.rgbToFS(c) + self.file.write("%s, " % aColor) + self.file.write("\" />") + self.writeIndented("\n",-1) + + def writeMaterial(self, mat, matName, world): + # look up material name, use it if available + if self.matNames.has_key(matName): + self.writeIndented("\n" % matName) + self.matNames[matName]+=1 + return; + + self.matNames[matName]=1 + + ambient = mat.amb/3 + diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] + if world: + ambi = world.getAmb() + ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2 + else: + ambi0, ambi1, ambi2 = 0, 0, 0 + emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2 + + shininess = mat.hard/512.0 + specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001)) + specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001)) + specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001)) + transp = 1-mat.alpha + matFlags = mat.getMode() + if matFlags & Blender.Material.Modes['SHADELESS']: + ambient = 1 + shine = 1 + specR = emitR = diffuseR + specG = emitG = diffuseG + specB = emitB = diffuseB + self.writeIndented("" % (round(transp,self.cp))) + self.writeIndented("\n",-1) + + def writeImageTexture(self, image): + name = image.name + filename = image.filename.split('/')[-1].split('\\')[-1] + if self.texNames.has_key(name): + self.writeIndented("\n" % self.cleanStr(name)) + self.texNames[name] += 1 + return + else: + self.writeIndented("" % name) + self.writeIndented("\n",-1) + self.texNames[name] = 1 + + def writeBackground(self, world, alltextures): + if world: worldname = world.name + else: return + blending = world.getSkytype() + grd = world.getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + sky = world.getZen() + sky0, sky1, sky2 = sky[0], sky[1], sky[2] + mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2] + mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2 + self.file.write("\n\n") + +########################################################## +# export routine +########################################################## + + def export(self, scene, world, alltextures,\ + EXPORT_APPLY_MODIFIERS = False,\ + EXPORT_TRI= False,\ + ): + + print "Info: starting X3D export to " + self.filename + "..." + self.writeHeader() + # self.writeScript() + self.writeNavigationInfo(scene) + self.writeBackground(world, alltextures) + self.writeFog(world) + self.proto = 0 + + + # COPIED FROM OBJ EXPORTER + if EXPORT_APPLY_MODIFIERS: + temp_mesh_name = '~tmp-mesh' + + # Get the container mesh. - used for applying modifiers and non mesh objects. + containerMesh = meshName = tempMesh = None + for meshName in Blender.NMesh.GetNames(): + if meshName.startswith(temp_mesh_name): + tempMesh = Mesh.Get(meshName) + if not tempMesh.users: + containerMesh = tempMesh + if not containerMesh: + containerMesh = Mesh.New(temp_mesh_name) + # -------------------------- + + + for ob_main in scene.objects.context: + for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + objType=ob.type + objName=ob.name + self.matonly = 0 + if objType == "Camera": + self.writeViewpoint(ob, ob_mat, scene) + elif objType in ("Mesh", "Curve", "Surf", "Text") : + if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': + me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) + else: + me = ob.getData(mesh=1) + + self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI) + elif objType == "Lamp": + data= ob.data + datatype=data.type + if datatype == Lamp.Types.Lamp: + self.writePointLight(ob, ob_mat, data, world) + elif datatype == Lamp.Types.Spot: + self.writeSpotLight(ob, ob_mat, data, world) + elif datatype == Lamp.Types.Sun: + self.writeDirectionalLight(ob, ob_mat, data, world) + else: + self.writeDirectionalLight(ob, ob_mat, data, world) + # do you think x3d could document what to do with dummy objects? + #elif objType == "Empty" and objName != "Empty": + # self.writeNode(ob, ob_mat) + else: + #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) + pass + + self.file.write("\n\n") + + if EXPORT_APPLY_MODIFIERS: + if containerMesh: + containerMesh.verts = None + + self.cleanup() + +########################################################## +# Utility methods +########################################################## + + def cleanup(self): + self.file.close() + self.texNames={} + self.matNames={} + self.indentLevel=0 + print "Info: finished X3D export to %s\n" % self.filename + + def cleanStr(self, name, prefix='rsvd_'): + """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" + + newName=name[:] + if len(newName) == 0: + self.nNodeID+=1 + return "%s%d" % (prefix, self.nNodeID) + + if newName in self.namesReserved: + newName='%s%s' % (prefix,newName) + + if newName[0].isdigit(): + newName='%s%s' % ('_',newName) + + for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']: + newName=newName.replace(bad,'_') + return newName + + def countIFSSetsNeeded(self, mesh, imageMap, sided, vColors): + """ + countIFFSetsNeeded() - should look at a blender mesh to determine + how many VRML IndexFaceSets or IndexLineSets are needed. A + new mesh created under the following conditions: + + o - split by UV Textures / one per mesh + o - split by face, one sided and two sided + o - split by smooth and flat faces + o - split when faces only have 2 vertices * needs to be an IndexLineSet + """ + + imageNameMap={} + faceMap={} + nFaceIndx=0 + + if mesh.faceUV: + for face in mesh.faces: + sidename=''; + if face.mode & Mesh.FaceModes.TWOSIDE: + sidename='two' + else: + sidename='one' + + if sided.has_key(sidename): + sided[sidename]+=1 + else: + sided[sidename]=1 + + image = face.image + if image: + faceName="%s_%s" % (face.image.name, sidename); + try: + imageMap[faceName].append(face) + except: + imageMap[faceName]=[face.image.name,sidename,face] + + if self.verbose > 2: + for faceName in imageMap.iterkeys(): + ifs=imageMap[faceName] + print "Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ + (faceName, ifs[0], ifs[1], len(ifs)-2) + + return len(imageMap) + + def faceToString(self,face): + + print "Debug: face.flag=0x%x (bitflags)" % face.flag + if face.sel: + print "Debug: face.sel=true" + + print "Debug: face.mode=0x%x (bitflags)" % face.mode + if face.mode & Mesh.FaceModes.TWOSIDE: + print "Debug: face.mode twosided" + + print "Debug: face.transp=0x%x (enum)" % face.transp + if face.transp == Mesh.FaceTranspModes.SOLID: + print "Debug: face.transp.SOLID" + + if face.image: + print "Debug: face.image=%s" % face.image.name + print "Debug: face.materialIndex=%d" % face.materialIndex + + def getVertexColorByIndx(self, mesh, indx): + c = None + for face in mesh.faces: + j=0 + for vertex in face.v: + if vertex.index == indx: + c=face.col[j] + break + j=j+1 + if c: break + return c + + def meshToString(self,mesh): + print "Debug: mesh.hasVertexUV=%d" % mesh.vertexColors + print "Debug: mesh.faceUV=%d" % mesh.faceUV + print "Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours() + print "Debug: mesh.verts=%d" % len(mesh.verts) + print "Debug: mesh.faces=%d" % len(mesh.faces) + print "Debug: mesh.materials=%d" % len(mesh.materials) + + def rgbToFS(self, c): + s="%s %s %s" % ( + round(c.r/255.0,self.cp), + round(c.g/255.0,self.cp), + round(c.b/255.0,self.cp)) + return s + + def computeDirection(self, mtx): + x,y,z=(0,-1.0,0) # point down + + ax,ay,az = (mtx*MATWORLD).toEuler() + + ax *= DEG2RAD + ay *= DEG2RAD + az *= DEG2RAD + # rot X + x1=x + y1=y*math.cos(ax)-z*math.sin(ax) + z1=y*math.sin(ax)+z*math.cos(ax) + + # rot Y + x2=x1*math.cos(ay)+z1*math.sin(ay) + y2=y1 + z2=z1*math.cos(ay)-x1*math.sin(ay) + + # rot Z + x3=x2*math.cos(az)-y2*math.sin(az) + y3=x2*math.sin(az)+y2*math.cos(az) + z3=z2 + + return [x3,y3,z3] + + + # swap Y and Z to handle axis difference between Blender and VRML + #------------------------------------------------------------------------ + def rotatePointForVRML(self, v): + x = v[0] + y = v[2] + z = -v[1] + + vrmlPoint=[x, y, z] + return vrmlPoint + + # For writing well formed VRML code + #------------------------------------------------------------------------ + def writeIndented(self, s, inc=0): + if inc < 1: + self.indentLevel = self.indentLevel + inc + + spaces="" + for x in xrange(self.indentLevel): + spaces = spaces + "\t" + self.file.write(spaces + s) + + if inc > 0: + self.indentLevel = self.indentLevel + inc + + # Converts a Euler to three new Quaternions + # Angles of Euler are passed in as radians + #------------------------------------------------------------------------ + def eulerToQuaternions(self, x, y, z): + Qx = [math.cos(x/2), math.sin(x/2), 0, 0] + Qy = [math.cos(y/2), 0, math.sin(y/2), 0] + Qz = [math.cos(z/2), 0, 0, math.sin(z/2)] + + quaternionVec=[Qx,Qy,Qz] + return quaternionVec + + # Multiply two Quaternions together to get a new Quaternion + #------------------------------------------------------------------------ + def multiplyQuaternions(self, Q1, Q2): + result = [((Q1[0] * Q2[0]) - (Q1[1] * Q2[1]) - (Q1[2] * Q2[2]) - (Q1[3] * Q2[3])), + ((Q1[0] * Q2[1]) + (Q1[1] * Q2[0]) + (Q1[2] * Q2[3]) - (Q1[3] * Q2[2])), + ((Q1[0] * Q2[2]) + (Q1[2] * Q2[0]) + (Q1[3] * Q2[1]) - (Q1[1] * Q2[3])), + ((Q1[0] * Q2[3]) + (Q1[3] * Q2[0]) + (Q1[1] * Q2[2]) - (Q1[2] * Q2[1]))] + + return result + + # Convert a Quaternion to an Angle Axis (ax, ay, az, angle) + # angle is in radians + #------------------------------------------------------------------------ + def quaternionToAngleAxis(self, Qf): + scale = math.pow(Qf[1],2) + math.pow(Qf[2],2) + math.pow(Qf[3],2) + ax = Qf[1] + ay = Qf[2] + az = Qf[3] + + if scale > .0001: + ax/=scale + ay/=scale + az/=scale + + angle = 2 * math.acos(Qf[0]) + + result = [ax, ay, az, angle] + return result + +########################################################## +# Callbacks, needed before Main +########################################################## + +def x3d_export(filename, \ + EXPORT_APPLY_MODIFIERS= False,\ + EXPORT_TRI= False,\ + EXPORT_GZIP= False,\ + ): + + if EXPORT_GZIP: + if not filename.lower().endswith('.x3dz'): + filename = '.'.join(filename.split('.')[:-1]) + '.x3dz' + else: + if not filename.lower().endswith('.x3d'): + filename = '.'.join(filename.split('.')[:-1]) + '.x3d' + + + scene = Blender.Scene.GetCurrent() + world = scene.world + alltextures = Blender.Texture.Get() + + wrlexport=x3d_class(filename) + wrlexport.export(\ + scene,\ + world,\ + alltextures,\ + \ + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS,\ + EXPORT_TRI = EXPORT_TRI,\ + ) + + +def x3d_export_ui(filename): + if not filename.endswith(extension): + filename += extension + #if _safeOverwrite and sys.exists(filename): + # result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0") + #if(result != 1): + # return + + # Get user options + EXPORT_APPLY_MODIFIERS = Draw.Create(1) + EXPORT_TRI = Draw.Create(0) + EXPORT_GZIP = Draw.Create( filename.lower().endswith('.x3dz') ) + + # Get USER Options + pup_block = [\ + ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object.'),\ + ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ + ('Compress', EXPORT_GZIP, 'GZip the resulting file, requires a full python install'),\ + ] + + if not Draw.PupBlock('Export...', pup_block): + return + + Blender.Window.EditMode(0) + Blender.Window.WaitCursor(1) + + x3d_export(filename,\ + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val,\ + EXPORT_TRI = EXPORT_TRI.val,\ + EXPORT_GZIP = EXPORT_GZIP.val\ + ) + + Blender.Window.WaitCursor(0) + + + +######################################################### +# main routine +######################################################### + + +if __name__ == '__main__': + Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) + + diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py new file mode 100644 index 00000000000..bcde82c4869 --- /dev/null +++ b/release/io/import_3ds.py @@ -0,0 +1,1007 @@ +#!BPY +""" +Name: '3D Studio (.3ds)...' +Blender: 244 +Group: 'Import' +Tooltip: 'Import from 3DS file format (.3ds)' +""" + +__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton', 'Mario Lapin'] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__= '0.996' +__bpydoc__= '''\ + +3ds Importer + +This script imports a 3ds file and the materials into Blender for editing. + +Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). + +0.996 by Mario Lapin (mario.lapin@gmail.com) 13/04/200
+ - Implemented workaround to correct association between name, geometry and materials of + imported meshes. + + Without this patch, version 0.995 of this importer would associate to each mesh object the + geometry and the materials of the previously parsed mesh object. By so, the name of the + first mesh object would be thrown away, and the name of the last mesh object would be + automatically merged with a '.001' at the end. No object would desappear, however object's + names and materials would be completely jumbled. + +0.995 by Campbell Barton
+- workaround for buggy mesh vert delete +- minor tweaks + +0.99 by Bob Holcomb
+- added support for floating point color values that previously broke on import. + +0.98 by Campbell Barton
+- import faces and verts to lists instead of a mesh, convert to a mesh later +- use new index mapping feature of mesh to re-map faces that were not added. + +0.97 by Campbell Barton
+- Strip material names of spaces +- Added import as instance to import the 3ds into its own + scene and add a group instance to the current scene +- New option to scale down imported objects so they are within a limited bounding area. + +0.96 by Campbell Barton
+- Added workaround for bug in setting UV's for Zero vert index UV faces. +- Removed unique name function, let blender make the names unique. + +0.95 by Campbell Barton
+- Removed workarounds for Blender 2.41 +- Mesh objects split by material- many 3ds objects used more then 16 per mesh. +- Removed a lot of unneeded variable creation. + +0.94 by Campbell Barton
+- Face import tested to be about overall 16x speedup over 0.93. +- Material importing speedup. +- Tested with more models. +- Support some corrupt models. + +0.93 by Campbell Barton
+- Tested with 400 3ds files from turbosquid and samples. +- Tactfully ignore faces that used the same verts twice. +- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. +- Converted from NMesh to Mesh. +- Faster and cleaner new names. +- Use external comprehensive image loader. +- Re intergrated 0.92 and 0.9 changes +- Fixes for 2.41 compat. +- Non textured faces do not use a texture flag. + +0.92
+- Added support for diffuse, alpha, spec, bump maps in a single material + +0.9
+- Reorganized code into object/material block functions
+- Use of Matrix() to copy matrix data
+- added support for material transparency
+ +0.83 2005-08-07: Campell Barton +- Aggressive image finding and case insensitivy for posisx systems. + +0.82a 2005-07-22 +- image texture loading (both for face uv and renderer) + +0.82 - image texture loading (for face uv) + +0.81a (fork- not 0.9) Campbell Barton 2005-06-08 +- Simplified import code +- Never overwrite data +- Faster list handling +- Leaves import selected + +0.81 Damien McGinnes 2005-01-09 +- handle missing images better + +0.8 Damien McGinnes 2005-01-08 +- copies sticky UV coords to face ones +- handles images better +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script + +''' + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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 ***** +# -------------------------------------------------------------------------- + +# Importing modules + +import Blender +import bpy +from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils +from Blender.Mathutils import Vector +import BPyImage + +import BPyMessages + +try: + from struct import calcsize, unpack +except: + calcsize= unpack= None + + + +# If python version is less than 2.4, try to get set stuff from module +try: + set +except: + from sets import Set as set + +BOUNDS_3DS= [] + + +#this script imports uvcoords as sticky vertex coords +#this parameter enables copying these to face uv coords +#which shold be more useful. + +def createBlenderTexture(material, name, image): + texture= bpy.data.textures.new(name) + texture.setType('Image') + texture.image= image + material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will see +#----- Primary Chunk, at the beginning of each file +PRIMARY= long('0x4D4D',16) + +#------ Main Chunks +OBJECTINFO = long('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long('0x0002',16); #This gives the version of the .3ds file +EDITKEYFRAME= long('0xB000',16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +#------ sub defines of MATERIAL_BLOCK +MAT_NAME = long('0xA000',16) # This holds the material name +MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material +MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material +MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material +MAT_SHINESS = long('0xA040',16) # ?? +MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material +MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material +MAT_WIRE = long('0xA085',16) # Only render's wireframe + +MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map +MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map +MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map +MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map +MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map +MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture + +MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats +MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes + +#>------ sub defines of OBJECT +OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object +OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object +OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght. +OBJECT_LAMP_OFF = long('0x4620',16); # The light off. +OBJECT_LAMP_ATTENUATE = long('0x4625',16); +OBJECT_LAMP_RAYSHADE = long('0x4627',16); +OBJECT_LAMP_SHADOWED = long('0x4630',16); +OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16); +OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16); +OBJECT_LAMP_SEE_CONE = long('0x4650',16); +OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16); +OBJECT_LAMP_EXCLUDE= long('0x4654',16); +OBJECT_LAMP_RANGE= long('0x4655',16); +OBJECT_LAMP_ROLL= long('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16); +OBJECT_LAMP_RAY_BIAS= long('0x4658',16); +OBJECT_LAMP_INNER_RANGE= long('0x4659',16); +OBJECT_LAMP_OUTER_RANGE= long('0x465A',16); +OBJECT_LAMP_MULTIPLIER = long('0x465B',16); +OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16); + + + +OBJECT_CAMERA= long('0x4700',16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long('0x4720',16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long('0x4110',16); # The objects vertices +OBJECT_FACES = long('0x4120',16); # The objects faces +OBJECT_MATERIAL = long('0x4130',16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long('0x4140',16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long('0x4160',16); # The Object Matrix + +global scn +scn= None + +#the chunk class +class chunk: + ID=0 + length=0 + bytes_read=0 + + #we don't read in the bytes_read, we compute that + binary_format='3): + print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version + + #is it an object info chunk? + elif (new_chunk.ID==OBJECTINFO): + #print 'elif (new_chunk.ID==OBJECTINFO):' + # print 'found an OBJECTINFO chunk' + process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) + + #keep track of how much we read in the main chunk + new_chunk.bytes_read+=temp_chunk.bytes_read + + #is it an object chunk? + elif (new_chunk.ID==OBJECT): + + if CreateBlenderObject: + putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) + contextMesh_vertls= []; contextMesh_facels= [] + + ## preparando para receber o proximo objeto + contextMeshMaterials= {} # matname:[face_idxs] + contextMeshUV= None + #contextMesh.vertexUV= 1 # Make sticky coords. + # Reset matrix + contextMatrix_rot= None + #contextMatrix_tx= None + + CreateBlenderObject= True + tempName= read_string(file) + contextObName= tempName + new_chunk.bytes_read += len(tempName)+1 + + #is it a material chunk? + elif (new_chunk.ID==MATERIAL): + #print 'elif (new_chunk.ID==MATERIAL):' + contextMaterial= bpy.data.materials.new('Material') + + elif (new_chunk.ID==MAT_NAME): + #print 'elif (new_chunk.ID==MAT_NAME):' + material_name= read_string(file) + + #plus one for the null character that ended the string + new_chunk.bytes_read+= len(material_name)+1 + + contextMaterial.name= material_name.rstrip() # remove trailing whitespace + MATDICT[material_name]= (contextMaterial.name, contextMaterial) + + elif (new_chunk.ID==MAT_AMBIENT): + #print 'elif (new_chunk.ID==MAT_AMBIENT):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_DIFFUSE): + #print 'elif (new_chunk.ID==MAT_DIFFUSE):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_SPECULAR): + #print 'elif (new_chunk.ID==MAT_SPECULAR):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_TEXTURE_MAP): + #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' + new_texture= bpy.data.textures.new('Diffuse') + new_texture.setType('Image') + img = None + while (new_chunk.bytes_read BOUNDS_3DS[i+3]: + BOUNDS_3DS[i+3]= v[i] # min + + # Get the max axis x/y/z + max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) + # print max_axis + if max_axis < 1<<30: # Should never be false but just make sure. + + # Get a new scale factor if set as an option + SCALE=1.0 + while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS: + SCALE/=10 + + # SCALE Matrix + SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + + for ob in importedObjects: + ob.setMatrix(ob.matrixWorld*SCALE_MAT) + + # Done constraining to bounds. + + # Select all new objects. + print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)) + file.close() + Blender.Window.WaitCursor(0) + + +DEBUG= False +if __name__=='__main__' and not DEBUG: + if calcsize==None: + Blender.Draw.PupMenu('Error%t|a full python installation not found') + else: + Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') + +# For testing compatibility +#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) +#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) +''' + +else: + import os + # DEBUG ONLY + TIME= Blender.sys.time() + import os + print 'Searching for files' + os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') + # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') + print '...Done' + file= open('/tmp/temp3ds_list', 'r') + lines= file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _3ds in enumerate(lines): + if between(i, 650,800): + #_3ds= _3ds[:-1] + print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) + _3ds_file= _3ds.split('/')[-1].split('\\')[-1] + newScn= Blender.Scene.New(_3ds_file) + newScn.makeCurrent() + load_3ds(_3ds, False) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) + +''' -- cgit v1.2.3 From 675936b42cc9aa3ea15c1cf4af06790e5b41ecae Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 10 Aug 2009 13:49:55 +0000 Subject: - ran 2to3 on export_3ds.py, import_3ds.py and export_x3d.py - added operators and menu items for ^ --- release/io/export_3ds.py | 164 +++++++++++++++++++++--------------- release/io/export_obj.py | 2 +- release/io/export_x3d.py | 114 ++++++++++++++++--------- release/io/import_3ds.py | 210 +++++++++++++++++++++++++++-------------------- release/ui/space_info.py | 3 + 5 files changed, 296 insertions(+), 197 deletions(-) diff --git a/release/io/export_3ds.py b/release/io/export_3ds.py index 69b4d00b4d8..c4a73a44b0c 100644 --- a/release/io/export_3ds.py +++ b/release/io/export_3ds.py @@ -46,14 +46,17 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. # Importing modules ###################################################### -import Blender +import struct + import bpy -from BPyMesh import getMeshFromObject -from BPyObject import getDerivedObjects -try: - import struct -except: - struct = None + +# import Blender +# from BPyMesh import getMeshFromObject +# from BPyObject import getDerivedObjects +# try: +# import struct +# except: +# struct = None # So 3ds max can open files, limit names to 12 in length # this is verry annoying for filenames! @@ -85,58 +88,58 @@ def sane_name(name): #Some of the chunks that we will export #----- Primary Chunk, at the beginning of each file -PRIMARY= long("0x4D4D",16) +PRIMARY= int("0x4D4D",16) #------ Main Chunks -OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information -VERSION = long("0x0002",16); #This gives the version of the .3ds file -KFDATA = long("0xB000",16); #This is the header for all of the key frame info +OBJECTINFO = int("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information +VERSION = int("0x0002",16); #This gives the version of the .3ds file +KFDATA = int("0xB000",16); #This is the header for all of the key frame info #------ sub defines of OBJECTINFO MATERIAL=45055 #0xAFFF // This stored the texture info OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... #>------ sub defines of MATERIAL -MATNAME = long("0xA000",16); # This holds the material name -MATAMBIENT = long("0xA010",16); # Ambient color of the object/material -MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material -MATSPECULAR = long("0xA030",16); # SPecular color of the object/material -MATSHINESS = long("0xA040",16); # ?? -MATMAP = long("0xA200",16); # This is a header for a new material -MATMAPFILE = long("0xA300",16); # This holds the file name of the texture +MATNAME = int("0xA000",16); # This holds the material name +MATAMBIENT = int("0xA010",16); # Ambient color of the object/material +MATDIFFUSE = int("0xA020",16); # This holds the color of the object/material +MATSPECULAR = int("0xA030",16); # SPecular color of the object/material +MATSHINESS = int("0xA040",16); # ?? +MATMAP = int("0xA200",16); # This is a header for a new material +MATMAPFILE = int("0xA300",16); # This holds the file name of the texture -RGB1= long("0x0011",16) -RGB2= long("0x0012",16) +RGB1= int("0x0011",16) +RGB2= int("0x0012",16) #>------ sub defines of OBJECT -OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object -OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object -OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object +OBJECT_MESH = int("0x4100",16); # This lets us know that we are reading a new object +OBJECT_LIGHT = int("0x4600",16); # This lets un know we are reading a light object +OBJECT_CAMERA= int("0x4700",16); # This lets un know we are reading a camera object #>------ sub defines of CAMERA -OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values +OBJECT_CAM_RANGES= int("0x4720",16); # The camera range values #>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = long("0x4110",16); # The objects vertices -OBJECT_FACES = long("0x4120",16); # The objects faces -OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color -OBJECT_UV = long("0x4140",16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix +OBJECT_VERTICES = int("0x4110",16); # The objects vertices +OBJECT_FACES = int("0x4120",16); # The objects faces +OBJECT_MATERIAL = int("0x4130",16); # This is found if the object has a material, either texture map or color +OBJECT_UV = int("0x4140",16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = int("0x4160",16); # The Object Matrix #>------ sub defines of KFDATA -KFDATA_KFHDR = long("0xB00A",16); -KFDATA_KFSEG = long("0xB008",16); -KFDATA_KFCURTIME = long("0xB009",16); -KFDATA_OBJECT_NODE_TAG = long("0xB002",16); +KFDATA_KFHDR = int("0xB00A",16); +KFDATA_KFSEG = int("0xB008",16); +KFDATA_KFCURTIME = int("0xB009",16); +KFDATA_OBJECT_NODE_TAG = int("0xB002",16); #>------ sub defines of OBJECT_NODE_TAG -OBJECT_NODE_ID = long("0xB030",16); -OBJECT_NODE_HDR = long("0xB010",16); -OBJECT_PIVOT = long("0xB013",16); -OBJECT_INSTANCE_NAME = long("0xB011",16); -POS_TRACK_TAG = long("0xB020",16); -ROT_TRACK_TAG = long("0xB021",16); -SCL_TRACK_TAG = long("0xB022",16); +OBJECT_NODE_ID = int("0xB030",16); +OBJECT_NODE_HDR = int("0xB010",16); +OBJECT_PIVOT = int("0xB013",16); +OBJECT_INSTANCE_NAME = int("0xB011",16); +POS_TRACK_TAG = int("0xB020",16); +ROT_TRACK_TAG = int("0xB021",16); +SCL_TRACK_TAG = int("0xB022",16); def uv_key(uv): return round(uv.x, 6), round(uv.y, 6) @@ -343,12 +346,12 @@ class _3ds_named_variable(object): def dump(self,indent): if (self.value!=None): spaces="" - for i in xrange(indent): + for i in range(indent): spaces+=" "; if (self.name!=""): - print spaces, self.name, " = ", self.value + print(spaces, self.name, " = ", self.value) else: - print spaces, "[unnamed]", " = ", self.value + print(spaces, "[unnamed]", " = ", self.value) #the chunk class @@ -408,9 +411,9 @@ class _3ds_chunk(object): Dump is used for debugging purposes, to dump the contents of a chunk to the standard output. Uses the dump function of the named variables and the subchunks to do the actual work.''' spaces="" - for i in xrange(indent): + for i in range(indent): spaces+=" "; - print spaces, "ID=", hex(self.ID.value), "size=", self.get_size() + print(spaces, "ID=", hex(self.ID.value), "size=", self.get_size()) for variable in self.variables: variable.dump(indent+1) for subchunk in self.subchunks: @@ -555,11 +558,11 @@ def remove_face_uv(verts, tri_list): # initialize a list of UniqueLists, one per vertex: #uv_list = [UniqueList() for i in xrange(len(verts))] - unique_uvs= [{} for i in xrange(len(verts))] + unique_uvs= [{} for i in range(len(verts))] # for each face uv coordinate, add it to the UniqueList of the vertex for tri in tri_list: - for i in xrange(3): + for i in range(3): # store the index into the UniqueList for future reference: # offset.append(uv_list[tri.vertex_index[i]].add(_3ds_point_uv(tri.faceuvs[i]))) @@ -589,7 +592,7 @@ def remove_face_uv(verts, tri_list): pt = _3ds_point_3d(vert.co) # reuse, should be ok uvmap = [None] * len(unique_uvs[i]) - for ii, uv_3ds in unique_uvs[i].itervalues(): + for ii, uv_3ds in unique_uvs[i].values(): # add a vertex duplicate to the vertex_array for every uv associated with this vertex: vert_array.add(pt) # add the uv coordinate to the uv array: @@ -607,7 +610,7 @@ def remove_face_uv(verts, tri_list): # Make sure the triangle vertex indices now refer to the new vertex list: for tri in tri_list: - for i in xrange(3): + for i in range(3): tri.offset[i]+=index_list[tri.vertex_index[i]] tri.vertex_index= tri.offset @@ -655,7 +658,7 @@ def make_faces_chunk(tri_list, mesh, materialDict): # obj_material_faces[tri.mat].add(_3ds_short(i)) face_chunk.add_variable("faces", face_list) - for mat_name, mat_faces in unique_mats.itervalues(): + for mat_name, mat_faces in unique_mats.values(): obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL) obj_material_chunk.add_variable("name", mat_name) obj_material_chunk.add_variable("face_list", mat_faces) @@ -677,7 +680,7 @@ def make_faces_chunk(tri_list, mesh, materialDict): obj_material_faces[tri.mat].add(_3ds_short(i)) face_chunk.add_variable("faces", face_list) - for i in xrange(n_materials): + for i in range(n_materials): obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL) obj_material_chunk.add_variable("name", obj_material_names[i]) obj_material_chunk.add_variable("face_list", obj_material_faces[i]) @@ -862,7 +865,7 @@ def make_kf_obj_node(obj, name_to_id): return kf_obj_node """ -import BPyMessages +# import BPyMessages def save_3ds(filename, context): '''Save the Blender scene to a 3ds file.''' # Time the export @@ -871,16 +874,16 @@ def save_3ds(filename, context): filename += '.3ds' # XXX -# if not BPyMessages.Warning_SaveOver(filename): -# return +# if not BPyMessages.Warning_SaveOver(filename): +# return # XXX - time1 = bpy.sys.time() -# time1= Blender.sys.time() -# Blender.Window.WaitCursor(1) + time1 = bpy.sys.time() +# time1= Blender.sys.time() +# Blender.Window.WaitCursor(1) sce = context.scene -# sce= bpy.data.scenes.active +# sce= bpy.data.scenes.active # Initialize the main chunk (primary): primary = _3ds_chunk(PRIMARY) @@ -948,7 +951,7 @@ def save_3ds(filename, context): f.mat = 0 # Make material chunks for all materials used in the meshes: - for mat_and_image in materialDict.itervalues(): + for mat_and_image in materialDict.values(): object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) # Give all objects a unique ID and build a dictionary from object name to object id: @@ -1011,15 +1014,44 @@ def save_3ds(filename, context): # Debugging only: report the exporting time: Blender.Window.WaitCursor(0) - print "3ds export time: %.2f" % (Blender.sys.time() - time1) + print("3ds export time: %.2f" % (Blender.sys.time() - time1)) # Debugging only: dump the chunk hierarchy: #primary.dump() -if __name__=='__main__': - if struct: - Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) - else: - Blender.Draw.PupMenu("Error%t|This script requires a full python installation") -# save_3ds('/test_b.3ds') +# if __name__=='__main__': +# if struct: +# Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) +# else: +# Blender.Draw.PupMenu("Error%t|This script requires a full python installation") +# # save_3ds('/test_b.3ds') + +class EXPORT_OT_3ds(bpy.types.Operator): + ''' + 3DS Exporter + ''' + __idname__ = "export.3ds" + __label__ = 'Export 3DS' + + # 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 3DS file", maxlen= 1024, default= ""), + ] + + def execute(self, context): + raise Exception("Not doing anything yet.") + 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_3ds) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index fa07c5408a7..b2d4af7c517 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -913,7 +913,7 @@ class EXPORT_OT_obj(bpy.types.Operator): # 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= ""), + bpy.props.StringProperty(attr="filename", name="File Name", description="File name used for exporting the OBJ file", maxlen= 1024, default= ""), # context group bpy.props.BoolProperty(attr="use_selection", name="Selection Only", description="", default= False), diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py index b12ff67d8a6..b57be2286e9 100644 --- a/release/io/export_x3d.py +++ b/release/io/export_x3d.py @@ -53,22 +53,27 @@ Known issues:
# Library dependancies #################################### -import Blender -from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh -from Blender.Scene import Render import math -import BPyObject -import BPyMesh + +import bpy +import Mathutils + +# import Blender +# from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh +# from Blender.Scene import Render +# import BPyObject +# import BPyMesh # DEG2RAD=0.017453292519943295 -MATWORLD= Blender.Mathutils.RotationMatrix(-90, 4, 'x') +MATWORLD= Mathutils.RotationMatrix(-90, 4, 'x') #################################### # Global Variables #################################### -filename = Blender.Get('filename') +filename = "" +# filename = Blender.Get('filename') _safeOverwrite = True extension = '' @@ -109,7 +114,7 @@ class x3d_class: import gzip self.file = gzip.open(filename, "w") except: - print "failed to import compression modules, exporting uncompressed" + print("failed to import compression modules, exporting uncompressed") self.filename = filename[:-1] # remove trailing z if self.file == None: @@ -383,7 +388,7 @@ class x3d_class: if nIFSCnt > 1: self.writeIndented("\n" % ("G_", meshName),1) - if sided.has_key('two') and sided['two'] > 0: + if 'two' in sided and sided['two'] > 0: bTwoSided=1 else: bTwoSided=0 @@ -414,8 +419,8 @@ class x3d_class: if not matFlags & Blender.Material.Modes['TEXFACE']: self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) if len(maters) > 1: - print "Warning: mesh named %s has multiple materials" % meshName - print "Warning: only one material per object handled" + print("Warning: mesh named %s has multiple materials" % meshName) + print("Warning: only one material per object handled") #-- textures if mesh.faceUV: @@ -433,7 +438,7 @@ class x3d_class: # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5 ifStyle="IndexedFaceSet" # look up mesh name, use it if available - if self.meshNames.has_key(meshME): + if meshME in self.meshNames: self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1) self.meshNames[meshME]+=1 else: @@ -547,7 +552,7 @@ class x3d_class: if self.writingtexture == 0: self.file.write("\n\t\t\ttexCoordIndex=\"") texIndxStr="" - for i in xrange(len(texIndexList)): + for i in range(len(texIndexList)): texIndxStr = texIndxStr + "%d, " % texIndexList[i] if texIndexList[i]==-1: self.file.write(texIndxStr) @@ -555,7 +560,7 @@ class x3d_class: self.file.write("\"\n\t\t\t") else: self.writeIndented("") self.writeIndented("\n", -1) @@ -569,7 +574,7 @@ class x3d_class: if face.col: c=face.col[0] if self.verbose > 2: - print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b) + print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) aColor = self.rgbToFS(c) self.file.write("%s, " % aColor) self.file.write("\" />") @@ -577,7 +582,7 @@ class x3d_class: def writeMaterial(self, mat, matName, world): # look up material name, use it if available - if self.matNames.has_key(matName): + if matName in self.matNames: self.writeIndented("\n" % matName) self.matNames[matName]+=1 return; @@ -617,7 +622,7 @@ class x3d_class: def writeImageTexture(self, image): name = image.name filename = image.filename.split('/')[-1].split('\\')[-1] - if self.texNames.has_key(name): + if name in self.texNames: self.writeIndented("\n" % self.cleanStr(name)) self.texNames[name] += 1 return @@ -671,7 +676,7 @@ class x3d_class: self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) alltexture = len(alltextures) - for i in xrange(alltexture): + for i in range(alltexture): namemat = alltextures[i].name pic = alltextures[i].getImage() if (namemat == "back") and (pic != None): @@ -697,7 +702,7 @@ class x3d_class: EXPORT_TRI= False,\ ): - print "Info: starting X3D export to " + self.filename + "..." + print("Info: starting X3D export to " + self.filename + "...") self.writeHeader() # self.writeScript() self.writeNavigationInfo(scene) @@ -771,7 +776,7 @@ class x3d_class: self.texNames={} self.matNames={} self.indentLevel=0 - print "Info: finished X3D export to %s\n" % self.filename + print("Info: finished X3D export to %s\n" % self.filename) def cleanStr(self, name, prefix='rsvd_'): """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" @@ -815,7 +820,7 @@ class x3d_class: else: sidename='one' - if sided.has_key(sidename): + if sidename in sided: sided[sidename]+=1 else: sided[sidename]=1 @@ -829,30 +834,30 @@ class x3d_class: imageMap[faceName]=[face.image.name,sidename,face] if self.verbose > 2: - for faceName in imageMap.iterkeys(): + for faceName in imageMap.keys(): ifs=imageMap[faceName] - print "Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ - (faceName, ifs[0], ifs[1], len(ifs)-2) + print("Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ + (faceName, ifs[0], ifs[1], len(ifs)-2)) return len(imageMap) def faceToString(self,face): - print "Debug: face.flag=0x%x (bitflags)" % face.flag + print("Debug: face.flag=0x%x (bitflags)" % face.flag) if face.sel: - print "Debug: face.sel=true" + print("Debug: face.sel=true") - print "Debug: face.mode=0x%x (bitflags)" % face.mode + print("Debug: face.mode=0x%x (bitflags)" % face.mode) if face.mode & Mesh.FaceModes.TWOSIDE: - print "Debug: face.mode twosided" + print("Debug: face.mode twosided") - print "Debug: face.transp=0x%x (enum)" % face.transp + print("Debug: face.transp=0x%x (enum)" % face.transp) if face.transp == Mesh.FaceTranspModes.SOLID: - print "Debug: face.transp.SOLID" + print("Debug: face.transp.SOLID") if face.image: - print "Debug: face.image=%s" % face.image.name - print "Debug: face.materialIndex=%d" % face.materialIndex + print("Debug: face.image=%s" % face.image.name) + print("Debug: face.materialIndex=%d" % face.materialIndex) def getVertexColorByIndx(self, mesh, indx): c = None @@ -867,12 +872,12 @@ class x3d_class: return c def meshToString(self,mesh): - print "Debug: mesh.hasVertexUV=%d" % mesh.vertexColors - print "Debug: mesh.faceUV=%d" % mesh.faceUV - print "Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours() - print "Debug: mesh.verts=%d" % len(mesh.verts) - print "Debug: mesh.faces=%d" % len(mesh.faces) - print "Debug: mesh.materials=%d" % len(mesh.materials) + print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors) + print("Debug: mesh.faceUV=%d" % mesh.faceUV) + print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()) + print("Debug: mesh.verts=%d" % len(mesh.verts)) + print("Debug: mesh.faces=%d" % len(mesh.faces)) + print("Debug: mesh.materials=%d" % len(mesh.materials)) def rgbToFS(self, c): s="%s %s %s" % ( @@ -924,7 +929,7 @@ class x3d_class: self.indentLevel = self.indentLevel + inc spaces="" - for x in xrange(self.indentLevel): + for x in range(self.indentLevel): spaces = spaces + "\t" self.file.write(spaces + s) @@ -1045,7 +1050,34 @@ def x3d_export_ui(filename): ######################################################### -if __name__ == '__main__': - Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) +# if __name__ == '__main__': +# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) + +class EXPORT_OT_x3d(bpy.types.Operator): + ''' + X3D Exporter + ''' + __idname__ = "export.x3d" + __label__ = 'Export X3D' + + # 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 X3D file", maxlen= 1024, default= ""), + ] + + def execute(self, context): + raise Exception("Not doing anything yet.") + 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_x3d) diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py index bcde82c4869..a08fdb8fc85 100644 --- a/release/io/import_3ds.py +++ b/release/io/import_3ds.py @@ -125,26 +125,29 @@ Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). # Importing modules -import Blender +from struct import calcsize, unpack + import bpy -from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils -from Blender.Mathutils import Vector -import BPyImage -import BPyMessages +# import Blender +# from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils +# from Blender.Mathutils import Vector +# import BPyImage + +# import BPyMessages -try: - from struct import calcsize, unpack -except: - calcsize= unpack= None +# try: +# from struct import calcsize, unpack +# except: +# calcsize= unpack= None -# If python version is less than 2.4, try to get set stuff from module -try: - set -except: - from sets import Set as set +# # If python version is less than 2.4, try to get set stuff from module +# try: +# set +# except: +# from sets import Set as set BOUNDS_3DS= [] @@ -167,12 +170,12 @@ def createBlenderTexture(material, name, image): #Some of the chunks that we will see #----- Primary Chunk, at the beginning of each file -PRIMARY= long('0x4D4D',16) +PRIMARY= int('0x4D4D',16) #------ Main Chunks -OBJECTINFO = long('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information -VERSION = long('0x0002',16); #This gives the version of the .3ds file -EDITKEYFRAME= long('0xB000',16); #This is the header for all of the key frame info +OBJECTINFO = int('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information +VERSION = int('0x0002',16); #This gives the version of the .3ds file +EDITKEYFRAME= int('0xB000',16); #This is the header for all of the key frame info #------ sub defines of OBJECTINFO MATERIAL=45055 #0xAFFF // This stored the texture info @@ -180,62 +183,62 @@ OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... #>------ sub defines of MATERIAL #------ sub defines of MATERIAL_BLOCK -MAT_NAME = long('0xA000',16) # This holds the material name -MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material -MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material -MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material -MAT_SHINESS = long('0xA040',16) # ?? -MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material -MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material -MAT_WIRE = long('0xA085',16) # Only render's wireframe - -MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map -MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map -MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map -MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map -MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map -MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture - -MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats -MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes +MAT_NAME = int('0xA000',16) # This holds the material name +MAT_AMBIENT = int('0xA010',16) # Ambient color of the object/material +MAT_DIFFUSE = int('0xA020',16) # This holds the color of the object/material +MAT_SPECULAR = int('0xA030',16) # SPecular color of the object/material +MAT_SHINESS = int('0xA040',16) # ?? +MAT_TRANSPARENCY= int('0xA050',16) # Transparency value of material +MAT_SELF_ILLUM = int('0xA080',16) # Self Illumination value of material +MAT_WIRE = int('0xA085',16) # Only render's wireframe + +MAT_TEXTURE_MAP = int('0xA200',16) # This is a header for a new texture map +MAT_SPECULAR_MAP= int('0xA204',16) # This is a header for a new specular map +MAT_OPACITY_MAP = int('0xA210',16) # This is a header for a new opacity map +MAT_REFLECTION_MAP= int('0xA220',16) # This is a header for a new reflection map +MAT_BUMP_MAP = int('0xA230',16) # This is a header for a new bump map +MAT_MAP_FILENAME = int('0xA300',16) # This holds the file name of the texture + +MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats +MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes #>------ sub defines of OBJECT -OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object -OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object -OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght. -OBJECT_LAMP_OFF = long('0x4620',16); # The light off. -OBJECT_LAMP_ATTENUATE = long('0x4625',16); -OBJECT_LAMP_RAYSHADE = long('0x4627',16); -OBJECT_LAMP_SHADOWED = long('0x4630',16); -OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16); -OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16); -OBJECT_LAMP_SEE_CONE = long('0x4650',16); -OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16); -OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16); -OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16); -OBJECT_LAMP_EXCLUDE= long('0x4654',16); -OBJECT_LAMP_RANGE= long('0x4655',16); -OBJECT_LAMP_ROLL= long('0x4656',16); -OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16); -OBJECT_LAMP_RAY_BIAS= long('0x4658',16); -OBJECT_LAMP_INNER_RANGE= long('0x4659',16); -OBJECT_LAMP_OUTER_RANGE= long('0x465A',16); -OBJECT_LAMP_MULTIPLIER = long('0x465B',16); -OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16); - - - -OBJECT_CAMERA= long('0x4700',16); # This lets un know we are reading a camera object +OBJECT_MESH = int('0x4100',16); # This lets us know that we are reading a new object +OBJECT_LAMP = int('0x4600',16); # This lets un know we are reading a light object +OBJECT_LAMP_SPOT = int('0x4610',16); # The light is a spotloght. +OBJECT_LAMP_OFF = int('0x4620',16); # The light off. +OBJECT_LAMP_ATTENUATE = int('0x4625',16); +OBJECT_LAMP_RAYSHADE = int('0x4627',16); +OBJECT_LAMP_SHADOWED = int('0x4630',16); +OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16); +OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16); +OBJECT_LAMP_SEE_CONE = int('0x4650',16); +OBJECT_LAMP_SPOT_RECTANGULAR= int('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT= int('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR= int('0x4653',16); +OBJECT_LAMP_EXCLUDE= int('0x4654',16); +OBJECT_LAMP_RANGE= int('0x4655',16); +OBJECT_LAMP_ROLL= int('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT= int('0x4657',16); +OBJECT_LAMP_RAY_BIAS= int('0x4658',16); +OBJECT_LAMP_INNER_RANGE= int('0x4659',16); +OBJECT_LAMP_OUTER_RANGE= int('0x465A',16); +OBJECT_LAMP_MULTIPLIER = int('0x465B',16); +OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16); + + + +OBJECT_CAMERA= int('0x4700',16); # This lets un know we are reading a camera object #>------ sub defines of CAMERA -OBJECT_CAM_RANGES= long('0x4720',16); # The camera range values +OBJECT_CAM_RANGES= int('0x4720',16); # The camera range values #>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = long('0x4110',16); # The objects vertices -OBJECT_FACES = long('0x4120',16); # The objects faces -OBJECT_MATERIAL = long('0x4130',16); # This is found if the object has a material, either texture map or color -OBJECT_UV = long('0x4140',16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = long('0x4160',16); # The Object Matrix +OBJECT_VERTICES = int('0x4110',16); # The objects vertices +OBJECT_FACES = int('0x4120',16); # The objects faces +OBJECT_MATERIAL = int('0x4130',16); # This is found if the object has a material, either texture map or color +OBJECT_UV = int('0x4140',16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = int('0x4160',16); # The Object Matrix global scn scn= None @@ -255,10 +258,10 @@ class chunk: self.bytes_read=0 def dump(self): - print 'ID: ', self.ID - print 'ID in hex: ', hex(self.ID) - print 'length: ', self.length - print 'bytes_read: ', self.bytes_read + print('ID: ', self.ID) + print('ID in hex: ', hex(self.ID)) + print('length: ', self.length) + print('bytes_read: ', self.bytes_read) def read_chunk(file, chunk): temp_data=file.read(calcsize(chunk.binary_format)) @@ -309,13 +312,13 @@ def add_texture_to_material(image, texture, material, mapto): elif mapto=='BUMP': map=Texture.MapTo.NOR else: - print '/tError: Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name) + print('/tError: Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name)) map=Texture.MapTo.COL if image: texture.setImage(image) # double check its an image. free_tex_slots= [i for i, tex in enumerate( material.getTextures() ) if tex==None] if not free_tex_slots: - print '/tError: Cannot add "%s" map. 10 Texture slots alredy used.' % mapto + print('/tError: Cannot add "%s" map. 10 Texture slots alredy used.' % mapto) else: material.setTexture(free_tex_slots[0],texture,Texture.TexCo.UV,map) @@ -374,7 +377,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): myVertMapping = {} vertMappingIndex = 0 - vertsToUse = [i for i in xrange(len(myContextMesh_vertls)) if faceVertUsers[i]] + vertsToUse = [i for i in range(len(myContextMesh_vertls)) if faceVertUsers[i]] myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] ) tempName= '%s_%s' % (contextObName, matName) # matName may be None. @@ -423,7 +426,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): importedObjects.append(ob) bmesh.calcNormals() - for matName, faces in myContextMeshMaterials.iteritems(): + for matName, faces in myContextMeshMaterials.items(): makeMeshMaterialCopy(matName, faces) if len(materialFaces)!=len(myContextMesh_facels): @@ -455,7 +458,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): new_chunk.bytes_read+= 4 #read the 4 bytes for the version number #this loader works with version 3 and below, but may not with 4 and above if (version>3): - print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version + print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version) #is it an object info chunk? elif (new_chunk.ID==OBJECTINFO): @@ -684,7 +687,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): return temp_data #contextMesh.verts.extend( [Vector(),] ) # DUMMYVERT! - remove when blenders internals are fixed. - contextMesh_vertls= [getvert() for i in xrange(num_verts)] + contextMesh_vertls= [getvert() for i in range(num_verts)] #print 'object verts: bytes read: ', new_chunk.bytes_read @@ -702,7 +705,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): v1,v2,v3,dummy= unpack('<4H', temp_data) return v1, v2, v3 - contextMesh_facels= [ getface() for i in xrange(num_faces) ] + contextMesh_facels= [ getface() for i in range(num_faces) ] elif (new_chunk.ID==OBJECT_MATERIAL): @@ -719,7 +722,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): new_chunk.bytes_read+= STRUCT_SIZE_UNSIGNED_SHORT return unpack(' Date: Wed, 12 Aug 2009 16:37:05 +0000 Subject: - converted 3ds exporter to 2.5 API - added Object.is_visible() RNA function to determine if an object is on the visible layer of active scene --- release/io/export_3ds.py | 151 ++++++++++++++++-------- source/blender/makesrna/intern/rna_object_api.c | 12 ++ 2 files changed, 117 insertions(+), 46 deletions(-) diff --git a/release/io/export_3ds.py b/release/io/export_3ds.py index c4a73a44b0c..56268b2925a 100644 --- a/release/io/export_3ds.py +++ b/release/io/export_3ds.py @@ -47,6 +47,8 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. ###################################################### import struct +import os +import time import bpy @@ -142,7 +144,8 @@ ROT_TRACK_TAG = int("0xB021",16); SCL_TRACK_TAG = int("0xB022",16); def uv_key(uv): - return round(uv.x, 6), round(uv.y, 6) + return round(uv[0], 6), round(uv[1], 6) +# return round(uv.x, 6), round(uv.y, 6) # size defines: SZ_SHORT = 2 @@ -275,7 +278,8 @@ class _3ds_rgb_color(object): return 3 def write(self,file): - file.write( struct.pack('<3c', chr(int(255*self.r)), chr(int(255*self.g)), chr(int(255*self.b)) ) ) + file.write( struct.pack('<3B', int(255*self.r), int(255*self.g), int(255*self.b) ) ) +# file.write( struct.pack('<3c', chr(int(255*self.r)), chr(int(255*self.g)), chr(int(255*self.b)) ) ) def __str__(self): return '{%f, %f, %f}' % (self.r, self.g, self.b) @@ -427,14 +431,19 @@ class _3ds_chunk(object): def get_material_images(material): # blender utility func. - images = [] if material: - for mtex in material.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - image = mtex.tex.image - if image: - images.append(image) # maye want to include info like diffuse, spec here. - return images + return [s.texture.image for s in material.textures if s and s.texture.type == 'IMAGE' and s.texture.image] + + return [] +# images = [] +# if material: +# for mtex in material.getTextures(): +# if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: +# image = mtex.tex.image +# if image: +# images.append(image) # maye want to include info like diffuse, spec here. +# return images + def make_material_subchunk(id, color): '''Make a material subchunk. @@ -457,7 +466,8 @@ def make_material_texture_chunk(id, images): mat_sub = _3ds_chunk(id) def add_image(img): - filename = image.filename.split('\\')[-1].split('/')[-1] + filename = os.path.basename(image.filename) +# filename = image.filename.split('\\')[-1].split('/')[-1] mat_sub_file = _3ds_chunk(MATMAPFILE) mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename))) mat_sub.add_subchunk(mat_sub_file) @@ -485,9 +495,12 @@ def make_material_chunk(material, image): material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, (1,1,1) )) else: - material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.amb for a in material.rgbCol] )) - material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.rgbCol)) - material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specCol)) + material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.ambient for a in material.diffuse_color] )) +# material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.amb for a in material.rgbCol] )) + material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.diffuse_color)) +# material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.rgbCol)) + material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specular_color)) +# material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specCol)) images = get_material_images(material) # can be None if image: images.append(image) @@ -516,28 +529,38 @@ def extract_triangles(mesh): If the mesh contains quads, they will be split into triangles.''' tri_list = [] - do_uv = mesh.faceUV + do_uv = len(mesh.uv_textures) +# do_uv = mesh.faceUV - if not do_uv: - face_uv = None +# if not do_uv: +# face_uv = None img = None - for face in mesh.faces: - f_v = face.v + for i, face in enumerate(mesh.faces): + f_v = face.verts +# f_v = face.v + + uf = mesh.active_uv_texture.data[i] if do_uv else None if do_uv: - f_uv = face.uv - img = face.image + f_uv = (uf.uv1, uf.uv2, uf.uv3, uf.uv4) if face.verts[3] else (uf.uv1, uf.uv2, uf.uv3) +# f_uv = face.uv + img = uf.image if uf else None +# img = face.image if img: img = img.name - - if len(f_v)==3: - new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img) + + if f_v[3] == 0: + # if len(f_v)==3: + new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img) +# new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img) if (do_uv): new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2]) tri_list.append(new_tri) else: #it's a quad - new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img) - new_tri_2 = tri_wrapper((f_v[0].index, f_v[2].index, f_v[3].index), face.mat, img) + new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img) +# new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img) + new_tri_2 = tri_wrapper((f_v[0], f_v[2], f_v[3]), face.material_index, img) +# new_tri_2 = tri_wrapper((f_v[0].index, f_v[2].index, f_v[3].index), face.mat, img) if (do_uv): new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2]) @@ -629,7 +652,8 @@ def make_faces_chunk(tri_list, mesh, materialDict): face_list = _3ds_array() - if mesh.faceUV: + if len(mesh.uv_textures): +# if mesh.faceUV: # Gather materials used in this mesh - mat/image pairs unique_mats = {} for i,tri in enumerate(tri_list): @@ -706,7 +730,8 @@ def make_mesh_chunk(mesh, materialDict): # Extract the triangles from the mesh: tri_list = extract_triangles(mesh) - if mesh.faceUV: + if len(mesh.uv_textures): +# if mesh.faceUV: # Remove the face UVs and convert it to vertex UV: vert_array, uv_array, tri_list = remove_face_uv(mesh.verts, tri_list) else: @@ -715,10 +740,13 @@ def make_mesh_chunk(mesh, materialDict): for vert in mesh.verts: vert_array.add(_3ds_point_3d(vert.co)) # If the mesh has vertex UVs, create an array of UVs: - if mesh.vertexUV: + if len(mesh.sticky): +# if mesh.vertexUV: uv_array = _3ds_array() - for vert in mesh.verts: - uv_array.add(_3ds_point_uv(vert.uvco)) + for uv in mesh.sticky: +# for vert in mesh.verts: + uv_array.add(_3ds_point_uv(uv.co)) +# uv_array.add(_3ds_point_uv(vert.uvco)) else: # no UV at all: uv_array = None @@ -878,7 +906,7 @@ def save_3ds(filename, context): # return # XXX - time1 = bpy.sys.time() + time1 = time.clock() # time1= Blender.sys.time() # Blender.Window.WaitCursor(1) @@ -909,31 +937,56 @@ def save_3ds(filename, context): # each material is added once): materialDict = {} mesh_objects = [] - for ob in context.selected_objects: + for ob in [ob for ob in context.scene.objects if ob.is_visible()]: # for ob in sce.objects.context: - for ob_derived, mat in getDerivedObjects(ob, False): - data = getMeshFromObject(ob_derived, None, True, False, sce) + + # get derived objects + derived = [] + + # ignore dupli children + if ob.parent and ob.parent.dupli_type != 'NONE': + continue + + if ob.dupli_type != 'NONE': + ob.create_dupli_list() + derived = [(dob.object, dob.matrix) for dob in ob.dupli_list] + else: + derived = [(ob, ob.matrix)] + + for ob_derived, mat in derived: +# for ob_derived, mat in getDerivedObjects(ob, False): + + if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'): + continue + + data = ob_derived.create_mesh(True, 'PREVIEW') +# data = getMeshFromObject(ob_derived, None, True, False, sce) if data: - data.transform(mat, recalc_normals=False) + data.transform(mat) +# data.transform(mat, recalc_normals=False) mesh_objects.append((ob_derived, data)) mat_ls = data.materials mat_ls_len = len(mat_ls) + # get material/image tuples. - if data.faceUV: + if len(data.uv_textures): +# if data.faceUV: if not mat_ls: mat = mat_name = None - for f in data.faces: + for f, uf in zip(data.faces, data.active_uv_texture.data): if mat_ls: - mat_index = f.mat + mat_index = f.material_index +# mat_index = f.mat if mat_index >= mat_ls_len: mat_index = f.mat = 0 mat = mat_ls[mat_index] if mat: mat_name = mat.name else: mat_name = None # else there alredy set to none - - img = f.image + + img = uf.image +# img = f.image if img: img_name = img.name else: img_name = None @@ -947,8 +1000,10 @@ def save_3ds(filename, context): # Why 0 Why! for f in data.faces: - if f.mat >= mat_ls_len: - f.mat = 0 + if f.material_index >= mat_ls_len: +# if f.mat >= mat_ls_len: + f.material_index = 0 +# f.mat = 0 # Make material chunks for all materials used in the meshes: for mat_and_image in materialDict.values(): @@ -980,7 +1035,10 @@ def save_3ds(filename, context): # make a kf object node for the object: kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) ''' - blender_mesh.verts = None +# if not blender_mesh.users: + bpy.data.remove_mesh(blender_mesh) +# blender_mesh.verts = None + i+=i # Create chunks for all empties: @@ -1013,8 +1071,9 @@ def save_3ds(filename, context): file.close() # Debugging only: report the exporting time: - Blender.Window.WaitCursor(0) - print("3ds export time: %.2f" % (Blender.sys.time() - time1)) +# Blender.Window.WaitCursor(0) + print("3ds export time: %.2f" % (time.clock() - time1)) +# print("3ds export time: %.2f" % (Blender.sys.time() - time1)) # Debugging only: dump the chunk hierarchy: #primary.dump() @@ -1042,7 +1101,7 @@ class EXPORT_OT_3ds(bpy.types.Operator): ] def execute(self, context): - raise Exception("Not doing anything yet.") + save_3ds(self.filename, context) return ('FINISHED',) def invoke(self, context, event): diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 8192801d9fb..f0a42987848 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -333,6 +333,11 @@ static Object *rna_Object_find_armature(Object *ob) return ob_arm; } +int rna_Object_is_visible(Object *ob, bContext *C) +{ + return ob->lay & CTX_data_scene(C)->lay; +} + /* static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) { @@ -443,6 +448,13 @@ void RNA_api_object(StructRNA *srna) func= RNA_def_function(srna, "make_display_list", "rna_Object_make_display_list"); RNA_def_function_ui_description(func, "Update object's display data."); /* XXX describe better */ RNA_def_function_flag(func, FUNC_USE_CONTEXT); + + /* View */ + func= RNA_def_function(srna, "is_visible", "rna_Object_is_visible"); + RNA_def_function_ui_description(func, "Determine if object is visible in active scene."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm= RNA_def_boolean(func, "is_visible", 0, "", "Object visibility."); + RNA_def_function_return(func, parm); } #endif -- cgit v1.2.3 From 44ddff5c516058a73f0297a94845b2e835307d2f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 13 Aug 2009 11:14:06 +0000 Subject: - 3ds importer working (without the "scale to size" option) - changing object.matrix now updates object.loc/rot/scale - added bpy.data.add_lamp() --- release/io/import_3ds.py | 886 ++++++++++++---------- release/io/import_obj.py | 15 +- source/blender/makesrna/intern/rna_main_api.c | 27 + source/blender/makesrna/intern/rna_material_api.c | 2 +- source/blender/makesrna/intern/rna_mesh_api.c | 6 +- source/blender/makesrna/intern/rna_object.c | 7 + 6 files changed, 553 insertions(+), 390 deletions(-) diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py index a08fdb8fc85..0269219b63d 100644 --- a/release/io/import_3ds.py +++ b/release/io/import_3ds.py @@ -125,9 +125,14 @@ Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). # Importing modules -from struct import calcsize, unpack +import os +import time +import struct + +from import_obj import unpack_face_list, load_image import bpy +import Mathutils # import Blender # from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils @@ -149,7 +154,7 @@ import bpy # except: # from sets import Set as set -BOUNDS_3DS= [] +BOUNDS_3DS = [] #this script imports uvcoords as sticky vertex coords @@ -157,9 +162,9 @@ BOUNDS_3DS= [] #which shold be more useful. def createBlenderTexture(material, name, image): - texture= bpy.data.textures.new(name) + texture = bpy.data.textures.new(name) texture.setType('Image') - texture.image= image + texture.image = image material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) @@ -170,7 +175,7 @@ def createBlenderTexture(material, name, image): #Some of the chunks that we will see #----- Primary Chunk, at the beginning of each file -PRIMARY= int('0x4D4D',16) +PRIMARY = int('0x4D4D',16) #------ Main Chunks OBJECTINFO = int('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information @@ -178,8 +183,8 @@ VERSION = int('0x0002',16); #This gives the version of the .3ds f EDITKEYFRAME= int('0xB000',16); #This is the header for all of the key frame info #------ sub defines of OBJECTINFO -MATERIAL=45055 #0xAFFF // This stored the texture info -OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... +MATERIAL = 45055 #0xAFFF // This stored the texture info +OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc... #>------ sub defines of MATERIAL #------ sub defines of MATERIAL_BLOCK @@ -213,16 +218,16 @@ OBJECT_LAMP_SHADOWED = int('0x4630',16); OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16); OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16); OBJECT_LAMP_SEE_CONE = int('0x4650',16); -OBJECT_LAMP_SPOT_RECTANGULAR= int('0x4651',16); -OBJECT_LAMP_SPOT_OVERSHOOT= int('0x4652',16); -OBJECT_LAMP_SPOT_PROJECTOR= int('0x4653',16); -OBJECT_LAMP_EXCLUDE= int('0x4654',16); -OBJECT_LAMP_RANGE= int('0x4655',16); -OBJECT_LAMP_ROLL= int('0x4656',16); -OBJECT_LAMP_SPOT_ASPECT= int('0x4657',16); -OBJECT_LAMP_RAY_BIAS= int('0x4658',16); -OBJECT_LAMP_INNER_RANGE= int('0x4659',16); -OBJECT_LAMP_OUTER_RANGE= int('0x465A',16); +OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16); +OBJECT_LAMP_EXCLUDE = int('0x4654',16); +OBJECT_LAMP_RANGE = int('0x4655',16); +OBJECT_LAMP_ROLL = int('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16); +OBJECT_LAMP_RAY_BIAS = int('0x4658',16); +OBJECT_LAMP_INNER_RANGE = int('0x4659',16); +OBJECT_LAMP_OUTER_RANGE = int('0x465A',16); OBJECT_LAMP_MULTIPLIER = int('0x465B',16); OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16); @@ -241,21 +246,21 @@ OBJECT_UV = int('0x4140',16); # The UV texture coordinates OBJECT_TRANS_MATRIX = int('0x4160',16); # The Object Matrix global scn -scn= None +scn = None #the chunk class class chunk: - ID=0 - length=0 - bytes_read=0 + ID = 0 + length = 0 + bytes_read = 0 #we don't read in the bytes_read, we compute that binary_format='3): + if (version > 3): print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version) #is it an object info chunk? - elif (new_chunk.ID==OBJECTINFO): - #print 'elif (new_chunk.ID==OBJECTINFO):' + elif (new_chunk.ID == OBJECTINFO): + #print 'elif (new_chunk.ID == OBJECTINFO):' # print 'found an OBJECTINFO chunk' process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) #keep track of how much we read in the main chunk - new_chunk.bytes_read+=temp_chunk.bytes_read + new_chunk.bytes_read += temp_chunk.bytes_read #is it an object chunk? - elif (new_chunk.ID==OBJECT): + elif (new_chunk.ID == OBJECT): if CreateBlenderObject: putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) - contextMesh_vertls= []; contextMesh_facels= [] + contextMesh_vertls = []; contextMesh_facels = [] ## preparando para receber o proximo objeto - contextMeshMaterials= {} # matname:[face_idxs] - contextMeshUV= None - #contextMesh.vertexUV= 1 # Make sticky coords. + contextMeshMaterials = {} # matname:[face_idxs] + contextMeshUV = None + #contextMesh.vertexUV = 1 # Make sticky coords. # Reset matrix - contextMatrix_rot= None - #contextMatrix_tx= None + contextMatrix_rot = None + #contextMatrix_tx = None - CreateBlenderObject= True - tempName= read_string(file) - contextObName= tempName + CreateBlenderObject = True + tempName = read_string(file) + contextObName = tempName new_chunk.bytes_read += len(tempName)+1 #is it a material chunk? - elif (new_chunk.ID==MATERIAL): - #print 'elif (new_chunk.ID==MATERIAL):' - contextMaterial= bpy.data.materials.new('Material') + elif (new_chunk.ID == MATERIAL): + +# print("read material") + + #print 'elif (new_chunk.ID == MATERIAL):' + contextMaterial = bpy.data.add_material('Material') +# contextMaterial = bpy.data.materials.new('Material') - elif (new_chunk.ID==MAT_NAME): - #print 'elif (new_chunk.ID==MAT_NAME):' - material_name= read_string(file) + elif (new_chunk.ID == MAT_NAME): + #print 'elif (new_chunk.ID == MAT_NAME):' + material_name = read_string(file) + +# print("material name", material_name) #plus one for the null character that ended the string - new_chunk.bytes_read+= len(material_name)+1 + new_chunk.bytes_read += len(material_name)+1 - contextMaterial.name= material_name.rstrip() # remove trailing whitespace + contextMaterial.name = material_name.rstrip() # remove trailing whitespace MATDICT[material_name]= (contextMaterial.name, contextMaterial) - elif (new_chunk.ID==MAT_AMBIENT): - #print 'elif (new_chunk.ID==MAT_AMBIENT):' + elif (new_chunk.ID == MAT_AMBIENT): + #print 'elif (new_chunk.ID == MAT_AMBIENT):' read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.mirror_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.mirror_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb else: skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read + new_chunk.bytes_read += temp_chunk.bytes_read - elif (new_chunk.ID==MAT_DIFFUSE): - #print 'elif (new_chunk.ID==MAT_DIFFUSE):' + elif (new_chunk.ID == MAT_DIFFUSE): + #print 'elif (new_chunk.ID == MAT_DIFFUSE):' read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.diffuse_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.diffuse_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb else: skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read - elif (new_chunk.ID==MAT_SPECULAR): - #print 'elif (new_chunk.ID==MAT_SPECULAR):' +# print("read material diffuse color", contextMaterial.diffuse_color) + + new_chunk.bytes_read += temp_chunk.bytes_read + + elif (new_chunk.ID == MAT_SPECULAR): + #print 'elif (new_chunk.ID == MAT_SPECULAR):' read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.specular_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.specular_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb else: skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read + new_chunk.bytes_read += temp_chunk.bytes_read - elif (new_chunk.ID==MAT_TEXTURE_MAP): - #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' - new_texture= bpy.data.textures.new('Diffuse') - new_texture.setType('Image') - img = None - while (new_chunk.bytes_read BOUNDS_3DS[i+3]: - BOUNDS_3DS[i+3]= v[i] # min + if v[i] > BOUNDS_3DS[i + 3]: + BOUNDS_3DS[i + 3]= v[i] # min # Get the max axis x/y/z - max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) + max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) # print max_axis - if max_axis < 1<<30: # Should never be false but just make sure. + if max_axis < 1 << 30: # Should never be false but just make sure. # Get a new scale factor if set as an option - SCALE=1.0 - while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS: + SCALE = 1.0 + while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS: SCALE/=10 # SCALE Matrix - SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) +# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) for ob in importedObjects: - ob.setMatrix(ob.matrixWorld*SCALE_MAT) + ob.setMatrix(ob.matrixWorld * SCALE_MAT) # Done constraining to bounds. # Select all new objects. - print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))) + print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1))) +# print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))) file.close() - Blender.Window.WaitCursor(0) +# Blender.Window.WaitCursor(0) -DEBUG= False +DEBUG = False # if __name__=='__main__' and not DEBUG: -# if calcsize==None: +# if calcsize == None: # Blender.Draw.PupMenu('Error%t|a full python installation not found') # else: # Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') @@ -976,14 +1095,14 @@ DEBUG= False else: import os # DEBUG ONLY - TIME= Blender.sys.time() + TIME = Blender.sys.time() import os print 'Searching for files' os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') print '...Done' - file= open('/tmp/temp3ds_list', 'r') - lines= file.readlines() + file = open('/tmp/temp3ds_list', 'r') + lines = file.readlines() file.close() # sort by filesize for faster testing lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] @@ -1001,7 +1120,7 @@ else: #_3ds= _3ds[:-1] print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) _3ds_file= _3ds.split('/')[-1].split('\\')[-1] - newScn= Blender.Scene.New(_3ds_file) + newScn = Blender.Scene.New(_3ds_file) newScn.makeCurrent() load_3ds(_3ds, False) @@ -1020,11 +1139,14 @@ class IMPORT_OT_3ds(bpy.types.Operator): # to the class instance from the operator settings before calling. __props__ = [ - bpy.props.StringProperty(attr="filename", name="File Name", description="File name used for importing the 3DS file", maxlen= 1024, default= ""), + bpy.props.StringProperty(attr="filename", name="File Name", description="File name used for importing the 3DS file", maxlen=1024, default= ""), +# bpy.props.FloatProperty(attr="size_constraint", name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0), +# bpy.props.BoolProperty(attr="search_images", name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True), +# bpy.props.BoolProperty(attr="apply_matrix", name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False), ] def execute(self, context): - raise Exception("Not doing anything yet.") + load_3ds(self.filename, context, 0.0, False, False) return ('FINISHED',) def invoke(self, context, event): @@ -1037,3 +1159,7 @@ class IMPORT_OT_3ds(bpy.types.Operator): return context.active_object != None bpy.ops.add(IMPORT_OT_3ds) + +# NOTES: +# why add 1 extra vertex? and remove it when done? +# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time) diff --git a/release/io/import_obj.py b/release/io/import_obj.py index f064561a512..484be6d54b4 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -294,18 +294,21 @@ def line_value(line_split): return ' '.join( line_split[1:] ) # limited replacement for BPyImage.comprehensiveImageLoad -def load_image(imagepath, direc): +def load_image(imagepath, dirname): if os.path.exists(imagepath): return bpy.data.add_image(imagepath) - im_base = os.path.basename(imagepath) + variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))] - tmp = os.path.join(direc, im_base) - if os.path.exists(tmp): - return bpy.data.add_image(tmp) + for path in variants: + if os.path.exists(path): + return bpy.data.add_image(path) + else: + print(path, "doesn't exist") # TODO comprehensiveImageLoad also searched in bpy.config.textureDir + return None def obj_image_load(imagepath, DIR, IMAGE_SEARCH): @@ -387,7 +390,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ # blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API elif type == 'Ks': - blender_material.add_texture(texture, "UV", "SPECULAR") + blender_material.add_texture(texture, "UV", "SPECULARITY") # blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) elif type == 'Bump': diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 17f3800e10e..9d42c473f50 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -44,6 +44,9 @@ #include "BKE_object.h" #include "BKE_material.h" #include "BKE_image.h" +#include "BKE_texture.h" + +#include "DNA_lamp_types.h" static Mesh *rna_Main_add_mesh(Main *main, char *name) { @@ -62,6 +65,23 @@ static void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me) /* XXX python now has invalid pointer? */ } +static Lamp *rna_Main_add_lamp(Main *main, char *name) +{ + Lamp *la= add_lamp(name); + la->id.us--; + return la; +} + +/* +static void rna_Main_remove_lamp(Main *main, ReportList *reports, Lamp *la) +{ + if(la->id.us == 0) + free_libblock(&main->lamp, la); + else + BKE_report(reports, RPT_ERROR, "Lamp must have zero users to be removed."); +} +*/ + static Object* rna_Main_add_object(Main *main, int type, char *name) { Object *ob= add_only_object(type, name); @@ -158,6 +178,13 @@ void RNA_api_main(StructRNA *srna) parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); RNA_def_property_flag(parm, PROP_REQUIRED); + func= RNA_def_function(srna, "add_lamp", "rna_Main_add_lamp"); + RNA_def_function_ui_description(func, "Add a new lamp."); + parm= RNA_def_string(func, "name", "Lamp", 0, "", "New name for the datablock."); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "mesh", "Lamp", "", "New lamp."); + RNA_def_function_return(func, parm); + func= RNA_def_function(srna, "add_material", "rna_Main_add_material"); RNA_def_function_ui_description(func, "Add a new material."); parm= RNA_def_string(func, "name", "Material", 0, "", "New name for the datablock."); /* optional */ diff --git a/source/blender/makesrna/intern/rna_material_api.c b/source/blender/makesrna/intern/rna_material_api.c index e2b47460fdb..aa28b6b923c 100644 --- a/source/blender/makesrna/intern/rna_material_api.c +++ b/source/blender/makesrna/intern/rna_material_api.c @@ -101,7 +101,7 @@ void RNA_api_material(StructRNA *srna) static EnumPropertyItem prop_texture_mapto_items[] = { {MAP_COL, "COLOR", 0, "Color", "Causes the texture to affect basic color of the material"}, {MAP_NORM, "NORMAL", 0, "Normal", "Causes the texture to affect the rendered normal"}, - {MAP_COLSPEC, "SPEC_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"}, + {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"}, {MAP_COLMIR, "MIRROR", 0, "Mirror", "Causes the texture to affect the mirror color"}, {MAP_REF, "REFLECTION", 0, "Reflection", "Causes the texture to affect the value of the materials reflectivity"}, {MAP_SPEC, "SPECULARITY", 0, "Specularity", "Causes the texture to affect the value of specularity"}, diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index b50cc678f4f..9d4dad1fb5b 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -248,7 +248,7 @@ static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) rna_Mesh_add_faces(mesh, faces); } -static void rna_Mesh_add_uv_layer(Mesh *me) +static void rna_Mesh_add_uv_texture(Mesh *me) { me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); } @@ -306,8 +306,8 @@ void RNA_api_mesh(StructRNA *srna) 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_uv_layer", "rna_Mesh_add_uv_layer"); - RNA_def_function_ui_description(func, "Add new UV layer to Mesh."); + func= RNA_def_function(srna, "add_uv_texture", "rna_Mesh_add_uv_texture"); + RNA_def_function_ui_description(func, "Add a UV texture layer to Mesh."); func= RNA_def_function(srna, "calc_normals", "rna_Mesh_calc_normals"); RNA_def_function_ui_description(func, "Calculate vertex normals."); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6fe254dcb68..32307709387 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -74,6 +74,12 @@ void rna_Object_update(bContext *C, PointerRNA *ptr) DAG_object_flush_update(CTX_data_scene(C), ptr->id.data, OB_RECALC_OB); } +void rna_Object_matrix_update(bContext *C, PointerRNA *ptr) +{ + ED_object_apply_obmat(ptr->id.data); + rna_Object_update(C, ptr); +} + void rna_Object_update_data(bContext *C, PointerRNA *ptr) { DAG_object_flush_update(CTX_data_scene(C), ptr->id.data, OB_RECALC_DATA); @@ -1101,6 +1107,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "obmat"); RNA_def_property_array(prop, 16); RNA_def_property_ui_text(prop, "Matrix", "Transformation matrix."); + RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_matrix_update"); /* collections */ prop= RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); -- cgit v1.2.3 From 09042ce9a507b7f9ea36a63e60bbda6266541579 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 17 Aug 2009 14:29:29 +0000 Subject: Ported X3D exporter. --- release/io/export_3ds.py | 36 ++-- release/io/export_x3d.py | 448 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 326 insertions(+), 158 deletions(-) diff --git a/release/io/export_3ds.py b/release/io/export_3ds.py index 56268b2925a..19c12146769 100644 --- a/release/io/export_3ds.py +++ b/release/io/export_3ds.py @@ -60,6 +60,22 @@ import bpy # except: # struct = None +# also used by X3D exporter +# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() +def create_derived_objects(ob): + if ob.parent and ob.parent.dupli_type != 'NONE': + return False, None + + if ob.dupli_type != 'NONE': + ob.create_dupli_list() + return True, [(dob.object, dob.matrix) for dob in ob.dupli_list] + else: + return False, [(ob, ob.matrix)] + +# also used by X3D exporter +def free_derived_objects(ob): + ob.free_dupli_list() + # So 3ds max can open files, limit names to 12 in length # this is verry annoying for filenames! name_unique = [] @@ -941,17 +957,9 @@ def save_3ds(filename, context): # for ob in sce.objects.context: # get derived objects - derived = [] + free, derived = create_derived_objects(ob) - # ignore dupli children - if ob.parent and ob.parent.dupli_type != 'NONE': - continue - - if ob.dupli_type != 'NONE': - ob.create_dupli_list() - derived = [(dob.object, dob.matrix) for dob in ob.dupli_list] - else: - derived = [(ob, ob.matrix)] + if derived == None: continue for ob_derived, mat in derived: # for ob_derived, mat in getDerivedObjects(ob, False): @@ -1003,8 +1011,12 @@ def save_3ds(filename, context): if f.material_index >= mat_ls_len: # if f.mat >= mat_ls_len: f.material_index = 0 -# f.mat = 0 - + # f.mat = 0 + + if free: + free_derived_objects(ob) + + # Make material chunks for all materials used in the meshes: for mat_and_image in materialDict.values(): object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py index b57be2286e9..30a4b1483b0 100644 --- a/release/io/export_x3d.py +++ b/release/io/export_x3d.py @@ -54,10 +54,13 @@ Known issues:
#################################### import math +import os import bpy import Mathutils +from export_3ds import create_derived_objects, free_derived_objects + # import Blender # from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh # from Blender.Scene import Render @@ -166,8 +169,10 @@ class x3d_class: self.file.write("\n") self.file.write("\n") self.file.write("\n") - self.file.write("\t\n" % sys.basename(bfile)) - self.file.write("\t\n" % Blender.Get('version')) + self.file.write("\t\n" % os.path.basename(bfile)) + # self.file.write("\t\n" % sys.basename(bfile)) + self.file.write("\t\n" % '2.5') + # self.file.write("\t\n" % Blender.Get('version')) self.file.write("\t\n") self.file.write("\n") self.file.write("\n") @@ -211,9 +216,12 @@ class x3d_class: ''' def writeViewpoint(self, ob, mat, scene): - context = scene.render - ratio = float(context.imageSizeY())/float(context.imageSizeX()) - lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180) + context = scene.render_data + # context = scene.render + ratio = float(context.resolution_x)/float(context.resolution_y) + # ratio = float(context.imageSizeY())/float(context.imageSizeX()) + lens = (360* (math.atan(ratio *16 / ob.data.lens) / math.pi))*(math.pi/180) + # lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180) lens = min(lens, math.pi) # get the camera location, subtract 90 degress from X to orient like X3D does @@ -221,7 +229,8 @@ class x3d_class: loc = self.rotatePointForVRML(mat.translationPart()) rot = mat.toEuler() - rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD) + rot = (((rot[0]-90)), rot[1], rot[2]) + # rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD) nRot = self.rotatePointForVRML( rot ) # convert to Quaternion and to Angle Axis Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2]) @@ -237,13 +246,18 @@ class x3d_class: def writeFog(self, world): if world: - mtype = world.getMistype() - mparam = world.getMist() - grd = world.getHor() + mtype = world.mist.falloff + # mtype = world.getMistype() + mparam = world.mist + # mparam = world.getMist() + grd = world.horizon_color + # grd = world.getHor() grd0, grd1, grd2 = grd[0], grd[1], grd[2] else: return - if (mtype == 1 or mtype == 2): + if (mtype == 'LINEAR' or mtype == 'INVERSE_QUADRATIC'): + mtype = 1 if mtype == 'LINEAR' else 2 + # if (mtype == 1 or mtype == 2): self.file.write("\n\n" % round(mparam[2],self.cp)) @@ -256,7 +270,8 @@ class x3d_class: def writeSpotLight(self, ob, mtx, lamp, world): safeName = self.cleanStr(ob.name) if world: - ambi = world.amb + ambi = world.ambient_color + # ambi = world.amb ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 else: ambi = 0 @@ -264,7 +279,8 @@ class x3d_class: # compute cutoff and beamwidth intensity=min(lamp.energy/1.75,1.0) - beamWidth=((lamp.spotSize*math.pi)/180.0)*.37; + beamWidth=((lamp.spot_size*math.pi)/180.0)*.37; + # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37; cutOffAngle=beamWidth*1.3 dx,dy,dz=self.computeDirection(mtx) @@ -275,12 +291,14 @@ class x3d_class: #location=(ob.matrixWorld*MATWORLD).translationPart() # now passed location=(mtx*MATWORLD).translationPart() - radius = lamp.dist*math.cos(beamWidth) + radius = lamp.distance*math.cos(beamWidth) + # radius = lamp.dist*math.cos(beamWidth) self.file.write("\n\n" % (round(dx,4),round(dy,4),round(dz,4))) def writePointLight(self, ob, mtx, lamp, world): safeName = self.cleanStr(ob.name) if world: - ambi = world.amb + ambi = world.ambient_color + # ambi = world.amb ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 else: ambi = 0 @@ -318,9 +339,11 @@ class x3d_class: self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) ''' def writeNode(self, ob, mtx): @@ -362,24 +385,41 @@ class x3d_class: vColors={} # 'multi':1 meshName = self.cleanStr(ob.name) - meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not + meshME = self.cleanStr(ob.data.name) # We dont care if its the mesh name or not + # meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not if len(mesh.faces) == 0: return - mode = 0 - if mesh.faceUV: - for face in mesh.faces: - mode |= face.mode + mode = [] + # mode = 0 + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + if face.halo and 'HALO' not in mode: + mode += ['HALO'] + if face.billboard and 'BILLBOARD' not in mode: + mode += ['BILLBOARD'] + if face.object_color and 'OBJECT_COLOR' not in mode: + mode += ['OBJECT_COLOR'] + if face.collision and 'COLLISION' not in mode: + mode += ['COLLISION'] + # mode |= face.mode - if mode & Mesh.FaceModes.HALO and self.halonode == 0: + if 'HALO' in mode and self.halonode == 0: + # if mode & Mesh.FaceModes.HALO and self.halonode == 0: self.writeIndented("\n",1) self.halonode = 1 - elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: + elif 'BILLBOARD' in mode and self.billnode == 0: + # elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: self.writeIndented("\n",1) self.billnode = 1 - elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0: + elif 'OBJECT_COLOR' in mode and self.matonly == 0: + # elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0: self.matonly = 1 - elif mode & Mesh.FaceModes.TILES and self.tilenode == 0: - self.tilenode = 1 - elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0: + # TF_TILES is marked as deprecated in DNA_meshdata_types.h + # elif mode & Mesh.FaceModes.TILES and self.tilenode == 0: + # self.tilenode = 1 + elif 'COLLISION' not in mode and self.collnode == 0: + # elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0: self.writeIndented("\n",1) self.collnode = 1 @@ -401,34 +441,44 @@ class x3d_class: quat = mtx.toQuat() rot= quat.axis - # self.writeIndented('\n' % (rot[0], rot[1], rot[2], rot[3])) self.writeIndented('\n' % \ - (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) ) + (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle) ) + # self.writeIndented('\n' % \ + # (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) ) self.writeIndented("\n",1) maters=mesh.materials hasImageTexture=0 issmooth=0 - if len(maters) > 0 or mesh.faceUV: + if len(maters) > 0 or mesh.active_uv_texture: + # if len(maters) > 0 or mesh.faceUV: self.writeIndented("\n", 1) # right now this script can only handle a single material per mesh. if len(maters) >= 1: mat=maters[0] - matFlags = mat.getMode() - if not matFlags & Blender.Material.Modes['TEXFACE']: - self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) + # matFlags = mat.getMode() + if not mat.face_texture: + # if not matFlags & Blender.Material.Modes['TEXFACE']: + self.writeMaterial(mat, self.cleanStr(mat.name,''), world) + # self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) if len(maters) > 1: print("Warning: mesh named %s has multiple materials" % meshName) print("Warning: only one material per object handled") #-- textures - if mesh.faceUV: - for face in mesh.faces: - if (hasImageTexture == 0) and (face.image): + face = None + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + if face.image: + # if (hasImageTexture == 0) and (face.image): self.writeImageTexture(face.image) - hasImageTexture=1 # keep track of face texture - if self.tilenode == 1: + # hasImageTexture=1 # keep track of face texture + break + if self.tilenode == 1 and face and face.image: + # if self.tilenode == 1: self.writeIndented("\n" % (face.image.xrep, face.image.yrep)) self.tilenode = 0 self.writeIndented("\n", -1) @@ -458,11 +508,13 @@ class x3d_class: issmooth=1 break if issmooth==1: - creaseAngle=(mesh.degr)*(math.pi/180.0) + creaseAngle=(mesh.autosmooth_angle)*(math.pi/180.0) + # creaseAngle=(mesh.degr)*(math.pi/180.0) self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) #--- output textureCoordinates if UV texture used - if mesh.faceUV: + if mesh.active_uv_texture: + # if mesh.faceUV: if self.matonly == 1 and self.share == 1: self.writeFaceColors(mesh) elif hasImageTexture == 1: @@ -476,7 +528,8 @@ class x3d_class: self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) #--- output textureCoordinates if UV texture used - if mesh.faceUV: + if mesh.active_uv_texture: + # if mesh.faceUV: if hasImageTexture == 1: self.writeTextureCoordinates(mesh) elif self.matonly == 1 and self.share == 1: @@ -516,16 +569,22 @@ class x3d_class: if self.writingcoords == 0: self.file.write('coordIndex="') for face in mesh.faces: - fv = face.v + fv = face.verts + # fv = face.v - if len(face)==3: - self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + if len(fv)==3: + # if len(face)==3: + self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) else: if EXPORT_TRI: - self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) - self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index)) + self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + self.file.write("%i %i %i -1, " % (fv[0], fv[2], fv[3])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index)) else: - self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index)) + self.file.write("%i %i %i %i -1, " % (fv[0], fv[1], fv[2], fv[3])) + # self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index)) self.file.write("\">\n") else: @@ -543,8 +602,12 @@ class x3d_class: texIndexList=[] j=0 - for face in mesh.faces: - for uv in face.uv: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.verts[3] else [face.uv1, face.uv2, face.uv3] + + for uv in uvs: + # for uv in face.uv: texIndexList.append(j) texCoordList.append(uv) j=j+1 @@ -568,15 +631,24 @@ class x3d_class: def writeFaceColors(self, mesh): if self.writingcolor == 0: self.file.write("colorPerVertex=\"false\" ") - else: + elif mesh.active_vertex_color: + # else: self.writeIndented(" 2: - print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) - aColor = self.rgbToFS(c) - self.file.write("%s, " % aColor) + for face in mesh.active_vertex_color.data: + c = face.color1 + if self.verbose > 2: + print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2])) + # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) + aColor = self.rgbToFS(c) + self.file.write("%s, " % aColor) + + # for face in mesh.faces: + # if face.col: + # c=face.col[0] + # if self.verbose > 2: + # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) + # aColor = self.rgbToFS(c) + # self.file.write("%s, " % aColor) self.file.write("\" />") self.writeIndented("\n",-1) @@ -589,22 +661,31 @@ class x3d_class: self.matNames[matName]=1 - ambient = mat.amb/3 - diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] + ambient = mat.ambient/3 + # ambient = mat.amb/3 + diffuseR, diffuseG, diffuseB = tuple(mat.diffuse_color) + # diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] if world: - ambi = world.getAmb() - ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2 + ambi = world.ambient_color + # ambi = world.getAmb() + ambi0, ambi1, ambi2 = (ambi[0]*mat.ambient)*2, (ambi[1]*mat.ambient)*2, (ambi[2]*mat.ambient)*2 + # ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2 else: ambi0, ambi1, ambi2 = 0, 0, 0 emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2 - shininess = mat.hard/512.0 - specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001)) - specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001)) - specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001)) + shininess = mat.specular_hardness/512.0 + # shininess = mat.hard/512.0 + specR = (mat.specular_color[0]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001)) + specG = (mat.specular_color[1]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001)) + specB = (mat.specular_color[2]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001)) transp = 1-mat.alpha - matFlags = mat.getMode() - if matFlags & Blender.Material.Modes['SHADELESS']: + # matFlags = mat.getMode() + if mat.shadeless: + # if matFlags & Blender.Material.Modes['SHADELESS']: ambient = 1 shine = 1 specR = emitR = diffuseR @@ -635,10 +716,13 @@ class x3d_class: def writeBackground(self, world, alltextures): if world: worldname = world.name else: return - blending = world.getSkytype() - grd = world.getHor() + blending = (world.blend_sky, world.paper_sky, world.real_sky) + # blending = world.getSkytype() + grd = world.horizon_color + # grd = world.getHor() grd0, grd1, grd2 = grd[0], grd[1], grd[2] - sky = world.getZen() + sky = world.zenith_color + # sky = world.getZen() sky0, sky1, sky2 = sky[0], sky[1], sky[2] mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2] mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2 @@ -646,27 +730,32 @@ class x3d_class: if worldname not in self.namesStandard: self.file.write("DEF=\"%s\" " % self.secureName(worldname)) # No Skytype - just Hor color - if blending == 0: + if blending == (0, 0, 0): + # if blending == 0: self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.file.write("skyColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) # Blend Gradient - elif blending == 1: + elif blending == (1, 0, 0): + # elif blending == 1: self.file.write("groundColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp))) self.file.write("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp))) # Blend+Real Gradient Inverse - elif blending == 3: + elif blending == (1, 0, 1): + # elif blending == 3: self.file.write("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp))) self.file.write("skyColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp))) # Paper - just Zen Color - elif blending == 4: + elif blending == (0, 0, 1): + # elif blending == 4: self.file.write("groundColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) # Blend+Real+Paper - komplex gradient - elif blending == 7: + elif blending == (1, 1, 1): + # elif blending == 7: self.writeIndented("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) self.writeIndented("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.writeIndented("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) @@ -675,22 +764,43 @@ class x3d_class: else: self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp))) + alltexture = len(alltextures) + for i in range(alltexture): - namemat = alltextures[i].name - pic = alltextures[i].getImage() + tex = alltextures[i] + + if tex.type != 'IMAGE': + continue + + namemat = tex.name + # namemat = alltextures[i].name + + pic = tex.image + + # using .expandpath just in case, os.path may not expect // + basename = os.path.basename(bpy.sys.expandpath(pic.filename)) + + pic = alltextures[i].image + # pic = alltextures[i].getImage() if (namemat == "back") and (pic != None): - self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.file.write("\n\tbackUrl=\"%s\" " % basename) + # self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) elif (namemat == "bottom") and (pic != None): - self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.writeIndented("bottomUrl=\"%s\" " % basename) + # self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) elif (namemat == "front") and (pic != None): - self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.writeIndented("frontUrl=\"%s\" " % basename) + # self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) elif (namemat == "left") and (pic != None): - self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.writeIndented("leftUrl=\"%s\" " % basename) + # self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) elif (namemat == "right") and (pic != None): - self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.writeIndented("rightUrl=\"%s\" " % basename) + # self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) elif (namemat == "top") and (pic != None): - self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) + self.writeIndented("topUrl=\"%s\" " % basename) + # self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1]) self.writeIndented("/>\n\n") ########################################################## @@ -711,44 +821,65 @@ class x3d_class: self.proto = 0 - # COPIED FROM OBJ EXPORTER - if EXPORT_APPLY_MODIFIERS: - temp_mesh_name = '~tmp-mesh' + # # COPIED FROM OBJ EXPORTER + # if EXPORT_APPLY_MODIFIERS: + # temp_mesh_name = '~tmp-mesh' - # Get the container mesh. - used for applying modifiers and non mesh objects. - containerMesh = meshName = tempMesh = None - for meshName in Blender.NMesh.GetNames(): - if meshName.startswith(temp_mesh_name): - tempMesh = Mesh.Get(meshName) - if not tempMesh.users: - containerMesh = tempMesh - if not containerMesh: - containerMesh = Mesh.New(temp_mesh_name) + # # Get the container mesh. - used for applying modifiers and non mesh objects. + # containerMesh = meshName = tempMesh = None + # for meshName in Blender.NMesh.GetNames(): + # if meshName.startswith(temp_mesh_name): + # tempMesh = Mesh.Get(meshName) + # if not tempMesh.users: + # containerMesh = tempMesh + # if not containerMesh: + # containerMesh = Mesh.New(temp_mesh_name) # -------------------------- - for ob_main in scene.objects.context: - for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + for ob_main in [o for o in scene.objects if o.is_visible()]: + # for ob_main in scene.objects.context: + + free, derived = create_derived_objects(ob_main) + + if derived == None: continue + + for ob, ob_mat in derived: + # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): objType=ob.type objName=ob.name self.matonly = 0 - if objType == "Camera": + if objType == "CAMERA": + # if objType == "Camera": self.writeViewpoint(ob, ob_mat, scene) - elif objType in ("Mesh", "Curve", "Surf", "Text") : - if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': - me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) + elif objType in ("MESH", "CURVE", "SURF", "TEXT") : + # elif objType in ("Mesh", "Curve", "Surf", "Text") : + if EXPORT_APPLY_MODIFIERS or objType != 'MESH': + # if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': + me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') + # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) else: - me = ob.getData(mesh=1) + me = ob.data + # me = ob.getData(mesh=1) self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI) - elif objType == "Lamp": + + # free mesh created with create_mesh() + if me != ob.data: + bpy.data.remove_mesh(me) + + elif objType == "LAMP": + # elif objType == "Lamp": data= ob.data datatype=data.type - if datatype == Lamp.Types.Lamp: + if datatype == 'POINT': + # if datatype == Lamp.Types.Lamp: self.writePointLight(ob, ob_mat, data, world) - elif datatype == Lamp.Types.Spot: + elif datatype == 'SPOT': + # elif datatype == Lamp.Types.Spot: self.writeSpotLight(ob, ob_mat, data, world) - elif datatype == Lamp.Types.Sun: + elif datatype == 'SUN': + # elif datatype == Lamp.Types.Sun: self.writeDirectionalLight(ob, ob_mat, data, world) else: self.writeDirectionalLight(ob, ob_mat, data, world) @@ -758,12 +889,15 @@ class x3d_class: else: #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) pass - + + if free: + free_derived_objects(ob_main) + self.file.write("\n\n") - if EXPORT_APPLY_MODIFIERS: - if containerMesh: - containerMesh.verts = None + # if EXPORT_APPLY_MODIFIERS: + # if containerMesh: + # containerMesh.verts = None self.cleanup() @@ -812,10 +946,13 @@ class x3d_class: faceMap={} nFaceIndx=0 - if mesh.faceUV: - for face in mesh.faces: + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: sidename=''; - if face.mode & Mesh.FaceModes.TWOSIDE: + if face.twoside: + # if face.mode & Mesh.FaceModes.TWOSIDE: sidename='two' else: sidename='one' @@ -859,31 +996,38 @@ class x3d_class: print("Debug: face.image=%s" % face.image.name) print("Debug: face.materialIndex=%d" % face.materialIndex) - def getVertexColorByIndx(self, mesh, indx): - c = None - for face in mesh.faces: - j=0 - for vertex in face.v: - if vertex.index == indx: - c=face.col[j] - break - j=j+1 - if c: break - return c + # XXX not used + # def getVertexColorByIndx(self, mesh, indx): + # c = None + # for face in mesh.faces: + # j=0 + # for vertex in face.v: + # if vertex.index == indx: + # c=face.col[j] + # break + # j=j+1 + # if c: break + # return c def meshToString(self,mesh): - print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors) - print("Debug: mesh.faceUV=%d" % mesh.faceUV) - print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()) + # print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors) + print("Debug: mesh.faceUV=%d" % (len(mesh.uv_textures) > 0)) + # print("Debug: mesh.faceUV=%d" % mesh.faceUV) + print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0)) + # print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()) print("Debug: mesh.verts=%d" % len(mesh.verts)) print("Debug: mesh.faces=%d" % len(mesh.faces)) print("Debug: mesh.materials=%d" % len(mesh.materials)) def rgbToFS(self, c): - s="%s %s %s" % ( - round(c.r/255.0,self.cp), - round(c.g/255.0,self.cp), - round(c.b/255.0,self.cp)) + s="%s %s %s" % (round(c[0]/255.0,self.cp), + round(c[1]/255.0,self.cp), + round(c[2]/255.0,self.cp)) + + # s="%s %s %s" % ( + # round(c.r/255.0,self.cp), + # round(c.g/255.0,self.cp), + # round(c.b/255.0,self.cp)) return s def computeDirection(self, mtx): @@ -891,9 +1035,10 @@ class x3d_class: ax,ay,az = (mtx*MATWORLD).toEuler() - ax *= DEG2RAD - ay *= DEG2RAD - az *= DEG2RAD + # ax *= DEG2RAD + # ay *= DEG2RAD + # az *= DEG2RAD + # rot X x1=x y1=y*math.cos(ax)-z*math.sin(ax) @@ -980,11 +1125,11 @@ class x3d_class: # Callbacks, needed before Main ########################################################## -def x3d_export(filename, \ - EXPORT_APPLY_MODIFIERS= False,\ - EXPORT_TRI= False,\ - EXPORT_GZIP= False,\ - ): +def x3d_export(filename, + context, + EXPORT_APPLY_MODIFIERS=False, + EXPORT_TRI=False, + EXPORT_GZIP=False): if EXPORT_GZIP: if not filename.lower().endswith('.x3dz'): @@ -994,9 +1139,13 @@ def x3d_export(filename, \ filename = '.'.join(filename.split('.')[:-1]) + '.x3d' - scene = Blender.Scene.GetCurrent() + scene = context.scene + # scene = Blender.Scene.GetCurrent() world = scene.world - alltextures = Blender.Texture.Get() + + # XXX these are global textures while .Get() returned only scene's? + alltextures = bpy.data.textures + # alltextures = Blender.Texture.Get() wrlexport=x3d_class(filename) wrlexport.export(\ @@ -1064,11 +1213,15 @@ class EXPORT_OT_x3d(bpy.types.Operator): # 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 X3D file", maxlen= 1024, default= ""), + bpy.props.StringProperty(attr="filename", name="File Name", description="File name used for exporting the X3D file", maxlen=1024, default=""), + + bpy.props.BoolProperty(attr="apply_modifiers", name="Apply Modifiers", description="Use transformed mesh data from each object.", default=True), + bpy.props.BoolProperty(attr="triangulate", name="Triangulate", description="Triangulate quads.", default=False), + bpy.props.BoolProperty(attr="compress", name="Compress", description="GZip the resulting file, requires a full python install.", default=False), ] def execute(self, context): - raise Exception("Not doing anything yet.") + x3d_export(self.filename, context, self.apply_modifiers, self.triangulate, self.compress) return ('FINISHED',) def invoke(self, context, event): @@ -1081,3 +1234,6 @@ class EXPORT_OT_x3d(bpy.types.Operator): return context.active_object != None bpy.ops.add(EXPORT_OT_x3d) + +# NOTES +# - blender version is hardcoded -- cgit v1.2.3 From 7220792f187f91a2ef3eb0c930a13674b2a8a80a Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Wed, 19 Aug 2009 09:52:13 +0000 Subject: Various fixes in rna_*_api.c files to remove compiler warnings. --- source/blender/editors/include/ED_mesh.h | 1 + source/blender/editors/mesh/editmesh_mods.c | 5 + source/blender/makesrna/intern/rna_action_api.c | 2 + source/blender/makesrna/intern/rna_image_api.c | 2 + source/blender/makesrna/intern/rna_internal.h | 6 +- source/blender/makesrna/intern/rna_mesh_api.c | 3 + source/blender/makesrna/intern/rna_object_api.c | 2 +- source/blender/makesrna/intern/rna_pose_api.c | 4 +- source/blender/makesrna/intern/rna_scene_api.c | 4 + source/blender/python/SConscript | 2 +- source/creator/creator.c | 4 + source/creator/tests/alltest.c | 176 ------------------------ source/creator/tests/test.c | 176 ++++++++++++++++++++++++ source/creator/tests/test.h | 6 + 14 files changed, 211 insertions(+), 182 deletions(-) delete mode 100644 source/creator/tests/alltest.c create mode 100644 source/creator/tests/test.c create mode 100644 source/creator/tests/test.h diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index cceebeadc96..696e8f823eb 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -118,6 +118,7 @@ void EM_select_face(struct EditFace *efa, int sel); void EM_select_face_fgon(struct EditMesh *em, struct EditFace *efa, int val); void EM_select_swap(struct EditMesh *em); void EM_toggle_select_all(struct EditMesh *em); +void EM_select_all(struct EditMesh *em); void EM_selectmode_flush(struct EditMesh *em); void EM_deselect_flush(struct EditMesh *em); void EM_selectmode_set(struct EditMesh *em); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index d27aa3f7e3a..363b6ecc4e4 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -3288,6 +3288,11 @@ void EM_toggle_select_all(EditMesh *em) /* exported for UV */ EM_set_flag_all(em, SELECT); } +void EM_select_all(EditMesh *em) +{ + EM_set_flag_all(em, SELECT); +} + static int toggle_select_all_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c index 2b51a424fcf..11efa6d5f8a 100644 --- a/source/blender/makesrna/intern/rna_action_api.c +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -36,6 +36,8 @@ #ifdef RNA_RUNTIME +#include "BKE_action.h" + #include "DNA_anim_types.h" #include "DNA_curve_types.h" diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index ccc9846600d..fee379cd285 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -41,6 +41,8 @@ #include "BKE_utildefines.h" #include "BKE_image.h" +#include "MEM_guardedalloc.h" + /* User should check if returned path exists before copying a file there. diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index cff77fbb34b..af94f0ccc6f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -197,13 +197,15 @@ void rna_Object_update_data(struct bContext *C, struct PointerRNA *ptr); /* API functions */ +void RNA_api_action(StructRNA *srna); +void RNA_api_image(struct StructRNA *srna); void RNA_api_main(struct StructRNA *srna); +void RNA_api_material(StructRNA *srna); void RNA_api_mesh(struct StructRNA *srna); void RNA_api_object(struct StructRNA *srna); +void RNA_api_scene(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); -void RNA_api_material(StructRNA *srna); /* ID Properties */ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 9d4dad1fb5b..1db2f155d14 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -42,6 +42,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_material.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" @@ -52,6 +53,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "MEM_guardedalloc.h" + static void rna_Mesh_calc_edges(Mesh *mesh) { CustomData edata; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index f0a42987848..3c79c1cbc21 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -273,7 +273,7 @@ static void rna_Object_convert_to_triface(Object *ob, bContext *C, ReportList *r make_editMesh(sce, ob); /* select all */ - EM_set_flag_all(me->edit_mesh, SELECT); + EM_select_all(me->edit_mesh); convert_to_triface(me->edit_mesh, 0); diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 9ac7713b2e9..42bb52d8544 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -45,8 +45,8 @@ void RNA_api_pose(StructRNA *srna) { - FunctionRNA *func; - PropertyRNA *parm; + /* FunctionRNA *func; */ + /* PropertyRNA *parm; */ } diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index f3cbb630df5..076fe38ed2f 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -38,8 +38,12 @@ #ifdef RNA_RUNTIME #include "BKE_scene.h" +#include "BKE_depsgraph.h" + #include "ED_object.h" +#include "WM_api.h" + static void rna_Scene_add_object(Scene *sce, ReportList *reports, Object *ob) { Base *base= object_in_scene(ob, sce); diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 357d2c99d3b..d44cf762a0f 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('intern/*.c') -incs = '. ../editors/include ../makesdna ../makesrna ../makesrna/intern ../blenlib ../blenkernel ../nodes' +incs = '. ../editors/include ../makesdna ../makesrna ../blenlib ../blenkernel ../nodes' incs += ' ../imbuf ../blenloader ../render/extern/include ../windowmanager' incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include' incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/creator/creator.c b/source/creator/creator.c index e196213c945..6ecde9e5546 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -97,6 +97,10 @@ #include "binreloc.h" #endif +#ifdef WITH_UNIT_TEST +#include "tests/test.h" +#endif + // from buildinfo.c #ifdef BUILD_DATE extern char * build_date; diff --git a/source/creator/tests/alltest.c b/source/creator/tests/alltest.c deleted file mode 100644 index 89a58a08dfd..00000000000 --- a/source/creator/tests/alltest.c +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include -#include - -#include "MEM_guardedalloc.h" - -#include "BKE_blender.h" -#include "BKE_image.h" -#include "BKE_utildefines.h" -#include "BKE_global.h" - -#include "BLI_listbase.h" -#include "BLI_util.h" -#include "BLI_fileops.h" -#include "BLI_string.h" - -#include "DNA_image_types.h" - -char bprogname[FILE_MAXDIR+FILE_MAXFILE]; -char btempdir[FILE_MAXDIR+FILE_MAXFILE]; - -typedef struct ImageTestResult { - char *path; - char *rel; - int ret; -} ImageTestResult; - -typedef struct ImageTestData { - char *path; /* image filename */ - ImageTestResult result[10]; -} ImageTestData; - -/* check that BKE_copy_images manipulates paths correctly */ -START_TEST(test_copy_images) -{ - char **dir; - ImageTestData *test; - int i,j; - -#ifdef WIN32 - /* TBD... */ -#else - /* - XXX are these paths possible in image->name?: - - ./foo/image.png - ../foo/image.png - - if so, BKE_copy_images currently doesn't support them! - */ - - const char *blend_dir = "/home/user/foo"; - char *dest_dir[] = {"/home/user/", "/home/user", "/home/user/export/", "/home/user/foo/", NULL}; - - static ImageTestData test_data[] = { - - /* image path | [expected output path | corresponding relative path | expected return value] */ - - /* relative, 0 level deep */ - {"//image.png", {{"/home/user/image.png", "image.png", 1}, - {"/home/user/image.png", "image.png", 1}, - {"/home/user/export/image.png", "image.png", 1}, - {"/home/user/foo/image.png", "image.png", 2},}}, - - /* relative, 1 level deep */ - {"//bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, - {"/home/user/bar/image.png", "bar/image.png", 1}, - {"/home/user/export/bar/image.png", "bar/image.png", 1}, - {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, - - /* relative, 2 level deep */ - {"//bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, - - /* absolute, not under .blend dir */ - {"/home/user/bar/image.png", {{"/home/user/image.png", "image.png", 1}, - {"/home/user/image.png", "image.png", 1}, - {"/home/user/export/image.png", "image.png", 1}, - {"/home/user/foo/image.png", "image.png", 1},}}, - - /* absolute, under .blend dir, 0 level deep */ - {"/home/user/foo/image.png", {{"/home/user/image.png", "image.png", 1}, - {"/home/user/image.png", "image.png", 1}, - {"/home/user/export/image.png", "image.png", 1}, - {"/home/user/foo/image.png", "image.png", 2},}}, - - /* absolute, under .blend dir, 1 level deep */ - {"/home/user/foo/bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, - {"/home/user/bar/image.png", "bar/image.png", 1}, - {"/home/user/export/bar/image.png", "bar/image.png", 1}, - {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, - - /* absolute, under .blend dir, 2 level deep */ - {"/home/user/foo/bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, - {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, - - /* empty image path, don't let these pass! */ - {"", {{"", 0}, - {"", 0}, - {"", 0}}}, - - {NULL}, - }; - - /* substitute G.sce */ - BLI_snprintf(G.sce, sizeof(G.sce), "%s/untitled.blend", blend_dir); -#endif - - for (dir= dest_dir, i= 0; *dir; dir++, i++) { - for (test= &test_data[0]; test->path; test++) { - Image image; - char path[FILE_MAX]; - char rel[FILE_MAX]; - char part[200]; - int ret; - - BLI_strncpy(image.name, test->path, sizeof(image.name)); - - /* passing NULL as abs path or rel path or both shouldn't break it */ - int abs_rel_null[][2]= {{0, 0}, {1, 0}, {0, 1}, {1, 1}, {-1}}; - - for (j= 0; abs_rel_null[j][0] != -1; j++) { - - int *is_null= abs_rel_null[j]; - - ret= BKE_get_image_export_path(&image, *dir, - is_null[0] ? NULL : path, sizeof(path), - is_null[1] ? NULL : rel, sizeof(rel)); - - BLI_snprintf(part, sizeof(part), "For image at %s (output abs path is %s, rel path is %s)", - test->path, is_null[0] ? "NULL" : "non-NULL", is_null[1] ? "NULL" : "non-NULL"); - - /* we should get what we expect */ - ImageTestResult *res= &test->result[i]; - fail_if(ret != res->ret, "%s, expected to return %d got %d.", part, res->ret, ret); - - if (!is_null[0] && res->path) - fail_if(strcmp(path, res->path), "%s, expected absolute path \"%s\" got \"%s\".", part, res->path, path); - if (!is_null[1] && res->rel) - fail_if(strcmp(rel, res->rel), "%s, expected relative path \"%s\" got \"%s\".", part, res->rel, rel); - } - } - } -} -END_TEST - -static Suite *image_suite(void) -{ - Suite *s= suite_create("Image"); - - /* Core test case */ - TCase *tc_core= tcase_create("Core"); - tcase_add_test(tc_core, test_copy_images); - suite_add_tcase(s, tc_core); - - return s; -} - -int run_tests() -{ - int totfail; - Suite *s= image_suite(); - SRunner *sr= srunner_create(s); - - /* run tests */ - srunner_run_all(sr, CK_VERBOSE); - - totfail= srunner_ntests_failed(sr); - srunner_free(sr); - - return !totfail ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/source/creator/tests/test.c b/source/creator/tests/test.c new file mode 100644 index 00000000000..89a58a08dfd --- /dev/null +++ b/source/creator/tests/test.c @@ -0,0 +1,176 @@ +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BKE_blender.h" +#include "BKE_image.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" + +#include "BLI_listbase.h" +#include "BLI_util.h" +#include "BLI_fileops.h" +#include "BLI_string.h" + +#include "DNA_image_types.h" + +char bprogname[FILE_MAXDIR+FILE_MAXFILE]; +char btempdir[FILE_MAXDIR+FILE_MAXFILE]; + +typedef struct ImageTestResult { + char *path; + char *rel; + int ret; +} ImageTestResult; + +typedef struct ImageTestData { + char *path; /* image filename */ + ImageTestResult result[10]; +} ImageTestData; + +/* check that BKE_copy_images manipulates paths correctly */ +START_TEST(test_copy_images) +{ + char **dir; + ImageTestData *test; + int i,j; + +#ifdef WIN32 + /* TBD... */ +#else + /* + XXX are these paths possible in image->name?: + + ./foo/image.png + ../foo/image.png + + if so, BKE_copy_images currently doesn't support them! + */ + + const char *blend_dir = "/home/user/foo"; + char *dest_dir[] = {"/home/user/", "/home/user", "/home/user/export/", "/home/user/foo/", NULL}; + + static ImageTestData test_data[] = { + + /* image path | [expected output path | corresponding relative path | expected return value] */ + + /* relative, 0 level deep */ + {"//image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"/home/user/foo/image.png", "image.png", 2},}}, + + /* relative, 1 level deep */ + {"//bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/export/bar/image.png", "bar/image.png", 1}, + {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, + + /* relative, 2 level deep */ + {"//bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, + + /* absolute, not under .blend dir */ + {"/home/user/bar/image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"/home/user/foo/image.png", "image.png", 1},}}, + + /* absolute, under .blend dir, 0 level deep */ + {"/home/user/foo/image.png", {{"/home/user/image.png", "image.png", 1}, + {"/home/user/image.png", "image.png", 1}, + {"/home/user/export/image.png", "image.png", 1}, + {"/home/user/foo/image.png", "image.png", 2},}}, + + /* absolute, under .blend dir, 1 level deep */ + {"/home/user/foo/bar/image.png", {{"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/bar/image.png", "bar/image.png", 1}, + {"/home/user/export/bar/image.png", "bar/image.png", 1}, + {"/home/user/foo/bar/image.png", "bar/image.png", 2},}}, + + /* absolute, under .blend dir, 2 level deep */ + {"/home/user/foo/bar/foo/image.png", {{"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/export/bar/foo/image.png", "bar/foo/image.png", 1}, + {"/home/user/foo/bar/foo/image.png", "bar/foo/image.png", 2},}}, + + /* empty image path, don't let these pass! */ + {"", {{"", 0}, + {"", 0}, + {"", 0}}}, + + {NULL}, + }; + + /* substitute G.sce */ + BLI_snprintf(G.sce, sizeof(G.sce), "%s/untitled.blend", blend_dir); +#endif + + for (dir= dest_dir, i= 0; *dir; dir++, i++) { + for (test= &test_data[0]; test->path; test++) { + Image image; + char path[FILE_MAX]; + char rel[FILE_MAX]; + char part[200]; + int ret; + + BLI_strncpy(image.name, test->path, sizeof(image.name)); + + /* passing NULL as abs path or rel path or both shouldn't break it */ + int abs_rel_null[][2]= {{0, 0}, {1, 0}, {0, 1}, {1, 1}, {-1}}; + + for (j= 0; abs_rel_null[j][0] != -1; j++) { + + int *is_null= abs_rel_null[j]; + + ret= BKE_get_image_export_path(&image, *dir, + is_null[0] ? NULL : path, sizeof(path), + is_null[1] ? NULL : rel, sizeof(rel)); + + BLI_snprintf(part, sizeof(part), "For image at %s (output abs path is %s, rel path is %s)", + test->path, is_null[0] ? "NULL" : "non-NULL", is_null[1] ? "NULL" : "non-NULL"); + + /* we should get what we expect */ + ImageTestResult *res= &test->result[i]; + fail_if(ret != res->ret, "%s, expected to return %d got %d.", part, res->ret, ret); + + if (!is_null[0] && res->path) + fail_if(strcmp(path, res->path), "%s, expected absolute path \"%s\" got \"%s\".", part, res->path, path); + if (!is_null[1] && res->rel) + fail_if(strcmp(rel, res->rel), "%s, expected relative path \"%s\" got \"%s\".", part, res->rel, rel); + } + } + } +} +END_TEST + +static Suite *image_suite(void) +{ + Suite *s= suite_create("Image"); + + /* Core test case */ + TCase *tc_core= tcase_create("Core"); + tcase_add_test(tc_core, test_copy_images); + suite_add_tcase(s, tc_core); + + return s; +} + +int run_tests() +{ + int totfail; + Suite *s= image_suite(); + SRunner *sr= srunner_create(s); + + /* run tests */ + srunner_run_all(sr, CK_VERBOSE); + + totfail= srunner_ntests_failed(sr); + srunner_free(sr); + + return !totfail ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/source/creator/tests/test.h b/source/creator/tests/test.h new file mode 100644 index 00000000000..37bdab301fc --- /dev/null +++ b/source/creator/tests/test.h @@ -0,0 +1,6 @@ +#ifndef _BF_UNIT_TEST +#define _BF_UNIT_TEST + +int run_tests(); + +#endif /* _BF_UNIT_TEST */ -- cgit v1.2.3 From ce70ed260b45c48ee43e5f13b372cc0d68f76be4 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 10:21:41 +0000 Subject: Smoke: * Bugifx for no shadow on startframe when loaded from cache --- source/blender/blenkernel/intern/smoke.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 67744ab56a2..6485e367b78 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1179,6 +1179,11 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM // simulate the actual smoke (c++ code in intern/smoke) if(framenr!=startframe) smoke_step(sds->fluid, smd->time); + + // create shadows before writing cache so we get nice shadows for sstartframe, too + if(get_lamp(scene, light)) + smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx); + BKE_ptcache_write_cache(&pid, framenr); if(sds->wt) @@ -1191,9 +1196,6 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM BKE_ptcache_write_cache(&pid_wt, framenr); } - if(get_lamp(scene, light)) - smoke_calc_transparency(sds->shadow, smoke_get_density(sds->fluid), sds->p0, sds->p1, sds->res, sds->dx, light, calc_voxel_transp, -7.0*sds->dx); - tend(); printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); } -- cgit v1.2.3 From b0a3224d898fdf58afe6c548dd53307172126856 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 10:37:13 +0000 Subject: Smoke: * put another drawing method in to test for broken --- source/blender/editors/space_view3d/drawobject.c | 47 +++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c02d45ca798..2c4d72f64ab 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5360,12 +5360,57 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) { if(!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { +// #if0 smd->domain->tex = NULL; GPU_create_smoke(smd, 0); draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->p0, smd->domain->p1, smd->domain->res, smd->domain->dx, smd->domain->tex_shadow); GPU_free_smoke(smd); +// #endif +#if 0 + int x, y, z; + float *density = smoke_get_density(smd->domain->fluid); + + wmLoadMatrix(rv3d->viewmat); + // wmMultMatrix(ob->obmat); + + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + + + // glPointSize(3.0); + bglBegin(GL_POINTS); + + for(x = 0; x < smd->domain->res[0]; x++) + for(y = 0; y < smd->domain->res[1]; y++) + for(z = 0; z < smd->domain->res[2]; z++) + { + float tmp[3]; + int index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z); + + if(density[index] > FLT_EPSILON) + { + float color[3]; + VECCOPY(tmp, smd->domain->p0); + tmp[0] += smd->domain->dx * x + smd->domain->dx * 0.5; + tmp[1] += smd->domain->dx * y + smd->domain->dx * 0.5; + tmp[2] += smd->domain->dx * z + smd->domain->dx * 0.5; + color[0] = color[1] = color[2] = 1.0; // density[index]; + glColor3fv(color); + bglVertex3fv(tmp); + } + } + + bglEnd(); + glPointSize(1.0); + + wmMultMatrix(ob->obmat); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + if(col) cpack(col); +#endif } - else if(smd->domain->wt || (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) + else if(smd->domain->wt && (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { smd->domain->tex = NULL; GPU_create_smoke(smd, 1); -- cgit v1.2.3 From f896b905ace685148dccad9ddfbda92ae1c65d85 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 14 Sep 2009 10:56:40 +0000 Subject: Bugfixes: * #19338: Crash when using Convert operator Uninitialised var (basact) * Spacebar when in 3D-View EditMode for Text gets overridden by Search Menu. I've tried adding a fix there, but it doesn't seem to work. Woraround for now is shift-space for entering text. * Fixed some compiled warnings in wm_operators.c about naming of var named 'main' --- source/blender/editors/object/object_add.c | 2 +- source/blender/windowmanager/intern/wm_operators.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 833d3914e47..ee9af61f516 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -885,7 +885,7 @@ static int convert_poll(bContext *C) static int convert_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Base *basen=NULL, *basact, *basedel=NULL; + Base *basen=NULL, *basact=NULL, *basedel=NULL; Object *ob, *ob1, *obact= CTX_data_active_object(C); DerivedMesh *dm; Curve *cu; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b57edcb4dfc..c01ce5b6e35 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -34,6 +34,7 @@ #include #include "DNA_ID.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" @@ -751,6 +752,7 @@ int wm_search_menu_poll(bContext *C) if(CTX_wm_window(C)==NULL) return 0; if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_CONSOLE) return 0; // XXX - so we can use the shortcut in the console if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_TEXT) return 0; // XXX - so we can use the spacebar in the text editor + if(CTX_data_edit_object(C) && CTX_data_edit_object(C)->type==OB_CURVE) return 0; // XXX - so we can use the spacebar for entering text return 1; } @@ -996,11 +998,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX]; int idcode; BlendHandle *bh; - struct Main *main= CTX_data_main(C); + struct Main *mainvar= CTX_data_main(C); struct Scene *scene= CTX_data_scene(C); struct Main *mainl= 0; - struct ScrArea *sa= CTX_wm_area(C); PropertyRNA *prop; int totfiles=0; short flag; @@ -1015,7 +1016,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) } else if (group[0]==0) { BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); return OPERATOR_FINISHED; - } else if (BLI_streq(main->name, libname)) { + } else if (BLI_streq(mainvar->name, libname)) { BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library"); return OPERATOR_FINISHED; } @@ -1063,11 +1064,11 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLO_library_append_end(C, mainl, &bh, idcode, flag); /* DISPLISTS? */ - recalc_all_library_objects(main); + recalc_all_library_objects(mainvar); /* Append, rather than linking */ if ((flag & FILE_LINK)==0) { - make_library_local(libname, main); + make_library_local(libname, mainvar); } /* do we need to do this? */ -- cgit v1.2.3 From e838af4d57ea1f0eef4fd62bfb0a8d6e320c72e0 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 14 Sep 2009 11:12:44 +0000 Subject: Bugfix #19337: Crash when tweaking knife operator Knife operator now doesn't crash, but repeat operator for this won't work now since the appropriate 3D-View context info is not set when the mouse is in the Tools region (i.e. when using repeat operator in the tools panels). --- source/blender/editors/mesh/editmesh_loop.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c index c98b387d28a..28103828dd4 100644 --- a/source/blender/editors/mesh/editmesh_loop.c +++ b/source/blender/editors/mesh/editmesh_loop.c @@ -60,6 +60,7 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv #include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_object.h" +#include "BKE_report.h" #include "BKE_utildefines.h" #include "PIL_time.h" @@ -637,6 +638,10 @@ static int knife_cut_exec(bContext *C, wmOperator *op) int len=0; short numcuts=1, mode= RNA_int_get(op->ptr, "type"); + /* edit-object needed for matrix, and ar->regiondata for projections to work */ + if (ELEM3(NULL, obedit, ar, ar->regiondata)) + return OPERATOR_CANCELLED; + if (EM_nvertices_selected(em) < 2) { error("No edges are selected to operate on"); BKE_mesh_end_editmesh(obedit->data, em); -- cgit v1.2.3 From d0aa03737eff52b1c54644cb5e9d3d68daa2986c Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 14 Sep 2009 11:25:33 +0000 Subject: * Fix for typo in icon_only commit, causing RNA property buttons text to be doubled up brecht: I think this is right now...? :) --- source/blender/editors/interface/interface_layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 6211c79beca..242ba31ccd4 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -506,7 +506,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, i but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, "Browse for file or directory."); } else - but= uiDefAutoButR(block, ptr, prop, index, (icon_only)? "": NULL, icon, x, y, w, h); + but= uiDefAutoButR(block, ptr, prop, index, (!icon_only)? "": NULL, icon, x, y, w, h); uiBlockSetCurLayout(block, layout); return but; -- cgit v1.2.3 From 75d4a836b8427f1d71f41d037390352bffeafee4 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 12:16:35 +0000 Subject: UI: don't hide Object menu in 3d view header when there is no active object, to avoid buttons jumping too much. Also small change in collision panel code. --- release/ui/buttons_physics_field.py | 8 +++----- release/ui/space_view3d.py | 2 ++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/release/ui/buttons_physics_field.py b/release/ui/buttons_physics_field.py index 58033d2c431..252b3bdb08a 100644 --- a/release/ui/buttons_physics_field.py +++ b/release/ui/buttons_physics_field.py @@ -184,18 +184,16 @@ class PHYSICS_PT_collision(PhysicButtonsPanel): #row.itemR(md, "render", text="") #row.itemR(md, "realtime", text="") - coll = md.settings + settings = md.settings else: # add modifier split.item_enumO("object.modifier_add", "type", 'COLLISION', text="Add") split.itemL() - coll = None + settings = None - if coll: - settings = context.object.collision - + if settings: layout.active = settings.enabled split = layout.split() diff --git a/release/ui/space_view3d.py b/release/ui/space_view3d.py index df6579542d4..2539ded18bf 100644 --- a/release/ui/space_view3d.py +++ b/release/ui/space_view3d.py @@ -34,6 +34,8 @@ class VIEW3D_HT_header(bpy.types.Header): if mode_string not in ['PAINT_WEIGHT', 'PAINT_TEXTURE']: sub.itemM("VIEW3D_MT_%s" % mode_string) + else: + sub.itemM("VIEW3D_MT_OBJECT") layout.template_header_3D() -- cgit v1.2.3 From 8d3955c28d4f3db7026dc7f1a33a421a727f89d3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 12:26:34 +0000 Subject: Depsgraph: * Move function to compute visible screen layers to BKE. * Use this now in the depsgraph, was still using this all layers to flush. Still missing a way to get the current scene in background mode.. * Also two more function to not require a scene pointer anymore: * DAG_object_update_flags is now DAG_id_update_flags. * DAG_ids_flush_update is now available next to DAG_scene_flush_update. --- source/blender/blenkernel/BKE_depsgraph.h | 13 ++-- source/blender/blenkernel/BKE_screen.h | 6 +- source/blender/blenkernel/intern/depsgraph.c | 75 +++++++++++++++++----- source/blender/blenkernel/intern/screen.c | 21 ++++++ source/blender/editors/animation/anim_deps.c | 14 +--- .../editors/armature/editarmature_retarget.c | 2 - source/blender/editors/include/ED_screen.h | 1 - source/blender/editors/preview/previewrender.c | 3 +- source/blender/editors/screen/screen_edit.c | 19 +----- 9 files changed, 96 insertions(+), 58 deletions(-) diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index e242ead3b87..17a4749f704 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -96,19 +96,24 @@ void draw_all_deps(void); /* ********** API *************** */ /* Note that the DAG never executes changes in Objects, only sets flags in Objects */ + /* (re)-create dependency graph for scene */ void DAG_scene_sort(struct Scene *sce); /* flag all objects that need recalc because they're animated */ void DAG_scene_update_flags(struct Scene *sce, unsigned int lay); - /* flag all objects that need recalc because they're animated, influencing this object only */ -void DAG_object_update_flags(struct Scene *sce, struct Object *ob, unsigned int lay); - /* flushes all recalc flags in objects down the dependency tree */ void DAG_scene_flush_update(struct Scene *sce, unsigned int lay, int time); + + /* flag all IDs that need recalc because they're animated, influencing + this ID only. only for objects currently */ +void DAG_id_update_flags(struct ID *id); /* flushes all recalc flags for this object down the dependency tree, - but not the DAG only supports objects and object data currently */ + but note the DAG only supports objects and object data currently */ void DAG_id_flush_update(struct ID *id, short flag); + /* when setting manual RECALC flags, call this afterwards */ +void DAG_ids_flush_update(int time); + /* (re)-create dependency graph for armature pose */ void DAG_pose_sort(struct Object *ob); #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 4fcb7c881be..ee04d4f47bc 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -230,11 +230,11 @@ void BKE_spacedata_copyfirst(ListBase *lb1, ListBase *lb2); /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); +void BKE_screen_area_free(struct ScrArea *sa); -void BKE_screen_area_free(struct ScrArea *sa); - +/* screen */ void free_screen(struct bScreen *sc); - +unsigned int BKE_screen_visible_layers(struct bScreen *screen); #endif diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 6a14762e0ed..58f3db50d0f 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -78,6 +78,7 @@ #include "BKE_pointcache.h" #include "BKE_utildefines.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "MEM_guardedalloc.h" @@ -2142,30 +2143,58 @@ void DAG_scene_update_flags(Scene *scene, unsigned int lay) } -void DAG_id_flush_update(ID *id, short flag) +static void dag_current_scene_layers(Main *bmain, Scene **sce, unsigned int *lay) { - Main *bmain= G.main; wmWindowManager *wm; wmWindow *win; - Scene *sce; - Object *obt, *ob= NULL; - short idtype; /* only one scene supported currently, making more scenes work correctly requires changes beyond just the dependency graph */ + *sce= NULL; + *lay= 0; + if((wm= bmain->wm.first)) { - /* if we have a windowmanager, use sce from first window */ + /* if we have a windowmanager, look into windows */ for(win=wm->windows.first; win; win=win->next) { - sce= (win->screen)? win->screen->scene: NULL; - - if(sce) - break; + if(win->screen) { + if(!*sce) *sce= win->screen->scene; + *lay |= BKE_screen_visible_layers(win->screen); + } } } - else + else { /* if not, use the first sce */ - sce= bmain->scene.first; + *sce= bmain->scene.first; + if(*sce) *lay= (*sce)->lay; + + /* XXX for background mode, we should get the scen + from somewhere, for the -S option, but it's in + the context, how to get it here? */ + } +} + +void DAG_ids_flush_update(int time) +{ + Main *bmain= G.main; + Scene *sce; + unsigned int lay; + + dag_current_scene_layers(bmain, &sce, &lay); + + if(sce) + DAG_scene_flush_update(sce, lay, time); +} + +void DAG_id_flush_update(ID *id, short flag) +{ + Main *bmain= G.main; + Scene *sce; + Object *obt, *ob= NULL; + short idtype; + unsigned int lay; + + dag_current_scene_layers(bmain, &sce, &lay); if(!id || !sce || !sce->theDag) return; @@ -2213,10 +2242,7 @@ void DAG_id_flush_update(ID *id, short flag) } /* flush to other objects that depend on this one */ -// XXX if(G.curscreen) -// DAG_scene_flush_update(sce, dag_screen_view3d_layers(), 0); -// else - DAG_scene_flush_update(sce, sce->lay, 0); + DAG_scene_flush_update(sce, lay, 0); } /* recursively descends tree, each node only checked once */ @@ -2251,10 +2277,25 @@ static int parent_check_node(DagNode *node, int curtime) /* all nodes that influence this object get tagged, for calculating the exact position of this object at a given timeframe */ -void DAG_object_update_flags(Scene *sce, Object *ob, unsigned int lay) +void DAG_id_update_flags(ID *id) { + Main *bmain= G.main; + Scene *sce; DagNode *node; DagAdjList *itA; + Object *ob; + unsigned int lay; + + dag_current_scene_layers(bmain, &sce, &lay); + + if(!id || !sce || !sce->theDag) + return; + + /* objects only currently */ + if(GS(id->name) != ID_OB) + return; + + ob= (Object*)id; /* tag nodes unchecked */ for(node = sce->theDag->DagNode.first; node; node= node->next) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index cc740d7fb3d..661d0da1550 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -33,8 +33,10 @@ #include "MEM_guardedalloc.h" +#include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_view3d_types.h" #include "BLI_blenlib.h" @@ -321,4 +323,23 @@ void free_screen(bScreen *sc) BLI_freelistN(&sc->areabase); } +/* for depsgraph */ +unsigned int BKE_screen_visible_layers(bScreen *screen) +{ + ScrArea *sa; + unsigned int layer= 0; + + if(!screen) + return layer; + + /* get all used view3d layers */ + for(sa= screen->areabase.first; sa; sa= sa->next) + if(sa->spacetype==SPACE_VIEW3D) + layer |= ((View3D *)sa->spacedata.first)->lay; + + if(!layer) + return screen->scene->lay; + + return layer; +} diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index af2355b91a5..62341a5d6ae 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -43,6 +43,7 @@ #include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_utildefines.h" #include "RNA_access.h" @@ -57,26 +58,17 @@ /* ***************** depsgraph calls and anim updates ************* */ /* ***************** only these can be called from editors ******** */ -/* generic update flush, reads from context Screen (layers) and scene */ -/* this is for compliancy, later it can do all windows etc */ void ED_anim_dag_flush_update(const bContext *C) { - Scene *scene= CTX_data_scene(C); - bScreen *screen= CTX_wm_screen(C); - - DAG_scene_flush_update(scene, ED_screen_view3d_layers(screen), 0); + DAG_ids_flush_update(0); } /* flushes changes from object to all relations in scene */ void ED_anim_object_flush_update(const bContext *C, Object *ob) { - Scene *scene= CTX_data_scene(C); - bScreen *screen= CTX_wm_screen(C); - - DAG_object_update_flags(scene, ob, ED_screen_view3d_layers(screen)); + DAG_id_update_flags(&ob->id); } - /* **************************** pose <-> action syncing ******************************** */ /* Summary of what needs to be synced between poses and actions: * 1) Flags diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 16e78f7c8d1..4d65059c4c6 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -2716,7 +2716,6 @@ static void finishRetarget(RigGraph *rigg) static void adjustGraphs(bContext *C, RigGraph *rigg) { - Scene *scene = CTX_data_scene(C); bArmature *arm= rigg->ob->data; RigArc *arc; @@ -2739,7 +2738,6 @@ static void adjustGraphs(bContext *C, RigGraph *rigg) static void retargetGraphs(bContext *C, RigGraph *rigg) { - Scene *scene = CTX_data_scene(C); bArmature *arm= rigg->ob->data; ReebGraph *reebg = rigg->link_mesh; RigNode *inode; diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 0153b3c9bdb..697565184f3 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -104,7 +104,6 @@ void ED_screen_new_window(struct bContext *C, struct rcti *position, int type); /* anim */ void ED_update_for_newframe(const struct bContext *C, int mute); -unsigned int ED_screen_view3d_layers(struct bScreen *screen); void ED_operatortypes_screen(void); void ED_keymap_screen(struct wmWindowManager *wm); diff --git a/source/blender/editors/preview/previewrender.c b/source/blender/editors/preview/previewrender.c index 714ebcef0fb..710ac3d6553 100644 --- a/source/blender/editors/preview/previewrender.c +++ b/source/blender/editors/preview/previewrender.c @@ -88,7 +88,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "ED_anim_api.h" #include "ED_previewrender.h" #include "ED_view3d.h" @@ -736,7 +735,7 @@ void BIF_view3d_previewrender(Scene *scene, ScrArea *sa) /* database can have created render-resol data... */ if(rstats->convertdone) - ED_anim_dag_flush_update(C); // <--- only current scene XXX + DAG_scene_flush_update(scene, scene->lay, 0); //printf("dbase update\n"); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index aa36675fb90..5d938ba36cc 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1580,23 +1580,6 @@ void ED_screen_animation_timer_update(bContext *C, int redraws) } } -unsigned int ED_screen_view3d_layers(bScreen *screen) -{ - if(screen) { - unsigned int layer= screen->scene->lay; /* as minimum this */ - ScrArea *sa; - - /* get all used view3d layers */ - for(sa= screen->areabase.first; sa; sa= sa->next) { - if(sa->spacetype==SPACE_VIEW3D) - layer |= ((View3D *)sa->spacedata.first)->lay; - } - return layer; - } - return 0; -} - - /* results in fully updated anim system */ void ED_update_for_newframe(const bContext *C, int mute) { @@ -1607,7 +1590,7 @@ void ED_update_for_newframe(const bContext *C, int mute) /* this function applies the changes too */ /* XXX future: do all windows */ - scene_update_for_newframe(scene, ED_screen_view3d_layers(screen)); /* BKE_scene.h */ + scene_update_for_newframe(scene, BKE_screen_visible_layers(screen)); /* BKE_scene.h */ //if ( (CFRA>1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB)) // audiostream_scrub( CFRA ); -- cgit v1.2.3 From 6cee5201ec580f48b16efdd0a5620c52e86ce70e Mon Sep 17 00:00:00 2001 From: William Reynish Date: Mon, 14 Sep 2009 12:28:59 +0000 Subject: Third widget commit ;) Thanks to Broken for finding the bug. --- .../blender/editors/interface/interface_widgets.c | 65 +++++++++++++++++----- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 2385b5ad15c..90b2c920613 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -129,17 +129,21 @@ static float jit[8][2]= {{0.468813 , -0.481430}, {-0.155755 , -0.352820}, {0.219306 , -0.238501}, {-0.393286 , -0.110949}, {-0.024699 , 0.013908}, {0.343805 , 0.147431}, {-0.272855 , 0.269918}, {0.095909 , 0.388710}}; -static float num_tria_vert[19][2]= { +static float num_tria_vert[3][2]= { +{-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}}; + +static int num_tria_face[1][3]= { +{0, 1, 2}}; + +static float scroll_circle_vert[16][2]= { {0.382684, 0.923879}, {0.000001, 1.000000}, {-0.382683, 0.923880}, {-0.707107, 0.707107}, {-0.923879, 0.382684}, {-1.000000, 0.000000}, {-0.923880, -0.382684}, {-0.707107, -0.707107}, {-0.382683, -0.923880}, {0.000000, -1.000000}, {0.382684, -0.923880}, {0.707107, -0.707107}, -{0.923880, -0.382684}, {1.000000, -0.000000}, {0.923880, 0.382683}, {0.707107, 0.707107}, -{-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.729843, -0.008353}}; +{0.923880, -0.382684}, {1.000000, -0.000000}, {0.923880, 0.382683}, {0.707107, 0.707107}}; -static int num_tria_face[19][3]= { -{13, 14, 18}, {17, 5, 6}, {12, 13, 18}, {17, 6, 7}, {15, 18, 14}, {16, 4, 5}, {16, 5, 17}, {18, 11, 12}, -{18, 17, 10}, {18, 10, 11}, {17, 9, 10}, {15, 0, 18}, {18, 0, 16}, {3, 4, 16}, {8, 9, 17}, {8, 17, 7}, -{2, 3, 16}, {1, 2, 16}, {16, 0, 1}}; +static int scroll_circle_face[14][3]= { +{0, 1, 2}, {2, 0, 3}, {3, 0, 15}, {3, 15, 4}, {4, 15, 14}, {4, 14, 5}, {5, 14, 13}, {5, 13, 6}, +{6, 13, 12}, {6, 12, 7}, {7, 12, 11}, {7, 11, 8}, {8, 11, 10}, {8, 10, 9}}; static float menu_tria_vert[6][2]= { {-0.41, 0.16}, {0.41, 0.16}, {0, 0.82}, @@ -451,15 +455,50 @@ static void widget_num_tria(uiWidgetTrias *tria, rcti *rect, float triasize, cha i2=0; i1= 1; } - for(a=0; a<19; a++) { + for(a=0; a<3; a++) { tria->vec[a][0]= sizex*num_tria_vert[a][i1] + centx; tria->vec[a][1]= sizey*num_tria_vert[a][i2] + centy; } - tria->tot= 19; + tria->tot= 1; tria->index= num_tria_face; } +static void widget_scroll_circle(uiWidgetTrias *tria, rcti *rect, float triasize, char where) +{ + float centx, centy, sizex, sizey, minsize; + int a, i1=0, i2=1; + + minsize= MIN2(rect->xmax-rect->xmin, rect->ymax-rect->ymin); + + /* center position and size */ + centx= (float)rect->xmin + 0.5f*minsize; + centy= (float)rect->ymin + 0.5f*minsize; + sizex= sizey= -0.5f*triasize*minsize; + + if(where=='r') { + centx= (float)rect->xmax - 0.5f*minsize; + sizex= -sizex; + } + else if(where=='t') { + centy= (float)rect->ymax - 0.5f*minsize; + sizey= -sizey; + i2=0; i1= 1; + } + else if(where=='b') { + sizex= -sizex; + i2=0; i1= 1; + } + + for(a=0; a<16; a++) { + tria->vec[a][0]= sizex*scroll_circle_vert[a][i1] + centx; + tria->vec[a][1]= sizey*scroll_circle_vert[a][i2] + centy; + } + + tria->tot= 14; + tria->index= scroll_circle_face; +} + static void widget_trias_draw(uiWidgetTrias *tria) { int a; @@ -1736,12 +1775,12 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int stat wcol->item[3]= 255; if(horizontal) { - widget_num_tria(&wtb.tria1, slider, 0.6f, 'l'); - widget_num_tria(&wtb.tria2, slider, 0.6f, 'r'); + widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l'); + widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r'); } else { - widget_num_tria(&wtb.tria1, slider, 0.6f, 'b'); - widget_num_tria(&wtb.tria2, slider, 0.6f, 't'); + widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b'); + widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't'); } } widgetbase_draw(&wtb, wcol); -- cgit v1.2.3 From 4539bb9a98efb33044bb54fd9e906e280fdc26bd Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 12:30:49 +0000 Subject: Link/Append, small changes: * Added separate menu items for Link and Append. * Change some OPERATOR_FINISHED to OPERATOR_CANCELLED. * Remove some IPO specific hacks, these are no longer ID blocks, so not necessary to take into account. * Some comment and code formatting tweaks. --- release/ui/space_info.py | 3 +- source/blender/blenkernel/intern/library.c | 14 +- source/blender/editors/space_file/filelist.c | 13 -- source/blender/windowmanager/intern/wm_operators.c | 146 +++++++++++---------- 4 files changed, 83 insertions(+), 93 deletions(-) diff --git a/release/ui/space_info.py b/release/ui/space_info.py index 6b2a457e89d..9fc35c46f29 100644 --- a/release/ui/space_info.py +++ b/release/ui/space_info.py @@ -61,7 +61,8 @@ class INFO_MT_file(bpy.types.Menu): layout.itemS() layout.operator_context = "INVOKE_AREA" - layout.itemO("wm.link_append", text="Append or Link") + layout.itemO("wm.link_append", text="Link") + layout.item_booleanO("wm.link_append", "link", False, text="Append") layout.itemS() layout.itemM("INFO_MT_file_import") diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index da7692d0cdb..45869a317e8 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -455,16 +455,14 @@ void flag_all_listbases_ids(short flag, short value) while(a--) flag_listbase_ids(lbarray[a], flag, value); } -void recalc_all_library_objects(struct Main *main) +void recalc_all_library_objects(Main *main) { - /* DISPLISTS? */ - Object *ob= main->object.first; - while(ob) { - if(ob->id.lib) { + Object *ob; + + /* flag for full recalc */ + for(ob=main->object.first; ob; ob=ob->id.next) + if(ob->id.lib) ob->recalc |= OB_RECALC; - } - ob= ob->id.next; - } } /* note: MAX_LIBARRAY define should match this code */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 23f24f26dc0..c0b16e639c0 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1184,11 +1184,6 @@ void filelist_from_main(struct FileList *filelist) id= lb->first; filelist->numfiles= 0; while(id) { - /* XXXXX TODO: the selection of the ipo blocktype might go somewhere else? - if(filelist->has_func && idcode==ID_IP) { - if(filelist->ipotype== ((Ipo *)id)->blocktype) filelist->numfiles++; - } - else */ if (!filelist->hide_dot || id->name[2] != '.') { filelist->numfiles++; } @@ -1214,14 +1209,6 @@ void filelist_from_main(struct FileList *filelist) totlib= totbl= 0; while(id) { -#if 0 - // XXXXX TODO: this is deprecated, checks for correct IPO block? - ok= 0; - if(filelist->has_func && idcode==ID_IP) { - if(filelist->ipotype== ((Ipo *)id)->blocktype) ok= 1; - } - else ok= 1; -#endif ok = 1; if(ok) { if (!filelist->hide_dot || id->name[2] != '.') { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index c01ce5b6e35..ad490bb599a 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -247,7 +247,7 @@ wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag) ot->idname= idname; ot->name= name; - ot->flag= OPTYPE_MACRO | flag; + ot->flag= OPTYPE_MACRO|flag; ot->exec= wm_macro_exec; ot->invoke= wm_macro_invoke; @@ -542,7 +542,7 @@ int WM_operator_winactive(bContext *C) } /* op->invoke */ -static void redo_cb(bContext *C, void *arg_op, void *arg2) +static void redo_cb(bContext *C, void *arg_op, int event) { wmOperator *lastop= arg_op; @@ -564,7 +564,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) block= uiBeginBlock(C, ar, "redo_popup", UI_EMBOSS); uiBlockClearFlag(block, UI_BLOCK_LOOP); uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1); - uiBlockSetFunc(block, redo_cb, arg_op, NULL); + uiBlockSetHandleFunc(block, redo_cb, arg_op); if(!op->properties) { IDPropertyTemplate val = {0}; @@ -881,21 +881,9 @@ static void WM_OT_open_recentfile(wmOperatorType *ot) RNA_def_enum_funcs(prop, open_recentfile_itemf); } -/* ********* main file *********** */ +/* *************** open file **************** */ -static void untitled(char *name) -{ - if (G.save_over == 0 && strlen(name) < FILE_MAX-16) { - char *c= BLI_last_slash(name); - - if (c) - strcpy(&c[1], "untitled.blend"); - else - strcpy(name, "untitled.blend"); - } -} - -static void load_set_load_ui(wmOperator *op) +static void open_set_load_ui(wmOperator *op) { if(!RNA_property_is_set(op->ptr, "load_ui")) RNA_boolean_set(op->ptr, "load_ui", !(U.flag & USER_FILENOUI)); @@ -904,7 +892,7 @@ static void load_set_load_ui(wmOperator *op) static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event) { RNA_string_set(op->ptr, "path", G.sce); - load_set_load_ui(op); + open_set_load_ui(op); WM_event_add_fileselect(C, op); @@ -916,7 +904,7 @@ static int wm_open_mainfile_exec(bContext *C, wmOperator *op) char path[FILE_MAX]; RNA_string_get(op->ptr, "path", path); - load_set_load_ui(op); + open_set_load_ui(op); if(RNA_boolean_get(op->ptr, "load_ui")) G.fileflags &= ~G_FILE_NO_UI; @@ -947,9 +935,11 @@ static void WM_OT_open_mainfile(wmOperatorType *ot) RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file."); } +/* **************** link/append *************** */ + static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if (RNA_property_is_set(op->ptr, "path")) { + if(RNA_property_is_set(op->ptr, "path")) { return WM_operator_call(C, op); } else { @@ -962,27 +952,24 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *event) static short wm_link_append_flag(wmOperator *op) { - short flag = 0; - if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; - if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY; - if (RNA_boolean_get(op->ptr, "relative_paths")) flag |= FILE_STRINGCODE; - if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK; - return flag; -} + short flag= 0; -#define GROUP_MAX 32 + if(RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; + if(RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY; + if(RNA_boolean_get(op->ptr, "relative_paths")) flag |= FILE_STRINGCODE; + if(RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK; + return flag; +} -static void make_library_local(const char *libname, Main *main) +static void wm_link_make_library_local(Main *main, const char *libname) { - struct Library *lib; + Library *lib; /* and now find the latest append lib file */ - lib= main->library.first; - while(lib) { - if (BLI_streq(libname, lib->filename)) break; - lib= lib->id.next; - } + for(lib= main->library.first; lib; lib=lib->id.next) + if(BLI_streq(libname, lib->filename)) + break; /* make local */ if(lib) { @@ -995,49 +982,51 @@ static void make_library_local(const char *libname, Main *main) static int wm_link_append_exec(bContext *C, wmOperator *op) { - char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX]; - int idcode; + Main *bmain= CTX_data_main(C); + Scene *scene= CTX_data_scene(C); + Main *mainl= 0; BlendHandle *bh; - struct Main *mainvar= CTX_data_main(C); - struct Scene *scene= CTX_data_scene(C); - struct Main *mainl= 0; - PropertyRNA *prop; - int totfiles=0; + char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX]; + int idcode, totfiles=0; short flag; name[0] = '\0'; RNA_string_get(op->ptr, "filename", name); RNA_string_get(op->ptr, "directory", dir); - if ( BLO_is_a_library(dir, libname, group)==0 ) { + /* test if we have a valid data */ + if(BLO_is_a_library(dir, libname, group) == 0) { BKE_report(op->reports, RPT_ERROR, "Not a library"); - return OPERATOR_FINISHED; - } else if (group[0]==0) { + return OPERATOR_CANCELLED; + } + else if(group[0] == 0) { BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); - return OPERATOR_FINISHED; - } else if (BLI_streq(mainvar->name, libname)) { + return OPERATOR_CANCELLED; + } + else if(BLI_streq(bmain->name, libname)) { BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library"); - return OPERATOR_FINISHED; + return OPERATOR_CANCELLED; } /* check if something is indicated for append/link */ prop = RNA_struct_find_property(op->ptr, "files"); - if (prop) { + if(prop) { totfiles= RNA_property_collection_length(op->ptr, prop); - if (totfiles == 0) { - if (name[0] == '\0') { + if(totfiles == 0) { + if(name[0] == '\0') { BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); - return OPERATOR_FINISHED; + return OPERATOR_CANCELLED; } } - } else if (name[0] == '\0') { + } + else if(name[0] == '\0') { BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); - return OPERATOR_FINISHED; + return OPERATOR_CANCELLED; } /* now we have or selected, or an indicated file */ - if (RNA_boolean_get(op->ptr, "autoselect")) + if(RNA_boolean_get(op->ptr, "autoselect")) scene_deselect_all(scene); bh = BLO_blendhandle_from_file(libname); @@ -1045,16 +1034,16 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) flag = wm_link_append_flag(op); - if((flag & FILE_LINK)==0) { - /* tag everything, all untagged data can be made local */ + /* tag everything, all untagged data can be made local */ + if((flag & FILE_LINK)==0) flag_all_listbases_ids(LIB_APPEND_TAG, 1); - } /* here appending/linking starts */ mainl = BLO_library_append_begin(C, &bh, libname); - if (totfiles == 0) { + if(totfiles == 0) { BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag); - } else { + } + else { RNA_BEGIN(op->ptr, itemptr, "files") { RNA_string_get(&itemptr, "name", name); BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag); @@ -1063,17 +1052,16 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) } BLO_library_append_end(C, mainl, &bh, idcode, flag); - /* DISPLISTS? */ - recalc_all_library_objects(mainvar); + /* mark all library linked objects to be updated */ + recalc_all_library_objects(bmain); - /* Append, rather than linking */ - if ((flag & FILE_LINK)==0) { - make_library_local(libname, mainvar); - } + /* append, rather than linking */ + if((flag & FILE_LINK)==0) + wm_link_make_library_local(bmain, libname); - /* do we need to do this? */ - if(scene) - DAG_scene_sort(scene); + /* recreate dependency graph to include new objects */ + DAG_scene_sort(scene); + DAG_ids_flush_update(0); BLO_blendhandle_close(bh); BLI_strncpy(G.lib, dir, FILE_MAX); @@ -1103,6 +1091,8 @@ static void WM_OT_link_append(wmOperatorType *ot) RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); } +/* *************** recover last session **************** */ + static int wm_recover_last_session_exec(bContext *C, wmOperator *op) { char scestr[FILE_MAX], filename[FILE_MAX]; @@ -1137,6 +1127,20 @@ static void WM_OT_recover_last_session(wmOperatorType *ot) ot->poll= WM_operator_winactive; } +/* *************** save file as **************** */ + +static void untitled(char *name) +{ + if(G.save_over == 0 && strlen(name) < FILE_MAX-16) { + char *c= BLI_last_slash(name); + + if(c) + strcpy(&c[1], "untitled.blend"); + else + strcpy(name, "untitled.blend"); + } +} + static void save_set_compress(wmOperator *op) { if(!RNA_property_is_set(op->ptr, "compress")) { @@ -1199,7 +1203,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot) RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file."); } -/* *************** Save file directly ******** */ +/* *************** save file directly ******** */ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event) { @@ -2113,7 +2117,7 @@ void wm_window_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_recentfile", OKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); -- cgit v1.2.3 From 733b20f695ab43fb979963b82683aceedf25b8c8 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Mon, 14 Sep 2009 13:31:58 +0000 Subject: *Changed texture blend property Flip XY to a proper enum. *Minor adjustments to lamp UI *Fixed issue #19319 (missing notifier) --- release/ui/buttons_data_lamp.py | 26 +++++++++++++------------- release/ui/buttons_texture.py | 5 ++++- source/blender/makesrna/intern/rna_lamp.c | 2 +- source/blender/makesrna/intern/rna_texture.c | 11 +++++++++-- source/blender/makesrna/intern/rna_world.c | 1 + 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/release/ui/buttons_data_lamp.py b/release/ui/buttons_data_lamp.py index 808a205b1b8..d5aaa5ad679 100644 --- a/release/ui/buttons_data_lamp.py +++ b/release/ui/buttons_data_lamp.py @@ -75,7 +75,7 @@ class DATA_PT_lamp(DataButtonsPanel): col.itemR(lamp, "diffuse") class DATA_PT_sunsky(DataButtonsPanel): - __label__ = "Sun/Sky" + __label__ = "Sky & Atmosphere" def poll(self, context): lamp = context.lamp @@ -86,9 +86,8 @@ class DATA_PT_sunsky(DataButtonsPanel): lamp = context.lamp.sky - row = layout.row() - row.itemR(lamp, "sky") - row.itemR(lamp, "atmosphere") + layout.itemR(lamp, "sky") + row = layout.row() row.active = lamp.sky or lamp.atmosphere @@ -98,38 +97,39 @@ class DATA_PT_sunsky(DataButtonsPanel): col = split.column() col.active = lamp.sky - col.itemL(text="Blend Mode:") - sub = col.column(align=True) + col.itemL(text="Blending:") + sub = col.column() sub.itemR(lamp, "sky_blend_type", text="") sub.itemR(lamp, "sky_blend", text="Factor") col.itemL(text="Color Space:") - sub = col.column(align=True) - sub.itemR(lamp, "sky_color_space", text="") + sub = col.column() + sub.row().itemR(lamp, "sky_color_space", expand=True) sub.itemR(lamp, "sky_exposure", text="Exposure") col = split.column() col.active = lamp.sky col.itemL(text="Horizon:") - sub = col.column(align=True) + sub = col.column() sub.itemR(lamp, "horizon_brightness", text="Brightness") sub.itemR(lamp, "spread", text="Spread") col.itemL(text="Sun:") - sub = col.column(align=True) + sub = col.column() sub.itemR(lamp, "sun_brightness", text="Brightness") sub.itemR(lamp, "sun_size", text="Size") sub.itemR(lamp, "backscattered_light", slider=True,text="Back Light") layout.itemS() + layout.itemR(lamp, "atmosphere") + split = layout.split() col = split.column() col.active = lamp.atmosphere - col.itemL(text="Sun:") - col.itemR(lamp, "sun_intensity", text="Intensity") - col.itemL(text="Scale Distance:") + col.itemL(text="Intensity:") + col.itemR(lamp, "sun_intensity", text="Sun") col.itemR(lamp, "atmosphere_distance_factor", text="Distance") col = split.column() diff --git a/release/ui/buttons_texture.py b/release/ui/buttons_texture.py index 90ce40b4832..3cea47a236e 100644 --- a/release/ui/buttons_texture.py +++ b/release/ui/buttons_texture.py @@ -381,7 +381,10 @@ class TEXTURE_PT_blend(TextureTypePanel): tex = context.texture layout.itemR(tex, "progression") - layout.itemR(tex, "flip_axis") + sub = layout.row() + + sub.active = (tex.progression in ('LINEAR', 'QUADRATIC', 'EASING', 'RADIAL')) + sub.itemR(tex, "flip_axis", expand=True) class TEXTURE_PT_stucci(TextureTypePanel): __label__ = "Stucci" diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index 57aa1ba2736..dc59a75edbc 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -431,7 +431,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) prop= RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "shdwr"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Shadow Color", "Color of shadows casted by the lamp."); + RNA_def_property_ui_text(prop, "Shadow Color", "Color of shadows cast by the lamp."); RNA_def_property_update(prop, NC_LAMP|ND_LIGHTING, NULL); prop= RNA_def_property(srna, "only_shadow", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index f6835f3e7b5..ce65dc37e5b 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -835,6 +835,11 @@ static void rna_def_texture_blend(BlenderRNA *brna) {TEX_RAD, "RADIAL", 0, "Radial", "Creates a radial progression"}, {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_flip_axis_items[]= { + {0, "HORIZONTAL", 0, "Horizontal", "Flips the texture's X and Y axis"}, + {TEX_FLIPBLEND, "VERTICAL", 0, "Vertical", "Flips the texture's X and Y axis"}, + {0, NULL, 0, NULL, NULL}}; + srna= RNA_def_struct(brna, "BlendTexture", "Texture"); RNA_def_struct_ui_text(srna, "Blend Texture", "Procedural color blending texture."); RNA_def_struct_sdna(srna, "Tex"); @@ -845,10 +850,12 @@ static void rna_def_texture_blend(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Progression", "Sets the style of the color blending"); RNA_def_property_update(prop, NC_TEXTURE, NULL); - prop= RNA_def_property(srna, "flip_axis", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_FLIPBLEND); + prop= RNA_def_property(srna, "flip_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_flip_axis_items); RNA_def_property_ui_text(prop, "Flip Axis", "Flips the texture's X and Y axis"); RNA_def_property_update(prop, NC_TEXTURE, NULL); + } static void rna_def_texture_stucci(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 0ed5016ccd2..d2eebbc61aa 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -431,6 +431,7 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "ambr"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Ambient Color", ""); + RNA_def_property_update(prop, NC_WORLD, NULL); /* exp, range */ prop= RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From c8af263e5d8d9d41a757e8438cdcf3b64d57e0c0 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Mon, 14 Sep 2009 14:55:49 +0000 Subject: Reverted Mesh.verts from dynamic array since it breaks foreach_set used by import scripts. Did a few fixes in scripts to reflect recent RNA changes. --- release/io/export_obj.py | 6 +++--- release/io/export_x3d.py | 2 +- release/io/import_3ds.py | 3 ++- release/io/import_obj.py | 2 +- source/blender/makesrna/intern/rna_mesh.c | 3 +++ source/blender/python/intern/bpy_array.c | 2 +- source/blender/python/intern/bpy_rna.c | 8 +------- 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index b2d4af7c517..d52ee8ec158 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -118,8 +118,8 @@ def write_mtl(scene, filename, copy_images): 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('Kd %.6f %.6f %.6f\n' % tuple([c*mat.diffuse_intensity for c in mat.diffuse_color]) ) # Diffuse + file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular if hasattr(mat, "ior"): file.write('Ni %.6f\n' % mat.ior) # Refraction index else: @@ -129,7 +129,7 @@ def write_mtl(scene, filename, copy_images): # 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: + elif mat.specular_intensity == 0: file.write('illum 1\n') # no specular. else: file.write('illum 2\n') # light normaly diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py index 30a4b1483b0..3661d78a343 100644 --- a/release/io/export_x3d.py +++ b/release/io/export_x3d.py @@ -770,7 +770,7 @@ class x3d_class: for i in range(alltexture): tex = alltextures[i] - if tex.type != 'IMAGE': + if tex.type != 'IMAGE' or tex.image == None: continue namemat = tex.name diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py index 0269219b63d..f2dc99d5b7e 100644 --- a/release/io/import_3ds.py +++ b/release/io/import_3ds.py @@ -463,7 +463,8 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): ''' if contextMatrix_rot: - ob.matrix = [x for row in contextMatrix_rot for x in row] + # ob.matrix = [x for row in contextMatrix_rot for x in row] + ob.matrix = contextMatrix_rot # ob.setMatrix(contextMatrix_rot) importedObjects.append(ob) diff --git a/release/io/import_obj.py b/release/io/import_obj.py index 484be6d54b4..34f6575dba2 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -715,7 +715,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l # face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) if verts_tex and me.faces: - me.add_uv_layer() + me.add_uv_texture() # me.faceUV= 1 # TEXMODE= Mesh.FaceModes['TEX'] diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index e1744bb3d23..f1a46b199b4 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -981,10 +981,13 @@ static void rna_def_mface(BlenderRNA *brna) // XXX allows creating invalid meshes prop= RNA_def_property(srna, "verts", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "v1"); RNA_def_property_array(prop, 4); + /* RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_dynamic_array_funcs(prop, "rna_MeshFace_verts_get_length"); RNA_def_property_int_funcs(prop, "rna_MeshFace_verts_get", "rna_MeshFace_verts_set", NULL); + */ RNA_def_property_ui_text(prop, "Vertices", "Vertex indices"); prop= RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/python/intern/bpy_array.c b/source/blender/python/intern/bpy_array.c index f11c95e7ed5..4459c7c313f 100644 --- a/source/blender/python/intern/bpy_array.c +++ b/source/blender/python/intern/bpy_array.c @@ -1,5 +1,5 @@ /** - * + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 8395e5c82e4..49105422325 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -545,9 +545,6 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v int len = RNA_property_array_length(ptr, prop); if (len > 0) { - /* char error_str[512]; */ - int ok= 1; - #ifdef USE_MATHUTILS if(MatrixObject_Check(value)) { MatrixObject *mat = (MatrixObject*)value; @@ -559,10 +556,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v PyErr_Format(PyExc_TypeError, "%.200s RNA array assignment expected a sequence instead of %.200s instance.", error_prefix, Py_TYPE(value)->tp_name); return -1; } - /* done getting the length */ - ok= pyrna_py_to_array(ptr, prop, data, value, error_prefix); - - if (!ok) { + else if (!pyrna_py_to_array(ptr, prop, data, value, error_prefix)) { /* PyErr_Format(PyExc_AttributeError, "%.200s %s", error_prefix, error_str); */ return -1; } -- cgit v1.2.3 From a3ce413f44ba13b5e95e53d3dc11a92a16ac1dd5 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Mon, 14 Sep 2009 16:00:42 +0000 Subject: Bugfix with py operator api and modal operators. Modal operators would keep a reference to Reports locally allocated in the api functions, which would crash and burn later when the operator would actually stop. This commit introduces a flag at the Reports level that can be used to indicate that it needs to be freed (on top of the flag already existing in the operator, which I guess could be removed). Reports for operators called through python are only persisted if they indicate that they are running modal. --- source/blender/makesdna/DNA_windowmanager_types.h | 1 + source/blender/python/intern/bpy_operator.c | 15 ++++++++++----- source/blender/windowmanager/intern/wm.c | 2 +- source/blender/windowmanager/intern/wm_event_system.c | 5 +++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 10f83c8b9ec..c3bbb759aff 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -80,6 +80,7 @@ typedef enum ReportType { enum ReportListFlags { RPT_PRINT = 1, RPT_STORE = 2, + RPT_FREE = 4, }; typedef struct Report { struct Report *next, *prev; diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 062db42e0e9..0c1d974c978 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -79,16 +79,21 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) if (error_val==0) { - ReportList reports; + ReportList *reports; - BKE_reports_init(&reports, RPT_STORE); + reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); + BKE_reports_init(reports, RPT_STORE); - WM_operator_call_py(C, ot, context, &ptr, &reports); + WM_operator_call_py(C, ot, context, &ptr, reports); - if(BPy_reports_to_error(&reports)) + if(BPy_reports_to_error(reports)) error_val = -1; - BKE_reports_clear(&reports); + BKE_reports_clear(reports); + if ((reports->flag & RPT_FREE) == 0) + { + MEM_freeN(reports); + } } WM_operator_properties_free(&ptr); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 651394d51af..0a91c5078b7 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -69,7 +69,7 @@ void WM_operator_free(wmOperator *op) MEM_freeN(op->properties); } - if(op->reports && (op->flag & OPERATOR_REPORT_FREE)) { + if(op->reports && ((op->flag & OPERATOR_REPORT_FREE) || (op->reports->flag & RPT_FREE))) { BKE_reports_clear(op->reports); MEM_freeN(op->reports); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 79441f33610..28814937ebe 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -555,6 +555,11 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA retval= wm_operator_call_internal(C, ot, context, properties, reports); + if (retval & OPERATOR_RUNNING_MODAL) + { + reports->flag |= RPT_FREE; + } + return retval; } -- cgit v1.2.3 From b3c49521787cd71918674b0fb5bbc88daeb199aa Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Mon, 14 Sep 2009 16:30:53 +0000 Subject: netrender: add "Animation on network" button to send job to master and gather the results in one step. --- release/io/netrender/operators.py | 34 ++++++++++++++++++++++++++++++++++ release/io/netrender/ui.py | 1 + 2 files changed, 35 insertions(+) diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index ccecef670d4..655afa6631f 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -6,6 +6,39 @@ from netrender.utils import * import netrender.client as client import netrender.model +@rnaOperator +class RENDER_OT_netclientanim(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "render.netclientanim" + __label__ = "Net Render Client Anim" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + scene = context.scene + + conn = clientConnection(scene) + + if conn: + # Sending file + scene.network_render.job_id = client.clientSendJob(conn, scene, True) + conn.close() + + bpy.ops.screen.render('INVOKE_AREA', animation=True) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + @rnaOperator class RENDER_OT_netclientsend(bpy.types.Operator): ''' @@ -30,6 +63,7 @@ class RENDER_OT_netclientsend(bpy.types.Operator): if conn: # Sending file scene.network_render.job_id = client.clientSendJob(conn, scene, True) + conn.close() return ('FINISHED',) diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index 12ac10b551f..eee95bdac19 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -48,6 +48,7 @@ class SCENE_PT_network_settings(RenderButtonsPanel): col = split.column() + col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") col.itemR(scene.network_render, "mode") col.itemR(scene.network_render, "server_address") col.itemR(scene.network_render, "server_port") -- cgit v1.2.3 From cd211af417d1785ab0b526ae45c551286b5c89c6 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 16:43:13 +0000 Subject: Smoke: * Introduce a better check for fragment support --- source/blender/editors/space_view3d/drawobject.c | 4 ++-- source/blender/editors/space_view3d/drawvolume.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 2c4d72f64ab..40eb74e8062 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5360,7 +5360,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) { if(!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { -// #if0 +// #if 0 smd->domain->tex = NULL; GPU_create_smoke(smd, 0); draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->p0, smd->domain->p1, smd->domain->res, smd->domain->dx, smd->domain->tex_shadow); @@ -5395,7 +5395,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) tmp[0] += smd->domain->dx * x + smd->domain->dx * 0.5; tmp[1] += smd->domain->dx * y + smd->domain->dx * 0.5; tmp[2] += smd->domain->dx * z + smd->domain->dx * 0.5; - color[0] = color[1] = color[2] = 1.0; // density[index]; + color[0] = color[1] = color[2] = density[index]; glColor3fv(color); bglVertex3fv(tmp); } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index cc4cb4771e7..3a79caed821 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -328,10 +328,10 @@ void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture // printf("i: %d\n", i); - if(GLEW_ARB_fragment_program) + if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { - glGenProgramsARB(1, &prog); glEnable(GL_FRAGMENT_PROGRAM_ARB); + glGenProgramsARB(1, &prog); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text); @@ -342,7 +342,7 @@ void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0); } else - printf("Your gfx card does not support 3dview smoke drawing."); + printf("Your gfx card does not support 3dview smoke drawing.\n"); GPU_texture_bind(tex, 0); if(tex_shadow) -- cgit v1.2.3 From 131c713fc163a8c404e10616438799f274b19a70 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 16:46:34 +0000 Subject: Smoke: * Fixing some gcc warnings --- source/blender/blenkernel/intern/pointcache.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index f351f8a4335..7725efe3885 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -570,9 +570,9 @@ static int ptcache_write_smoke_turbulence(PTCacheFile *pf, void *smoke_v) SmokeDomainSettings *sds = smd->domain; if(sds->wt) { - unsigned int res_big_array[3]; - unsigned int res_big; - unsigned int res = sds->res[0]*sds->res[1]*sds->res[2]; + int res_big_array[3]; + int res_big; + int res = sds->res[0]*sds->res[1]*sds->res[2]; float *dens, *densold, *tcu, *tcv, *tcw; unsigned int in_len = sizeof(float)*(unsigned int)res; unsigned int in_len_big; @@ -678,8 +678,8 @@ static void ptcache_read_smoke_turbulence(PTCacheFile *pf, void *smoke_v) SmokeDomainSettings *sds = smd->domain; if(sds->fluid) { - unsigned int res = sds->res[0]*sds->res[1]*sds->res[2]; - unsigned int res_big, res_big_array[3]; + int res = sds->res[0]*sds->res[1]*sds->res[2]; + int res_big, res_big_array[3]; float *dens, *densold, *tcu, *tcv, *tcw; unsigned int out_len = sizeof(float)*(unsigned int)res; unsigned int out_len_big; -- cgit v1.2.3 From ba5df38d66cd70d64084456ac882df0cae19d880 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 14 Sep 2009 16:52:06 +0000 Subject: use static functions where possible for some local functions. --- source/blender/blenfont/intern/blf.c | 2 +- source/blender/blenfont/intern/blf_dir.c | 2 +- source/blender/blenfont/intern/blf_font.c | 2 +- source/blender/blenfont/intern/blf_glyph.c | 2 +- source/blender/blenkernel/intern/action.c | 6 ++-- source/blender/blenkernel/intern/anim_sys.c | 2 +- source/blender/blenkernel/intern/brush.c | 2 +- source/blender/blenkernel/intern/cloth.c | 10 +++--- source/blender/blenkernel/intern/collision.c | 16 ++++----- source/blender/blenkernel/intern/curve.c | 8 ++--- source/blender/blenkernel/intern/displist.c | 2 +- source/blender/blenkernel/intern/fcurve.c | 6 ++-- source/blender/blenkernel/intern/font.c | 2 +- source/blender/blenkernel/intern/implicit.c | 22 ++++++------ source/blender/blenkernel/intern/ipo.c | 2 +- source/blender/blenkernel/intern/modifier.c | 42 +++++++++++----------- source/blender/blenkernel/intern/multires.c | 4 +-- source/blender/blenkernel/intern/nla.c | 2 +- source/blender/blenkernel/intern/object.c | 2 +- source/blender/blenkernel/intern/packedFile.c | 2 +- source/blender/blenkernel/intern/particle_system.c | 2 +- source/blender/blenkernel/intern/sequence.c | 20 +++++------ source/blender/blenkernel/intern/smoke.c | 10 +++--- source/blender/blenkernel/intern/writeffmpeg.c | 2 +- source/blender/blenlib/intern/BLI_kdopbvh.c | 4 +-- source/blender/blenlib/intern/BLI_kdtree.c | 2 +- source/blender/blenlib/intern/arithb.c | 16 ++++----- source/blender/blenlib/intern/freetypefont.c | 4 +-- source/blender/blenlib/intern/graph.c | 6 ++-- source/blender/blenlib/intern/noise.c | 12 +++---- source/blender/blenlib/intern/threads.c | 2 +- source/blender/makesrna/intern/rna_action.c | 4 +-- source/blender/makesrna/intern/rna_animation.c | 4 +-- source/blender/makesrna/intern/rna_armature.c | 2 +- source/blender/makesrna/intern/rna_brush.c | 2 +- source/blender/makesrna/intern/rna_constraint.c | 2 +- source/blender/makesrna/intern/rna_curve.c | 2 +- source/blender/makesrna/intern/rna_define.c | 6 ++-- source/blender/makesrna/intern/rna_fcurve.c | 10 +++--- source/blender/makesrna/intern/rna_gpencil.c | 12 +++---- source/blender/makesrna/intern/rna_group.c | 2 +- source/blender/makesrna/intern/rna_main_api.c | 4 +-- source/blender/makesrna/intern/rna_material.c | 8 ++--- source/blender/makesrna/intern/rna_meta.c | 4 +-- source/blender/makesrna/intern/rna_nla.c | 6 ++-- source/blender/makesrna/intern/rna_nodetree.c | 2 +- source/blender/makesrna/intern/rna_object_api.c | 2 +- source/blender/makesrna/intern/rna_pose.c | 10 +++--- source/blender/makesrna/intern/rna_scene.c | 6 ++-- source/blender/makesrna/intern/rna_sensor.c | 30 ++++++++-------- source/blender/makesrna/intern/rna_sequence.c | 2 +- source/blender/makesrna/intern/rna_space.c | 10 +++--- source/blender/makesrna/intern/rna_texture.c | 4 +-- source/blender/makesrna/intern/rna_wm.c | 2 +- source/blender/windowmanager/intern/wm_operators.c | 2 +- 55 files changed, 178 insertions(+), 178 deletions(-) diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 8cb237a19ac..db88d84d0b5 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -102,7 +102,7 @@ void BLF_exit(void) blf_font_exit(); } -int blf_search(char *name) +static int blf_search(char *name) { FontBLF *font; int i; diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c index b4d902ff428..aac6cd7d2fc 100644 --- a/source/blender/blenfont/intern/blf_dir.c +++ b/source/blender/blenfont/intern/blf_dir.c @@ -51,7 +51,7 @@ static ListBase global_font_dir= { NULL, NULL }; -DirBLF *blf_dir_find(const char *path) +static DirBLF *blf_dir_find(const char *path) { DirBLF *p; diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 2cd72809579..0a3dd259f6c 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -453,7 +453,7 @@ void blf_font_free(FontBLF *font) MEM_freeN(font); } -void blf_font_fill(FontBLF *font) +static void blf_font_fill(FontBLF *font) { font->aspect= 1.0f; font->pos[0]= 0.0f; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index f3db3ddc9a5..7d1e43a38df 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -136,7 +136,7 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) MEM_freeN(gc); } -void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) +static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) { int tot_mem, i; unsigned char *buf; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 47de044ea25..2bde61818bf 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -214,7 +214,7 @@ bAction *copy_action (bAction *src) /* Get the active action-group for an Action */ -bActionGroup *get_active_actiongroup (bAction *act) +static bActionGroup *get_active_actiongroup (bAction *act) { bActionGroup *agrp= NULL; @@ -1165,7 +1165,7 @@ typedef struct NlaIpoChannel { int type; } NlaIpoChannel; -void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime) +static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime) { bActionChannel *achan= get_action_channel(act, name); IpoCurve *icu; @@ -1258,7 +1258,7 @@ static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int } } -int execute_ipochannels(ListBase *lb) +static int execute_ipochannels(ListBase *lb) { NlaIpoChannel *nic; int count = 0; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 2d6a97c48ae..643aa6bc779 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -438,7 +438,7 @@ void BKE_keyingsets_free (ListBase *list) * - path: original path string (as stored in F-Curve data) * - dst: destination string to write data to */ -short animsys_remap_path (AnimMapper *remap, char *path, char **dst) +static short animsys_remap_path (AnimMapper *remap, char *path, char **dst) { /* is there a valid remapping table to use? */ //if (remap) { diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index bce4e1120be..76a26762abe 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -711,7 +711,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, i } } -void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float *pos) +static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float *pos) { Brush *brush= painter->brush; BrushPainterCache *cache= &painter->cache; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index d25c329f49f..9ee6be903fa 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -95,7 +95,7 @@ static CM_SOLVER_DEF solvers [] = static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh *dm); static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ); static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first); -int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); +static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); @@ -155,7 +155,7 @@ void cloth_init ( ClothModifierData *clmd ) clmd->sim_parms->goalfrict = 0.0f; } -BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) +static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; @@ -196,7 +196,7 @@ BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) return bvhtree; } -BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) +static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; BVHTree *bvhtree; @@ -998,7 +998,7 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in return 0; } -void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist) +static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist) { unsigned int i = 0; @@ -1031,7 +1031,7 @@ void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgeli BLI_edgehash_free ( cloth->edgehash, NULL ); } -int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) +static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 37e9c93a108..8ef1c285370 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -313,7 +313,7 @@ gsl_poly_solve_quadratic (double a, double b, double c, * See Bridson et al. "Robust Treatment of Collision, Contact and Friction for Cloth Animation" * page 4, left column */ -int cloth_get_collision_time ( double a[3], double b[3], double c[3], double d[3], double e[3], double f[3], double solution[3] ) +static int cloth_get_collision_time ( double a[3], double b[3], double c[3], double d[3], double e[3], double f[3], double solution[3] ) { int num_sols = 0; @@ -427,7 +427,7 @@ int cloth_get_collision_time ( double a[3], double b[3], double c[3], double d[3 // w3 is not perfect -void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 ) +static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 ) { double tempV1[3], tempV2[3], tempV4[3]; double a,b,c,d,e,f; @@ -726,7 +726,7 @@ CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap return collpair; } -int cloth_collision_response_moving( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +static int cloth_collision_response_moving( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) { int result = 0; Cloth *cloth1; @@ -891,7 +891,7 @@ static void findClosestPointsEE(float *x1, float *x2, float *x3, float *x4, floa } // calculates the distance of 2 edges -float edgedge_distance(float np11[3], float np12[3], float np21[3], float np22[3], float *out_a1, float *out_a2, float *out_normal) +static float edgedge_distance(float np11[3], float np12[3], float np21[3], float np22[3], float *out_a1, float *out_a2, float *out_normal) { float line1[3], line2[3], cross[3]; float length; @@ -1065,7 +1065,7 @@ float edgedge_distance(float np11[3], float np12[3], float np21[3], float np22[3 return 0; } -int cloth_collision_moving_edges ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair ) +static int cloth_collision_moving_edges ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair ) { EdgeCollPair edgecollpair; Cloth *cloth1=NULL; @@ -1275,7 +1275,7 @@ int cloth_collision_moving_edges ( ClothModifierData *clmd, CollisionModifierDat return result; } -int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +static int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) { Cloth *cloth1; cloth1 = clmd->clothObject; @@ -1392,7 +1392,7 @@ CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *nu return objs; } -void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap) +static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap) { int i; @@ -1405,7 +1405,7 @@ void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModi } } -int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index) +static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index) { Cloth *cloth = clmd->clothObject; int i=0, j = 0, numfaces = 0, numverts = 0; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index eec3cb73d8a..ea3fce9ffaf 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -68,7 +68,7 @@ /* globals */ /* local */ -int cu_isectLL(float *v1, float *v2, float *v3, float *v4, +static int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec); @@ -977,7 +977,7 @@ void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int i } } -void forward_diff_bezier_cotangent(float *p0, float *p1, float *p2, float *p3, float *p, int it, int stride) +static void forward_diff_bezier_cotangent(float *p0, float *p1, float *p2, float *p3, float *p, int it, int stride) { /* note that these are not purpendicular to the curve * they need to be rotated for this, @@ -1363,7 +1363,7 @@ void makebevelcurve(Scene *scene, Object *ob, ListBase *disp) } } -int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec) +static int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec) { /* return: -1: colliniar @@ -1882,7 +1882,7 @@ static void make_bevel_list_3D_tangent(BevList *bl) } } -void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode) +static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode) { switch(twist_mode) { case CU_TWIST_TANGENT: diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index d87dbc833c5..266a528dc57 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1131,7 +1131,7 @@ static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) } -void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase) +static void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase) { if(cu->flag & CU_3D) return; diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 31f6e2c6067..54d2f85457f 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -916,7 +916,7 @@ void correct_bezpart (float *v1, float *v2, float *v3, float *v4) } /* find root ('zero') */ -int findzero (float x, float q0, float q1, float q2, float q3, float *o) +static int findzero (float x, float q0, float q1, float q2, float q3, float *o) { double c0, c1, c2, c3, a, b, c, p, q, d, t, phi; int nr= 0; @@ -1010,7 +1010,7 @@ int findzero (float x, float q0, float q1, float q2, float q3, float *o) } } -void berekeny (float f1, float f2, float f3, float f4, float *o, int b) +static void berekeny (float f1, float f2, float f3, float f4, float *o, int b) { float t, c0, c1, c2, c3; int a; @@ -1026,7 +1026,7 @@ void berekeny (float f1, float f2, float f3, float f4, float *o, int b) } } -void berekenx (float *f, float *o, int b) +static void berekenx (float *f, float *o, int b) { float t, c0, c1, c2, c3; int a; diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 411b2448dea..4e05bf45d3d 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -129,7 +129,7 @@ wcsleninu8(wchar_t *src) } int -utf8slen(char *src) +static utf8slen(char *src) { int size = 0, index = 0; unsigned char c; diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 0bce71b57eb..956a5851827 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -43,7 +43,7 @@ #include static LARGE_INTEGER _itstart, _itend; static LARGE_INTEGER ifreq; -void itstart(void) +static void itstart(void) { static int first = 1; if(first) { @@ -52,7 +52,7 @@ void itstart(void) } QueryPerformanceCounter(&_itstart); } -void itend(void) +static void itend(void) { QueryPerformanceCounter(&_itend); } @@ -74,7 +74,7 @@ double itval() { gettimeofday(&_itstart, &itz); } -void itend(void) +static void itend(void) { gettimeofday(&_itend,&itz); } @@ -155,7 +155,7 @@ DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vec /* printf vector[3] on console: for debug output */ -void print_fvector(float m3[3]) +static void print_fvector(float m3[3]) { printf("%f\n%f\n%f\n\n",m3[0],m3[1],m3[2]); } @@ -297,7 +297,7 @@ DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], f // 3x3 matrix /////////////////////////// /* printf 3x3 matrix on console: for debug output */ -void print_fmatrix(float m3[3][3]) +static void print_fmatrix(float m3[3][3]) { printf("%f\t%f\t%f\n",m3[0][0],m3[0][1],m3[0][2]); printf("%f\t%f\t%f\n",m3[1][0],m3[1][1],m3[1][2]); @@ -496,7 +496,7 @@ DO_INLINE void mulsub_fmatrix_fvector(float to[3], float matrix[3][3], float fro // SPARSE SYMMETRIC big matrix with 3x3 matrix entries /////////////////////////// /* printf a big matrix on console: for debug output */ -void print_bfmatrix(fmatrix3x3 *m3) +static void print_bfmatrix(fmatrix3x3 *m3) { unsigned int i = 0; @@ -887,7 +887,7 @@ DO_INLINE void filter(lfVector *V, fmatrix3x3 *S) } } -int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S) +static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S) { // Solves for unknown X in equation AX=B unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100; @@ -970,7 +970,7 @@ DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv) } /* // version 1.3 -int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv) +static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv) { unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100; float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0; @@ -1038,7 +1038,7 @@ int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fma } */ // version 1.4 -int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI) +static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI) { unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100; float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0, tol = 0; @@ -1391,7 +1391,7 @@ static void CalcFloat4( float *v1, float *v2, float *v3, float *v4, float *n) n[2]= n1[0]*n2[1]-n1[1]*n2[0]; } -float calculateVertexWindForce(float wind[3], float vertexnormal[3]) +static float calculateVertexWindForce(float wind[3], float vertexnormal[3]) { return (INPR(wind, vertexnormal)); } @@ -1595,7 +1595,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF, // printf("\n"); } -void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *M, fmatrix3x3 *bigI) +static void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *M, fmatrix3x3 *bigI) { unsigned int numverts = dFdV[0].vcount; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 2f0e0931588..62f44d92d25 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -820,7 +820,7 @@ static char *particle_adrcodes_to_paths (int adrcode, int *array_index) * - array_index - index in property's array (if applicable) to use * - return - the allocated path... */ -char *get_rna_access (int blocktype, int adrcode, char actname[], char constname[], int *array_index) +static char *get_rna_access (int blocktype, int adrcode, char actname[], char constname[], int *array_index) { DynStr *path= BLI_dynstr_new(); char *propname=NULL, *rpath=NULL; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index f06173264ee..4f2264a052f 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -214,7 +214,7 @@ static void curveModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tcmd->name, cmd->name, 32); } -CustomDataMask curveModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask curveModifier_requiredDataMask(Object *ob, ModifierData *md) { CurveModifierData *cmd = (CurveModifierData *)md; CustomDataMask dataMask = 0; @@ -290,7 +290,7 @@ static void latticeModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tlmd->name, lmd->name, 32); } -CustomDataMask latticeModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask latticeModifier_requiredDataMask(Object *ob, ModifierData *md) { LatticeModifierData *lmd = (LatticeModifierData *)md; CustomDataMask dataMask = 0; @@ -1104,7 +1104,7 @@ static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, Sc } } -float vertarray_size(MVert *mvert, int numVerts, int axis) +static float vertarray_size(MVert *mvert, int numVerts, int axis) { int i; float min_co, max_co; @@ -1771,7 +1771,7 @@ static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, S /* finds the best possible flipped name. For renaming; check for unique names afterwards */ /* if strip_number: removes number extensions */ -void vertgroup_flip_name (char *name, int strip_number) +static void vertgroup_flip_name (char *name, int strip_number) { int len; char prefix[128]={""}; /* The part before the facing */ @@ -3401,7 +3401,7 @@ static void bevelModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tbmd->defgrp_name, bmd->defgrp_name, 32); } -CustomDataMask bevelModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask bevelModifier_requiredDataMask(Object *ob, ModifierData *md) { BevelModifierData *bmd = (BevelModifierData *)md; CustomDataMask dataMask = 0; @@ -3481,7 +3481,7 @@ static void displaceModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tdmd->uvlayer_name, dmd->uvlayer_name, 32); } -CustomDataMask displaceModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask displaceModifier_requiredDataMask(Object *ob, ModifierData *md) { DisplaceModifierData *dmd = (DisplaceModifierData *)md; CustomDataMask dataMask = 0; @@ -3825,7 +3825,7 @@ static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target) tumd->aspecty = umd->aspecty; } -CustomDataMask uvprojectModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask uvprojectModifier_requiredDataMask(Object *ob, ModifierData *md) { CustomDataMask dataMask = 0; @@ -4278,7 +4278,7 @@ static void smoothModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tsmd->defgrp_name, smd->defgrp_name, 32); } -int smoothModifier_isDisabled(ModifierData *md) +static int smoothModifier_isDisabled(ModifierData *md) { SmoothModifierData *smd = (SmoothModifierData*) md; short flag; @@ -4291,7 +4291,7 @@ int smoothModifier_isDisabled(ModifierData *md) return 0; } -CustomDataMask smoothModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask smoothModifier_requiredDataMask(Object *ob, ModifierData *md) { SmoothModifierData *smd = (SmoothModifierData *)md; CustomDataMask dataMask = 0; @@ -4508,7 +4508,7 @@ static void castModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tcmd->defgrp_name, cmd->defgrp_name, 32); } -int castModifier_isDisabled(ModifierData *md) +static int castModifier_isDisabled(ModifierData *md) { CastModifierData *cmd = (CastModifierData*) md; short flag; @@ -4520,7 +4520,7 @@ int castModifier_isDisabled(ModifierData *md) return 0; } -CustomDataMask castModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask castModifier_requiredDataMask(Object *ob, ModifierData *md) { CastModifierData *cmd = (CastModifierData *)md; CustomDataMask dataMask = 0; @@ -5151,7 +5151,7 @@ static void waveModifier_updateDepgraph( } } -CustomDataMask waveModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask waveModifier_requiredDataMask(Object *ob, ModifierData *md) { WaveModifierData *wmd = (WaveModifierData *)md; CustomDataMask dataMask = 0; @@ -5487,7 +5487,7 @@ static void armatureModifier_copyData(ModifierData *md, ModifierData *target) strncpy(tamd->defgrp_name, amd->defgrp_name, 32); } -CustomDataMask armatureModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask armatureModifier_requiredDataMask(Object *ob, ModifierData *md) { CustomDataMask dataMask = 0; @@ -5602,7 +5602,7 @@ static void hookModifier_copyData(ModifierData *md, ModifierData *target) strncpy(thmd->subtarget, hmd->subtarget, 32); } -CustomDataMask hookModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask hookModifier_requiredDataMask(Object *ob, ModifierData *md) { HookModifierData *hmd = (HookModifierData *)md; CustomDataMask dataMask = 0; @@ -5947,7 +5947,7 @@ static void clothModifier_updateDepgraph( } } -CustomDataMask clothModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask clothModifier_requiredDataMask(Object *ob, ModifierData *md) { CustomDataMask dataMask = 0; @@ -6371,7 +6371,7 @@ static DerivedMesh *booleanModifier_applyModifier( return derivedData; } -CustomDataMask booleanModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask booleanModifier_requiredDataMask(Object *ob, ModifierData *md) { CustomDataMask dataMask = (1 << CD_MTFACE) + (1 << CD_MEDGE); @@ -6419,7 +6419,7 @@ static void particleSystemModifier_copyData(ModifierData *md, ModifierData *targ tpsmd->psys = psmd->psys; } -CustomDataMask particleSystemModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask particleSystemModifier_requiredDataMask(Object *ob, ModifierData *md) { ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md; CustomDataMask dataMask = 0; @@ -6832,7 +6832,7 @@ static int explodeModifier_dependsOnTime(ModifierData *md) { return 1; } -CustomDataMask explodeModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask explodeModifier_requiredDataMask(Object *ob, ModifierData *md) { ExplodeModifierData *emd= (ExplodeModifierData*) md; CustomDataMask dataMask = 0; @@ -7746,7 +7746,7 @@ static void meshdeformModifier_copyData(ModifierData *md, ModifierData *target) tmmd->object = mmd->object; } -CustomDataMask meshdeformModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask meshdeformModifier_requiredDataMask(Object *ob, ModifierData *md) { MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; CustomDataMask dataMask = 0; @@ -8126,7 +8126,7 @@ static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target) tsmd->subsurfLevels = smd->subsurfLevels; } -CustomDataMask shrinkwrapModifier_requiredDataMask(Object *ob, ModifierData *md) +static CustomDataMask shrinkwrapModifier_requiredDataMask(Object *ob, ModifierData *md) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; CustomDataMask dataMask = 0; @@ -9137,7 +9137,7 @@ int modifiers_indexInObject(Object *ob, ModifierData *md_seek) return i; } -int modifiers_usesPointCache(Object *ob) +static int modifiers_usesPointCache(Object *ob) { ModifierData *md = ob->modifiers.first; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 37e7e55050a..e7159b82d49 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -596,7 +596,7 @@ static void find_displacer_edges(MultiresDisplacer *d, DerivedMesh *dm, Displace } /* Returns in out the corners [0-3] that use v1 and v2 */ -void find_face_corners(MFace *f, int v1, int v2, int out[2]) +static void find_face_corners(MFace *f, int v1, int v2, int out[2]) { int i, end = f->v4 ? 4 : 3; @@ -1259,7 +1259,7 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i ***************************/ /* Does not actually free lvl itself */ -void multires_free_level(MultiresLevel *lvl) +static void multires_free_level(MultiresLevel *lvl) { if(lvl) { if(lvl->faces) MEM_freeN(lvl->faces); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 480c79fbc1a..83ee71bfe40 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1048,7 +1048,7 @@ short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max) /* Is the given NLA-strip the first one to occur for the given AnimData block */ // TODO: make this an api method if necesary, but need to add prefix first -short nlastrip_is_first (AnimData *adt, NlaStrip *strip) +static short nlastrip_is_first (AnimData *adt, NlaStrip *strip) { NlaTrack *nlt; NlaStrip *ns; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 8fe7beeb247..ed4e82cb3c6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1406,7 +1406,7 @@ int object_data_is_libdata(Object *ob) /* *************** PROXY **************** */ /* when you make proxy, ensure the exposed layers are extern */ -void armature_set_id_extern(Object *ob) +static void armature_set_id_extern(Object *ob) { bArmature *arm= ob->data; bPoseChannel *pchan; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index bd0b1a5e36e..0de97b9c703 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -236,7 +236,7 @@ void packAll(Main *bmain, ReportList *reports) // attempt to create a function that generates an unique filename // this will work when all funtions in fileops.c understand relative filenames... -char *find_new_name(char *name) +static char *find_new_name(char *name) { char tempname[FILE_MAXDIR + FILE_MAXFILE]; char *newname; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index fb12cfe3147..72b580a4543 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2252,7 +2252,7 @@ void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys) BKE_ptcache_disk_to_mem(&pid); } -void psys_clear_temp_pointcache(ParticleSystem *psys) +static void psys_clear_temp_pointcache(ParticleSystem *psys) { if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0) return; diff --git a/source/blender/blenkernel/intern/sequence.c b/source/blender/blenkernel/intern/sequence.c index c6b714c3125..7f3e2789232 100644 --- a/source/blender/blenkernel/intern/sequence.c +++ b/source/blender/blenkernel/intern/sequence.c @@ -127,7 +127,7 @@ void new_tstripdata(Sequence *seq) /* free */ -void free_proxy_seq(Sequence *seq) +static void free_proxy_seq(Sequence *seq) { if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) { IMB_free_anim(seq->strip->proxy->anim); @@ -682,7 +682,7 @@ void clear_scene_in_allseqs(Scene *sce) } } -char *give_seqname_by_type(int type) +static char *give_seqname_by_type(int type) { switch(type) { case SEQ_META: return "Meta"; @@ -949,7 +949,7 @@ static TStripElem* alloc_tstripdata(int len, const char * name) return se; } -TStripElem *give_tstripelem(Sequence *seq, int cfra) +static TStripElem *give_tstripelem(Sequence *seq, int cfra) { TStripElem *se; int nr; @@ -1297,7 +1297,7 @@ static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int re se->ibuf = 0; } -void seq_proxy_rebuild(Scene *scene, Sequence * seq) +static void seq_proxy_rebuild(Scene *scene, Sequence * seq) { int cfra; float rsize = seq->strip->proxy->size; @@ -2623,7 +2623,7 @@ ImBuf *give_ibuf_seq(Scene *scene, int rectx, int recty, int cfra, int chanshown } /* check used when we need to change seq->blend_mode but not to effect or audio strips */ -int seq_can_blend(Sequence *seq) +static int seq_can_blend(Sequence *seq) { if (ELEM4(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE)) { return 1; @@ -2749,7 +2749,7 @@ static void *seq_prefetch_thread(void * This_) return 0; } -void seq_start_threads(Scene *scene) +static void seq_start_threads(Scene *scene) { int i; @@ -2782,7 +2782,7 @@ void seq_start_threads(Scene *scene) BLI_init_threads(0, 0, 0); } -void seq_stop_threads() +static void seq_stop_threads() { PrefetchThread *tslot; PrefetchQueueElem *e; @@ -2850,7 +2850,7 @@ void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown, pthread_mutex_unlock(&wakeup_lock); } -void seq_wait_for_prefetch_ready() +static void seq_wait_for_prefetch_ready() { PrefetchThread *tslot; @@ -2984,7 +2984,7 @@ static void free_anim_seq(Sequence *seq) } } -void free_imbuf_seq_except(Scene *scene, int cfra) +static void free_imbuf_seq_except(Scene *scene, int cfra) { Editing *ed= seq_give_editing(scene, FALSE); Sequence *seq; @@ -3178,7 +3178,7 @@ void free_imbuf_seq() } #endif -void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo) +static void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo) { /* force update of all sequences with this ipo, on ipo changes */ Editing *ed= seq_give_editing(scene, FALSE); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 6485e367b78..66aaa97af55 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -526,7 +526,7 @@ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int } } -void smokeModifier_freeDomain(SmokeModifierData *smd) +static void smokeModifier_freeDomain(SmokeModifierData *smd) { if(smd->domain) { @@ -550,7 +550,7 @@ void smokeModifier_freeDomain(SmokeModifierData *smd) } } -void smokeModifier_freeFlow(SmokeModifierData *smd) +static void smokeModifier_freeFlow(SmokeModifierData *smd) { if(smd->flow) { @@ -567,7 +567,7 @@ void smokeModifier_freeFlow(SmokeModifierData *smd) } } -void smokeModifier_freeCollision(SmokeModifierData *smd) +static void smokeModifier_freeCollision(SmokeModifierData *smd) { if(smd->coll) { @@ -741,7 +741,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd) } // forward decleration -void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct); +static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct); static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); static int get_lamp(Scene *scene, float *light) { @@ -1337,7 +1337,7 @@ static void get_cell(float *p0, int res[3], float dx, float *pos, int *cell, int } } -void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct) +static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct) { int x, y, z; float bv[6]; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index e7164dc4794..9e86dcbe491 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -613,7 +613,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex } /* essential functions -- start, append, end */ -void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) +static void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) { /* Handle to the output file */ AVFormatContext* of; diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 61d9cce1a58..48bbfc12370 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -329,7 +329,7 @@ static void sort(BVHNode **a0, int begin, int end, int axis) bvh_insertionsort(a, begin, end, axis); } } -void sort_along_axis(BVHTree *tree, int start, int end, int axis) +static void sort_along_axis(BVHTree *tree, int start, int end, int axis) { sort(tree->nodes, start, end, axis); } @@ -337,7 +337,7 @@ void sort_along_axis(BVHTree *tree, int start, int end, int axis) //after a call to this function you can expect one of: // every node to left of a[n] are smaller or equal to it // every node to the right of a[n] are greater or equal to it -int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){ +static int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){ int begin = _begin, end = _end, cut; while(end-begin > 3) { diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index 1f3a861ba6a..ccf79ed42dc 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -337,7 +337,7 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, KDTree return found; } -int range_compare(const void * a, const void * b) +static int range_compare(const void * a, const void * b) { const KDTreeNearest *kda = a; const KDTreeNearest *kdb = b; diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index 9e769e19674..339a7250295 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -4093,19 +4093,19 @@ void spheremap(float x, float y, float z, float *u, float *v) /* proposed api by ton and zr, not used yet */ #if 0 /* ***************** m1 = m2 ***************** */ -void cpy_m3_m3(float m1[][3], float m2[][3]) +static void cpy_m3_m3(float m1[][3], float m2[][3]) { memcpy(m1[0], m2[0], 9*sizeof(float)); } /* ***************** m1 = m2 ***************** */ -void cpy_m4_m4(float m1[][4], float m2[][4]) +static void cpy_m4_m4(float m1[][4], float m2[][4]) { memcpy(m1[0], m2[0], 16*sizeof(float)); } /* ***************** identity matrix ***************** */ -void ident_m4(float m[][4]) +static void ident_m4(float m[][4]) { m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0; @@ -4116,7 +4116,7 @@ void ident_m4(float m[][4]) } /* ***************** m1 = m2 (pre) * m3 (post) ***************** */ -void mul_m3_m3m3(float m1[][3], float m2[][3], float m3[][3]) +static void mul_m3_m3m3(float m1[][3], float m2[][3], float m3[][3]) { float m[3][3]; @@ -4136,7 +4136,7 @@ void mul_m3_m3m3(float m1[][3], float m2[][3], float m3[][3]) } /* ***************** m1 = m2 (pre) * m3 (post) ***************** */ -void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]) +static void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]) { float m[4][4]; @@ -4164,7 +4164,7 @@ void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4]) } /* ***************** m1 = inverse(m2) ***************** */ -void inv_m3_m3(float m1[][3], float m2[][3]) +static void inv_m3_m3(float m1[][3], float m2[][3]) { short a,b; float det; @@ -4187,7 +4187,7 @@ void inv_m3_m3(float m1[][3], float m2[][3]) } /* ***************** m1 = inverse(m2) ***************** */ -int inv_m4_m4(float inverse[][4], float mat[][4]) +static int inv_m4_m4(float inverse[][4], float mat[][4]) { int i, j, k; double temp; @@ -4240,7 +4240,7 @@ int inv_m4_m4(float inverse[][4], float mat[][4]) } /* ***************** v1 = v2 * mat ***************** */ -void mul_v3_v3m4(float *v1, float *v2, float mat[][4]) +static void mul_v3_v3m4(float *v1, float *v2, float mat[][4]) { float x, y; diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 985700efda1..cb5632df569 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -65,7 +65,7 @@ static FT_Library library; static FT_Error err; -void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) +static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) { // Blender struct Nurb *nu; @@ -275,7 +275,7 @@ void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) } } -int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) +static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) { // Freetype2 FT_Face face; diff --git a/source/blender/blenlib/intern/graph.c b/source/blender/blenlib/intern/graph.c index cc15c499290..49a3cad53f1 100644 --- a/source/blender/blenlib/intern/graph.c +++ b/source/blender/blenlib/intern/graph.c @@ -354,7 +354,7 @@ void BLI_ReflagSubgraph(BGraph *graph, int old_subgraph, int new_subgraph) /*************************************** CYCLE DETECTION ***********************************************/ -int detectCycle(BNode *node, BArc *src_arc) +static int detectCycle(BNode *node, BArc *src_arc) { int value = 0; @@ -520,7 +520,7 @@ void BLI_calcGraphLength(BGraph *graph) /********************************* SYMMETRY DETECTION **************************************************/ -void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit); +static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit); void BLI_mirrorAlongAxis(float v[3], float center[3], float axis[3]) { @@ -935,7 +935,7 @@ static void markdownSecondarySymmetry(BGraph *graph, BNode *node, int depth, int } } -void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit) +static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit) { int i; diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index 0bd30a69d05..66e9a65dba5 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -42,9 +42,9 @@ #endif /* local */ -float noise3_perlin(float vec[3]); -float turbulence_perlin(float *point, float lofreq, float hifreq); -float turbulencep(float noisesize, float x, float y, float z, int nr); +static float noise3_perlin(float vec[3]); +static float turbulence_perlin(float *point, float lofreq, float hifreq); +static float turbulencep(float noisesize, float x, float y, float z, int nr); #define HASHVEC(x,y,z) hashvectf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255] @@ -915,7 +915,7 @@ float g[512+2][3]= { r1 = r0 - 1.; -float noise3_perlin(float vec[3]) +static float noise3_perlin(float vec[3]) { int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; float rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v; @@ -976,7 +976,7 @@ float noise3_perlin(float vec[3]) return 1.5 * lerp(sz, c, d); /* interpolate in z */ } -float turbulence_perlin(float *point, float lofreq, float hifreq) +static float turbulence_perlin(float *point, float lofreq, float hifreq) { float freq, t, p[3]; @@ -1029,7 +1029,7 @@ float BLI_hnoisep(float noisesize, float x, float y, float z) return noise3_perlin(vec); } -float turbulencep(float noisesize, float x, float y, float z, int nr) +static float turbulencep(float noisesize, float x, float y, float z, int nr) { float vec[3]; diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index ed3e07b7f7e..ce9f9adeb90 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -316,7 +316,7 @@ typedef struct WorkParam { int index; } WorkParam; -void *exec_work_fnct(void *v_param) +static void *exec_work_fnct(void *v_param) { WorkParam *p = (WorkParam*)v_param; void *value; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index e376d3125e3..99090b62938 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -38,7 +38,7 @@ #else -void rna_def_action_group(BlenderRNA *brna) +static void rna_def_action_group(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -76,7 +76,7 @@ void rna_def_action_group(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Custom Color", "Index of custom color set."); } -void rna_def_action(BlenderRNA *brna) +static void rna_def_action(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index e4bea893992..a8d3a6edaae 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -93,7 +93,7 @@ static void rna_ksPath_RnaPath_set(PointerRNA *ptr, const char *value) #else -void rna_def_keyingset_path(BlenderRNA *brna) +static void rna_def_keyingset_path(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -132,7 +132,7 @@ void rna_def_keyingset_path(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Entire Array", "When an 'array/vector' type is chosen (Location, Rotation, Color, etc.), entire array is to be used."); } -void rna_def_keyingset(BlenderRNA *brna) +static void rna_def_keyingset(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 57eb3c1de4a..dcf89b7ac1e 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -520,7 +520,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) RNA_define_verify_sdna(1); } -void rna_def_armature(BlenderRNA *brna) +static void rna_def_armature(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 612863e1ab9..70daa3690da 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -89,7 +89,7 @@ static void rna_Brush_active_texture_set(PointerRNA *ptr, PointerRNA value) #else -void rna_def_brush(BlenderRNA *brna) +static void rna_def_brush(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 815023ee315..04d56eb666e 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -89,7 +89,7 @@ EnumPropertyItem space_object_items[] = { #include "ED_object.h" -StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) +static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) { bConstraint *con= (bConstraint*)ptr->data; diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 121812c189c..4a5af56d64a 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -66,7 +66,7 @@ EnumPropertyItem beztriple_keyframe_type_items[] = { #include "WM_api.h" -StructRNA *rna_Curve_refine(PointerRNA *ptr) +static StructRNA *rna_Curve_refine(PointerRNA *ptr) { Curve *cu= (Curve*)ptr->data; short obtype= curve_type(cu); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 6bca237e02f..0b54d4a8e14 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -66,7 +66,7 @@ void rna_addtail(ListBase *listbase, void *vlink) listbase->last = link; } -void rna_remlink(ListBase *listbase, void *vlink) +static void rna_remlink(ListBase *listbase, void *vlink) { Link *link= vlink; @@ -155,7 +155,7 @@ PropertyDefRNA *rna_find_struct_property_def(StructRNA *srna, PropertyRNA *prop) return NULL; } -PropertyDefRNA *rna_find_property_def(PropertyRNA *prop) +static PropertyDefRNA *rna_find_property_def(PropertyRNA *prop) { PropertyDefRNA *dprop; @@ -239,7 +239,7 @@ PropertyDefRNA *rna_find_parameter_def(PropertyRNA *parm) return NULL; } -ContainerDefRNA *rna_find_container_def(ContainerRNA *cont) +static ContainerDefRNA *rna_find_container_def(ContainerRNA *cont) { StructDefRNA *ds; FunctionDefRNA *dfunc; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index bafe83f1812..2802665c639 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -52,7 +52,7 @@ EnumPropertyItem fmodifier_type_items[] = { /* --------- */ -StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr) +static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr) { FModifier *fcm= (FModifier *)ptr->data; @@ -460,7 +460,7 @@ static void rna_def_fmodifier_noise(BlenderRNA *brna) /* --------- */ -void rna_def_fmodifier(BlenderRNA *brna) +static void rna_def_fmodifier(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -510,7 +510,7 @@ void rna_def_fmodifier(BlenderRNA *brna) /* *********************** */ -void rna_def_drivertarget(BlenderRNA *brna) +static void rna_def_drivertarget(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -536,7 +536,7 @@ void rna_def_drivertarget(BlenderRNA *brna) RNA_def_property_ui_text(prop, "RNA Array Index", "Index to the specific property used (if applicable)"); } -void rna_def_channeldriver(BlenderRNA *brna) +static void rna_def_channeldriver(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -590,7 +590,7 @@ static void rna_def_fpoint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Point", "Point coordinates"); } -void rna_def_fcurve(BlenderRNA *brna) +static void rna_def_fcurve(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 15f5ef7884f..2a4ff112c3c 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -48,7 +48,7 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr) return 1; } -void rna_GPencilLayer_active_set(PointerRNA *ptr, int value) +static void rna_GPencilLayer_active_set(PointerRNA *ptr, int value) { bGPdata *gpd= ptr->id.data; bGPDlayer *gpl= ptr->data; @@ -68,7 +68,7 @@ void rna_GPencilLayer_active_set(PointerRNA *ptr, int value) #else -void rna_def_gpencil_stroke_point(BlenderRNA *brna) +static void rna_def_gpencil_stroke_point(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -88,7 +88,7 @@ void rna_def_gpencil_stroke_point(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it."); } -void rna_def_gpencil_stroke(BlenderRNA *brna) +static void rna_def_gpencil_stroke(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -107,7 +107,7 @@ void rna_def_gpencil_stroke(BlenderRNA *brna) // TODO... } -void rna_def_gpencil_frame(BlenderRNA *brna) +static void rna_def_gpencil_frame(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -138,7 +138,7 @@ void rna_def_gpencil_frame(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Selected", "Frame is selected for editing in the DopeSheet."); } -void rna_def_gpencil_layer(BlenderRNA *brna) +static void rna_def_gpencil_layer(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -215,7 +215,7 @@ void rna_def_gpencil_layer(BlenderRNA *brna) } -void rna_def_gpencil_data(BlenderRNA *brna) +static void rna_def_gpencil_data(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index 31bc6ccc74b..dddc2062f07 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -33,7 +33,7 @@ #ifdef RNA_RUNTIME -PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter) +static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal= iter->internal; diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 6d56b2b00f9..d0a3789b9d8 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -40,14 +40,14 @@ #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); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index cd1159bc138..e23333713c4 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -212,7 +212,7 @@ static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, int value) ma->ramp_spec= add_colorband(0); } -void rna_Material_use_nodes_set(PointerRNA *ptr, int value) +static void rna_Material_use_nodes_set(PointerRNA *ptr, int value) { Material *ma= (Material*)ptr->data; @@ -1267,7 +1267,7 @@ static void rna_def_material_sss(BlenderRNA *brna) RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); } -void rna_def_material_specularity(StructRNA *srna) +static void rna_def_material_specularity(StructRNA *srna) { PropertyRNA *prop; @@ -1327,7 +1327,7 @@ void rna_def_material_specularity(StructRNA *srna) RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); } -void rna_def_material_strand(BlenderRNA *brna) +static void rna_def_material_strand(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -1394,7 +1394,7 @@ void rna_def_material_strand(BlenderRNA *brna) RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); } -void rna_def_material_physics(BlenderRNA *brna) +static void rna_def_material_physics(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c index f3160a7bb18..1a4e4da886b 100644 --- a/source/blender/makesrna/intern/rna_meta.c +++ b/source/blender/makesrna/intern/rna_meta.c @@ -67,7 +67,7 @@ static void rna_MetaBall_update_data(bContext *C, PointerRNA *ptr) #else -void rna_def_metaelement(BlenderRNA *brna) +static void rna_def_metaelement(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -143,7 +143,7 @@ void rna_def_metaelement(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_MetaBall_update_data"); } -void rna_def_metaball(BlenderRNA *brna) +static void rna_def_metaball(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 690a198f12c..20d1a898303 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -47,7 +47,7 @@ /* temp constant defined for these funcs only... */ #define NLASTRIP_MIN_LEN_THRESH 0.1f -void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value) +static void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value) { NlaStrip *data= (NlaStrip *)ptr->data; @@ -280,7 +280,7 @@ EnumPropertyItem nla_mode_extend_items[] = { {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame."}, {0, NULL, 0, NULL, NULL}}; -void rna_def_nlastrip(BlenderRNA *brna) +static void rna_def_nlastrip(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -433,7 +433,7 @@ void rna_def_nlastrip(BlenderRNA *brna) // - sync length } -void rna_def_nlatrack(BlenderRNA *brna) +static void rna_def_nlatrack(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 3fd358a1c16..99f61c7a724 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -39,7 +39,7 @@ #ifdef RNA_RUNTIME -StructRNA *rna_Node_refine(struct PointerRNA *ptr) +static StructRNA *rna_Node_refine(struct PointerRNA *ptr) { bNode *node = (bNode*)ptr->data; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 3541bc2b1b0..6545898c1ab 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -43,7 +43,7 @@ #include "DNA_scene_types.h" /* copied from init_render_mesh (render code) */ -Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) +static Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) { CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; DerivedMesh *dm; diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 3a03e7a624d..b568fb38dfb 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -98,7 +98,7 @@ static void rna_BoneGroup_color_set_set(PointerRNA *ptr, int value) } } -IDProperty *rna_PoseChannel_idproperties(PointerRNA *ptr, int create) +static IDProperty *rna_PoseChannel_idproperties(PointerRNA *ptr, int create) { bPoseChannel *pchan= ptr->data; @@ -323,7 +323,7 @@ static void rna_Pose_active_bone_group_index_range(PointerRNA *ptr, int *min, in *max= MAX2(0, *max); } -void rna_pose_bgroup_name_index_get(PointerRNA *ptr, char *value, int index) +static void rna_pose_bgroup_name_index_get(PointerRNA *ptr, char *value, int index) { bPose *pose= (bPose*)ptr->data; bActionGroup *grp; @@ -334,7 +334,7 @@ void rna_pose_bgroup_name_index_get(PointerRNA *ptr, char *value, int index) else BLI_strncpy(value, "", sizeof(grp->name)); // XXX if invalid pointer, won't this crash? } -int rna_pose_bgroup_name_index_length(PointerRNA *ptr, int index) +static int rna_pose_bgroup_name_index_length(PointerRNA *ptr, int index) { bPose *pose= (bPose*)ptr->data; bActionGroup *grp; @@ -343,7 +343,7 @@ int rna_pose_bgroup_name_index_length(PointerRNA *ptr, int index) return (grp)? strlen(grp->name): 0; } -void rna_pose_bgroup_name_index_set(PointerRNA *ptr, const char *value, short *index) +static void rna_pose_bgroup_name_index_set(PointerRNA *ptr, const char *value, short *index) { bPose *pose= (bPose*)ptr->data; bActionGroup *grp; @@ -359,7 +359,7 @@ void rna_pose_bgroup_name_index_set(PointerRNA *ptr, const char *value, short *i *index= 0; } -void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen) +static void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen) { bPose *pose= (bPose*)ptr->data; bActionGroup *grp; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 965796c6d5b..15329b126d3 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -70,7 +70,7 @@ EnumPropertyItem prop_mode_items[] ={ #include "RE_pipeline.h" -PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter) +static PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal= iter->internal; @@ -371,7 +371,7 @@ static void rna_SceneRenderLayer_pass_update(bContext *C, PointerRNA *ptr) ntreeCompositForceHidden(scene->nodetree, scene); } -void rna_Scene_use_nodes_set(PointerRNA *ptr, int value) +static void rna_Scene_use_nodes_set(PointerRNA *ptr, int value) { Scene *scene= (Scene*)ptr->data; @@ -784,7 +784,7 @@ void rna_def_render_layer_common(StructRNA *srna, int scene) else RNA_def_property_clear_flag(prop, PROP_EDITABLE); } -void rna_def_scene_game_data(BlenderRNA *brna) +static void rna_def_scene_game_data(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index 53bd230870f..a5d76fdb039 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -73,7 +73,7 @@ static StructRNA* rna_Sensor_refine(struct PointerRNA *ptr) #else -void rna_def_sensor(BlenderRNA *brna) +static void rna_def_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -129,14 +129,14 @@ void rna_def_sensor(BlenderRNA *brna) RNA_def_property_range(prop, 0, 10000); } -void rna_def_always_sensor(BlenderRNA *brna) +static void rna_def_always_sensor(BlenderRNA *brna) { StructRNA *srna; srna= RNA_def_struct(brna, "AlwaysSensor", "Sensor"); RNA_def_struct_ui_text(srna, "Always Sensor", "Sensor to generate continuous pulses."); } -void rna_def_near_sensor(BlenderRNA *brna) +static void rna_def_near_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -160,7 +160,7 @@ void rna_def_near_sensor(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 10000.0f); } -void rna_def_mouse_sensor(BlenderRNA *brna) +static void rna_def_mouse_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -186,7 +186,7 @@ void rna_def_mouse_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mouse Event", "Specify the type of event this mouse sensor should trigger on."); } -void rna_def_touch_sensor(BlenderRNA *brna) +static void rna_def_touch_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -201,7 +201,7 @@ void rna_def_touch_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Material", "Only look for floors with this material."); } -void rna_def_keyboard_sensor(BlenderRNA *brna) +static void rna_def_keyboard_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -240,7 +240,7 @@ void rna_def_keyboard_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "All Keys", "Trigger this sensor on any keystroke."); } -void rna_def_property_sensor(BlenderRNA *brna) +static void rna_def_property_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -278,7 +278,7 @@ void rna_def_property_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Maximum Value", "Specify maximum value in Interval type."); } -void rna_def_actuator_sensor(BlenderRNA *brna) +static void rna_def_actuator_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -292,7 +292,7 @@ void rna_def_actuator_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Actuator", "Actuator name, actuator active state modifications will be detected."); } -void rna_def_delay_sensor(BlenderRNA *brna) +static void rna_def_delay_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -314,7 +314,7 @@ void rna_def_delay_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Repeat", "Toggle repeat option. If selected, the sensor restarts after Delay+Dur logic tics."); } -void rna_def_collision_sensor(BlenderRNA *brna) +static void rna_def_collision_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -341,7 +341,7 @@ void rna_def_collision_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Collision Type", "Toggle collision on material or property."); } -void rna_def_radar_sensor(BlenderRNA *brna) +static void rna_def_radar_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -376,7 +376,7 @@ void rna_def_radar_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Distance", "Depth of the radar cone."); } -void rna_def_random_sensor(BlenderRNA *brna) +static void rna_def_random_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -390,7 +390,7 @@ void rna_def_random_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Seed", "Initial seed of the generator. (Choose 0 for not random)."); } -void rna_def_ray_sensor(BlenderRNA *brna) +static void rna_def_ray_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -438,7 +438,7 @@ void rna_def_ray_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Axis", "Specify along which axis the ray is cast."); } -void rna_def_message_sensor(BlenderRNA *brna) +static void rna_def_message_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -451,7 +451,7 @@ void rna_def_message_sensor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Subject", "Optional subject filter: only accept messages with this subject, or empty for all."); } -void rna_def_joystick_sensor(BlenderRNA *brna) +static void rna_def_joystick_sensor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index 9f016f73694..4e12aab853e 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -514,7 +514,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_function_return(func, RNA_def_pointer(func, "elem", "SequenceElement", "", "strip element of the current frame")); } -void rna_def_editor(BlenderRNA *brna) +static void rna_def_editor(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 542f6e2aeda..bb01ab9a9c7 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -211,7 +211,7 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *C, P /* Space Text Editor */ -void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) +static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) { SpaceText *st= (SpaceText*)(ptr->data); @@ -219,7 +219,7 @@ void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) st->left= 0; } -void rna_SpaceTextEditor_text_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceTextEditor_text_set(PointerRNA *ptr, PointerRNA value) { SpaceText *st= (SpaceText*)(ptr->data); @@ -227,7 +227,7 @@ void rna_SpaceTextEditor_text_set(PointerRNA *ptr, PointerRNA value) st->top= 0; } -void rna_SpaceFileBrowser_params_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceFileBrowser_params_set(PointerRNA *ptr, PointerRNA value) { SpaceFile *sfile= (SpaceFile*)(ptr->data); @@ -236,7 +236,7 @@ void rna_SpaceFileBrowser_params_set(PointerRNA *ptr, PointerRNA value) /* Space Properties */ -StructRNA *rna_SpaceProperties_pin_id_typef(PointerRNA *ptr) +static StructRNA *rna_SpaceProperties_pin_id_typef(PointerRNA *ptr) { SpaceButs *sbuts= (SpaceButs*)(ptr->data); @@ -246,7 +246,7 @@ StructRNA *rna_SpaceProperties_pin_id_typef(PointerRNA *ptr) return &RNA_ID; } -void rna_SpaceProperties_align_set(PointerRNA *ptr, int value) +static void rna_SpaceProperties_align_set(PointerRNA *ptr, int value) { SpaceButs *sbuts= (SpaceButs*)(ptr->data); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index ce65dc37e5b..7a81138a3be 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -55,7 +55,7 @@ static EnumPropertyItem texture_filter_items[] = { #include "BKE_texture.h" #include "ED_node.h" -StructRNA *rna_Texture_refine(struct PointerRNA *ptr) +static StructRNA *rna_Texture_refine(struct PointerRNA *ptr) { Tex *tex= (Tex*)ptr->data; @@ -202,7 +202,7 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value) tex->coba= add_colorband(0); } -void rna_Texture_use_nodes_set(PointerRNA *ptr, int v) +static void rna_Texture_use_nodes_set(PointerRNA *ptr, int v) { Tex *tex= (Tex*)ptr->data; diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index af3ac4a0a82..53532e3f383 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -197,7 +197,7 @@ static StructRNA *rna_OperatorProperties_refine(PointerRNA *ptr) return ptr->type; } -IDProperty *rna_OperatorProperties_idproperties(PointerRNA *ptr, int create) +static IDProperty *rna_OperatorProperties_idproperties(PointerRNA *ptr, int create) { if(create && !ptr->data) { IDPropertyTemplate val = {0}; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ad490bb599a..86a02e2731a 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -747,7 +747,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* op->poll */ -int wm_search_menu_poll(bContext *C) +static int wm_search_menu_poll(bContext *C) { if(CTX_wm_window(C)==NULL) return 0; if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_CONSOLE) return 0; // XXX - so we can use the shortcut in the console -- cgit v1.2.3 From bee18c57d4b674282bf8d51ec0491a79e6b13faa Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 14 Sep 2009 17:13:58 +0000 Subject: fix warning --- source/blender/python/generic/Mathutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c index 32262276d0a..d354aea6614 100644 --- a/source/blender/python/generic/Mathutils.c +++ b/source/blender/python/generic/Mathutils.c @@ -437,7 +437,7 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) mat[8] = 1.0f; } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { //arbitrary rotation - AxisAngleToMat3(vec->vec, angle, (float *)mat); + AxisAngleToMat3(vec->vec, angle, (float (*)[3])mat); } else { PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); -- cgit v1.2.3 From c6107e0c7602db46ee535542a205d1afcccaebfb Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 17:22:51 +0000 Subject: Smoke: * Only simulate smoke when starting from startframe --- source/blender/blenkernel/intern/smoke.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 66aaa97af55..99d4176c937 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1123,17 +1123,22 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM cache_wt = sds->point_cache[1]; BKE_ptcache_id_from_smoke_turbulence(&pid_wt, ob, smd); + if(!smd->domain->fluid) + { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + BKE_ptcache_id_reset(scene, &pid_wt, PTCACHE_RESET_OUTDATED); + } + if(framenr < startframe) return; if(framenr > endframe) return; - if(!smd->domain->fluid) - { - BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - BKE_ptcache_id_reset(scene, &pid_wt, PTCACHE_RESET_OUTDATED); - } + if(!smd->domain->fluid && (framenr != startframe)) + return; + + // printf("startframe: %d, framenr: %d\n", startframe, framenr); if(!smokeModifier_init(smd, ob, scene, dm)) { -- cgit v1.2.3 From 725c30f6063354182628e4adbb563eadb4980222 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 19:12:29 +0000 Subject: 2.5 Bugfixes #19345: can't get out of grayed out pointer field. #19342: item_pointerR fields can't be cleared with one item. #19341: fix hanging tooltips when manipulating regions. #19339: context panel still allowed tabbing, but it has no header. #19334: editing SSS settings crashed previewrender. #19330: object mode could not be switched on from the header menu. --- source/blender/blenkernel/intern/material.c | 6 ++-- source/blender/blenloader/intern/readfile.c | 9 ++++++ source/blender/editors/include/ED_screen.h | 1 + .../blender/editors/interface/interface_handlers.c | 32 ++++++++++++++-------- source/blender/editors/interface/interface_panel.c | 1 + .../blender/editors/interface/interface_regions.c | 2 +- source/blender/editors/object/object_edit.c | 19 ++++++------- source/blender/editors/screen/area.c | 13 +++++++++ source/blender/editors/screen/screen_ops.c | 16 ++++++----- source/blender/editors/space_file/file_ops.c | 10 ++----- source/blender/editors/space_graph/graph_buttons.c | 10 ++----- source/blender/editors/space_image/image_buttons.c | 10 ++----- source/blender/editors/space_logic/logic_buttons.c | 10 ++----- source/blender/editors/space_nla/nla_buttons.c | 10 ++----- .../editors/space_sequencer/sequencer_buttons.c | 10 ++----- source/blender/editors/space_text/text_header.c | 11 +------- source/blender/editors/space_view3d/space_view3d.c | 2 ++ .../blender/editors/space_view3d/view3d_buttons.c | 10 ++----- source/blender/editors/space_view3d/view3d_snap.c | 12 ++++---- .../blender/editors/space_view3d/view3d_toolbar.c | 10 ++----- source/blender/render/intern/source/pipeline.c | 2 +- source/blender/render/intern/source/sss.c | 13 ++++++--- 22 files changed, 108 insertions(+), 111 deletions(-) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index e6f9ac2f404..1667bd97102 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -159,9 +159,9 @@ void init_material(Material *ma) ma->sss_radius[0]= 1.0f; ma->sss_radius[1]= 1.0f; ma->sss_radius[2]= 1.0f; - ma->sss_col[0]= 0.8f; - ma->sss_col[1]= 0.8f; - ma->sss_col[2]= 0.8f; + ma->sss_col[0]= 1.0f; + ma->sss_col[1]= 1.0f; + ma->sss_col[2]= 1.0f; ma->sss_error= 0.05f; ma->sss_scale= 0.1f; ma->sss_ior= 1.3f; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c2d745bfc8e..d0264002214 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4861,6 +4861,10 @@ static void view3d_split_250(View3D *v3d, ListBase *regions) QUATCOPY(rv3d->viewquat, v3d->viewquat); } } + + /* this was not initialized correct always */ + if(v3d->twtype == 0) + v3d->twtype= V3D_MANIP_TRANSLATE; } static void direct_link_screen(FileData *fd, bScreen *sc) @@ -9687,6 +9691,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* put 2.50 compatibility code here until next subversion bump */ { + Scene *sce; + + for(sce = main->scene.first; sce; sce = sce->id.next) + if(sce->unit.scale_length == 0.0f) + sce->unit.scale_length= 1.0f; } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 697565184f3..63b6a067389 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -58,6 +58,7 @@ void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar); void ED_region_panels(const struct bContext *C, struct ARegion *ar, int vertical, char *context, int contextnr); void ED_region_header_init(struct ARegion *ar); void ED_region_header(const struct bContext *C, struct ARegion *ar); +void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar); void region_scissor_winrct(struct ARegion *ar, struct rcti *winrct); /* spaces */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 259ccba6b89..466c1d08ba3 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1440,16 +1440,20 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa for(but= actbut->next; but; but= but->next) { if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { - data->postbut= but; - data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; - return; + if(!(but->flag & UI_BUT_DISABLED)) { + data->postbut= but; + data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; + return; + } } } for(but= block->buttons.first; but!=actbut; but= but->next) { if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { - data->postbut= but; - data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; - return; + if(!(but->flag & UI_BUT_DISABLED)) { + data->postbut= but; + data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; + return; + } } } } @@ -1464,16 +1468,20 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa for(but= actbut->prev; but; but= but->prev) { if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { - data->postbut= but; - data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; - return; + if(!(but->flag & UI_BUT_DISABLED)) { + data->postbut= but; + data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; + return; + } } } for(but= block->buttons.last; but!=actbut; but= but->prev) { if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { - data->postbut= but; - data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; - return; + if(!(but->flag & UI_BUT_DISABLED)) { + data->postbut= but; + data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; + return; + } } } } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 05001109b53..776122380bf 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -990,6 +990,7 @@ static void test_add_new_tabs(ARegion *ar) } if(pasel==NULL || palap==NULL) return; + if(palap->type && palap->type->flag & PNL_NO_HEADER) return; /* the overlapped panel becomes a tab */ palap->paneltab= pasel; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 1d911fef418..dfcdea59f68 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -758,7 +758,7 @@ void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, int reset) data->active= a+1; if(cpoin) cpoin[0]= '|'; } - if(data->items.totitem==1) + if(data->items.totitem==1 && but->editstr[0]) data->active= 1; } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index e5a8df8cb26..c734a7c606d 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1957,29 +1957,26 @@ static int object_mode_set_compat(bContext *C, wmOperator *op, Object *ob) ObjectMode mode = RNA_enum_get(op->ptr, "mode"); if(ob) { + if(mode == OB_MODE_OBJECT) + return 1; + switch(ob->type) { - case OB_EMPTY: - case OB_LAMP: - case OB_CAMERA: - if(mode & OB_MODE_OBJECT) - return 1; - return 0; case OB_MESH: - if(mode & ( OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT|OB_MODE_PARTICLE_EDIT)) + if(mode & (OB_MODE_EDIT|OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT|OB_MODE_PARTICLE_EDIT)) return 1; return 0; case OB_CURVE: case OB_SURF: case OB_FONT: case OB_MBALL: - if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT)) + if(mode & (OB_MODE_EDIT)) return 1; return 0; case OB_LATTICE: - if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT)) + if(mode & (OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT)) return 1; case OB_ARMATURE: - if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_POSE)) + if(mode & (OB_MODE_EDIT|OB_MODE_POSE)) return 1; } } @@ -2036,7 +2033,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - prop= RNA_def_enum(ot->srna, "mode", object_mode_items, 0, "Mode", ""); + prop= RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", ""); RNA_def_enum_funcs(prop, object_mode_set_itemsf); RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 81f06611c39..8940f560677 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -916,6 +916,19 @@ void ED_region_init(bContext *C, ARegion *ar) } +void ED_region_toggle_hidden(bContext *C, ARegion *ar) +{ + ScrArea *sa= CTX_wm_area(C); + + ar->flag ^= RGN_FLAG_HIDDEN; + ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ + + if(ar->flag & RGN_FLAG_HIDDEN) + WM_event_remove_handlers(C, &ar->handlers); + + ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); + ED_area_tag_redraw(sa); +} /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */ /* area vertices were set */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index dba882200ce..f32b11812cf 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1320,10 +1320,11 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) CLAMP(rmd->ar->type->minsizex, 0, 1000); if(rmd->ar->type->minsizex < 24) { rmd->ar->type->minsizex= rmd->origval; - rmd->ar->flag |= RGN_FLAG_HIDDEN; + if(!(rmd->ar->flag & RGN_FLAG_HIDDEN)) + ED_region_toggle_hidden(C, rmd->ar); } - else - rmd->ar->flag &= ~RGN_FLAG_HIDDEN; + else if(rmd->ar->flag & RGN_FLAG_HIDDEN) + ED_region_toggle_hidden(C, rmd->ar); } else { delta= event->y - rmd->origy; @@ -1332,10 +1333,11 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) CLAMP(rmd->ar->type->minsizey, 0, 1000); if(rmd->ar->type->minsizey < 24) { rmd->ar->type->minsizey= rmd->origval; - rmd->ar->flag |= RGN_FLAG_HIDDEN; + if(!(rmd->ar->flag & RGN_FLAG_HIDDEN)) + ED_region_toggle_hidden(C, rmd->ar); } - else - rmd->ar->flag &= ~RGN_FLAG_HIDDEN; + else if(rmd->ar->flag & RGN_FLAG_HIDDEN) + ED_region_toggle_hidden(C, rmd->ar); } WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); @@ -1346,7 +1348,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) if(event->val==0) { if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) { - rmd->ar->flag ^= RGN_FLAG_HIDDEN; + ED_region_toggle_hidden(C, rmd->ar); WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } MEM_freeN(op->customdata); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 9705a36fc75..d2d1d11ec5c 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -855,13 +855,9 @@ int file_bookmark_toggle_exec(bContext *C, wmOperator *unused) ScrArea *sa= CTX_wm_area(C); ARegion *ar= file_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index fb995285ab7..9aa02b45950 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -427,13 +427,9 @@ static int graph_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= graph_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 21fccdc65f8..647b9a4b51f 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1452,13 +1452,9 @@ static int image_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= image_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c index 58c1eddb6c1..304c3601cdd 100644 --- a/source/blender/editors/space_logic/logic_buttons.c +++ b/source/blender/editors/space_logic/logic_buttons.c @@ -124,13 +124,9 @@ static int logic_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= logic_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 8532d78aa06..a5ba63fd15d 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -458,13 +458,9 @@ static int nla_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= nla_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c index 789843f5490..72cbacd9b6d 100644 --- a/source/blender/editors/space_sequencer/sequencer_buttons.c +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -112,13 +112,9 @@ static int sequencer_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= sequencer_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c index 089436cfcf9..d0a02f558e1 100644 --- a/source/blender/editors/space_text/text_header.c +++ b/source/blender/editors/space_text/text_header.c @@ -186,15 +186,6 @@ ARegion *text_has_properties_region(ScrArea *sa) return arnew; } -void text_toggle_properties_region(bContext *C, ScrArea *sa, ARegion *ar) -{ - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); -} - static int properties_poll(bContext *C) { return (CTX_wm_space_text(C) != NULL); @@ -206,7 +197,7 @@ static int properties_exec(bContext *C, wmOperator *op) ARegion *ar= text_has_properties_region(sa); if(ar) - text_toggle_properties_region(C, sa, ar); + ED_region_toggle_hidden(C, ar); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 2250c2e7718..05bf1c80b43 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -190,6 +190,8 @@ static SpaceLink *view3d_new(const bContext *C) v3d->lens= 35.0f; v3d->near= 0.01f; v3d->far= 500.0f; + + v3d->twtype= V3D_MANIP_TRANSLATE; /* header */ ar= MEM_callocN(sizeof(ARegion), "header for view3d"); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 54a8c375e69..1ff5dca7307 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1458,13 +1458,9 @@ static int view3d_properties(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= view3d_has_buttons_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index b4b54cd1d88..767f18649fa 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -1122,13 +1122,13 @@ static int snap_menu_invoke(bContext *C, wmOperator *unused, wmEvent *event) uiPopupMenu *pup= uiPupMenuBegin(C, "Snap", 0); uiLayout *layout= uiPupMenuLayout(pup); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_grid"); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_cursor"); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_center"); + uiItemO(layout, "Selected to Grid", 0, "VIEW3D_OT_snap_selected_to_grid"); + uiItemO(layout, "Selected to Cursor", 0, "VIEW3D_OT_snap_selected_to_cursor"); + uiItemO(layout, "Selected to Center", 0, "VIEW3D_OT_snap_selected_to_center"); uiItemS(layout); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_selected"); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_grid"); - uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_active"); + uiItemO(layout, "Cursor to Selected", 0, "VIEW3D_OT_snap_cursor_to_selected"); + uiItemO(layout, "Cursor to Grid", 0, "VIEW3D_OT_snap_cursor_to_grid"); + uiItemO(layout, "Cursor to Active", 0, "VIEW3D_OT_snap_cursor_to_active"); uiPupMenuEnd(C, pup); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 58248f675da..46341f53c26 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -309,13 +309,9 @@ static int view3d_toolbar(bContext *C, wmOperator *op) ScrArea *sa= CTX_wm_area(C); ARegion *ar= view3d_has_tools_region(sa); - if(ar) { - ar->flag ^= RGN_FLAG_HIDDEN; - ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ - - ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); - } + if(ar) + ED_region_toggle_hidden(C, ar); + return OPERATOR_FINISHED; } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index a6b089c6029..8ef52991ca2 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1526,7 +1526,7 @@ static void threaded_tile_processor(Render *re) if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) { RE_FreeRenderResult(re->result); - if(re->sss_points) + if(re->sss_points && render_display_draw_enabled(re)) re->result= new_render_result(re, &re->disprect, 0, 0); else if(re->r.scemode & R_FULL_SAMPLE) re->result= new_full_sample_buffers_exr(re); diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index bd022e768f8..29f4d7729fe 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -872,12 +872,17 @@ static void sss_create_tree_mat(Render *re, Material *mat) re->sss_points= &points; re->sss_mat= mat; re->i.partsdone= 0; - re->result= NULL; - RE_TileProcessor(re, 0, !(re->r.mode & R_PREVIEWBUTS)); - RE_FreeRenderResult(re->result); + if(!(re->r.scemode & R_PREVIEWBUTS)) + re->result= NULL; + + RE_TileProcessor(re, 0, 1); + + if(!(re->r.scemode & R_PREVIEWBUTS)) { + RE_FreeRenderResult(re->result); + re->result= rr; + } - re->result= rr; re->i.partsdone= partsdone; re->sss_mat= NULL; re->sss_points= NULL; -- cgit v1.2.3 From f302ebeb670f021d627388ab7f0e1fc682183250 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 19:49:40 +0000 Subject: 2.5 Bugfixes #19343: vertex paint blur was not working. shared vcol was disabled for speed, but blurring still needs it. Also fixed brushes with size > 64 not working correct. #19314: non-zbuffer selection did not work with background image, drawing it made the WM matrix go out of sync. Forgot to mention these in previous commit: * Manipulator type was not properly initialized, .B.blend update helps, but still needed version patch & correct setting for new space. * Added a utility function for the toggling region hide, instead of duplicating the code. * SSS preview render preprocessing pass now also uses multiple threads. * Added version patch for unit scale, was still 0.0. --- source/blender/editors/sculpt_paint/paint_vertex.c | 8 +++++++- source/blender/editors/space_view3d/view3d_draw.c | 14 ++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 25ff57ca87f..2375e4e70ec 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -710,7 +710,9 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x if(totface+4>=MAXINDEX) return 0; - if(size>64.0) size= 64.0; + /* brecht: disabled this because it obviously failes for + brushes with size > 64, why is this here? */ + /*if(size>64.0) size= 64.0;*/ ibuf= view3d_read_backbuf(vc, x-size, y-size, x+size, y+size); if(ibuf) { @@ -1732,6 +1734,10 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } Mat4SwapMat4(vc->rv3d->persmat, mat); + + /* was disabled because it is slow, but necessary for blur */ + if(vp->mode == VP_BLUR) + do_shared_vertexcol(me); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 918aebda8e1..f8584b14e2b 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1416,12 +1416,9 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - -// glaDefine2DArea(&ar->winrct); + /* need to use wm push/pop matrix because ED_region_pixelspace + uses the wm functions too, otherwise gets out of sync */ + wmPushMatrix(); ED_region_pixelspace(ar); glEnable(GL_BLEND); @@ -1433,10 +1430,7 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) glPixelZoom(1.0, 1.0); glPixelTransferf(GL_ALPHA_SCALE, 1.0f); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + wmPopMatrix(); glDisable(GL_BLEND); if(v3d->zbuf) glEnable(GL_DEPTH_TEST); -- cgit v1.2.3 From 1b2344a1f1c2d1a8e0a914c1eb46bf4e36323c66 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Mon, 14 Sep 2009 20:17:56 +0000 Subject: Also set utf8 encoded hint for window title. --- intern/ghost/intern/GHOST_WindowX11.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 88ae8afd0ce..3aff9d64a17 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -294,7 +294,7 @@ GHOST_WindowX11( } // Create some hints for the window manager on how - // we want this window treated. + // we want this window treated. XSizeHints * xsizehints = XAllocSizeHints(); xsizehints->flags = USPosition | USSize; @@ -514,7 +514,7 @@ GHOST_WindowX11:: getXWindow( ){ return m_window; -} +} bool GHOST_WindowX11:: @@ -528,7 +528,17 @@ GHOST_WindowX11:: setTitle( const STR_String& title ){ + Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0); + Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0); + XChangeProperty(m_display, m_window, + name, utf8str, 8, PropModeReplace, + (const unsigned char*) title.ReadPtr(), + strlen(title.ReadPtr())); + +// This should convert to valid x11 string +// and getTitle would need matching change XStoreName(m_display,m_window,title); + XFlush(m_display); } -- cgit v1.2.3 From be69305d85f09079c80df23b30c7a7c8f3663ab6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 14 Sep 2009 20:48:05 +0000 Subject: 2.5 Bugfixes #19302: the spin operator did not redo correct when changing properties. Actually the problem was somewhere else, the search menu always did an unnecessary undo push, which conflicted with an operator undo push with the same name. Only in the case of "Spin" was this noticed, because it's name is so short and you actually type it completely. #19328: swapping areas could crash when dragging mouse outside the window. Attempted fix for #19331, #19335 as well, where backspace and some other keys give square characters instead of working as expected. Couldn't reproducable here, so please test. --- source/blender/editors/include/UI_interface.h | 1 + source/blender/editors/interface/interface.c | 3 +++ source/blender/editors/interface/interface_handlers.c | 3 +-- source/blender/editors/interface/interface_layout.c | 2 +- source/blender/editors/screen/screen_ops.c | 2 +- source/blender/windowmanager/intern/wm_event_system.c | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index b45ab2d4997..921aa60f9b2 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -146,6 +146,7 @@ typedef struct uiLayout uiLayout; #define UI_BUT_DRIVEN (1<<22) #define UI_BUT_INACTIVE (1<<23) #define UI_BUT_LAST_ACTIVE (1<<24) +#define UI_BUT_UNDO (1<<25) #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 3c6e12905d6..221618b340e 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2264,6 +2264,9 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short } } + if(!ELEM7(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, SEARCH_MENU)) + but->flag |= UI_BUT_UNDO; + BLI_addtail(&block->buttons, but); if(block->curlayout) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 466c1d08ba3..152695c9162 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -292,8 +292,7 @@ static void ui_apply_autokey_undo(bContext *C, uiBut *but) uiAfterFunc *after; char *str= NULL; - if ELEM6(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX); - else { + if(but->flag & UI_BUT_UNDO) { /* define which string to use for undo */ if ELEM(but->type, LINK, INLINK) str= "Add button link"; else if ELEM(but->type, MENU, ICONTEXTROW) str= but->drawstr; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 242ba31ccd4..b6afc4daa9b 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1107,7 +1107,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN but->hardmax= MAX2(but->hardmax, 256); but->rnasearchpoin= *searchptr; but->rnasearchprop= searchprop; - but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT; + but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT|UI_BUT_UNDO; uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f32b11812cf..0bb1969ce3c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -605,7 +605,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: /* release LMB */ if(event->val==0) { - if(sad->sa1 == sad->sa2) { + if(!sad->sa2 || sad->sa1 == sad->sa2) { return area_swap_cancel(C, op); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 28814937ebe..b5ecc6f4d58 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -715,7 +715,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) /* the matching rules */ if(kmitype==KM_TEXTINPUT) - if(ISKEYBOARD(winevent->type)) return 1; + if(ISKEYBOARD(winevent->type) && winevent->ascii) return 1; if(kmitype!=KM_ANY) if(winevent->type!=kmitype) return 0; -- cgit v1.2.3 From 524a8e32b157a4a8e8eafcb47bed378838342a19 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 21:55:48 +0000 Subject: Smoke: * Fixing compile warning --- source/blender/editors/space_view3d/drawvolume.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 3a79caed821..a81174ff768 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -223,7 +223,7 @@ void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture "MUL temp.b, temp.b, shadow.r;\n" "MOV result.color, temp;\n" "END\n"; - unsigned int prog; + GLuint prog; float size[3]; @@ -328,7 +328,7 @@ void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture // printf("i: %d\n", i); - if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) + if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &prog); -- cgit v1.2.3 From 41ed712ea3937d8baf601131df4f2063e8997764 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Mon, 14 Sep 2009 22:27:10 +0000 Subject: Smoke: * Bugfix for non working 3dview Credits: Thanks to Wahooney, jesterKing and a big thanks to Matt/broken for hunting this down! --- source/blender/gpu/intern/gpu_extensions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index d7b54e425fd..4a31df04627 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -348,7 +348,7 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels) type = GL_FLOAT; // GL_UNSIGNED_BYTE format = GL_RED; - internalformat = GL_RED; + internalformat = GL_INTENSITY; //if (fpixels) // pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); -- cgit v1.2.3 From 223bc8aee1c6f0c1e6d16d0edd8cf23387c33a3f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Tue, 15 Sep 2009 03:54:13 +0000 Subject: * Added RNA path functionality to fluidsim modifier settings, to allow keying of fluidsim settings properties. Note: Although the properties can be animated with the RNA system, the values are not exported to the actual fluid sim yet, that can come later. --- source/blender/blenkernel/intern/fluidsim.c | 1 + source/blender/blenloader/intern/readfile.c | 13 +++++++++++++ source/blender/makesdna/DNA_object_fluidsim.h | 1 + source/blender/makesrna/intern/rna_fluidsim.c | 9 +++++++++ 4 files changed, 24 insertions(+) diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index ad9e481ffd2..aa163b821c8 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -80,6 +80,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd) if(!fss) return; + fss->fmd = fluidmd; fss->type = OB_FLUIDSIM_ENABLE; fss->show_advancedoptions = 0; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d0264002214..bb7262c01d4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9692,10 +9692,23 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* put 2.50 compatibility code here until next subversion bump */ { Scene *sce; + Object *ob; for(sce = main->scene.first; sce; sce = sce->id.next) if(sce->unit.scale_length == 0.0f) sce->unit.scale_length= 1.0f; + + for(ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + + /* add backwards pointer for fluidsim modifier RNA access */ + for (md=ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fluidmd= (FluidsimModifierData*) md; + fluidmd->fss->fmd = fluidmd; + } + } + } } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h index 09288b24c20..da55fb1d47c 100644 --- a/source/blender/makesdna/DNA_object_fluidsim.h +++ b/source/blender/makesdna/DNA_object_fluidsim.h @@ -41,6 +41,7 @@ struct Ipo; struct MVert; typedef struct FluidsimSettings { + struct FluidsimModifierData *fmd; /* for fast RNA access */ /* domain,fluid or obstacle */ short type; /* display advanced options in fluid sim tab (on=1,off=0)*/ diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index a62002365c9..c415b3d716a 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -151,6 +151,14 @@ static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr) return 32; } +static char *rna_FluidSettings_path(PointerRNA *ptr) +{ + FluidsimSettings *fss = (FluidsimSettings*)ptr->data; + ModifierData *md= (ModifierData *)fss->fmd; + + return BLI_sprintfN("modifiers[%s].settings", md->name); +} + #else static void rna_def_fluidsim_slip(StructRNA *srna) @@ -509,6 +517,7 @@ void RNA_def_fluidsim(BlenderRNA *brna) srna= RNA_def_struct(brna, "FluidSettings", NULL); RNA_def_struct_sdna(srna, "FluidsimSettings"); RNA_def_struct_refine_func(srna, "rna_FluidSettings_refine"); + RNA_def_struct_path_func(srna, "rna_FluidSettings_path"); RNA_def_struct_ui_text(srna, "Fluid Simulation Settings", "Fluid simulation settings for an object taking part in the simulation."); prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); -- cgit v1.2.3 From 689b77ba9df8b618e0d7b58feda9161317361d74 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Sep 2009 10:01:20 +0000 Subject: - new property attribute - default_array, which returns a variable size array useful to get the defaults for operator & function arrays. - updated python api to check for array types rather then the length since a variable length array can be 1 or 0 length. - python docgen added .0 to the end of floats which messed up values like 1e-05 --- source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_access.c | 17 ++++++ source/blender/makesrna/intern/rna_particle.c | 2 +- source/blender/makesrna/intern/rna_rna.c | 80 +++++++++++++++++++++++++-- source/blender/python/epy_doc_gen.py | 2 +- source/blender/python/intern/bpy_rna.c | 62 ++++++++++----------- 6 files changed, 125 insertions(+), 39 deletions(-) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 05f39d73842..ca3ac62ba00 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -586,6 +586,7 @@ PropertyUnit RNA_property_unit(PropertyRNA *prop); int RNA_property_flag(PropertyRNA *prop); int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop); +int RNA_property_array_check(PointerRNA *ptr, PropertyRNA *prop); int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension); int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]); char RNA_property_array_item_char(PropertyRNA *prop, int index); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index e4bda24cf20..9472cdb300c 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -225,6 +225,18 @@ static int rna_ensure_property_array_length(PointerRNA *ptr, PropertyRNA *prop) } } +static int rna_ensure_property_array_check(PointerRNA *ptr, PropertyRNA *prop) +{ + if(prop->magic == RNA_MAGIC) { + return (prop->getlength || prop->totarraylength) ? 1:0; + } + else { + IDProperty *idprop= (IDProperty*)prop; + + return idprop->type == IDP_ARRAY ? 1:0; + } +} + static void rna_ensure_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int length[]) { if(prop->magic == RNA_MAGIC) { @@ -574,6 +586,11 @@ int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop) return rna_ensure_property_array_length(ptr, prop); } +int RNA_property_array_check(PointerRNA *ptr, PropertyRNA *prop) +{ + return rna_ensure_property_array_check(ptr, prop); +} + /* used by BPY to make an array from the python object */ int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]) { diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index e6f0a462f03..bbbb13c6e97 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -254,7 +254,7 @@ static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr) } static void rna_Particle_hair_dynamics(bContext *C, PointerRNA *ptr) { - Scene *scene = CTX_data_scene(C); + /* Scene *scene = CTX_data_scene(C); */ ParticleSystem *psys = (ParticleSystem*)ptr->data; if(psys && !psys->clmd) { diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 8df6398f1f4..196d25ada86 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -458,6 +458,62 @@ static int rna_IntProperty_default_get(PointerRNA *ptr) rna_idproperty_check(&prop, ptr); return ((IntPropertyRNA*)prop)->defaultvalue; } +/* int/float/bool */ +static int rna_NumberProperty_default_array_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + PropertyRNA *prop= (PropertyRNA*)ptr->data; + rna_idproperty_check(&prop, ptr); + + length[0]= prop->totarraylength; + + return length[0]; +} +static void rna_IntProperty_default_array_get(PointerRNA *ptr, int *values) +{ + PropertyRNA *prop= (PropertyRNA*)ptr->data; + IntPropertyRNA *nprop= (IntPropertyRNA*)prop; + rna_idproperty_check(&prop, ptr); + + if(nprop->defaultarray) { + memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(int)); + } + else { + int i; + for(i=0; i < prop->totarraylength; i++) + values[i]= nprop->defaultvalue; + } +} +static void rna_BoolProperty_default_array_get(PointerRNA *ptr, int *values) +{ + PropertyRNA *prop= (PropertyRNA*)ptr->data; + BooleanPropertyRNA *nprop= (BooleanPropertyRNA*)prop; + rna_idproperty_check(&prop, ptr); + + if(nprop->defaultarray) { + memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(int)); + } + else { + int i; + for(i=0; i < prop->totarraylength; i++) + values[i]= nprop->defaultvalue; + } +} +static void rna_FloatProperty_default_array_get(PointerRNA *ptr, float *values) +{ + PropertyRNA *prop= (PropertyRNA*)ptr->data; + FloatPropertyRNA *nprop= (FloatPropertyRNA*)prop; + rna_idproperty_check(&prop, ptr); + + if(nprop->defaultarray) { + memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(float)); + } + else { + int i; + for(i=0; i < prop->totarraylength; i++) + values[i]= nprop->defaultvalue; + } +} + static int rna_IntProperty_hard_min_get(PointerRNA *ptr) { PropertyRNA *prop= (PropertyRNA*)ptr->data; @@ -932,13 +988,27 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type) } -#if 0 // XXX - Variable length arrays prop= RNA_def_property(srna, "default_array", type, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - if(type == PROP_INT) RNA_def_property_int_funcs(prop, "rna_IntProperty_default_array_get", NULL, NULL); - else RNA_def_property_float_funcs(prop, "rna_FloatProperty_default_array_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Default", "Default value for this number"); -#endif + RNA_def_property_array(prop, RNA_MAX_ARRAY_DIMENSION); /* no fixed default length, important its not 0 though */ + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_dynamic_array_funcs(prop, "rna_NumberProperty_default_array_get_length"); /* same for all types */ + + switch(type) { + case PROP_BOOLEAN: + RNA_def_property_boolean_funcs(prop, "rna_BoolProperty_default_array_get", NULL); + break; + case PROP_INT: + RNA_def_property_int_funcs(prop, "rna_IntProperty_default_array_get", NULL, NULL); + break; + case PROP_FLOAT: + RNA_def_property_float_funcs(prop, "rna_FloatProperty_default_array_get", NULL, NULL); + break; + default: + break; + } + RNA_def_property_ui_text(prop, "Default Array", "Default value for this array"); + prop= RNA_def_property(srna, "array_length", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/python/epy_doc_gen.py b/source/blender/python/epy_doc_gen.py index c2ef6bbc0d0..4ff5c8102e2 100644 --- a/source/blender/python/epy_doc_gen.py +++ b/source/blender/python/epy_doc_gen.py @@ -225,7 +225,7 @@ def write_func(rna, ident, out, func_type): elif rna_prop_type=='float': if length==0: val_str= '%g' % val - if '.' not in val_str: + if '.' not in val_str and '-' not in val_str: # value could be 1e-05 val_str += '.0' else: # array diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index dd6bc35fc0a..820f96f1e81 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -349,9 +349,8 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) { PyObject *ret; int type = RNA_property_type(prop); - int len = RNA_property_array_length(ptr, prop); - if (len > 0) { + if (RNA_property_array_check(ptr, prop)) { return pyrna_py_from_array(ptr, prop); } @@ -521,9 +520,10 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v { /* XXX hard limits should be checked here */ int type = RNA_property_type(prop); - int len = RNA_property_array_length(ptr, prop); - if (len > 0) { + + if (RNA_property_array_check(ptr, prop)) { + /* char error_str[512]; */ int ok= 1; @@ -819,13 +819,11 @@ static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self ) if (RNA_property_type(self->prop) == PROP_COLLECTION) { len = RNA_property_collection_length(&self->ptr, self->prop); - } else { + } else if (RNA_property_array_check(&self->ptr, self->prop)) { len = pyrna_prop_array_length(self); - - if (len==0) { /* not an array*/ - PyErr_SetString(PyExc_AttributeError, "len() only available for collection and array RNA types"); - return -1; - } + } else { + PyErr_SetString(PyExc_AttributeError, "len() only available for collection and array RNA types"); + len = -1; /* error value */ } return len; @@ -979,7 +977,7 @@ static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key ) { if (RNA_property_type(self->prop) == PROP_COLLECTION) { return prop_subscript_collection(self, key); - } else if (RNA_property_array_length(&self->ptr, self->prop)) { /* zero length means its not an array */ + } else if (RNA_property_array_check(&self->ptr, self->prop)) { return prop_subscript_array(self, key); } @@ -1681,32 +1679,31 @@ static PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args) PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) { /* Try get values from a collection */ - PyObject *ret = pyrna_prop_values(self); + PyObject *ret; - if (ret==NULL) { - /* collection did not work, try array */ + if(RNA_property_array_check(&self->ptr, self->prop)) { int len = pyrna_prop_array_length(self); + int i; + PyErr_Clear(); + ret = PyList_New(len); - if (len) { - int i; - PyErr_Clear(); - ret = PyList_New(len); - - for (i=0; i < len; i++) { - PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(self, i)); - } + for (i=0; i < len; i++) { + PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(self, i)); } } - - if (ret) { - /* we know this is a list so no need to PyIter_Check */ - PyObject *iter = PyObject_GetIter(ret); - Py_DECREF(ret); - return iter; + else if (ret = pyrna_prop_values(self)) { + /* do nothing */ + } + else { + PyErr_SetString( PyExc_TypeError, "this BPy_PropertyRNA object is not iterable" ); + return NULL; } - PyErr_SetString( PyExc_TypeError, "this BPy_PropertyRNA object is not iterable" ); - return NULL; + + /* we know this is a list so no need to PyIter_Check */ + PyObject *iter = PyObject_GetIter(ret); + Py_DECREF(ret); + return iter; } static struct PyMethodDef pyrna_struct_methods[] = { @@ -1776,11 +1773,12 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) { PyObject *ret; int type = RNA_property_type(prop); - int len = RNA_property_array_length(ptr, prop); int a; - if(len > 0) { + if(RNA_property_array_check(ptr, prop)) { + int len = RNA_property_array_length(ptr, prop); + /* resolve the array from a new pytype */ ret = PyTuple_New(len); -- cgit v1.2.3 From 9a2cd02ae4baf4f759f076e1db4db4c8c2e69a39 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 15 Sep 2009 10:23:44 +0000 Subject: UI: renamed 3dview menus to be lower case, not too important now, but once these become extensible we need consistent names. --- release/ui/space_view3d.py | 272 ++++++++++++++++++++++----------------------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/release/ui/space_view3d.py b/release/ui/space_view3d.py index 2539ded18bf..33f9fbb853d 100644 --- a/release/ui/space_view3d.py +++ b/release/ui/space_view3d.py @@ -25,17 +25,17 @@ class VIEW3D_HT_header(bpy.types.Header): # Select Menu if mode_string not in ('EDIT_TEXT', 'SCULPT', 'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'): - sub.itemM("VIEW3D_MT_select_%s" % mode_string) + sub.itemM("VIEW3D_MT_select_%s" % mode_string.lower()) if edit_object: - sub.itemM("VIEW3D_MT_edit_%s" % edit_object.type) + sub.itemM("VIEW3D_MT_edit_%s" % edit_object.type.lower()) elif object: ob_mode_string = object.mode if mode_string not in ['PAINT_WEIGHT', 'PAINT_TEXTURE']: - sub.itemM("VIEW3D_MT_%s" % mode_string) + sub.itemM("VIEW3D_MT_%s" % mode_string.lower()) else: - sub.itemM("VIEW3D_MT_OBJECT") + sub.itemM("VIEW3D_MT_object") layout.template_header_3D() @@ -155,7 +155,7 @@ class VIEW3D_MT_view_cameras(bpy.types.Menu): # ********** Select menus, suffix from context.mode ********** -class VIEW3D_MT_select_OBJECT(bpy.types.Menu): +class VIEW3D_MT_select_object(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -174,7 +174,7 @@ class VIEW3D_MT_select_OBJECT(bpy.types.Menu): layout.item_enumO("object.select_by_type", "type", "", text="Select All by Type...") layout.itemO("object.select_grouped", text="Select Grouped...") -class VIEW3D_MT_select_POSE(bpy.types.Menu): +class VIEW3D_MT_select_pose(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -205,7 +205,7 @@ class VIEW3D_MT_select_POSE(bpy.types.Menu): props.extend = True props.direction = 'CHILD' -class VIEW3D_MT_select_PARTICLE(bpy.types.Menu): +class VIEW3D_MT_select_particle(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -224,7 +224,7 @@ class VIEW3D_MT_select_PARTICLE(bpy.types.Menu): layout.itemO("particle.select_more") layout.itemO("particle.select_less") -class VIEW3D_MT_select_EDIT_MESH(bpy.types.Menu): +class VIEW3D_MT_select_edit_mesh(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -268,7 +268,7 @@ class VIEW3D_MT_select_EDIT_MESH(bpy.types.Menu): layout.itemO("mesh.loop_to_region") layout.itemO("mesh.region_to_loop") -class VIEW3D_MT_select_EDIT_CURVE(bpy.types.Menu): +class VIEW3D_MT_select_edit_curve(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -297,7 +297,7 @@ class VIEW3D_MT_select_EDIT_CURVE(bpy.types.Menu): layout.itemO("curve.select_more") layout.itemO("curve.select_less") -class VIEW3D_MT_select_EDIT_SURFACE(bpy.types.Menu): +class VIEW3D_MT_select_edit_surface(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -323,7 +323,7 @@ class VIEW3D_MT_select_EDIT_SURFACE(bpy.types.Menu): layout.itemO("curve.select_more") layout.itemO("curve.select_less") -class VIEW3D_MT_select_EDIT_METABALL(bpy.types.Menu): +class VIEW3D_MT_select_edit_metaball(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -341,7 +341,7 @@ class VIEW3D_MT_select_EDIT_METABALL(bpy.types.Menu): layout.itemO("mball.select_random_metaelems") -class VIEW3D_MT_select_EDIT_LATTICE(bpy.types.Menu): +class VIEW3D_MT_select_edit_lattice(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -354,7 +354,7 @@ class VIEW3D_MT_select_EDIT_LATTICE(bpy.types.Menu): layout.itemO("lattice.select_all_toggle", text="Select/Deselect All") -class VIEW3D_MT_select_EDIT_ARMATURE(bpy.types.Menu): +class VIEW3D_MT_select_edit_armature(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -383,7 +383,7 @@ class VIEW3D_MT_select_EDIT_ARMATURE(bpy.types.Menu): props.extend = True props.direction = 'CHILD' -class VIEW3D_MT_select_FACE(bpy.types.Menu):# XXX no matching enum +class VIEW3D_MT_select_face(bpy.types.Menu):# XXX no matching enum __space_type__ = 'VIEW_3D' __label__ = "Select" @@ -394,7 +394,7 @@ class VIEW3D_MT_select_FACE(bpy.types.Menu):# XXX no matching enum # ********** Object menu ********** -class VIEW3D_MT_OBJECT(bpy.types.Menu): +class VIEW3D_MT_object(bpy.types.Menu): __space_type__ = 'VIEW_3D' __context__ = "objectmode" __label__ = "Object" @@ -402,7 +402,7 @@ class VIEW3D_MT_OBJECT(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.itemM("VIEW3D_MT_OBJECT_clear") + layout.itemM("VIEW3D_MT_object_clear") layout.itemM("VIEW3D_MT_snap") layout.itemS() @@ -419,10 +419,10 @@ class VIEW3D_MT_OBJECT(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_OBJECT_parent") - layout.itemM("VIEW3D_MT_OBJECT_track") - layout.itemM("VIEW3D_MT_OBJECT_group") - layout.itemM("VIEW3D_MT_OBJECT_constraints") + layout.itemM("VIEW3D_MT_object_parent") + layout.itemM("VIEW3D_MT_object_track") + layout.itemM("VIEW3D_MT_object_group") + layout.itemM("VIEW3D_MT_object_constraints") layout.itemS() @@ -430,9 +430,9 @@ class VIEW3D_MT_OBJECT(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_OBJECT_showhide") + layout.itemM("VIEW3D_MT_object_showhide") -class VIEW3D_MT_OBJECT_clear(bpy.types.Menu): +class VIEW3D_MT_object_clear(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Clear" @@ -444,7 +444,7 @@ class VIEW3D_MT_OBJECT_clear(bpy.types.Menu): layout.itemO("object.scale_clear", text="Scale") layout.itemO("object.origin_clear", text="Origin") -class VIEW3D_MT_OBJECT_parent(bpy.types.Menu): +class VIEW3D_MT_object_parent(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Parent" @@ -454,7 +454,7 @@ class VIEW3D_MT_OBJECT_parent(bpy.types.Menu): layout.itemO("object.parent_set", text="Set") layout.itemO("object.parent_clear", text="Clear") -class VIEW3D_MT_OBJECT_track(bpy.types.Menu): +class VIEW3D_MT_object_track(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Track" @@ -464,7 +464,7 @@ class VIEW3D_MT_OBJECT_track(bpy.types.Menu): layout.itemO("object.track_set", text="Set") layout.itemO("object.track_clear", text="Clear") -class VIEW3D_MT_OBJECT_group(bpy.types.Menu): +class VIEW3D_MT_object_group(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Group" @@ -479,7 +479,7 @@ class VIEW3D_MT_OBJECT_group(bpy.types.Menu): layout.itemO("group.objects_add_active") layout.itemO("group.objects_remove_active") -class VIEW3D_MT_OBJECT_constraints(bpy.types.Menu): +class VIEW3D_MT_object_constraints(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Constraints" @@ -489,7 +489,7 @@ class VIEW3D_MT_OBJECT_constraints(bpy.types.Menu): layout.itemO("object.constraint_add_with_targets") layout.itemO("object.constraints_clear") -class VIEW3D_MT_OBJECT_showhide(bpy.types.Menu): +class VIEW3D_MT_object_showhide(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Show/Hide" @@ -502,7 +502,7 @@ class VIEW3D_MT_OBJECT_showhide(bpy.types.Menu): # ********** Vertex paint menu ********** -class VIEW3D_MT_PAINT_VERTEX(bpy.types.Menu): +class VIEW3D_MT_paint_vertex(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Paint" @@ -517,7 +517,7 @@ class VIEW3D_MT_PAINT_VERTEX(bpy.types.Menu): # ********** Sculpt menu ********** -class VIEW3D_MT_SCULPT(bpy.types.Menu): +class VIEW3D_MT_sculpt(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Sculpt" @@ -553,7 +553,7 @@ class VIEW3D_MT_SCULPT(bpy.types.Menu): # ********** Particle menu ********** -class VIEW3D_MT_PARTICLE(bpy.types.Menu): +class VIEW3D_MT_particle(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Particle" @@ -576,14 +576,14 @@ class VIEW3D_MT_PARTICLE(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_PARTICLE_showhide") + layout.itemM("VIEW3D_MT_particle_showhide") -class VIEW3D_MT_PARTICLE_showhide(VIEW3D_MT_showhide): +class VIEW3D_MT_particle_showhide(VIEW3D_MT_showhide): _operator_name = "particle" # ********** Pose Menu ********** -class VIEW3D_MT_POSE(bpy.types.Menu): +class VIEW3D_MT_pose(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Pose" @@ -595,7 +595,7 @@ class VIEW3D_MT_POSE(bpy.types.Menu): if arm.drawtype in ('BBONE', 'ENVELOPE'): layout.item_enumO("tfm.transform", "mode", 'BONESIZE', text="Scale Envelope Distance") - layout.itemM("VIEW3D_MT_POSE_transform") + layout.itemM("VIEW3D_MT_pose_transform") layout.itemS() @@ -614,14 +614,14 @@ class VIEW3D_MT_POSE(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_POSE_pose") - layout.itemM("VIEW3D_MT_POSE_motion") - layout.itemM("VIEW3D_MT_POSE_group") + layout.itemM("VIEW3D_MT_pose_pose") + layout.itemM("VIEW3D_MT_pose_motion") + layout.itemM("VIEW3D_MT_pose_group") layout.itemS() - layout.itemM("VIEW3D_MT_POSE_ik") - layout.itemM("VIEW3D_MT_POSE_constraints") + layout.itemM("VIEW3D_MT_pose_ik") + layout.itemM("VIEW3D_MT_pose_constraints") layout.itemS() @@ -640,10 +640,10 @@ class VIEW3D_MT_POSE(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_POSE_showhide") + layout.itemM("VIEW3D_MT_pose_showhide") layout.item_menu_enumO("pose.flags_set", 'mode', text="Bone Settings") -class VIEW3D_MT_POSE_transform(bpy.types.Menu): +class VIEW3D_MT_pose_transform(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Clear Transform" @@ -658,7 +658,7 @@ class VIEW3D_MT_POSE_transform(bpy.types.Menu): layout.itemL(text="Origin") -class VIEW3D_MT_POSE_pose(bpy.types.Menu): +class VIEW3D_MT_pose_pose(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Pose Library" @@ -673,7 +673,7 @@ class VIEW3D_MT_POSE_pose(bpy.types.Menu): layout.itemO("poselib.pose_rename", text="Rename Pose...") layout.itemO("poselib.pose_remove", text="Remove Pose...") -class VIEW3D_MT_POSE_motion(bpy.types.Menu): +class VIEW3D_MT_pose_motion(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Motion Paths" @@ -683,7 +683,7 @@ class VIEW3D_MT_POSE_motion(bpy.types.Menu): layout.itemO("pose.paths_calculate", text="Calculate") layout.itemO("pose.paths_clear", text="Clear") -class VIEW3D_MT_POSE_group(bpy.types.Menu): +class VIEW3D_MT_pose_group(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Bone Groups" @@ -698,7 +698,7 @@ class VIEW3D_MT_POSE_group(bpy.types.Menu): layout.itemO("pose.group_unassign") -class VIEW3D_MT_POSE_ik(bpy.types.Menu): +class VIEW3D_MT_pose_ik(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Inverse Kinematics" @@ -708,7 +708,7 @@ class VIEW3D_MT_POSE_ik(bpy.types.Menu): layout.itemO("pose.ik_add") layout.itemO("pose.ik_clear") -class VIEW3D_MT_POSE_constraints(bpy.types.Menu): +class VIEW3D_MT_pose_constraints(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Constraints" @@ -718,13 +718,13 @@ class VIEW3D_MT_POSE_constraints(bpy.types.Menu): layout.itemO("pose.constraint_add_with_targets", text="Add (With Targets)...") layout.itemO("pose.constraints_clear") -class VIEW3D_MT_POSE_showhide(VIEW3D_MT_showhide): +class VIEW3D_MT_pose_showhide(VIEW3D_MT_showhide): _operator_name = "pose" # ********** Edit Menus, suffix from ob.type ********** # Edit MESH -class VIEW3D_MT_edit_MESH(bpy.types.Menu): +class VIEW3D_MT_edit_mesh(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Mesh" @@ -752,10 +752,10 @@ class VIEW3D_MT_edit_MESH(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_edit_MESH_vertices") - layout.itemM("VIEW3D_MT_edit_MESH_edges") - layout.itemM("VIEW3D_MT_edit_MESH_faces") - layout.itemM("VIEW3D_MT_edit_MESH_normals") + layout.itemM("VIEW3D_MT_edit_mesh_vertices") + layout.itemM("VIEW3D_MT_edit_mesh_edges") + layout.itemM("VIEW3D_MT_edit_mesh_faces") + layout.itemM("VIEW3D_MT_edit_mesh_normals") layout.itemS() @@ -765,9 +765,9 @@ class VIEW3D_MT_edit_MESH(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_edit_MESH_showhide") + layout.itemM("VIEW3D_MT_edit_mesh_showhide") -class VIEW3D_MT_edit_MESH_vertices(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Vertices" @@ -784,7 +784,7 @@ class VIEW3D_MT_edit_MESH_vertices(bpy.types.Menu): layout.itemO("mesh.vertices_smooth") layout.itemO("mesh.remove_doubles") -class VIEW3D_MT_edit_MESH_edges(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Edges" @@ -809,7 +809,7 @@ class VIEW3D_MT_edit_MESH_edges(bpy.types.Menu): layout.item_enumO("mesh.edge_rotate", "direction", 'CW', text="Rotate Edge CW") layout.item_enumO("mesh.edge_rotate", "direction", 'CCW', text="Rotate Edge CCW") -class VIEW3D_MT_edit_MESH_faces(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Faces" @@ -831,7 +831,7 @@ class VIEW3D_MT_edit_MESH_faces(bpy.types.Menu): layout.itemO("mesh.faces_shade_smooth") layout.itemO("mesh.faces_shade_flat") -class VIEW3D_MT_edit_MESH_normals(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_normals(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Normals" @@ -845,13 +845,13 @@ class VIEW3D_MT_edit_MESH_normals(bpy.types.Menu): layout.itemO("mesh.flip_normals") -class VIEW3D_MT_edit_MESH_showhide(VIEW3D_MT_showhide): +class VIEW3D_MT_edit_mesh_showhide(VIEW3D_MT_showhide): _operator_name = "mesh" -# Edit CURVE +# Edit Curve -# draw_CURVE is used by VIEW3D_MT_edit_CURVE and VIEW3D_MT_edit_SURFACE -def draw_CURVE(self, context): +# draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface +def draw_curve(self, context): layout = self.layout settings = context.tool_settings @@ -869,8 +869,8 @@ def draw_CURVE(self, context): layout.itemS() - layout.itemM("VIEW3D_MT_edit_CURVE_ctrlpoints") - layout.itemM("VIEW3D_MT_edit_CURVE_segments") + layout.itemM("VIEW3D_MT_edit_curve_ctrlpoints") + layout.itemM("VIEW3D_MT_edit_curve_segments") layout.itemS() @@ -879,15 +879,15 @@ def draw_CURVE(self, context): layout.itemS() - layout.itemM("VIEW3D_MT_edit_CURVE_showhide") + layout.itemM("VIEW3D_MT_edit_curve_showhide") -class VIEW3D_MT_edit_CURVE(bpy.types.Menu): +class VIEW3D_MT_edit_curve(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Curve" - draw = draw_CURVE + draw = draw_curve -class VIEW3D_MT_edit_CURVE_ctrlpoints(bpy.types.Menu): +class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Control Points" @@ -905,7 +905,7 @@ class VIEW3D_MT_edit_CURVE_ctrlpoints(bpy.types.Menu): layout.item_menu_enumO("curve.handle_type_set", "type") -class VIEW3D_MT_edit_CURVE_segments(bpy.types.Menu): +class VIEW3D_MT_edit_curve_segments(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Segments" @@ -915,18 +915,18 @@ class VIEW3D_MT_edit_CURVE_segments(bpy.types.Menu): layout.itemO("curve.subdivide") layout.itemO("curve.switch_direction") -class VIEW3D_MT_edit_CURVE_showhide(VIEW3D_MT_showhide): +class VIEW3D_MT_edit_curve_showhide(VIEW3D_MT_showhide): _operator_name = "curve" # Edit SURFACE -class VIEW3D_MT_edit_SURFACE(bpy.types.Menu): +class VIEW3D_MT_edit_surface(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Surface" - draw = draw_CURVE + draw = draw_curve # Edit TEXT -class VIEW3D_MT_edit_TEXT(bpy.types.Menu): +class VIEW3D_MT_edit_text(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Text" @@ -937,9 +937,9 @@ class VIEW3D_MT_edit_TEXT(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_edit_TEXT_chars") + layout.itemm("view3d_mt_edit_text_chars") -class VIEW3D_MT_edit_TEXT_chars(bpy.types.Menu): +class VIEW3D_MT_edit_text_chars(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Special Characters" @@ -974,7 +974,7 @@ class VIEW3D_MT_edit_TEXT_chars(bpy.types.Menu): layout.item_stringO("font.text_insert", "text", b'\xC2\xA1'.decode(), text="Spanish Exclamation Mark|Alt !") # Edit META -class VIEW3D_MT_edit_META(bpy.types.Menu): +class VIEW3D_MT_edit_meta(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Metaball" @@ -1002,9 +1002,9 @@ class VIEW3D_MT_edit_META(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_edit_META_showhide") + layout.itemM("VIEW3D_MT_edit_meta_showhide") -class VIEW3D_MT_edit_META_showhide(bpy.types.Menu): +class VIEW3D_MT_edit_meta_showhide(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Show/Hide" @@ -1016,7 +1016,7 @@ class VIEW3D_MT_edit_META_showhide(bpy.types.Menu): layout.item_booleanO("mball.hide_metaelems", "unselected", True, text="Hide Unselected") # Edit LATTICE -class VIEW3D_MT_edit_LATTICE(bpy.types.Menu): +class VIEW3D_MT_edit_lattice(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Lattice" @@ -1037,7 +1037,7 @@ class VIEW3D_MT_edit_LATTICE(bpy.types.Menu): layout.item_menu_enumR(settings, "proportional_editing_falloff") # Edit ARMATURE -class VIEW3D_MT_edit_ARMATURE(bpy.types.Menu): +class VIEW3D_MT_edit_armature(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Armature" @@ -1048,7 +1048,7 @@ class VIEW3D_MT_edit_ARMATURE(bpy.types.Menu): arm = edit_object.data layout.itemM("VIEW3D_MT_snap") - layout.itemM("VIEW3D_MT_edit_ARMATURE_roll") + layout.itemM("VIEW3D_MT_edit_armature_roll") if arm.drawtype == 'ENVELOPE': layout.item_enumO("tfm.transform", "mode", 'BONESIZE', text="Scale Envelope Distance") @@ -1088,13 +1088,13 @@ class VIEW3D_MT_edit_ARMATURE(bpy.types.Menu): layout.itemS() - layout.itemM("VIEW3D_MT_edit_ARMATURE_parent") + layout.itemM("VIEW3D_MT_edit_armature_parent") layout.itemS() layout.item_menu_enumO("armature.flags_set", "mode", text="Bone Settings") -class VIEW3D_MT_edit_ARMATURE_parent(bpy.types.Menu): +class VIEW3D_MT_edit_armature_parent(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Parent" @@ -1104,7 +1104,7 @@ class VIEW3D_MT_edit_ARMATURE_parent(bpy.types.Menu): layout.itemO("armature.parent_set", text="Make") layout.itemO("armature.parent_clear", text="Clear") -class VIEW3D_MT_edit_ARMATURE_roll(bpy.types.Menu): +class VIEW3D_MT_edit_armature_roll(bpy.types.Menu): __space_type__ = 'VIEW_3D' __label__ = "Bone Roll" @@ -1285,68 +1285,68 @@ bpy.types.register(VIEW3D_MT_view_navigation) bpy.types.register(VIEW3D_MT_view_align) bpy.types.register(VIEW3D_MT_view_cameras) -bpy.types.register(VIEW3D_MT_select_OBJECT) # Select Menus -bpy.types.register(VIEW3D_MT_select_POSE) -bpy.types.register(VIEW3D_MT_select_PARTICLE) -bpy.types.register(VIEW3D_MT_select_EDIT_MESH) -bpy.types.register(VIEW3D_MT_select_EDIT_CURVE) -bpy.types.register(VIEW3D_MT_select_EDIT_SURFACE) -bpy.types.register(VIEW3D_MT_select_EDIT_METABALL) -bpy.types.register(VIEW3D_MT_select_EDIT_LATTICE) -bpy.types.register(VIEW3D_MT_select_EDIT_ARMATURE) -bpy.types.register(VIEW3D_MT_select_FACE) # XXX todo - -bpy.types.register(VIEW3D_MT_OBJECT) # Object Menu -bpy.types.register(VIEW3D_MT_OBJECT_clear) -bpy.types.register(VIEW3D_MT_OBJECT_parent) -bpy.types.register(VIEW3D_MT_OBJECT_track) -bpy.types.register(VIEW3D_MT_OBJECT_group) -bpy.types.register(VIEW3D_MT_OBJECT_constraints) -bpy.types.register(VIEW3D_MT_OBJECT_showhide) - -bpy.types.register(VIEW3D_MT_SCULPT) # Sculpt Menu - -bpy.types.register(VIEW3D_MT_PAINT_VERTEX) - -bpy.types.register(VIEW3D_MT_PARTICLE) # Particle Menu -bpy.types.register(VIEW3D_MT_PARTICLE_showhide) - -bpy.types.register(VIEW3D_MT_POSE) # POSE Menu -bpy.types.register(VIEW3D_MT_POSE_transform) -bpy.types.register(VIEW3D_MT_POSE_pose) -bpy.types.register(VIEW3D_MT_POSE_motion) -bpy.types.register(VIEW3D_MT_POSE_group) -bpy.types.register(VIEW3D_MT_POSE_ik) -bpy.types.register(VIEW3D_MT_POSE_constraints) -bpy.types.register(VIEW3D_MT_POSE_showhide) +bpy.types.register(VIEW3D_MT_select_object) # Select Menus +bpy.types.register(VIEW3D_MT_select_pose) +bpy.types.register(VIEW3D_MT_select_particle) +bpy.types.register(VIEW3D_MT_select_edit_mesh) +bpy.types.register(VIEW3D_MT_select_edit_curve) +bpy.types.register(VIEW3D_MT_select_edit_surface) +bpy.types.register(VIEW3D_MT_select_edit_metaball) +bpy.types.register(VIEW3D_MT_select_edit_lattice) +bpy.types.register(VIEW3D_MT_select_edit_armature) +bpy.types.register(VIEW3D_MT_select_face) # XXX todo + +bpy.types.register(VIEW3D_MT_object) # Object Menu +bpy.types.register(VIEW3D_MT_object_clear) +bpy.types.register(VIEW3D_MT_object_parent) +bpy.types.register(VIEW3D_MT_object_track) +bpy.types.register(VIEW3D_MT_object_group) +bpy.types.register(VIEW3D_MT_object_constraints) +bpy.types.register(VIEW3D_MT_object_showhide) + +bpy.types.register(VIEW3D_MT_sculpt) # Sculpt Menu + +bpy.types.register(VIEW3D_MT_paint_vertex) + +bpy.types.register(VIEW3D_MT_particle) # Particle Menu +bpy.types.register(VIEW3D_MT_particle_showhide) + +bpy.types.register(VIEW3D_MT_pose) # POSE Menu +bpy.types.register(VIEW3D_MT_pose_transform) +bpy.types.register(VIEW3D_MT_pose_pose) +bpy.types.register(VIEW3D_MT_pose_motion) +bpy.types.register(VIEW3D_MT_pose_group) +bpy.types.register(VIEW3D_MT_pose_ik) +bpy.types.register(VIEW3D_MT_pose_constraints) +bpy.types.register(VIEW3D_MT_pose_showhide) bpy.types.register(VIEW3D_MT_snap) # Edit Menus -bpy.types.register(VIEW3D_MT_edit_MESH) -bpy.types.register(VIEW3D_MT_edit_MESH_vertices) -bpy.types.register(VIEW3D_MT_edit_MESH_edges) -bpy.types.register(VIEW3D_MT_edit_MESH_faces) -bpy.types.register(VIEW3D_MT_edit_MESH_normals) -bpy.types.register(VIEW3D_MT_edit_MESH_showhide) +bpy.types.register(VIEW3D_MT_edit_mesh) +bpy.types.register(VIEW3D_MT_edit_mesh_vertices) +bpy.types.register(VIEW3D_MT_edit_mesh_edges) +bpy.types.register(VIEW3D_MT_edit_mesh_faces) +bpy.types.register(VIEW3D_MT_edit_mesh_normals) +bpy.types.register(VIEW3D_MT_edit_mesh_showhide) -bpy.types.register(VIEW3D_MT_edit_CURVE) -bpy.types.register(VIEW3D_MT_edit_CURVE_ctrlpoints) -bpy.types.register(VIEW3D_MT_edit_CURVE_segments) -bpy.types.register(VIEW3D_MT_edit_CURVE_showhide) +bpy.types.register(VIEW3D_MT_edit_curve) +bpy.types.register(VIEW3D_MT_edit_curve_ctrlpoints) +bpy.types.register(VIEW3D_MT_edit_curve_segments) +bpy.types.register(VIEW3D_MT_edit_curve_showhide) -bpy.types.register(VIEW3D_MT_edit_SURFACE) +bpy.types.register(VIEW3D_MT_edit_surface) -bpy.types.register(VIEW3D_MT_edit_TEXT) -bpy.types.register(VIEW3D_MT_edit_TEXT_chars) +bpy.types.register(VIEW3D_MT_edit_text) +bpy.types.register(VIEW3D_MT_edit_text_chars) -bpy.types.register(VIEW3D_MT_edit_META) -bpy.types.register(VIEW3D_MT_edit_META_showhide) +bpy.types.register(VIEW3D_MT_edit_meta) +bpy.types.register(VIEW3D_MT_edit_meta_showhide) -bpy.types.register(VIEW3D_MT_edit_LATTICE) +bpy.types.register(VIEW3D_MT_edit_lattice) -bpy.types.register(VIEW3D_MT_edit_ARMATURE) -bpy.types.register(VIEW3D_MT_edit_ARMATURE_parent) -bpy.types.register(VIEW3D_MT_edit_ARMATURE_roll) +bpy.types.register(VIEW3D_MT_edit_armature) +bpy.types.register(VIEW3D_MT_edit_armature_parent) +bpy.types.register(VIEW3D_MT_edit_armature_roll) bpy.types.register(VIEW3D_PT_3dview_properties) # Panels bpy.types.register(VIEW3D_PT_3dview_display) -- cgit v1.2.3 From c8618348e0feab2f28d348b539b8a6420301be1f Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Tue, 15 Sep 2009 10:26:36 +0000 Subject: Smoke: * Less verbose * More OpenGL error messages (on blender -d) --- source/blender/blenkernel/intern/smoke.c | 16 ++++++++-------- source/blender/editors/space_view3d/drawvolume.c | 2 ++ source/blender/gpu/intern/gpu_extensions.c | 9 +++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 99d4176c937..1b6b4d4838e 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -167,7 +167,7 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive // calc other res with max_res provided VECSUB(size, max, min); - printf("size: %f, %f, %f\n", size[0], size[1], size[2]); + // printf("size: %f, %f, %f\n", size[0], size[1], size[2]); // prevent crash when initializing a plane as domain if((size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON)) @@ -212,7 +212,7 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive } } - printf("smd->domain->dx: %f\n", smd->domain->dx); + // printf("smd->domain->dx: %f\n", smd->domain->dx); // TODO: put in failsafe if res<=0 - dg @@ -228,8 +228,8 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive smd->domain->res_wt[1] = smd->domain->res[1] * (smd->domain->amplify + 1); smd->domain->res_wt[2] = smd->domain->res[2] * (smd->domain->amplify + 1); smd->domain->dx_wt = smd->domain->dx / (smd->domain->amplify + 1); - printf("smd->domain->amplify: %d\n", smd->domain->amplify); - printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n"); + // printf("smd->domain->amplify: %d\n", smd->domain->amplify); + // printf("(smd->domain->flags & MOD_SMOKE_HIGHRES)\n"); } if(!smd->domain->shadow) @@ -240,7 +240,7 @@ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, Derive if(smd->domain->wt) { smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength)); - printf("smoke_initWaveletBlenderRNA\n"); + // printf("smoke_initWaveletBlenderRNA\n"); } return 1; } @@ -624,7 +624,7 @@ void smokeModifier_reset(struct SmokeModifierData *smd) smd->time = -1; - printf("reset domain end\n"); + // printf("reset domain end\n"); } else if(smd->flow) { @@ -1111,7 +1111,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM framenr = scene->r.cfra; - printf("time: %d\n", scene->r.cfra); + // printf("time: %d\n", scene->r.cfra); if(framenr == smd->time) return; @@ -1148,7 +1148,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM /* try to read from cache */ cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec); - printf("cache_result: %d\n", cache_result); + // printf("cache_result: %d\n", cache_result); if(cache_result == PTCACHE_READ_EXACT) { diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index a81174ff768..0bdc65b5461 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -347,6 +347,8 @@ void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture GPU_texture_bind(tex, 0); if(tex_shadow) GPU_texture_bind(tex_shadow, 1); + else + printf("No volume shadow\n"); if (!GLEW_ARB_texture_non_power_of_two) { cor[0] = (float)res[0]/(float)larger_pow2(res[0]); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 4a31df04627..55e4b337a77 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -346,6 +346,8 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels) tex->number = 0; glBindTexture(tex->target, tex->bindcode); + GPU_print_error("3D glBindTexture"); + type = GL_FLOAT; // GL_UNSIGNED_BYTE format = GL_RED; internalformat = GL_INTENSITY; @@ -355,16 +357,23 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels) glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, 0); + GPU_print_error("3D glTexImage3D"); + if (fpixels) { glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels); + GPU_print_error("3D glTexSubImage3D"); } + glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor); + GPU_print_error("3D GL_TEXTURE_BORDER_COLOR"); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GPU_print_error("3D GL_LINEAR"); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + GPU_print_error("3D GL_CLAMP_TO_BORDER"); if (pixels) MEM_freeN(pixels); -- cgit v1.2.3 From daa968df227438ea592fc0702f1e4727dfc9357d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Sep 2009 10:52:36 +0000 Subject: - opening the file selector was freeing a NULL pointer - some warnings in last commit. --- source/blender/editors/space_file/space_file.c | 6 ++++-- source/blender/python/intern/bpy_rna.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 47839ea0342..68eeb8718a2 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -156,8 +156,10 @@ static void file_free(SpaceLink *sl) static void file_init(struct wmWindowManager *wm, ScrArea *sa) { SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; - MEM_freeN(sfile->params); - sfile->params = 0; + if(sfile->params) { + MEM_freeN(sfile->params); + sfile->params = 0; + } printf("file_init\n"); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 820f96f1e81..c2335bea995 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1680,6 +1680,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) { /* Try get values from a collection */ PyObject *ret; + PyObject *iter; if(RNA_property_array_check(&self->ptr, self->prop)) { int len = pyrna_prop_array_length(self); @@ -1691,7 +1692,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(self, i)); } } - else if (ret = pyrna_prop_values(self)) { + else if ((ret = pyrna_prop_values(self))) { /* do nothing */ } else { @@ -1701,7 +1702,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) /* we know this is a list so no need to PyIter_Check */ - PyObject *iter = PyObject_GetIter(ret); + iter = PyObject_GetIter(ret); Py_DECREF(ret); return iter; } -- cgit v1.2.3 From 8513ab471c0b2ae1e84f9b14e932e080a7fdd32c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Sep 2009 10:59:42 +0000 Subject: didnt change all filename's to path's --- release/io/export_ply.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release/io/export_ply.py b/release/io/export_ply.py index 7a3253b2d16..491ffe6b9df 100644 --- a/release/io/export_ply.py +++ b/release/io/export_ply.py @@ -256,10 +256,10 @@ class EXPORT_OT_ply(bpy.types.Operator): def execute(self, context): # print("Selected: " + context.active_object.name) - if not self.filename: + if not self.path: raise Exception("filename not set") - write(self.filename, context.scene, context.active_object,\ + write(self.path, context.scene, context.active_object,\ EXPORT_APPLY_MODIFIERS = self.use_modifiers, EXPORT_NORMALS = self.use_normals, EXPORT_UV = self.use_uvs, @@ -277,6 +277,6 @@ class EXPORT_OT_ply(bpy.types.Operator): bpy.ops.add(EXPORT_OT_ply) if __name__ == "__main__": - bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply") + bpy.ops.EXPORT_OT_ply(path="/tmp/test.ply") -- cgit v1.2.3 From 499e6f0067ff629fcc7705e5552d5d35ff587ab3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 15 Sep 2009 11:35:10 +0000 Subject: 2.5: node group/ungroup/edit operators, patch by Michal Ziulek, with some small changes. --- release/ui/space_node.py | 9 +- source/blender/editors/space_node/node_draw.c | 2 +- source/blender/editors/space_node/node_edit.c | 234 ++++++++++++++++-------- source/blender/editors/space_node/node_intern.h | 5 +- source/blender/editors/space_node/node_ops.c | 7 + 5 files changed, 169 insertions(+), 88 deletions(-) diff --git a/release/ui/space_node.py b/release/ui/space_node.py index 55b2065084b..b32e6a9f61a 100644 --- a/release/ui/space_node.py +++ b/release/ui/space_node.py @@ -98,11 +98,10 @@ class NODE_MT_node(bpy.types.Menu): # XXX # layout.itemS() # layout.itemO("node.make_link") - # layout.itemS() - # layout.itemO("node.edit_group") - # layout.itemO("node.ungroup") - # layout.itemO("node.group") - # layout.itemO("node.make_link") + layout.itemS() + layout.itemO("node.group_edit") + layout.itemO("node.group_ungroup") + layout.itemO("node.group_make") layout.itemS() diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index f3df7a29c2e..a872413b4e1 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -601,7 +601,7 @@ static void do_node_internal_buttons(bContext *C, void *node_v, int event) //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); } else { - node= snode_get_editgroup(snode); + node= node_tree_get_editgroup(snode->nodetree); if(node) NodeTagIDChanged(snode->nodetree, node->id); } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 159a4036914..4fd6995b8fd 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -58,6 +58,7 @@ #include "BKE_material.h" #include "BKE_paint.h" #include "BKE_texture.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_utildefines.h" @@ -84,6 +85,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" #include "UI_view2d.h" #include "node_intern.h" @@ -327,12 +329,12 @@ static void set_node_imagepath(char *str) /* called from fileselect */ #endif /* 0 */ -bNode *snode_get_editgroup(SpaceNode *snode) +bNode *node_tree_get_editgroup(bNodeTree *nodetree) { bNode *gnode; /* get the groupnode */ - for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next) + for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next) if(gnode->flag & NODE_GROUP_EDIT) break; return gnode; @@ -441,7 +443,7 @@ static void composit_node_event(SpaceNode *snode, short event) addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); } else { - node= snode_get_editgroup(snode); + node= node_tree_get_editgroup(snode->nodetree); if(node) NodeTagIDChanged(snode->nodetree, node->id); @@ -722,7 +724,7 @@ void node_set_active(SpaceNode *snode, bNode *node) NodeTagChanged(snode->edittree, node); /* if inside group, tag entire group */ - gnode= snode_get_editgroup(snode); + gnode= node_tree_get_editgroup(snode->nodetree); if(gnode) NodeTagIDChanged(snode->nodetree, gnode->id); @@ -753,6 +755,8 @@ void node_set_active(SpaceNode *snode, bNode *node) #endif /* 0 */ } +/* ***************** Edit Group operator ************* */ + void snode_make_group_editable(SpaceNode *snode, bNode *gnode) { bNode *node; @@ -768,12 +772,9 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode) } if(gnode && gnode->type==NODE_GROUP && gnode->id) { - if(gnode->id->lib) { - // XXX if(okee("Make Group Local")) - // ntreeMakeLocal((bNodeTree *)gnode->id); - // else - return; - } + if(gnode->id->lib) + ntreeMakeLocal((bNodeTree *)gnode->id); + gnode->flag |= NODE_GROUP_EDIT; snode->edittree= (bNodeTree *)gnode->id; @@ -794,43 +795,102 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode) // XXX BIF_preview_changed(-1); /* temp hack to force texture preview to update */ } +} + +static int node_group_edit_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNode *gnode; + + gnode= nodeGetActive(snode->edittree); + snode_make_group_editable(snode, gnode); + + WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); + + return OPERATOR_FINISHED; +} + +static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNode *gnode; + + gnode= nodeGetActive(snode->edittree); + if(gnode && gnode->type==NODE_GROUP && gnode->id && gnode->id->lib) { + uiPupMenuOkee(C, op->type->idname, "Make group local?"); + return OPERATOR_CANCELLED; + } + + return node_group_edit_exec(C, op); +} + +void NODE_OT_group_edit(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edit Group"; + ot->description = "Edit node group."; + ot->idname = "NODE_OT_group_edit"; - // allqueue(REDRAWNODE, 0); + /* api callbacks */ + ot->invoke = node_group_edit_invoke; + ot->exec = node_group_edit_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } -#if 0 +/* ******************** Ungroup operator ********************** */ -void node_ungroup(SpaceNode *snode) +static int node_group_ungroup_exec(bContext *C, wmOperator *op) { + SpaceNode *snode = CTX_wm_space_node(C); bNode *gnode; /* are we inside of a group? */ - gnode= snode_get_editgroup(snode); + gnode= node_tree_get_editgroup(snode->nodetree); if(gnode) snode_make_group_editable(snode, NULL); gnode= nodeGetActive(snode->edittree); - if(gnode==NULL) return; + if(gnode==NULL) + return OPERATOR_CANCELLED; - if(gnode->type!=NODE_GROUP) - error("Not a group"); - else { - if(nodeGroupUnGroup(snode->edittree, gnode)) { - - // allqueue(REDRAWNODE, 0); - } - else - error("Can't ungroup"); + if(gnode->type!=NODE_GROUP) { + BKE_report(op->reports, RPT_ERROR, "Not a group"); + return OPERATOR_CANCELLED; + } + else if(!nodeGroupUnGroup(snode->edittree, gnode)) { + BKE_report(op->reports, RPT_ERROR, "Can't ungroup"); + return OPERATOR_CANCELLED; } + + WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); + + return OPERATOR_FINISHED; +} + +void NODE_OT_group_ungroup(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Ungroup"; + ot->description = "Ungroup selected nodes."; + ot->idname = "NODE_OT_group_ungroup"; + + /* api callbacks */ + ot->exec = node_group_ungroup_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } -#endif /* 0 */ /* when links in groups change, inputs/outputs change, nodes added/deleted... */ -static void snode_verify_groups(SpaceNode *snode) +static void node_tree_verify_groups(bNodeTree *nodetree) { bNode *gnode; - gnode= snode_get_editgroup(snode); + gnode= node_tree_get_editgroup(nodetree); /* does all materials */ if(gnode) @@ -1263,7 +1323,7 @@ static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node) sock->flag &= ~SOCK_HIDDEN; } else { - bNode *gnode= snode_get_editgroup(snode); + bNode *gnode= node_tree_get_editgroup(snode->nodetree); /* hiding inside group should not break links in other group users */ if(gnode) { @@ -1291,7 +1351,7 @@ static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node) } // allqueue(REDRAWNODE, 1); - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); } @@ -1418,7 +1478,7 @@ void node_active_link_viewer(SpaceNode *snode) float mx=0, my=0; // XXX short mval[2]; - gnode= snode_get_editgroup(snode); + gnode= node_tree_get_editgroup(snode->nodetree); if(gnode==NULL) return 0; // XXX getmouseco_areawin(mval); @@ -1618,13 +1678,13 @@ bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float node->locy= locy + 60.0f; // arbitrary.. so its visible node->flag |= SELECT; - gnode= snode_get_editgroup(snode); + gnode= node_tree_get_editgroup(snode->nodetree); if(gnode) { node->locx -= gnode->locx; node->locy -= gnode->locy; } - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); node_set_active(snode, node); if(snode->nodetree->type==NTREE_COMPOSIT) { @@ -1654,7 +1714,7 @@ void node_mute(SpaceNode *snode) bNode *node; /* no disabling inside of groups */ - if(snode_get_editgroup(snode)) + if(node_tree_get_editgroup(snode->nodetree)) return; for(node= snode->edittree->nodes.first; node; node= node->next) { @@ -1680,7 +1740,7 @@ int node_duplicate_exec(bContext *C, wmOperator *op) ntreeCopyTree(snode->edittree, 1); /* 1 == internally selected nodes */ ntreeSolveOrder(snode->edittree); - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); snode_handle_recalc(C, snode); return OPERATOR_FINISHED; @@ -1891,7 +1951,7 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) } ntreeSolveOrder(snode->edittree); - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); snode_handle_recalc(C, snode); MEM_freeN(op->customdata); @@ -2000,35 +2060,6 @@ void NODE_OT_link(wmOperatorType *ot) } -void node_delete(SpaceNode *snode) -{ - bNode *node, *next; - bNodeSocket *sock; - - for(node= snode->edittree->nodes.first; node; node= next) { - next= node->next; - if(node->flag & SELECT) { - /* set selin and selout NULL if the sockets belong to a node to be deleted */ - for(sock= node->inputs.first; sock; sock= sock->next) - if(snode->edittree->selin == sock) snode->edittree->selin= NULL; - - for(sock= node->outputs.first; sock; sock= sock->next) - if(snode->edittree->selout == sock) snode->edittree->selout= NULL; - - /* check id user here, nodeFreeNode is called for free dbase too */ - if(node->id) - node->id->us--; - nodeFreeNode(snode->edittree, node); - } - } - - snode_verify_groups(snode); - // NODE_FIX_ME - // snode_handle_recalc(snode); - // allqueue(REDRAWNODE, 1); -} - - void node_hide(SpaceNode *snode) { bNode *node; @@ -2098,7 +2129,7 @@ void node_make_link(SpaceNode *snode) else return; ntreeSolveOrder(snode->edittree); - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); // XXX snode_handle_recalc(snode); } @@ -2153,7 +2184,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) } ntreeSolveOrder(snode->edittree); - snode_verify_groups(snode); + node_tree_verify_groups(snode->nodetree); snode_handle_recalc(C, snode); return OPERATOR_FINISHED; @@ -2253,15 +2284,16 @@ void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser) } } -/* ********************** */ +/* ****************** Make Group operator ******************* */ -void node_make_group(SpaceNode *snode) +static int node_group_make_exec(bContext *C, wmOperator *op) { + SpaceNode *snode = CTX_wm_space_node(C); bNode *gnode; if(snode->edittree!=snode->nodetree) { -// XXX error("Can not add a new Group in a Group"); - return; + BKE_report(op->reports, RPT_ERROR, "Can not add a new Group in a Group"); + return OPERATOR_CANCELLED; } /* for time being... is too complex to handle */ @@ -2271,20 +2303,39 @@ void node_make_group(SpaceNode *snode) if(gnode->type==CMP_NODE_R_LAYERS) break; } + if(gnode) { -// XXX error("Can not add RenderLayer in a Group"); - return; + BKE_report(op->reports, RPT_ERROR, "Can not add RenderLayer in a Group"); + return OPERATOR_CANCELLED; } } gnode= nodeMakeGroupFromSelected(snode->nodetree); if(gnode==NULL) { -// XXX error("Can not make Group"); + BKE_report(op->reports, RPT_ERROR, "Can not make Group"); + return OPERATOR_CANCELLED; } else { nodeSetActive(snode->nodetree, gnode); ntreeSolveOrder(snode->nodetree); } + + return OPERATOR_FINISHED; +} + +void NODE_OT_group_make(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Group"; + ot->description = "Make group from selected nodes."; + ot->idname = "NODE_OT_group_make"; + + /* api callbacks */ + ot->exec = node_group_make_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } #if 0 @@ -2498,29 +2549,50 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt) } #endif -static int node_delete_selection_exec(bContext *C, wmOperator *op) +/* ****************** Delete operator ******************* */ + +static int node_delete_exec(bContext *C, wmOperator *op) { SpaceNode *snode= CTX_wm_space_node(C); - ARegion *ar= CTX_wm_region(C); + bNode *node, *next; + bNodeSocket *sock; + + for(node= snode->edittree->nodes.first; node; node= next) { + next= node->next; + if(node->flag & SELECT) { + /* set selin and selout NULL if the sockets belong to a node to be deleted */ + for(sock= node->inputs.first; sock; sock= sock->next) + if(snode->edittree->selin == sock) snode->edittree->selin= NULL; + + for(sock= node->outputs.first; sock; sock= sock->next) + if(snode->edittree->selout == sock) snode->edittree->selout= NULL; + + /* check id user here, nodeFreeNode is called for free dbase too */ + if(node->id) + node->id->us--; + nodeFreeNode(snode->edittree, node); + } + } - node_delete(snode); - ED_region_tag_redraw(ar); + node_tree_verify_groups(snode->nodetree); + + // NODE_FIX_ME + // snode_handle_recalc(snode); + WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); /* Do we need to pass the scene? */ return OPERATOR_FINISHED; } -/* operators */ - void NODE_OT_delete(wmOperatorType *ot) { - /* identifiers */ ot->name= "Delete"; + ot->description = "Delete selected nodes."; ot->idname= "NODE_OT_delete"; /* api callbacks */ - ot->exec= node_delete_selection_exec; + ot->exec= node_delete_exec; ot->poll= ED_operator_node_active; /* flags */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 6fdaeca7701..2a929472c68 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -81,7 +81,7 @@ void snode_home(ScrArea *sa, ARegion *ar, SpaceNode *snode); void node_set_active(SpaceNode *snode, bNode *node); void node_deselectall(SpaceNode *snode); void snode_composite_job(const struct bContext *C, ScrArea *sa); -bNode *snode_get_editgroup(SpaceNode *snode); +bNode *node_tree_get_editgroup(bNodeTree *ntree); void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag); void NODE_OT_duplicate(struct wmOperatorType *ot); @@ -89,6 +89,9 @@ void NODE_OT_link(struct wmOperatorType *ot); void NODE_OT_delete(struct wmOperatorType *ot); void NODE_OT_resize(struct wmOperatorType *ot); void NODE_OT_links_cut(struct wmOperatorType *ot); +void NODE_OT_group_make(struct wmOperatorType *ot); +void NODE_OT_group_ungroup(struct wmOperatorType *ot); +void NODE_OT_group_edit(struct wmOperatorType *ot); // XXXXXX diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index af857d57634..a10cabfa983 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -62,6 +62,9 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_resize); WM_operatortype_append(NODE_OT_links_cut); WM_operatortype_append(NODE_OT_duplicate); + WM_operatortype_append(NODE_OT_group_make); + WM_operatortype_append(NODE_OT_group_ungroup); + WM_operatortype_append(NODE_OT_group_edit); } void node_keymap(struct wmWindowManager *wm) @@ -88,6 +91,10 @@ void node_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "NODE_OT_select_all", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_select_linked_to", LKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_select_linked_from", LKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "NODE_OT_group_make", GKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "NODE_OT_group_ungroup", GKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0); transform_keymap_for_space(wm, keymap, SPACE_NODE); } -- cgit v1.2.3 From e6b5a2e99ee1e7bb7cb13526ba7e126ebcd0649d Mon Sep 17 00:00:00 2001 From: William Reynish Date: Tue, 15 Sep 2009 12:45:05 +0000 Subject: UI tweaks *Cleaned up Transform panel in n-key area. It's now single column so that this view can be nice and slim, while you can still access everything. This is especially important in edit mode where you cannot change the transform values numerically from the Properties. Transform properties don't seem to work for Metaball edit yet, so wasn't able to test this *Removed some lingering tools in curve transform and put them in the toolbar instead. *Improved alignment in toolbar *Made Image Properties use regular checkmark toggle buttons *Added Delete as an alternative to X key, as it was in 2.4x --- release/ui/space_view3d.py | 15 +- release/ui/space_view3d_toolbar.py | 120 ++++----- source/blender/editors/metaball/mball_ops.c | 1 + source/blender/editors/object/object_ops.c | 3 +- source/blender/editors/space_image/image_buttons.c | 14 +- source/blender/editors/space_node/node_ops.c | 1 + source/blender/editors/space_view3d/space_view3d.c | 2 +- .../blender/editors/space_view3d/view3d_buttons.c | 279 +++++++++++---------- 8 files changed, 219 insertions(+), 216 deletions(-) diff --git a/release/ui/space_view3d.py b/release/ui/space_view3d.py index 33f9fbb853d..62b7fa0d91f 100644 --- a/release/ui/space_view3d.py +++ b/release/ui/space_view3d.py @@ -1136,16 +1136,17 @@ class VIEW3D_PT_3dview_properties(bpy.types.Panel): scene = context.scene col = layout.column() - col.itemR(view, "camera") + col.itemL(text="Camera:") + col.itemR(view, "camera", text="") col.itemR(view, "lens") - layout.itemL(text="Clip:") col = layout.column(align=True) + col.itemL(text="Clip:") col.itemR(view, "clip_start", text="Start") col.itemR(view, "clip_end", text="End") - layout.itemL(text="Grid:") col = layout.column(align=True) + col.itemL(text="Grid:") col.itemR(view, "grid_lines", text="Lines") col.itemR(view, "grid_spacing", text="Spacing") col.itemR(view, "grid_subdivisions", text="Subdivisions") @@ -1156,7 +1157,8 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel): __space_type__ = 'VIEW_3D' __region_type__ = 'UI' __label__ = "Display" - + __default_closed__ = True + def poll(self, context): view = context.space_data return (view) @@ -1177,7 +1179,7 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel): layout.itemS() - layout.itemO("screen.region_foursplit") + layout.itemO("screen.region_foursplit", text="Toggle Quad View") col = layout.column() col.itemR(view, "lock_rotation") @@ -1272,9 +1274,10 @@ class VIEW3D_PT_background_image(bpy.types.Panel): #col.itemR(bg, "image_user") col.itemR(bg, "size") col.itemR(bg, "transparency", slider=True) - col.itemL(text="Offset:") + col = layout.column(align=True) + col.itemL(text="Offset:") col.itemR(bg, "offset_x", text="X") col.itemR(bg, "offset_y", text="Y") diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 40ebb6883f0..fe0f4ca5a21 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -14,36 +14,32 @@ class VIEW3D_PT_tools_objectmode(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Object:") - col = layout.column(align=True) + col.itemL(text="Object:") col.itemO("object.duplicate") col.itemO("object.delete") active_object= context.active_object if active_object and active_object.type == 'MESH': - layout.itemL(text="Shading:") - + col = layout.column(align=True) + col.itemL(text="Shading:") col.itemO("object.shade_smooth", text="Smooth") col.itemO("object.shade_flat", text="Flat") - layout.itemL(text="Keyframes:") - col = layout.column(align=True) + col.itemL(text="Keyframes:") col.itemO("anim.insert_keyframe_menu", text="Insert") col.itemO("anim.delete_keyframe_v3d", text="Remove") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -57,43 +53,37 @@ class VIEW3D_PT_tools_meshedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Mesh:") - col = layout.column(align=True) + col.itemL(text="Mesh:") col.itemO("mesh.duplicate") col.itemO("mesh.delete") - layout.itemL(text="Modeling:") - col = layout.column(align=True) + col.itemL(text="Modeling:") col.itemO("mesh.extrude") col.itemO("mesh.subdivide") col.itemO("mesh.spin") col.itemO("mesh.screw") - layout.itemL(text="Shading:") - col = layout.column(align=True) + col.itemL(text="Shading:") col.itemO("mesh.faces_shade_smooth", text="Smooth") col.itemO("mesh.faces_shade_flat", text="Flat") - layout.itemL(text="UV Mapping:") - col = layout.column(align=True) + col.itemL(text="UV Mapping:") col.itemO("uv.mapping_menu", text="Unwrap") col.itemO("mesh.uvs_rotate") col.itemO("mesh.uvs_mirror") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -107,31 +97,34 @@ class VIEW3D_PT_tools_curveedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - - layout.itemL(text="Curve:") col = layout.column(align=True) + col.itemL(text="Curve:") col.itemO("curve.duplicate") col.itemO("curve.delete") col.itemO("curve.cyclic_toggle") col.itemO("curve.switch_direction") col.itemO("curve.spline_type_set") - layout.itemL(text="Modeling:") - col = layout.column(align=True) + col.itemL(text="Handles:") + col.item_enumO("curve.handle_type_set", "type", 'AUTOMATIC') + col.item_enumO("curve.handle_type_set", "type", 'VECTOR') + col.item_enumO("curve.handle_type_set", "type", 'ALIGN') + col.item_enumO("curve.handle_type_set", "type", 'FREE_ALIGN') + + col = layout.column(align=True) + col.itemL(text="Modeling:") col.itemO("curve.extrude") col.itemO("curve.subdivide") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -145,30 +138,26 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Curve:") - col = layout.column(align=True) + col.itemL(text="Curve:") col.itemO("curve.duplicate") col.itemO("curve.delete") col.itemO("curve.cyclic_toggle") col.itemO("curve.switch_direction") - layout.itemL(text="Modeling:") - col = layout.column(align=True) + col.itemL(text="Modeling:") col.itemO("curve.extrude") col.itemO("curve.subdivide") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -182,22 +171,21 @@ class VIEW3D_PT_tools_textedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Text Edit:") + col = layout.column(align=True) + col.itemL(text="Text Edit:") col.itemO("font.text_copy", text="Copy") col.itemO("font.text_cut", text="Cut") col.itemO("font.text_paste", text="Paste") - layout.itemL(text="Style:") - col = layout.column(align=True) + col.itemL(text="Style:") col.itemO("font.case_set") col.itemO("font.style_toggle") - - layout.itemL(text="Repeat:") - + col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -211,26 +199,26 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") + col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - - layout.itemL(text="Bones:") col = layout.column(align=True) + col.itemL(text="Bones:") col.itemO("armature.bone_primitive_add", text="Add") col.itemO("armature.duplicate", text="Duplicate") col.itemO("armature.delete", text="Delete") - layout.itemL(text="Modeling:") - layout.itemO("armature.extrude") - - layout.itemL(text="Repeat:") + col = layout.column(align=True) + col.itemL(text="Modeling:") + col.itemO("armature.extrude") col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -244,16 +232,14 @@ class VIEW3D_PT_tools_mballedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -267,16 +253,14 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") - col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") @@ -290,40 +274,36 @@ class VIEW3D_PT_tools_posemode(View3DPanel): def draw(self, context): layout = self.layout - layout.itemL(text="Transform:") + col = layout.column(align=True) + col.itemL(text="Transform:") col.itemO("tfm.translate") col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") - layout.itemL(text="Bones:") - col = layout.column(align=True) + col.itemL(text="Bones:") col.itemO("pose.hide", text="Hide") col.itemO("pose.reveal", text="Reveal") - layout.itemL(text="Keyframes:") - col = layout.column(align=True) + layout.itemL(text="Keyframes:") col.itemO("anim.insert_keyframe_menu", text="Insert") col.itemO("anim.delete_keyframe_v3d", text="Remove") - layout.itemL(text="Pose:") - col = layout.column(align=True) + col.itemL(text="Pose:") col.itemO("pose.copy", text="Copy") col.itemO("pose.paste", text="Paste") - layout.itemL(text="Library:") - col = layout.column(align=True) + col.itemL(text="Library:") col.itemO("poselib.pose_add", text="Add") col.itemO("poselib.pose_remove", text="Remove") - layout.itemL(text="Repeat:") - col = layout.column(align=True) + col.itemL(text="Repeat:") col.itemO("screen.repeat_last") col.itemO("screen.repeat_history", text="History...") col.itemO("screen.redo_last", text="Tweak...") diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index 38593af372f..b469bb3e400 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -60,6 +60,7 @@ void ED_keymap_metaball(wmWindowManager *wm) RNA_enum_set(WM_keymap_add_item(keymap, "MBALL_OT_hide_metaelems", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1); WM_keymap_add_item(keymap, "MBALL_OT_delete_metaelems", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MBALL_OT_delete_metaelems", DELKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MBALL_OT_duplicate_metaelems", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "MBALL_OT_select_deselect_all_metaelems", AKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index ddcecdeb1f1..6ee43765475 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -227,7 +227,8 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_restrictview_set", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_restrictview_set", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1); - WM_keymap_verify_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OBJECT_OT_primitive_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0)->ptr, "linked", 1); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 647b9a4b51f..456e802194e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1326,14 +1326,14 @@ void ED_image_uiblock_panel(const bContext *C, uiBlock *block, Image **ima_pp, I /* fields */ - but= uiDefButBitS(block, TOGBUT, IMA_FIELDS, imagechanged, "Fields", 0, 80, 200, 20, &ima->flag, 0, 0, 0, 0, "Click to enable use of fields in Image"); + but= uiDefButBitS(block, OPTION, IMA_FIELDS, imagechanged, "Fields", 0, 80, 200, 20, &ima->flag, 0, 0, 0, 0, "Click to enable use of fields in Image"); uiButSetFunc(but, image_field_test, ima, iuser); - uiDefButBitS(block, TOGBUT, IMA_STD_FIELD, B_NOP, "Odd", 0, 55, 200, 20, &ima->flag, 0, 0, 0, 0, "Standard Field Toggle"); + uiDefButBitS(block, OPTION, IMA_STD_FIELD, B_NOP, "Odd", 0, 55, 200, 20, &ima->flag, 0, 0, 0, 0, "Standard Field Toggle"); uiBlockSetFunc(block, image_reload_cb, ima, iuser); - uiDefButBitS(block, TOGBUT, IMA_ANTIALI, B_NOP, "Anti", 0, 5, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles Image anti-aliasing, only works with solid colors"); - uiDefButBitS(block, TOGBUT, IMA_DO_PREMUL, imagechanged, "Premul", 0, -20, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles premultiplying alpha"); + uiDefButBitS(block, OPTION, IMA_ANTIALI, B_NOP, "Anti-Aliasing", 0, 5, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles Image anti-aliasing, only works with solid colors"); + uiDefButBitS(block, OPTION, IMA_DO_PREMUL, imagechanged, "Premultiply", 0, -20, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles premultiplying alpha"); if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { @@ -1356,9 +1356,9 @@ void ED_image_uiblock_panel(const bContext *C, uiBlock *block, Image **ima_pp, I uiDefButI(block, NUM, imagechanged, "Offset:", 220, 30, 200, 20, &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation"); uiDefButS(block, NUM, imagechanged, "Fields:", 0, 30, 200, 20, &iuser->fie_ima, 1.0, 200.0, 0, 0, "The number of fields per rendered frame (2 fields is 1 image)"); - uiDefButBitS(block, TOG, IMA_ANIM_ALWAYS, B_NOP, "Auto Refresh", 220, 5, 200, 20, &iuser->flag, 0, 0, 0, 0, "Always refresh Image on frame changes"); + uiDefButBitS(block, OPTION, IMA_ANIM_ALWAYS, B_NOP, "Auto Refresh", 220, 5, 200, 20, &iuser->flag, 0, 0, 0, 0, "Always refresh Image on frame changes"); - uiDefButS(block, TOG, imagechanged, "Cyclic", 220, -20, 200, 20, &iuser->cycl, 0.0, 1.0, 0, 0, "Cycle the images in the movie"); + uiDefButS(block, OPTION, imagechanged, "Cyclic", 220, -20, 200, 20, &iuser->cycl, 0.0, 1.0, 0, 0, "Cycle the images in the movie"); uiBlockSetFunc(block, NULL, iuser, NULL); } @@ -1372,7 +1372,7 @@ void ED_image_uiblock_panel(const bContext *C, uiBlock *block, Image **ima_pp, I uiDefButS(block, NUM, imagechanged, "Y:", 220, 35,200,20, &ima->gen_y, 1.0, 5000.0, 0, 0, "Image size y"); uiBlockEndAlign(block); - uiDefButS(block, TOGBUT, imagechanged, "UV Test grid", 220,10,200,20, &ima->gen_type, 0.0, 1.0, 0, 0, ""); + uiDefButS(block, OPTION, imagechanged, "UV Test grid", 220,10,200,20, &ima->gen_type, 0.0, 1.0, 0, 0, ""); uiBlockSetFunc(block, NULL, NULL, NULL); } } diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index a10cabfa983..4c2fbf7b9dc 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -87,6 +87,7 @@ void node_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "NODE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_select_border", BKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "NODE_OT_delete", DELKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_select_all", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_select_linked_to", LKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 05bf1c80b43..b5e5de928b5 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -912,7 +912,7 @@ void ED_spacetype_view3d(void) /* regions: listview/buttons */ art= MEM_callocN(sizeof(ARegionType), "spacetype view3d region"); art->regionid = RGN_TYPE_UI; - art->minsizex= 220; // XXX + art->minsizex= 180; // XXX art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES; art->listener= view3d_buttons_area_listener; art->init= view3d_buttons_area_init; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 1ff5dca7307..7d4e3337fe3 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -302,60 +302,68 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d, if((ob->parent) && (ob->partype == PARBONE)) but_y = 135; else but_y = 150; - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 20, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); - uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 20, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); - uiBlockEndAlign(block); + memcpy(tfp->ve_median, median, sizeof(tfp->ve_median)); uiBlockBeginAlign(block); if(tot==1) { uiDefBut(block, LABEL, 0, "Vertex:", 0, 130, 200, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); - if(totw==1) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Vertex W:", 0, 50, 200, 19, &(tfp->ve_median[3]), 0.01, 100.0, 10, 3, ""); - uiBlockEndAlign(block); - - if(defstr[0]) { - uiDefBut(block, LABEL, 1, "Vertex Deform Groups", 0, 40, 200, 20, NULL, 0.0, 0.0, 0, 0, ""); - + + if(totw==1) { + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 10, 3, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NOP, "Weight:", 10, 20, 150, 20, tfp->defweightp, 0.0f, 1.0f, 10, 3, "Weight value"); - uiDefButI(block, MENU, B_REDR, defstr, 160, 20, 140, 20, &tfp->curdef, 0.0, 0.0, 0, 0, "Current Vertex Group"); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); + if(totweight) + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); + } + else { + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiBlockEndAlign(block); + if(totweight) + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); } - else if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); - } else { - uiDefBut(block, LABEL, 0, "Median:", 0, 130, 200, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Median:", 0, 130, 200, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); - if(totw==tot) + if(totw==tot) { uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 10, 3, ""); - uiBlockEndAlign(block); - if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); - } - - if(ob->type==OB_CURVE && (totw==0)) { /* bez curves have no w */ - uiBlockBeginAlign(block); - uiDefBut(block, BUT,B_SETPT_AUTO,"Auto", 10, 44, 72, 19, 0, 0, 0, 0, 0, "Auto handles (Shift H)"); - uiDefBut(block, BUT,B_SETPT_VECTOR,"Vector",82, 44, 73, 19, 0, 0, 0, 0, 0, "Vector handles (V)"); - uiDefBut(block, BUT,B_SETPT_ALIGN,"Align",155, 44, 73, 19, 0, 0, 0, 0, 0, "Align handles (H Toggles)"); - uiDefBut(block, BUT,B_SETPT_FREE,"Free", 227, 44, 72, 19, 0, 0, 0, 0, 0, "Align handles (H Toggles)"); - uiBlockEndAlign(block); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiBlockEndAlign(block); + if(totweight) + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); + uiBlockEndAlign(block); + } + else { + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiBlockEndAlign(block); + if(totweight) + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); + uiBlockEndAlign(block); + } } - + if(totedge==1) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease W:", 0, 45, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, ""); else if(totedge>1) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median Crease W:", 0, 45, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, ""); } else { // apply @@ -503,14 +511,6 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if(bone && (bone->flag & BONE_ACTIVE) && (bone->layer & arm->layer)) break; } - if (!pchan || !bone) return; - - if((ob->parent) && (ob->partype == PARBONE)) - but= uiDefBut (block, TEX, B_NOP, "Bone:", 160, 130, 140, 19, bone->name, 1, 31, 0, 0, ""); - else - but= uiDefBut(block, TEX, B_NOP, "Bone:", 160, 140, 140, 19, bone->name, 1, 31, 0, 0, ""); - uiButSetFunc(but, validate_bonebutton_cb, bone, NULL); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); if (pchan->rotmode == PCHAN_ROT_AXISANGLE) { float quat[4]; @@ -526,29 +526,43 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float tfp->ob_eul[1]*= 180.0/M_PI; tfp->ob_eul[2]*= 180.0/M_PI; + uiDefBut(block, LABEL, 0, "Location:", 0, 240, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, B_REDR, ICON_UNLOCKED, 10,140,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocX:", 30, 140, 120, 19, pchan->loc, -lim, lim, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, B_REDR, ICON_UNLOCKED, 10,120,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocY:", 30, 120, 120, 19, pchan->loc+1, -lim, lim, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, B_REDR, ICON_UNLOCKED, 10,100,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocZ:", 30, 100, 120, 19, pchan->loc+2, -lim, lim, 100, 3, ""); - + uiDefButF(block, NUM, B_ARMATUREPANEL2, "X:", 0, 220, 120, 19, pchan->loc, -lim, lim, 100, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL2, "Y:", 0, 200, 120, 19, pchan->loc+1, -lim, lim, 100, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL2, "Z:", 0, 180, 120, 19, pchan->loc+2, -lim, lim, 100, 3, ""); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 10,70,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotX:", 30, 70, 120, 19, tfp->ob_eul, -1000.0, 1000.0, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 10,50,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotY:", 30, 50, 120, 19, tfp->ob_eul+1, -1000.0, 1000.0, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 10,30,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotZ:", 30, 30, 120, 19, tfp->ob_eul+2, -1000.0, 1000.0, 100, 3, ""); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, B_REDR, ICON_UNLOCKED, 125, 220, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects X Location value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, B_REDR, ICON_UNLOCKED, 125, 200, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects Y Location value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, B_REDR, ICON_UNLOCKED, 125, 180, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects Z Location value from being Transformed"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "Rotation:", 0, 160, 100, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_ARMATUREPANEL3, "X:", 0, 140, 120, 19, tfp->ob_eul, -1000.0, 1000.0, 100, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL3, "Y:", 0, 120, 120, 19, tfp->ob_eul+1, -1000.0, 1000.0, 100, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL3, "Z:", 0, 100, 120, 19, tfp->ob_eul+2, -1000.0, 1000.0, 100, 3, ""); + uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, B_REDR, ICON_UNLOCKED, 160,70,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleX:", 180, 70, 120, 19, pchan->size, -lim, lim, 10, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, B_REDR, ICON_UNLOCKED, 160,50,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleY:", 180, 50, 120, 19, pchan->size+1, -lim, lim, 10, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, B_REDR, ICON_UNLOCKED, 160,30,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleZ:", 180, 30, 120, 19, pchan->size+2, -lim, lim, 10, 3, ""); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 125, 140, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects X Rotation value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 125, 120, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects Y Rotation value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 125, 100, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects Z Rotation value from being Transformed"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "Scale:", 0, 80, 100, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_ARMATUREPANEL2, "X:", 0, 60, 120, 19, pchan->size, -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL2, "Y:", 0, 40, 120, 19, pchan->size+1, -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL2, "Z:", 0, 20, 120, 19, pchan->size+2, -lim, lim, 10, 3, ""); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, B_REDR, ICON_UNLOCKED, 125, 60, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects X Scale value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, B_REDR, ICON_UNLOCKED, 125, 40, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects Y Scale value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, B_REDR, ICON_UNLOCKED, 125, 20, 25, 19, &(pchan->protectflag), 0, 0, 0, 0, "Protects z Scale value from being Transformed"); uiBlockEndAlign(block); } @@ -585,34 +599,31 @@ static void v3d_editarmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if (!ebone) return; - if((ob->parent) && (ob->partype == PARBONE)) - but= uiDefBut(block, TEX, B_NOP, "Bone:", 160, 130, 140, 19, ebone->name, 1, 31, 0, 0, ""); - else - but= uiDefBut(block, TEX, B_NOP, "Bone:", 160, 150, 140, 19, ebone->name, 1, 31, 0, 0, ""); - uiButSetFunc(but, validate_editbonebutton_cb, ebone, NULL); - + uiDefBut(block, LABEL, 0, "Head:", 0, 210, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadX:", 10, 70, 140, 19, ebone->head, -lim, lim, 10, 3, ""); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadY:", 10, 50, 140, 19, ebone->head+1, -lim, lim, 10, 3, ""); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadZ:", 10, 30, 140, 19, ebone->head+2, -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "X:", 0, 190, 100, 19, ebone->head, -lim, lim, 10, 3, "X Location of the head end of the bone"); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Y:", 0, 170, 100, 19, ebone->head+1, -lim, lim, 10, 3, "Y Location of the head end of the bone"); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Z:", 0, 150, 100, 19, ebone->head+2, -lim, lim, 10, 3, "Z Location of the head end of the bone"); + if (ebone->parent && ebone->flag & BONE_CONNECTED ) + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Radius:", 0, 130, 100, 19, &ebone->parent->rad_tail, 0, lim, 10, 3, "Head radius. Visualize with the Envelope display option"); + else + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Radius:", 0, 130, 100, 19, &ebone->rad_head, 0, lim, 10, 3, "Head radius. Visualize with the Envelope display option"); + uiBlockEndAlign(block); + + uiBlockEndAlign(block); + uiDefBut(block, LABEL, 0, "Tail:", 0, 110, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailX:", 160, 70, 140, 19, ebone->tail, -lim, lim, 10, 3, ""); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailY:", 160, 50, 140, 19, ebone->tail+1, -lim, lim, 10, 3, ""); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailZ:", 160, 30, 140, 19, ebone->tail+2, -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "X:", 0, 90, 100, 19, ebone->tail, -lim, lim, 10, 3, "X Location of the tail end of the bone"); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Y:", 0, 70, 100, 19, ebone->tail+1, -lim, lim, 10, 3, "Y Location of the tail end of the bone"); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Z:", 0, 50, 100, 19, ebone->tail+2, -lim, lim, 10, 3, "Z Location of the tail end of the bone"); + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Radius:", 0, 30, 100, 19, &ebone->rad_tail, 0, lim, 10, 3, "Tail radius. Visualize with the Envelope display option"); uiBlockEndAlign(block); tfp->ob_eul[0]= 180.0*ebone->roll/M_PI; - uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, ""); - - uiDefButBitI(block, TOG, BONE_EDITMODE_LOCKED, B_REDR, "Lock", 160, 100, 140, 19, &(ebone->flag), 0, 0, 0, 0, "Prevents bone from being transformed in edit mode"); - + uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 0, 0, 100, 19, tfp->ob_eul, -lim, lim, 1000, 3, "Bone rotation around head-tail axis"); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailRadius:", 10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, ""); - if (ebone->parent && ebone->flag & BONE_CONNECTED ) - uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadRadius:", 10, 130, 140, 19, &ebone->parent->rad_tail, 0, lim, 10, 3, ""); - else - uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadRadius:", 10, 130, 140, 19, &ebone->rad_head, 0, lim, 10, 3, ""); - uiBlockEndAlign(block); + + } static void v3d_editmetaball_buts(uiBlock *block, Object *ob, float lim) @@ -1083,19 +1094,8 @@ static void view3d_panel_object(const bContext *C, Panel *pa) if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)) { } else { - //bt= uiDefBut(block, TEX, B_IDNAME, "OB: ", 10,180,140,20, ob->id.name+2, 0.0, 21.0, 0, 0, ""); - //uiButSetFunc(bt, test_idbutton_cb, ob->id.name, NULL); - if((ob->mode & OB_MODE_PARTICLE_EDIT)==0) { - // uiBlockBeginAlign(block); - // uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_OBJECTPANELPARENT, "Par:", 160, 180, 140, 20, &ob->parent, "Parent Object"); - if((ob->parent) && (ob->partype == PARBONE)) { - // bt= uiDefBut(block, TEX, B_OBJECTPANELPARENT, "ParBone:", 160, 160, 140, 20, ob->parsubstr, 0, 30, 0, 0, ""); - // uiButSetCompleteFunc(bt, autocomplete_bone, (void *)ob->parent); - } - else { - strcpy(ob->parsubstr, ""); - } + strcpy(ob->parsubstr, ""); uiBlockEndAlign(block); } } @@ -1113,14 +1113,18 @@ static void view3d_panel_object(const bContext *C, Panel *pa) else { BoundBox *bb = NULL; - uiDefBut(block, LABEL, 0, "Location:", 10, 170, 100, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Location:", 0, 300, 100, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_OBJECTPANEL, "X:", 0, 280, 120, 19, &(ob->loc[0]), -lim, lim, 100, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANEL, "Y:", 0, 260, 120, 19, &(ob->loc[1]), -lim, lim, 100, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANEL, "Z:", 0, 240, 120, 19, &(ob->loc[2]), -lim, lim, 100, 3, ""); + uiBlockEndAlign(block); + uiBlockBeginAlign(block); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, B_REDR, ICON_UNLOCKED, 10,150,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANEL, "X:", 30, 150, 120, 19, &(ob->loc[0]), -lim, lim, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, B_REDR, ICON_UNLOCKED, 10,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANEL, "Y:", 30, 130, 120, 19, &(ob->loc[1]), -lim, lim, 100, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, B_REDR, ICON_UNLOCKED, 10,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANEL, "Z:", 30, 110, 120, 19, &(ob->loc[2]), -lim, lim, 100, 3, ""); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, B_REDR, ICON_UNLOCKED, 125, 280, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects X Location value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, B_REDR, ICON_UNLOCKED, 125, 260, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Y Location value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, B_REDR, ICON_UNLOCKED, 125, 240, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Z Location value from being Transformed"); + uiBlockEndAlign(block); tfp->ob_eul[0]= 180.0*ob->rot[0]/M_PI; tfp->ob_eul[1]= 180.0*ob->rot[1]/M_PI; @@ -1128,40 +1132,53 @@ static void view3d_panel_object(const bContext *C, Panel *pa) uiBlockBeginAlign(block); if ((ob->parent) && (ob->partype == PARBONE)) { - uiDefBut(block, LABEL, 0, "Rotation:", 160, 170, 100, 20, 0, 0, 0, 0, 0, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 160,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "X:", 180, 130, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 160,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "Y:", 180, 110, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 160,90,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "Z:", 180, 90, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, ""); + uiDefBut(block, LABEL, 0, "Rotation:", 0, 220, 100, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_OBJECTPANELROT, "X:", 0, 200, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELROT, "Y:", 0, 180, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELROT, "Z:", 0, 160, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, ""); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 125, 200, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects X Rotation from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 125, 180, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Y Rotation value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 125, 160, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Z Rotation value from being Transformed"); + uiBlockEndAlign(block); } else { - uiDefBut(block, LABEL, 0, "Rotation:", 160, 170, 100, 20, 0, 0, 0, 0, 0, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 160,150,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "X:", 180, 150, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 160,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "Y:", 180, 130, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 160,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELROT, "Z:", 180, 110, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, ""); + uiDefBut(block, LABEL, 0, "Rotation:", 0, 220, 100, 20, 0, 0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_OBJECTPANELROT, "X:", 0, 200, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELROT, "Y:", 0, 180, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELROT, "Z:", 0, 160, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, ""); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, B_REDR, ICON_UNLOCKED, 125, 200, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects X Rotation value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, B_REDR, ICON_UNLOCKED, 125, 180, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Y Rotation value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, B_REDR, ICON_UNLOCKED, 125, 160, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Z Rotation value from being Transformed"); + uiBlockEndAlign(block); } tfp->ob_scale[0]= ob->size[0]; tfp->ob_scale[1]= ob->size[1]; tfp->ob_scale[2]= ob->size[2]; - uiDefBut(block, LABEL, 0, "Scale:", 10, 90, 100, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Scale:", 0, 140, 100, 20, 0, 0, 0, 0, 0, ""); + uiDefButS(block, OPTION, B_REDR, "Link", 60, 140, 50, 19, &(tfp->link_scale), 0, 1, 0, 0, "Scale values vary proportionally in all directions"); uiBlockBeginAlign(block); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, B_REDR, ICON_UNLOCKED, 10, 70, 20, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELSCALE, "X:", 30, 70, 120, 19, &(tfp->ob_scale[0]), -lim, lim, 10, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, B_REDR, ICON_UNLOCKED, 10, 50, 20, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELSCALE, "Y:", 30, 50, 120, 19, &(tfp->ob_scale[1]), -lim, lim, 10, 3, ""); - uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, B_REDR, ICON_UNLOCKED, 10, 30, 20, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed"); - uiDefButF(block, NUM, B_OBJECTPANELSCALE, "Z:", 30, 30, 120, 19, &(tfp->ob_scale[2]), -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELSCALE, "X:", 0, 120, 120, 19, &(tfp->ob_scale[0]), -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELSCALE, "Y:", 0, 100, 120, 19, &(tfp->ob_scale[1]), -lim, lim, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELSCALE, "Z:", 0, 80, 120, 19, &(tfp->ob_scale[2]), -lim, lim, 10, 3, ""); uiBlockEndAlign(block); - uiDefButS(block, TOG, B_REDR, "Link Scale", 10, 0, 140, 19, &(tfp->link_scale), 0, 1, 0, 0, "Scale values vary proportionally in all directions"); + uiBlockBeginAlign(block); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, B_REDR, ICON_UNLOCKED, 125, 120, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects X Scale value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, B_REDR, ICON_UNLOCKED, 125, 100, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Y Scale value from being Transformed"); + uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, B_REDR, ICON_UNLOCKED, 125, 80, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Z Scale value from being Transformed"); + + bb= object_get_boundbox(ob); if (bb) { @@ -1175,19 +1192,19 @@ static void view3d_panel_object(const bContext *C, Panel *pa) if ((ob->parent) && (ob->partype == PARBONE)) { - uiDefBut(block, LABEL, 0, "Dimensions:", 160, 90, 100, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Dimensions:", 0, 60, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "X:", 160, 70, 140, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate bounding box size"); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Y:", 160, 50, 140, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate bounding box size"); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Z:", 160, 30, 140, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "X:", 0, 40, 150, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate X bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Y:", 0, 20, 150, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate Y bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Z:", 0, 0, 150, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate Z bounding box size"); } else { - uiDefBut(block, LABEL, 0, "Dimensions:", 160, 90, 100, 20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Dimensions:", 0, 60, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "X:", 160, 70, 140, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate bounding box size"); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Y:", 160, 50, 140, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate bounding box size"); - uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Z:", 160, 30, 140, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "X:", 0, 40, 150, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate X bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Y:", 0, 20, 150, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate Y bounding box size"); + uiDefButF(block, NUM, B_OBJECTPANELDIMS, "Z:", 0, 0, 150, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate Z bounding box size"); } uiBlockEndAlign(block); -- cgit v1.2.3 From 971e984b083c1d0a44d257294f18e2750522853a Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Tue, 15 Sep 2009 13:28:36 +0000 Subject: Update MSVC project files --- projectfiles_vc9/blender/editors/ED_editors.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projectfiles_vc9/blender/editors/ED_editors.vcproj b/projectfiles_vc9/blender/editors/ED_editors.vcproj index 5a6519d3d35..81d80436a00 100644 --- a/projectfiles_vc9/blender/editors/ED_editors.vcproj +++ b/projectfiles_vc9/blender/editors/ED_editors.vcproj @@ -1214,6 +1214,10 @@ RelativePath="..\..\..\source\blender\editors\mesh\editmesh_tools.c" > + + -- cgit v1.2.3 From 0a8fa9ff70af7e2262584d12ef8305c27bdf7cc8 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Tue, 15 Sep 2009 16:05:59 +0000 Subject: Smoke: * This should make low res bake too if high res gets baked --- source/blender/blenkernel/intern/pointcache.c | 19 +++++++++++++++++++ source/blender/blenkernel/intern/smoke.c | 1 + 2 files changed, 20 insertions(+) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 7725efe3885..d685bc29568 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -2119,6 +2119,25 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker) if((cache->flag & PTCACHE_BAKED)==0) { if(pid->type==PTCACHE_TYPE_PARTICLES) psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe); + else if(pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) { + /* get all pids from the object and search for smoke low res */ + ListBase pidlist2; + PTCacheID *pid2; + BKE_ptcache_ids_from_object(&pidlist2, pid->ob); + for(pid2=pidlist2.first; pid2; pid2=pid2->next) { + if(pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) + { + if(pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) { + if(bake || pid2->cache->flag & PTCACHE_REDO_NEEDED) + BKE_ptcache_id_clear(pid2, PTCACHE_CLEAR_ALL, 0); + if(bake) { + pid2->cache->flag |= PTCACHE_BAKING; + pid2->cache->flag &= ~PTCACHE_BAKED; + } + } + } + } + } if(bake || cache->flag & PTCACHE_REDO_NEEDED) BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 1b6b4d4838e..62463b3d555 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1182,6 +1182,7 @@ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedM cache->simframe= framenr; // simulate the actual smoke (c++ code in intern/smoke) + // DG: interesting commenting this line + deactivating loading of noise files if(framenr!=startframe) smoke_step(sds->fluid, smd->time); -- cgit v1.2.3 From fd664970f17b71764753ffe3fb87388f40c91da2 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Tue, 15 Sep 2009 16:25:53 +0000 Subject: Completely move freeing flag to report, operator flag is uneeded. Also bugfix for py operators. Reports need to be kept alive when operator is registered. --- source/blender/makesdna/DNA_windowmanager_types.h | 1 - source/blender/windowmanager/intern/wm.c | 2 +- source/blender/windowmanager/intern/wm_event_system.c | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index c3bbb759aff..4274cb7ebc0 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -298,7 +298,6 @@ typedef struct wmOperator { #define OPERATOR_PASS_THROUGH 8 /* wmOperator flag */ -#define OPERATOR_REPORT_FREE 1 /* ************** wmEvent ************************ */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 0a91c5078b7..4405b52888d 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -69,7 +69,7 @@ void WM_operator_free(wmOperator *op) MEM_freeN(op->properties); } - if(op->reports && ((op->flag & OPERATOR_REPORT_FREE) || (op->reports->flag & RPT_FREE))) { + if(op->reports && (op->reports->flag & RPT_FREE)) { BKE_reports_clear(op->reports); MEM_freeN(op->reports); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b5ecc6f4d58..306b99dcfcc 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -349,8 +349,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P } else { op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); - BKE_reports_init(op->reports, RPT_STORE); - op->flag |= OPERATOR_REPORT_FREE; + BKE_reports_init(op->reports, RPT_STORE|RPT_FREE); } /* recursive filling of operator macro list */ @@ -555,7 +554,8 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA retval= wm_operator_call_internal(C, ot, context, properties, reports); - if (retval & OPERATOR_RUNNING_MODAL) + /* keep the reports around if needed later */ + if (retval & OPERATOR_RUNNING_MODAL || ot->flag & OPTYPE_REGISTER) { reports->flag |= RPT_FREE; } -- cgit v1.2.3 From 22274d38079f7e1e1e0bf24e777c333961ed18f7 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Tue, 15 Sep 2009 19:53:18 +0000 Subject: More automatic stuff. Server can now be set to broadcast on local network (every 10s, approximately 20 bytes of data) where client and slave can pick up its existence. This is on by default. Default ip address is now "[default]", which means for the master that it will listen to all interface and for the clients and slave that they will automatically work out the master's address from its broadcast. --- release/io/netrender/client.py | 13 +++++++------ release/io/netrender/master.py | 24 +++++++++++++++++++++-- release/io/netrender/operators.py | 41 +++++++++++++++++++++++++++++++++++++-- release/io/netrender/slave.py | 27 ++++++++++++++++++-------- release/io/netrender/ui.py | 24 +++++++++++++++++------ release/io/netrender/utils.py | 7 +++++-- 6 files changed, 110 insertions(+), 26 deletions(-) diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py index d059387cfcf..a6cfb4e020d 100644 --- a/release/io/netrender/client.py +++ b/release/io/netrender/client.py @@ -138,12 +138,12 @@ class NetworkRenderEngine(bpy.types.RenderEngine): print("UNKNOWN OPERATION MODE") def render_master(self, scene): - server_address = (scene.network_render.server_address, scene.network_render.server_port) - httpd = master.RenderMasterServer(server_address, master.RenderHandler, scene.network_render.path) - httpd.timeout = 1 - httpd.stats = self.update_stats - while not self.test_break(): - httpd.handle_request() + netsettings = scene.network_render + + address = "" if netsettings.server_address == "[default]" else netsettings.server_address + + master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break) + def render_slave(self, scene): slave.render_slave(self, scene) @@ -152,6 +152,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): netsettings = scene.network_render self.update_stats("", "Network render client initiation") + conn = clientConnection(scene) if conn: diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 78e9243bc9d..13e8b399d6c 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -1,5 +1,5 @@ import sys, os -import http, http.client, http.server, urllib +import http, http.client, http.server, urllib, socket import subprocess, shutil, time, hashlib from netrender.utils import * @@ -529,7 +529,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_frame = int(self.headers['job-frame']) buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".log", 'wb') + f = open(job.save_path + "%04d" % job_frame + ".log", 'ab') f.write(buf) f.close() @@ -613,3 +613,23 @@ class RenderMasterServer(http.server.HTTPServer): return job, job.getFrames() return None, None + +def runMaster(address, broadcast, path, update_stats, test_break): + httpd = RenderMasterServer(address, RenderHandler, path) + httpd.timeout = 1 + httpd.stats = update_stats + + if broadcast: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + start_time = time.time() + + while not test_break(): + httpd.handle_request() + + if broadcast: + if time.time() - start_time >= 10: # need constant here + print("broadcasting address") + s.sendto(bytes("%s:%i" % address, encoding='utf8'), 0, ('',address[1])) + start_time = time.time() diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index 655afa6631f..928c2b9efaf 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -1,6 +1,6 @@ import bpy import sys, os -import http, http.client, http.server, urllib +import http, http.client, http.server, urllib, socket from netrender.utils import * import netrender.client as client @@ -316,4 +316,41 @@ class netclientdownload(bpy.types.Operator): return ('FINISHED',) def invoke(self, context, event): - return self.execute(context) \ No newline at end of file + return self.execute(context) + +@rnaOperator +class netclientscan(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientscan" + __label__ = "Net Render Client Scan" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.settimeout(30) + + s.bind(('', netsettings.server_port)) + + try: + buf, address = s.recvfrom(128) + + print("received:", buf) + + netsettings.server_address = address[0] + except socket.timeout: + print("no server info") + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index c12c846231d..1dcb608931e 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -105,6 +105,8 @@ def render_slave(engine, scene): process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + headers = {"job-id":job.id, "slave-id":slave_id} + cancelled = False stdout = bytes() run_t = time.time() @@ -113,10 +115,18 @@ def render_slave(engine, scene): current_t = time.time() cancelled = engine.test_break() if current_t - run_t > CANCEL_POLL_SPEED: + + # update logs. Eventually, it should support one log file for many frames + for frame in job.frames: + headers["job-frame"] = str(frame.number) + conn.request("PUT", "log", stdout, headers=headers) + response = conn.getresponse() + + stdout = bytes() + + run_t = current_t if testCancel(conn, job.id): cancelled = True - else: - run_t = current_t if cancelled: # kill process if needed @@ -132,6 +142,13 @@ def render_slave(engine, scene): print("status", status) + # flush the rest of the logs + if stdout: + for frame in job.frames: + headers["job-frame"] = str(frame.number) + conn.request("PUT", "log", stdout, headers=headers) + response = conn.getresponse() + headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} if status == 0: # non zero status is error @@ -150,12 +167,6 @@ def render_slave(engine, scene): # send error result back to server conn.request("PUT", "render", headers=headers) response = conn.getresponse() - - for frame in job.frames: - headers["job-frame"] = str(frame.number) - # send log in any case - conn.request("PUT", "log", stdout, headers=headers) - response = conn.getresponse() else: if timeout < MAX_TIMEOUT: timeout += INCREMENT_TIMEOUT diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index eee95bdac19..df2b6288fb0 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -48,17 +48,24 @@ class SCENE_PT_network_settings(RenderButtonsPanel): col = split.column() - col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") + if scene.network_render.mode == "RENDER_CLIENT": + col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") + col.itemR(scene.network_render, "mode") + col.itemR(scene.network_render, "path") col.itemR(scene.network_render, "server_address") col.itemR(scene.network_render, "server_port") - col.itemR(scene.network_render, "path") + + if scene.network_render.mode == "RENDER_MASTER": + col.itemR(scene.network_render, "server_broadcast") + else: + col.itemO("render.netclientscan", icon="ICON_FILE_REFRESH", text="") if scene.network_render.mode == "RENDER_CLIENT": - col.itemR(scene.network_render, "chunks") - col.itemR(scene.network_render, "priority") - col.itemR(scene.network_render, "job_name") col.itemO("render.netclientsend", text="send job to server") + col.itemR(scene.network_render, "job_name") + col.itemR(scene.network_render, "priority") + col.itemR(scene.network_render, "chunks") @rnaType class SCENE_PT_network_slaves(RenderButtonsPanel): @@ -192,7 +199,7 @@ NetRenderSettings.StringProperty( attr="server_address", name="Server address", description="IP or name of the master render server", maxlen = 128, - default = "127.0.0.1") + default = "[default]") NetRenderSettings.IntProperty( attr="server_port", name="Server port", @@ -201,6 +208,11 @@ NetRenderSettings.IntProperty( attr="server_port", min=1, max=65535) +NetRenderSettings.BoolProperty( attr="server_broadcast", + name="Broadcast server address", + description="broadcast server address on local network", + default = True) + NetRenderSettings.StringProperty( attr="path", name="Path", description="Path for temporary files", diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index db6646e6916..72a29472748 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -22,9 +22,12 @@ def rnaOperator(rna_op): return rna_op def clientConnection(scene): - netrender = scene.network_render + netsettings = scene.network_render - conn = http.client.HTTPConnection(netrender.server_address, netrender.server_port) + if netsettings.server_address == "[default]": + bpy.ops.render.netclientscan() + + conn = http.client.HTTPConnection(netsettings.server_address, netsettings.server_port) if clientVerifyVersion(conn): return conn -- cgit v1.2.3 From 063d806f152e003b662a0e22a19c27a4afbfb7fa Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Tue, 15 Sep 2009 20:47:34 +0000 Subject: 2.5 filebrowser bugfix #1: SpaceFile->files needs to be deleted on exec and cancel of the filebrowser and in init to ensure correct setting of the read function. bugfix #2: SpaceFile->params needs to be set in file_init otherwise Python can't access params in header ui. --- source/blender/editors/space_file/file_ops.c | 10 ++++++++++ source/blender/editors/space_file/filesel.c | 7 +------ source/blender/editors/space_file/space_file.c | 6 ++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d2d1d11ec5c..0e0ad88906e 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -496,6 +496,12 @@ int file_cancel_exec(bContext *C, wmOperator *unused) WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL); sfile->op = NULL; + if (sfile->files) { + filelist_free(sfile->files); + MEM_freeN(sfile->files); + sfile->files= NULL; + } + return OPERATOR_FINISHED; } @@ -567,6 +573,10 @@ int file_exec(bContext *C, wmOperator *unused) BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs"); fsmenu_write_file(fsmenu_get(), name); WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC); + + filelist_free(sfile->files); + MEM_freeN(sfile->files); + sfile->files= NULL; } return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 085eecd2a7d..a0787ef989d 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -169,18 +169,13 @@ short ED_fileselect_set_params(SpaceFile *sfile) } else { /* default values, if no operator */ + params->type = FILE_UNIX; params->flag |= FILE_HIDE_DOT; params->display = FILE_SHORTDISPLAY; params->filter = 0; params->sort = FILE_SORT_ALPHA; } - /* new params, refresh file list */ - if(sfile->files) { - filelist_free(sfile->files); - filelist_setdir(sfile->files, params->dir); - } - return 1; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 68eeb8718a2..27948618d03 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -159,6 +159,12 @@ static void file_init(struct wmWindowManager *wm, ScrArea *sa) if(sfile->params) { MEM_freeN(sfile->params); sfile->params = 0; + ED_fileselect_set_params(sfile); + if (sfile->files) { + filelist_free(sfile->files); + MEM_freeN(sfile->files); + sfile->files= NULL; + } } printf("file_init\n"); } -- cgit v1.2.3 From 581cb64f2ccdd49790fe06834d95e08f92c7308f Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Tue, 15 Sep 2009 22:34:10 +0000 Subject: Make verification of committed .mo files optional. --- po/Makefile | 2 ++ source/nan_definitions.mk | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/po/Makefile b/po/Makefile index 425efbc08b3..b656a00fb38 100644 --- a/po/Makefile +++ b/po/Makefile @@ -50,9 +50,11 @@ LINGUAS_DEST= $(foreach LINGUA, $(LINGUAS),$(DIR)$(LINGUA)/LC_MESSAGES/blender.m $(DIR)%/LC_MESSAGES/blender.mo: %.po mkdir -p $(@D) msgfmt -o $@ $< +ifeq ($(BF_VERIFY_MO_FILES), true) @cmp $@ $(NANBLENDERHOME)/bin/.blender/locale/$(basename $<)/LC_MESSAGES/blender.mo \ || ( echo Mismatch between generated and commited $(basename $<).mo catalog && \ rm -f $@ && false ) +endif all debug:: $(LINGUAS_DEST) # Just trigger the deps diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk index 8c47bcf11c1..6d4a7139d5b 100644 --- a/source/nan_definitions.mk +++ b/source/nan_definitions.mk @@ -143,6 +143,9 @@ ifndef CONFIG_GUESS export NAN_FFMPEGCFLAGS = $(shell pkg-config --cflags libavcodec libavdevice libavformat libswscale libavutil) endif + # Compare recreated .mo files with committed ones + export BF_VERIFY_MO_FILES ?= true + # Platform Dependent settings go below: ifeq ($(OS),darwin) @@ -309,6 +312,9 @@ ifndef CONFIG_GUESS # enable l10n export INTERNATIONAL ?= true + # Different endianess will make it fail, rely on other plataforms for checks + export BF_VERIFY_MO_FILES = false + else ifeq ($(OS),linux) -- cgit v1.2.3 From 0befb9b01d354b66403c1606c7533a3ec0da64d4 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Tue, 15 Sep 2009 23:37:20 +0000 Subject: Sync names with real content. --- release/datafiles/splash.jpg | Bin 197165 -> 0 bytes release/datafiles/splash.png | Bin 0 -> 197165 bytes source/blender/editors/datafiles/splash.jpg.c | 2483 ------------------------- source/blender/editors/datafiles/splash.png.c | 2483 +++++++++++++++++++++++++ source/blender/editors/include/ED_datafiles.h | 4 +- 5 files changed, 2485 insertions(+), 2485 deletions(-) delete mode 100644 release/datafiles/splash.jpg create mode 100644 release/datafiles/splash.png delete mode 100644 source/blender/editors/datafiles/splash.jpg.c create mode 100644 source/blender/editors/datafiles/splash.png.c diff --git a/release/datafiles/splash.jpg b/release/datafiles/splash.jpg deleted file mode 100644 index e35a26a2c23..00000000000 Binary files a/release/datafiles/splash.jpg and /dev/null differ diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png new file mode 100644 index 00000000000..e35a26a2c23 Binary files /dev/null and b/release/datafiles/splash.png differ diff --git a/source/blender/editors/datafiles/splash.jpg.c b/source/blender/editors/datafiles/splash.jpg.c deleted file mode 100644 index c1ca8b575e6..00000000000 --- a/source/blender/editors/datafiles/splash.jpg.c +++ /dev/null @@ -1,2483 +0,0 @@ -/* DataToC output of file */ - -int datatoc_splash_jpg_size= 79258; -char datatoc_splash_jpg[]= { -255,216,255,224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,255,225, 0, 22, 69,120, -105,102, 0, 0, 77, 77, 0, 42, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,255,219, 0, 67, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,219, 0, 67, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,192, 0, 17, - 8, 1, 15, 1,245, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1,255,196, 0, 31, 0, 0, 1, 3, 5, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, 7, 10, 3, 5, 6, 8, 9, 2, 1, 11,255,196, 0,103, 16, 0, 1, 3, 3, 2, 4, 3, 4, 6, 4, 7, - 11, 5, 9, 13, 9, 1, 2, 3, 4, 5, 6, 17, 0, 7, 8, 18, 33, 49, 19, 65, 81, 9, 20, 34, 97, 10, 21,113,129,145,240, 35, - 50,161,193, 22, 23, 24, 66,177,209,225, 25, 26, 36, 40, 51, 56, 73, 82, 98,232,241, 72,104,105,136,168, 41, 52, 57, 67, 84, 88, -120,150,178, 37, 38, 68, 83, 87,115,130,135,147,152,181,200,210, 54, 89, 99,114,146,184,213,214,215,255,196, 0, 29, 1, 0, 0, - 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 6, 7, 1, 4, 8, 9,255,196, 0, 80, 17, 0, 2, 1, - 2, 4, 4, 3, 4, 6, 7, 5, 7, 0, 7, 9, 0, 1, 2, 3, 4, 17, 0, 5, 18, 33, 6, 19, 49, 65, 7, 34, 81, 20, 97,113, -240, 8, 35, 50,129,161,209, 21, 66, 82,145,177,193,210, 36, 51, 98,162,225, 9, 67, 83, 84,114,130,241, 52, 56, 68, 85,116,148, -211, 22, 23, 24,115,131,146,147,180,181,255,218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0,159,198,150,150,150,134, 6, 22, -150,150,190,100,122,143,199, 67, 3, 31,116,203,220, 60, 68,108,181,171,123, 70,219,170,254,224,209, 41,183,140,167, 25,101, 20, -135,189,241, 73,101,249, 28,165,136,243,170, 77, 69, 84, 74,116,149,133,163,149,185, 15,180,226,185,211,132,158, 97,151,159, 35, -212,126, 35, 92,108,227, 63,131, 43,145, 85,251,143,120, 54,213, 18,235,236, 86, 37,191, 87,185,237,148,243, 72,170, 67,146,224, - 11,147, 81,162,128, 57,167, 69, 42, 5, 75,143,213,230,242, 75, 94, 34, 50,148, 86,158, 42,113, 39, 27,112,159, 14, 38,119,193, - 60, 55, 23, 19,212, 81,204,173, 89, 4,134, 67, 34,209,128,198, 87,130, 56,138,188,146, 2, 0,242,151, 49,169, 50,114,101, 1, -128,179,188, 40,225,158, 7,226,222, 37,108,143,142, 56,150,110, 23,166,172,133,150,142,120,196, 98, 54,173, 44,162, 36,158, 73, - 85,146, 56,200, 44,124,193, 4,140, 4,124,232,139, 41, 61,145,109,196, 58,132,173,181, 37,104, 80,200, 82, 72, 32,131,243, 26, -247,174, 11,240,211,199, 61,219,180,206, 66,179, 55, 36, 79,186,108,118, 29, 68, 54,166, 58, 92,122,228,181,217, 65, 13, 22,219, - 47, 30,106,157, 61,174, 95,242, 14, 16,243, 97, 37, 45, 44,128,150,181,219,219, 46,247,181,247, 6,129, 2,231,180, 43, 48,171, -148,106,139, 65,216,211, 33, 58, 29, 65,232, 57,219,113, 63,172,203,233, 86, 66,219, 88, 74,208,160, 66,146, 14,147,240,211,197, -174, 19,241, 67, 46, 53, 25, 37, 79,179,102,180,202, 13, 86, 95, 49, 2,166,156,244, 38,219, 9, 97,213,178,207, 29,212,220, 7, - 17,201,120,194,158, 38,248, 69,197,190, 22,102, 66,159, 60,166,246,156,166,165,136,165,204, 33, 4,210,212,142,160, 95,115, 12, -218,119,104, 36,179, 11, 18,134, 72,237, 33,202,244,180,180,181,103,226,173,194,210,210,210,208,192,194,210,210,210,208,192,194, -210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210, -215, 13,125,163,254,220, 13,158,224,130,240,159,178,214, 5,156,238,249,111,173, 45,150, 21,116, 81,219,173,155,110,200,219,199, - 39,194, 98,116, 8,215, 53,192,138,116,167,170,213,245, 68,151, 17,255, 0,171, 32,177,132, 50,233, 76,186,132, 39,249, 26, 91, -214, 67,195,217,207, 19,102, 9,149,228,116, 47, 95, 90,224,177, 85, 42,161, 80, 16, 11,200,238, 85, 35, 64, 72, 5,157,128,185, - 10, 46,204, 1, 98,226, 46, 38,200,248, 79, 45,124,219,136, 51, 20,203,104, 81,130, 6, 96,204,206,237,114,169, 28,104, 26, 73, - 28,128, 78,148, 86, 58, 85,152,128,170,196,119, 43, 75, 80,124, 63, 73,159,141,131, 84, 83,195,103, 56, 94, 20, 82,242,212,138, -127,240,103,117, 13, 77, 44, 20,171,195,105, 85,127,227,115,194, 91,193,101, 37, 75, 16,146, 20, 1, 1,180,147,204, 58,247,192, - 39,183,219,102,184,168,189,173,253,156,222,171, 32,236, 38,233,221, 18,227,210,109, 58,154,110, 6,238, 13,182,188,107,111,132, -162, 53, 29,138,204,184,113, 36,218,181,233,114, 84, 26,131, 10, 91, 82, 88,144,233, 68,118,234,107,152,244,120,206,205,115,175, - 7,248,243, 35,161,151, 49,169,202, 86,166,150,157, 75,200,105,230,142,102,141, 64,185,102,140, 17, 33, 10, 55, 98,138,225, 64, - 44,108,160,156, 64,178, 47, 27,188, 58,226, 12,194, 28,174,151, 57,106, 90,186,150, 9, 16,169,134, 72, 82, 71, 38,202,171, 35, - 3, 26,179, 27, 5, 18, 50, 22, 36, 42,130,196, 12, 72, 35, 75, 94, 80,180,173, 41, 90, 8, 82, 84, 1, 73, 29, 65, 7,204, 29, -122,213, 97,139,107, 11, 75, 75, 94, 29,117,182, 91,113,231,156, 67, 76,180,133, 56,235,174, 41, 40,109,182,208,146,165,184,226, -212, 64, 66, 2, 65, 36,147,128, 6, 78,134, 6, 61,233,107,140, 28, 63,123, 94,236,238, 39,253,160,119,151, 9,219, 61,108,210, - 43,219, 63,103, 88,247, 29, 77,157,231, 77, 86, 91,178,239, 43,178,215,171, 80,169,213, 69,219, 84,214,227,166, 57,178,252,106, -195,236,197,150, 92,117, 83,126,173,247,214, 23,238,178, 89, 3,231,181,219,218,129,127,123, 56, 15, 15,137,177,182,194,209,220, -115,188,169,221, 85, 85, 13,213, 86,172,210,254,165,254, 47, 78,219,136, 94,225,245, 74, 79,188,123,199,240,222, 95,139,226,126, -167,184,183,201,250,202,212,182, 30, 7,226,105,179,220,183,134,191, 71,242,179,156,218, 1, 81, 12, 50, 72,136,121, 70, 41, 38, - 5,203, 48, 17,183, 46, 39, 37, 28,171,130, 52,149, 12,109,136, 92,222, 32,240,164, 60, 61,154,241, 87,233, 46,118, 69,147, 78, -105,167,158, 56,228,145,121,162,104,160, 34, 48,170, 90, 84,230,202,138, 36,140, 50, 48, 58,149,138,139,227,180, 26, 90,134, 23, -247,207,155,251,255, 0,155, 30,209,127,235, 93,227,255, 0,232,210,254,249,243,127,127,243, 99,218, 47,253,107,188,127,253, 26, -152,127,247, 29,226, 55,254,233,139,255, 0,155,166,255, 0,234, 98, 19,255, 0,226, 11,194,239,253,245, 55,255, 0, 37, 87,255, - 0,210,196,207,116,181,166,252, 3,241, 57, 89,226,255, 0,133,157,171,223,235,138,219,165,218, 85,203,250,153, 89,157, 81,183, -232,178,101,204,165,211,157,166, 93, 53,202, 3,109,195,147, 56,120,175, 33,108, 82,154,113, 69,125, 66,221, 80, 29, 0,214,228, -106,172,174,163,168,203,171,107, 50,250,180, 17,213, 80, 75, 36, 50,168, 33,128,146, 39, 40,224, 48, 36, 16, 25, 72,184, 36, 30, -160,219, 22,246, 95, 93, 77,154, 80, 80,230, 84,110,100,163,204, 97,138,120,152,130,165,163,153, 22, 68, 37, 88, 6, 82, 85,129, - 32,128, 71, 66, 47,133,165,165,165,173, 92,110, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105, -105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,107, - 3,168,110, 45, 6, 60,249,116,122, 75, 21,123,182,183, 5,239,118,155, 75,181, 41,174, 85, 12, 9, 92,174,168,197,170, 85,150, -166,169,212,105, 67,194, 32,183, 54,108,117,130,164,229, 32, 40, 29, 12, 12,103,154, 90,104,166,239, 21, 38,143, 91,167,219,119, - 13,169,123,209, 43,245,152, 83, 39,208,233, 9,165, 83, 46,121,213,134, 41,225,159,126, 83, 12, 88,181,170,177,130,134,188, 97, -151, 38,251,171, 42,228, 95, 35,139,228, 86, 47,143, 95, 53, 54,130,157,111,109,119, 6, 76, 70,208, 28,118, 91, 44, 90, 40, 45, -183,221,106, 77, 58, 85,222,220,217, 43, 74,114, 75,108,197,113,213, 99,149,182,214,178, 18, 70, 6, 28, 29, 45, 88,232, 23, 37, - 18,231,136,236,202, 36,244, 76,110, 60,135, 33,205, 97, 77,191, 18,125, 54,115, 56, 47, 83,234,212,201,141, 55, 38,149, 80, 64, - 82, 10,216,146,211, 78,164, 45, 36,160, 5, 2,111,154, 24, 24, 90, 90, 90, 90, 24, 24, 90, 90, 90, 90, 24, 24, 99,120,143,168, -110,117, 51,103,174,233, 91, 65, 29,201, 23,200,138,203,116,255, 0,119,109,167,170, 12, 69,114, 67,104,169, 72,165, 50,240, 40, -118,166,136, 69,226,200, 32,144,175,137, 0,184, 17,174, 20, 60,223, 25, 18, 95,121,199,215,190,238, 72, 83,138, 83,202, 92,139, -187,156,186,165, 18,178,175,210,126,183, 54,117, 36,133, 36, 40, 16,160, 8, 61, 8, 35, 32,253,218,208,158, 40, 56,198,176, 54, - 85,185,246,165,163, 22,151,119,238,105, 66,153, 92, 54,212,151,168,214,187,171, 78, 67,245,249, 12, 43,244,179, 83,148,148,194, -109, 65,206,185,121,108,167,148, 47,157, 60,116,224,190, 27,204, 99,139,140, 56,175,196,124,203,131,114,188,170, 14, 66,193, 75, - 56, 17, 77, 38,167,144,114, 96,182,185, 42,165,190,146, 16, 51, 50, 70,132,233, 84,102,199, 72,120, 15,198,220, 77,151, 75, 55, - 7,112,151,134,185,103, 26,102,153,172,252,246,158,170, 2,101,134, 61, 49,198,121,211,223, 68,116,145, 17,172, 23,210,170,242, - 53,139, 51,170,227,143,215, 53,223,196,133,153,238,191,194,219,167,117,237,195, 59,196,247, 52,214,107,151, 20, 5,201, 13, 99, -196, 83, 45,200,148,149, 45, 41, 42, 0,144, 49,147,140,231, 88,195, 91,199,188,114, 93,109,134, 55, 39,112,100, 60,226,194, 90, -101,171,158,186,235,142, 44,159,133, 40,109, 50,201, 90,179,216, 0, 78,177,155,198,244,186,247, 18,225,151,114, 93,181,137,181, -218,221, 69,209,207, 34, 82,202,131,105, 39, 13, 68,134,194,112,136,145, 17,156, 33,166,210,148, 36,118, 25, 36,157,221,188, 47, - 45,145,246,104,112,186,239, 19, 59,221, 70, 93,217,123,214,159,133, 73,179,173, 8,106,140,213,106,227,187, 42,177, 94,153, 78, -181,233, 18, 37,182,177, 72,167,177, 22, 51,207,212,167,150,214, 25,110, 59,132, 37,229,170, 52,119,121, 7,194,159, 15,120,203, -198,222, 60,159,134,248, 23,136, 51,106,108,146, 23, 75,212, 85,212,201, 45, 66,164,141,162, 37, 49,195, 36, 81, 52,243,178,187, - 44, 97,214, 56,145, 92,188,204,177,150,110,196,241,107,196,110, 10,240, 51,128, 32,226,126, 62,225,252,162,167, 58,153, 28,251, - 61, 37, 52,112,211, 51, 70,161,230, 97, 36,209,203, 42,211,192,172,138,210, 20,105, 37,118,141, 82, 21,105, 2,174,163, 72,218, -189,222,170,162, 69,126, 85,135,123,206, 76,183, 23, 46, 77, 77,218, 13, 81,227, 33,199,137, 91,146, 29,120,199, 37,106, 82,148, - 73, 81,238, 73, 58,203,118, 91,127, 55, 47,135,155,149,114,173,233, 18, 19, 1,201, 8, 23, 5,159, 86, 18, 27,166,212,210,217, -229, 80,122, 50,192, 84, 10,130, 81,144,135,219, 1,196,246, 80, 91,101, 77,171,150, 85, 47,164,143,198, 35,151, 97,170, 81,118, -183, 97,169, 54,130, 37,133,179,102, 61,111, 92, 53, 14,120, 40, 95,195, 22, 93,192,171,133,185, 46, 62,166,176, 22,235, 65,161, -204, 74,144,218, 6, 18, 59,121,195,151, 16, 59, 31,237,121,225,250,232,188,108,251, 74, 62,216,241, 35,181,232,138,205,221,106, - 37,246,165,173,185,210, 97,201,126,152,244, 42,139,108,182,186,213,159, 85, 16,103, 34, 50,222,109, 50, 33,200,136,182, 92, 7, -194, 14,201,234,207, 16,126,128,222, 38,248, 71,147,143, 16,120, 59,138,106, 38,207, 50,127,174,217,162, 46,210, 29,204,124,216, -156,104,105,141,227, 9, 42, 77, 79, 51,176,134, 89, 64,146,237,200,222, 28,127,180, 43,194,191, 25, 51,195,225,207, 24,112,181, - 60, 89, 30,113,245, 32, 50,202, 17, 98, 29, 36, 17, 76,191, 88,176,139, 72,205, 19,193, 81, 10, 35, 77, 20, 76, 99, 32,118, 27, - 96,248,137,177,183,250,218, 21,123,106, 66,161,213,225, 37,166,235,214,228,213,160, 84,232,242,156, 78, 64,113, 41, 56,147, 13, -101, 43,240,159, 71,192,224, 65, 7,149,105, 90, 19,106,226, 39,139,222, 29,184, 78,110,198,145,196, 38,229, 82,246,206, 6,226, -214, 42, 20, 27, 86,171, 91,137, 84, 93, 38, 85, 78,151, 17,153,211, 89,157, 82,131, 5,214,105, 13,162, 43,237,171,196,148,182, - 91, 86, 72, 74,138,129, 26,224,102,199,110,133,115, 99,247, 86,135,116,199, 84,134, 26,129, 81,250,170,231,166, 5,148, 9,180, -119, 95, 17,234,144,223,108, 28, 41,230,185, 75,173,103, 33, 47,197, 65,236, 8, 56,167,210,118,170,198,173,240,251,194, 53, 82, - 35,168,126, 52,237,202,189, 36,178,235,106, 10,109,214,222,179,169,238, 54,226, 20, 58, 41, 37, 10, 4, 31, 67,171, 87,232,151, -199,112,248,245, 61, 22, 67,196,119,203,243,234, 9,141, 61,127,179,133, 66,234,105,230,150, 10,168,209,213,213, 57,175, 11,164, -177,216,133,120,223, 78,133,116, 11, 85,125, 48,120, 26,127,163,229, 30, 99,196, 92, 52, 23, 49,200,107, 97, 90,156,188, 84,150, -112,140, 42, 96,138,162,146, 87, 70, 70,147,148,147, 35,197, 32, 96, 89, 36,143, 86,182, 71, 38, 80,214, 61,247,102,238,101,169, - 68,190,118,250,231,162, 94, 86,117,203, 5,186,157, 2,229,183,106, 17,170,180, 90,196, 7, 74,146,220,186,125, 66, 35,138,110, - 83, 5, 72, 80,230, 66,136,202, 72,238, 8,214, 89,168, 64,112,175,237,189,221,253,134,225,159,102,120,123,225,163,133,105,251, -189, 82,218,155, 26, 53, 58,249,186, 43,172, 93, 53, 88,104,168, 59, 62,163, 61,244, 83, 40, 54, 52,101, 57, 18,156,216,146, 0, -149, 42, 82, 84,242,185,200,142,216, 71, 50,250, 53,193,103,210, 48,176, 55,151,114, 45,253,161,226,123,106,154,216,235,138,230, -171,179,111,210,175,154, 45,102, 69, 70,198, 98,189, 45,246,226, 66,166, 92,208, 43, 49,218,153,107, 54,228,197,120, 94,244,183, -101, 50,219,175, 32, 72, 17,218, 11,121, 61, 57,156,120, 63,198,153,119,233, 74,154,108,168,214, 80, 80, 73, 45,180,205, 3,212, -154,116,102,229,204,244,233, 33,144,107,140, 7,210, 20,181,143,217, 29,185,103, 35,241,187,128,243, 63,209, 20,149, 89,184,162, -204,179, 40,225, 7, 84, 53, 9, 74, 42, 93, 19,153, 2, 84,188, 98, 35,203,145,140,122,139,232,184,251,102,226,253,250,171,113, - 37,195,245, 6,251,107,107,171, 91,211,182, 52,173,200,122,165, 79,163, 51, 98,207,189,104, 17,110,183,106,213,101, 50,154, 93, - 53, 20, 39,167, 9, 42,157, 33, 82, 99,134, 90, 13,243,184, 95, 72, 64, 60,195, 47, 80, 32,128, 65, 4, 17,144, 71, 98, 53, 2, -158, 50, 84,211,191, 72, 26,128,243, 1, 10, 14,113, 65,195,147,232, 82, 80,159,137,193, 34,193, 91, 78,246,248,156, 5, 45,144, -174,224,164, 16,122, 13,118, 87,143, 15,111, 68, 62, 31,247, 89,238, 25,120, 83,218,134, 55,231,120,232,117, 24,214,189,203, 90, -170, 59, 86,145,107, 83,239, 39, 22, 24,122,204,183,168, 86,222, 39,222, 53,230, 36, 56,219, 82, 84,212,136,236,177, 41, 11,138, -145, 33,196, 56, 91, 91, 48,240,167, 51,118,225, 88,120,116,201,154,212,103,249,106,102, 51,243, 57,112,197, 76,172, 19, 86,169, - 89,130, 8,193,123, 6, 98, 25,182, 0, 19,182, 17,203, 60, 97,202,145, 56,190,163,137,196,121, 61, 47, 14,230,178,101,148,252, -190,100,210,213,186,151,211,162, 37, 82,237, 35, 4,185, 84, 5, 84, 92,179, 1,190, 36,133,165,168,139,220,190,218,255, 0,106, -111, 13,237, 80,239,190, 41,184, 29,183,169, 27, 89, 90,168, 69,138,228,225, 66,187,237, 23, 16,167,193,117, 20,246, 46, 35, 90, -169, 70,163, 85,156,101, 14,120, 77, 84, 34,149,172,182,172, 54, 74, 84, 7, 85, 46,223,109,143, 13, 22,231, 5,182, 47, 26,148, -171,102,247,187,237, 43,183,112,233,251, 83, 88,178, 40,166,138,205,225,100, 95, 50, 40, 85,218,228,250, 85,194,221, 66,123,108, -120, 76, 51, 65,115,145,214,150,161, 37,154,132, 89, 13, 39,195,116,242,177,215,248,105,197,180, 35, 47,120,168,226,205,105,243, - 57,189,158, 25,168,170, 33,169,137,167,177, 60,146,241,185, 8,246, 6,193,244,130, 65, 0,146, 8,196,131, 46,241, 91,131, 43, -206,100,147, 87, 77,147,212,229, 48,251, 76,240,215,211, 79, 73, 50,211,220, 14,112,142, 68, 5,227,187, 45,202,106, 32, 16, 72, - 0,223, 29,148,210,212, 92,183, 35,233, 31,162,243,160,209,233,124, 25,112,161,184,187,163,185, 51, 34, 63, 58,227,131,120, 83, -170,147,233,118,147, 44,202,113,150,152,250,163,111,196,153,119, 10,221,142, 27,116,188,153, 48,153, 96,159, 12,248,202, 37, 72, -198,248, 54,250, 69,151,109,251,190,214,214,200,241,107,178, 86,230,220,166,238,185, 96,217,113, 46,235, 45, 87, 21, 53,219, 86, -231,169,204, 77, 62,159, 26,239,181,110,153, 50, 30, 76, 37,212, 94,142,195,174,178,251, 78, 69, 46,135, 23, 29,196,133, 99,108, -248, 71,199,171, 65, 85, 94,249, 46,143, 99, 86,119,128,205, 7,180,136,210,247,113, 0,144,200, 87, 98, 84, 91, 83,129,116, 86, - 4, 95, 68,120,211,225,211,102, 52,121,116,121,233,147,219,157, 99,142,160, 83,212,123, 33,145,237,166, 51, 80, 99, 17,134,243, - 0,198,250, 99, 38,210, 50,144,109, 43, 29,120,113,198,217,109,199,157, 90, 91,105,164, 45,199, 28, 89, 9, 67,109,161, 37, 75, - 90,212,122, 37, 33, 32,146,124,128,215, 14,253,164,222,219,221,157,224, 86,233, 59, 61,101,218, 15,111, 86,249, 34,155, 14,165, - 92,161, 49, 88, 69, 18,210,176, 89,169,199,110,101, 41,155,170,176,220,103,222,151, 90,126, 19,172,190,154,124, 86,130,209, 30, - 75, 79, 63, 37,143, 17,182,220,230, 77,175,244,142, 56,132,142,220,122,222,253,112, 91,245, 86,205, 92,140,191, 79, 85,221,100, - 38,245,165, 74,102, 61, 69,151, 99,183, 46,153, 83,187,226,187, 77,174,184,128,224, 80,100, 59, 27,198, 13,148,165,214,201,230, - 8,229, 94, 22,113,190,113,150, 83,230,244,153, 69,168,170,198,168,121,147, 65, 20,147,169, 23, 6, 24,228,145, 93,245, 13,211, - 97,172, 88,173,193, 4,175,156,120,191,192, 25, 38,109, 81,146,214,231,119,174,163, 58,103,229, 65, 81, 52, 84,237,123, 17, 52, -177, 70,232,133, 78,207,185,229,155,135,210, 65, 2, 71,219, 95,199,191, 8,187,217,187,147,118, 59,104, 55,194,208,220,189,198, -166,208,234, 87, 13, 70,153,102, 59, 46,189, 76,133, 76,164,205,137, 79,158,183,238, 88, 81, 85, 78, 18, 91,151, 54, 58, 11, 41, -148,167, 73, 89, 33, 4, 37, 68,109,254,160, 19,244,127,110,123,126,214,227,115,113,175, 26,237, 82, 45, 14,212,183,182, 43,113, - 46, 74,213,102,160,164,196,131, 73,183,233, 85,139,126,167, 62,165, 57,121, 34, 52, 86, 32, 48,235,174, 30,161, 9,104,247,198, -186,103,185, 63, 72, 83,125,183,147,120, 38,237, 23,179,215,133,198,183, 45,182,164, 77, 98,145,112,222, 16,174, 10,229,197,113, -192,167, 58, 82,245,199, 30,212,183,230, 68,102,215,162, 45, 1, 42, 11,168, 75,116,161,181,165, 79,248, 14, 57,225, 53, 36,226, - 95, 8,115, 26, 94, 38,172,201,120,104, 61, 93, 6, 89, 75, 4,245, 53,117,114,195, 4, 81, 25, 67,146,100,145,185,104,163,202, - 74,160,212,224, 2, 73, 32, 18, 34,220, 41,227, 94, 89, 89,194,148, 57,247, 21,178, 81,102, 57,181,101, 69, 61, 45, 29, 20, 83, -212, 77, 48,132,160, 2, 56,151,153, 35,155,184, 12,231, 66, 18, 85, 64, 4,128,101,135,165,168,156,219,158,223, 30, 44,184,114, -221, 75,123,111,253,161,252, 36, 55,183,244, 42,247,131, 37,117,235, 78,155, 93,160, 92, 80,232,239,201, 68,119,171,244,186,109, -102,169, 54,159,121,211,227, 40, 44, 58,212, 57,113,220,230, 73, 71,139,226, 0,218,186, 89,198, 87,182,211,135, 30, 14,235, 27, - 75, 6,163,102,223, 59,171, 70,222, 93,176,167,238,197,161,117, 88, 18, 40, 31, 82,200,182,106,181, 25,180,248, 5, 70,177, 61, -135,125,225,126,226,183, 10,124, 49,200,151, 18,149,128,224, 82, 83, 20,171,240,211,140,105,171,114,250, 40,178,177,152,182,106, -143, 37, 52,148,179, 67, 60, 19,172, 66,242, 24,230, 71,208, 74, 13,202,146, 26,219,128, 70,248,152,209,120,173,192,245,116, 57, -149,124,217,177,202,215, 39,120,227,171,138,178, 9,169,234, 41,218, 83,166, 46,100, 14,156,192, 28,236, 25, 67, 45,246, 36, 29, -177,217,173,112,163,112,253,133, 28, 55, 95,188,105,212,248,162,173,202,171,215,108,187,186,163, 93,190, 47,125,152,175,202,157, - 87,160,214,183, 90,175, 85,141, 82,118,228,122,179, 46,114,165,201,181,228, 73,126,179, 50,101, 17,245, 57, 25,115, 93,105,180, - 56, 41, 5,116,160,202,240,191,237,190,220,158, 50,248,231,219, 77,158,218, 29,130,147,111,112,189, 93,145,119,193,184,247, 10, -229,165,214,170, 87,151,189,209,182,206,237,185,233,142,205,168,210,100,170,143,106, 52,237,203, 71,166, 71,110, 59,134, 83,174, -180,249, 30, 48,117,228, 33,185, 31,161, 92,200, 74,187,115, 37, 42,199,166, 64, 58, 74,170, 30, 49,240,218,181,169, 26,169,242, - 74,252,226,140, 25, 82, 41, 81,156, 65, 43,200,129, 36, 40, 91,149, 48,104,217,133,136,150, 59,130, 25, 75, 17,133,169, 38,224, -127, 20,232, 22,181,105, 35,207,242,236,146,184,136,164,154, 23, 84, 53, 16,164,110, 94, 33, 32, 83, 44, 44,178,170,155,131, 20, -182, 33,149,130,131,134,126,151,176,123, 71, 74,180, 27,176,226,237,253,162,205,158,136,126,226, 45,102,173,218, 59, 86,224,136, - 80, 27, 49, 69, 13,184, 98, 40,143,200, 0,228, 13,114,224, 99, 24,212, 4,189,180, 92, 57,109,223, 10,156,122, 93,182,174,205, -192,141,105,218,119, 45,169,102,238,133, 50,218,161,145, 14,159,102,213,171,255, 0, 88, 69,169,211,168,140,199,193,165, 66, 53, -106, 19,243,227,176,217, 74, 34,138,178, 89,140,150,163, 54,195, 77,254,136, 21, 90,173, 54,133, 75,169, 86,235, 51,225,210,168, -244,120, 19, 42,149, 90,165, 66, 67, 81, 32, 83,105,180,248,238, 75,157, 62,108,183,214,148, 70,136,204, 86, 93,113,199, 22,160, -132, 33,181, 41, 68, 0, 78,191, 57, 62, 35,175,107,151,218,161,237, 50,184, 37,109,235, 50,196, 29,229,220,202, 77,141,183,190, - 43, 14,184,170, 30,215, 90, 80,163, 80, 97,220,243, 97, 43, 10,140,219,118,133, 14,117,126,160,198, 73,109,217, 50,144,146,162, - 19,155, 39,192, 39,174,139, 62,226, 12,218,122,167,135, 34,160,161,145,235, 29,217,140, 69,217,213,208,184, 38,197,194, 71, 52, -154,236, 88, 42,184,189,156,131, 86,125, 35,211, 47,155,135,120,111, 38,167,164, 73,184,135, 50,204, 35,142,133, 17, 84, 74, 17, - 81,146, 64,132, 0, 66, 51,201, 4,122, 1, 10, 89,144,218,233,113, 61,206, 11,119, 14,189,187, 28, 40,240,239,185, 23, 75,138, -118,228,190,118, 83,107,110,250,243,171, 32,173,202,197,203, 99,208,235, 85, 53,168,134,209,146,102,205,124,159,129, 61, 79,234, -167,176,217,253, 55, 59, 75,100,210,182,231,110,237, 11, 38,133, 20, 65,162,218,246,245, 30,223,164, 66, 7,152, 68,165, 81,169, -241,233,212,232,193, 88, 25, 13,196,142,210,123, 15,213,211,141,170, 34,178, 72,102,172,170,154,158, 62, 77, 60,178, 59, 34,126, -202, 51, 18,171,255, 0,106,144, 62,236,116, 69, 12, 83,193, 69, 71, 5, 76,188,250,152, 98,141, 36,127,219,117, 64, 29,191,238, - 96, 79,223,133,168,165,123,119,125,170,238,209, 91,175,240, 39,195,117,192,235,151, 29, 77, 14, 81,120,135,190, 40, 15,243,187, - 74,135, 49, 41,105,123, 57,111, 76,138,162,181,214,165, 33,194, 46, 23, 26, 41, 49,152, 90, 40,225, 78, 63, 38,166,204, 61,237, -246,205,251, 82,224,240, 79,182,174,108,238,209, 85,161,203,226,135,116, 40,142,253, 82,227, 78, 37,255, 0,226,146,206,156,167, -161,191,184, 53, 54, 18, 8, 53,247,252, 41,108, 80, 99, 56, 82, 61,229,165,212,159, 75,177,161, 8,147,185, 93,236,136,246, 94, -213,106,214,149,199,198,255, 0, 17,212,217,179,238, 10,173,173,115,221, 27, 61, 64,185, 22,228,217,136, 85, 70,147, 62,106,247, - 98,229, 19,146,183,100,220, 18,214,234,221,164,120,203, 82,154,110, 66,170,174, 5,201,122, 11,177,110, 14, 3,225,236,179,135, -178,212,241, 23,140, 33,215, 71, 11,133,202,168,154,193,235,170,175,228,151, 73,191,212,196,192,178,146, 8, 37, 76,132, 21, 68, - 89,105, 31, 17,120,151, 54,226,108,214, 79, 12, 56, 34,126, 93,116,209,151,206, 43,214,229, 40, 41, 45,231,132, 50,145,245,242, -169, 10,202, 8, 32, 50,196, 8,105, 29,161,210,223,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199,236,141,116, 43,233, - 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,207, 95,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199, -236,141,116, 43,233, 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,106,102,159,250,197,112,231,255, 0, 5, 39, -255, 0,208,175,197, 59,147,255, 0,234,195,197, 95,252,124,127,255, 0,161,150,227,167,222,201,206, 30,246, 78,244,224, 27,134, -234,253,209,181,155,125, 93,172,206,219,232,206,205,170, 85,108,219,118,161, 80,150,239,214, 85, 36,151,101, 76,151, 78, 91,146, - 29,229, 74, 71, 50,212, 78, 0,235,174,142,127, 36,254, 28,127,249, 20,218,239,253, 65,181,127,255, 0, 21,168, 67,236,206,242, -251,107,106, 27, 11,183,118,135, 14,118,230,248,218,123, 35, 96,219, 49,169,246,138,246,239,108,225, 81, 63,132, 20,246, 12,185, - 95, 92,181,113, 85,232,203,170, 93,234,124,188,224,255, 0, 4,146,236, 21, 45,180,166, 60,100, 57,144,172,147,102,189,184,158, -209,254, 22,247, 41, 54,175, 17, 19,170,123,167, 72,160, 84, 35,193,188,246,187,121,108,216, 86,109,253, 75, 99,149,165,201, 68, - 43,134, 21, 2, 5, 86,143, 93, 49, 75,106,105, 85, 86,234, 49,190, 62,117, 68, 87,136, 87,168, 78,113,225, 63, 21,230,217,158, -127, 91,147,241, 53, 5,117, 75, 84,212,207,236, 81, 87, 72,103, 68,121,153,145, 24, 4,229,164,150,101, 82,174,202,138,219,115, - 58, 98,193,200,252,101,224,252,151, 41,225,202, 12,239,133, 51, 44,186,145, 41,105, 96,246,233,178,248,197, 59,201, 28, 17,171, -186,157,124,201, 35,186,179, 6, 68,121, 25, 70,174, 95,164,237,173, 75, 62,218,177,233, 17,168, 22,157, 22,153,111,209, 33, 37, -105,135, 73,163,193,139, 77,167, 68, 67,142,173,231, 17, 26, 20, 54,144,211, 9, 83,206, 56,178, 16,144, 10,156, 82,143, 82, 78, -178, 93, 49, 28, 53,113, 19,183, 28, 85,108,189,139,190,123, 87, 80,118,125,159,125,210, 5, 74, 19,114,219,105,138,157, 46, 99, - 18, 31,167,214, 40, 85,152,204,188,226, 34,214, 96, 85,226, 78,135, 45,180, 56,227,105,126, 18,252, 55, 93,108,161,197, 62,250, -231,250,168,106, 41,170,106, 41,234,227,104,170,224,119, 73, 85,193, 14,178, 43, 21,117,112,119, 12, 24, 16,215,222,247,190, 58, - 70,146,122, 90,170, 74,106,154, 41, 18,106, 58,136,209,225,120,200, 40,209, 58,134,141,144,141,138, 50,144, 84,141,172, 69,176, -180,180,180,180,134, 54, 48,180,180,180,180, 48, 48,180,180,181,192,111,104, 5,251,125, 80, 56,143,220,198, 45,253,213,169, 89, - 9,183, 54,167,110,238, 27,118, 11,123,151,122, 90, 50,220,172,139,138,158,153, 72,178, 45,251,125,102, 37,197,116, 63, 9, 82, - 82,182, 38, 6, 89, 68,111, 26, 95,138, 30,142,216, 47, 57, 30, 78,249,221, 99, 81,164,226, 6, 84, 47,168,169,111,215, 68,181, -129, 7,171,130, 78,246, 0,236, 78,216,215,169,168, 20,209,243, 10,234, 23,181,175,110,196,255, 0, 44,119,231, 75, 81,244,103, -138, 29,229,219,186,190,226, 38,204,169, 55,100, 67,220,238, 34,247, 45,250,213,217,125, 65,164,205,147,104,206,165,216,118, 61, - 94,129,106,212, 95,186,100,197,162, 91,207, 73,151, 86,156,153, 30, 59,169, 82,141, 53,244,196,109,181, 55,135,114,241,198,191, - 22, 21,107, 15,123,247, 58, 21,239,182, 80, 41,252, 61,195,225,246, 85, 90,221,164,217,177,110, 10,125,254,238,232, 42, 29, 18, -168, 34,221, 38,172, 62,174,129,245,162, 36,204, 82,163, 52,225, 82,101,134, 98,190,203,109, 37,110, 59,183, 5,230, 62, 70, 90, -152, 57,114,114,192, 44,206, 14,169, 36, 72,144, 16,168,246,213, 43,132, 6,228, 91,204,218, 84,223, 8, 12,198, 29,193, 70,184, -191, 64, 58, 0, 88,157,200,232,162,231,111,112,185,199,119, 52,181, 31,219,163,138, 13,215,187,247, 63,109,175,153, 87,125, 18, -185,126,217, 23,151, 19, 82,104,252, 60,211, 45,201, 52,233,150, 71,240, 34,193,174,162,217,167,220,143,211,222, 93, 66,233,145, - 84,147, 75,108,134,220, 72,230,113,130,136,203, 97, 74,115,194,187,218, 60,116,241, 71, 94,159,183, 22,253, 63,112, 54,166,175, - 63,117,119, 39,104,237,104,115,229, 80,109,233,245, 11, 49,235,225,117,154,109,106,149, 86,182, 45, 90,232,117,138, 91, 85, 35, - 79, 91,126,254,228,106,167, 37, 61,109,158, 66,226,214,144,220, 23,153, 8,213,214,162, 27,132,212,225,139,174,147,174, 69, 33, - 78,131,172, 1, 25,109,118, 10,194,252,179, 32, 1,136, 25,140, 58,136, 42,221,108, 45, 99,125,129,245,219,115,107,117, 29,237, -142,245,233,107,147,209,223,222, 43, 46,151,189,123,171, 87,168, 91,247, 45,193, 96,238,236,107, 86,163,184, 18,175, 13,204,135, - 26,223, 51,155,219,155,122,229,185,225,109, 4,121,171,160, 11, 66,149, 6,229,173, 86, 75, 18,101,144,211, 81, 94, 47, 30, 86, -130,245,116,153,197,253,205,104,175,125,224,212,119, 98,196,186,104,182, 78,217,238,236,253,159,220, 25, 80,109,250, 84, 61,204, -189,109, 75,111,110,106,180, 88,240, 28,129, 37, 16, 46,122,140, 59,158,240,173,209,164, 71,165, 4,181, 37,202, 9,253, 10, 30, - 67,199, 90, 31,253,157,169,144,255, 0,100,153, 42,109, 96,108, 24, 93,173, 25, 33,108, 27, 96, 37, 66, 3,232,144,141, 71,151, -101, 98, 20,246,180, 31,222, 41, 75,252, 58,110, 5,250,122, 30,151, 3,109,247, 24,234,110,150,185,121,125,113, 27,190,246,141, - 14,226,220,138, 85,122,149, 95,137, 79,221, 29,192,219, 42, 86,219,187,104, 69,247, 57, 66,135,195,181,213,186,212,122,171,149, -122,104, 85, 74, 93, 76, 92,212, 56,173,120, 13,169,182, 94,140,242,153, 95,134,178, 36,161,188,127,125,171, 86,214,225,238, 11, - 22,199, 16, 84,107,178,163,121, 39,108,124, 29,207, 68,141,169,183,108, 72,233,163,237,245,233, 92,170,211,106, 53,186,204, 89, - 52,202, 39, 35,139,138,182, 99, 49, 2,101, 90, 83, 81,212,194,240,184,239, 73, 25,143,134,171, 36, 66,194,104,254,198,161,110, - 97, 23, 14,138,202,199, 64, 11,164, 54,162,119, 6,214, 93, 86, 98,161,171, 35, 6,218, 79, 91,118,238, 9, 4, 11,239,126,158, -238,246,218,253,134,210,215, 23,168,252, 66,238,173,122,152,237,253, 54,243, 85,110,231,171, 76,225,138,243,161,236,203, 18,102, -193,102,123,213,219, 34,129, 34,173, 62,218,133, 2,172,137,173,218,242, 46,180,203,140,244, 86, 80,236, 39,101,213,208,220,211, - 33,228,132,186,236, 80,248,135,221,139,146,237,218,187, 18,214,222,123,102,243,129,185, 51,246,200,220,219,133,110,217,182,220, -151, 54,246,175,118, 89, 27,207,114,220, 59,126,196, 88,238, 61, 5,154,162,127,128,148, 71,161,179, 83, 67,181, 56, 13,161,255, - 0,172, 27,152,151,144, 18,105,120, 98,178, 37,118, 51,199,104,151, 83,147,204, 1,108,138,237,184, 67,125, 33,173,125,181, 16, - 66,106,107,129,133,173,141,136, 1, 79,155,167, 77,247, 32,119,239,248,119,182, 58,147,171, 69,118,187, 74,182,233,114,107, 21, -153,105,135, 2, 47,132,149,185,225,188,251,206,189, 33,212, 71,139, 18, 28, 72,205,173,217,211,223,148,235, 45, 49, 29,148, 45, -231,222,121, 13, 52,133,184,180,164,182, 60, 63, 94, 23, 13,249,180,118,173,203,117,202,141, 58,225,125,219,146,149, 84,168, 68, -134,221, 57,154,140,139,106,235,174,219, 34,165,238, 12,168,183, 13,217, 13, 81,219,121,198,219,253, 26, 28,125, 73,108, 37, 1, - 41, 13, 62,232,111,214,218, 88, 87, 53,221, 90,189,235,241,103, 84, 54,214, 35,223,192,237,191,166,243,212, 43,146,234,168,162, -210,230,214,174, 85,210,219,108, 4, 84, 20,139,146, 5, 54, 10,228, 56,219,108, 55,239, 43,109,212,137,238, 41, 44, 50,192,240, -207, 45, 59, 88,201, 19,178, 27,116,186,146, 13,137,182,215, 29, 72, 27,117,198,210,176,101, 86, 29, 24, 3,251,247,199,221,233, -222,106,181,159, 75,167, 84,174,234, 93, 66,210,177,231, 69,184,235,115,168,180, 74,161,155,188,183, 37,187,104, 81,151, 91,175, - 70,163, 80, 40,200, 81,166, 32, 83, 84,169, 82,149, 18, 91,178,216,139, 78, 83, 11,126,159, 42,107, 42,103,136,187,179,237, 34, -226,147,119,235, 63,197,223, 8,251,124,189,158,219,184, 97, 16, 40,176,233,212,196, 92,251,157, 84,166,150,212,167,102,185, 76, -180, 34, 77,106,221,117,114, 22, 2, 25,135, 45, 15, 52,181, 45,110,204,125, 71,175,108,182, 23,109,174,187,130,169, 84,222,157, -223,125,186,149,249,123, 65,247,101,210, 60,100,212,104, 54, 69,155, 36, 7,224,237,133,176,149, 2,203,148,166,146,166,158,173, -205,109, 3,235,170,160, 43, 86, 98, 69,134,211, 59, 51,104,216,150, 77,129, 77,110,141, 99, 90, 54,213,159, 74,109, 41, 66,105, -246,205, 18,155, 68,137,132,126,169, 91, 20,232,205,165,197,117, 57, 82,129, 81, 36,146, 73, 39, 78,217,109, 94, 95,150, 60,146, - 85, 80,254,145,169, 22,208, 11, 40,141, 58,223, 82,180,114, 93,186, 91, 96, 71, 98,164, 27,234,212,195, 81, 80, 21, 35,159,217, -227,223, 81, 0,150, 61, 45, 98, 25,108, 58,223,168,247, 17,136,175,109,165,111,136, 46, 22,110, 90,253,251,188, 55,190,238, 65, -226, 39,118,227, 73, 22,188, 43,214,173, 93, 15,170,216,230,151, 29, 53, 11,198, 13, 89,199, 26,118,108,119, 24,169, 38,135, 69, - 37,232,207,174, 19,213,119,127,239, 68, 64,213, 43,151,138,189,231,148,233, 93,203,191,247,220,103, 10,148,232,142,246,226, 85, -105, 32, 96,149, 21, 51, 79,141, 84,100, 37, 35,175, 68, 55,129,142,128,107,190, 92, 81,109,158,214,113, 35, 67,184,108,237,202, -102, 60, 43, 2,198,163,212, 42,247, 21,248,211, 49,155,173, 80, 37,183,202,252,118,173,218,155,209,221, 83, 79,170,117, 53,160, -227, 77, 36,169,228, 67,121, 32,178,242,233,207, 57,194,234, 71, 15,220, 39, 90, 75,109,193, 77,191,119, 2,124, 94, 96,220,151, -161,219,182,108,103,243,144, 18,185, 21,119,174, 89,106,100,163, 0,129,224,171,201, 60,131, 83,252,135, 54,165,204,160,150,105, - 50,197,106,184,152, 41, 60,176,194,223,170, 17,180, 5, 22, 29, 67, 58,155,146,119,189,240,193, 93, 73, 45, 59,170, 45, 73,228, -176,184, 26,172,111,176, 36,139,220,223,181,129,216, 91,107, 91, 29, 21,246,100,113, 47,186, 91,235,125,110, 4, 59,162, 92, 75, -222,214,164, 89,244,136,116,189,196,146,195,109, 87,221, 69, 6,164,227, 77, 68,157, 83,101,164,170,228,142,252,250,245, 93,166, - 94,150, 12,132,127, 7, 30, 90, 93,113,183, 73, 87,102,245,197, 62, 8,247, 59,106,118,179,113, 23,103, 90,182, 36, 75, 2, 30, -235, 85,168,116, 25, 13,199,172,212,107, 14, 87, 43,209,216,152,205,189, 33,239,126, 9,109,170,147,105,114, 75, 75, 16,216,138, -219,177, 93, 46, 62,219,134, 27, 74, 71,107, 53, 4,226,104,132,121,180,197, 40,197, 20,114, 5,101, 80, 0, 13,113,230,112, 20, -149, 23,107,139, 2,109,109,247,185, 47,153,107, 22,165, 75,205,206,101,184, 39,115,107,116, 27,128,122, 88,239,235,233,133,165, -165,165,168,254, 55,240,180, 29, 66,161, 2,147, 6, 93, 78,169, 50, 45, 58,157, 2, 59,178,166,206,154,251,113,162, 68,140,194, - 11,143, 72,147, 33,229, 4,178,202, 80,149, 21, 41, 68, 0, 6, 73,209,154,212,158, 53,182,250,255, 0,220,189,141,169,219,187, -118,235,139,169,181, 89,166,213,106,148,134,158, 12, 59,113, 81, 32, 51, 52,201,162,180,181, 16,149, 58,102, 59, 6, 74, 80,165, - 0,225,167, 6,243,149, 0, 88,184,159, 52,173,201, 56,123, 58,205,242,220,170, 76,242,191, 45,166,150,104,105, 34,254,242,162, - 68, 66,203, 18,216, 19,118, 35,162,171, 57, 23, 8,172,214, 82,253,194,249, 85, 14,121,196, 89, 38, 79,153,230,209,228, 89,126, -101, 83, 12, 51, 86, 75,253,221, 60,114, 56, 87,149,174, 85,108,160,245,102, 84, 6,197,221, 86,236, 52,131,138, 95,104, 4,186, -199,214, 54, 22,197, 77,122, 13, 40,151,161,213,183, 5, 41, 91, 51,234, 13,245,109,214,109,116, 44, 5, 64,138,174,191,225,138, - 1,245,164,254,133, 45,116,112,232,102,217,108,157,245,187,134,183, 88,166,198,146,138, 37, 30, 21, 78,171, 88,184,102, 54,243, -205,188,244, 72,207, 77,118, 44,101, 40,243, 79,168,186,180, 97, 88, 36, 32,185,206,226,129, 32, 43,100, 54, 19,129,203,238,248, -173,181, 55,114, 41,115,173, 91,118, 27,233,241,105,111,225,154,189, 85, 72, 80,230,100,242, 40,251,132, 63, 37, 44,159, 21, 64, -225,180,167, 62, 34,123,107,102,109,165,171,100,219,108, 91, 52,106, 68, 40,116,214, 97, 24, 34, 35, 12, 33,184,233,142,182,203, -107,104, 54, 7, 80,164,169, 92,196,228,168,168,149, 18, 73, 58,227, 46, 26,240,155,196, 15, 27,243,131,198,254, 48,212, 79,148, -100,169,175,216,178,205, 50, 64,197, 79,217, 84,129,142,186, 74, 91,129,173,223,251, 93, 72, 91,234, 0,172,216,237, 78, 38,241, -115,195,223, 3, 50, 97,192,254, 13, 83, 65,156,103,114, 20, 53,217,166,164,168, 64, 71,218,103,168, 81,162,174,168,169,109, 8, -159,217, 41, 75, 17,164,144,208,226, 44, 52,185, 13,195,169,211,165,188,142,118, 98,207,137, 33,212, 30,203,109,137, 13,184,226, - 8,249,165, 36,125,250,127,189,191, 59, 1,126,241, 15,193, 94,202,238,238,208,211,167, 93,244,109,151,184,170,119,101,215, 68, -161,176,236,233,235,179,175, 10, 4, 24,142, 93, 76, 66,140, 20,185, 76,211, 95,167, 69, 50, 66, 18,165,179, 30,166,244,130, 3, - 76, 60,164,211,226,127,101, 42, 59, 29,186,181,187,117,109, 62,187,118,168,251,213,155, 78,162,182,200,106, 93, 34, 91,202, 95, -186,135, 57, 66, 85, 38, 43,203, 84,119, 64,193,253, 26, 87,128,151, 18, 75,183,195, 79, 26, 53,221,151,166,139, 34,240,164,187, -122,109,226,148,224,141, 17, 46,182,154,189, 13,183,212,165, 72,102, 2,165, 31, 10,109, 61, 74, 90,213,238,238,148, 4, 41,106, - 40,113, 41, 37, 5,151,232,189,226,236,127, 70,191, 20,115,188,175,140,233,189,135,151, 83, 26, 73, 43,163, 50, 69, 61, 47, 62, - 45, 50,104, 12,254,207, 83, 5, 76,154, 39,141, 95, 65, 49, 74, 20,198,204,234,241,244,170,240,114, 79,164,247,132,249, 46, 99, -193,117, 94,220, 37,165,149,227,137, 29, 21,229,130,168,211,204, 26, 46, 97, 84,246,154, 89,233,163,215, 79, 35, 71,204, 2, 88, -139, 9, 21, 81,160, 87,169,110,253, 27, 78, 31,247, 14,201, 78,246,241, 53,120, 64,159,107,237,173,207,108, 82,237,139, 90, 69, - 85,167,160,179,114, 68,163, 76,149, 92,175,220,241,144,248, 79,137, 70,138, 26,139, 29,153, 56, 45,188,228,137, 73,109, 71,193, - 94,122, 95, 89,143,236,147,185,110, 37,110, 61,103,134,205,190,118,245,118, 71,214, 47,186,246,201, 80, 28,168, 63, 81,230,241, - 76,135,214,152, 94,233, 38,103,139,215,198,113, 69,124,221,121,181,134,239,223, 25, 43,190,109,119, 54,195,105,109,159,226,243, -110, 28, 97, 16,106, 24, 17,153,172,214,169,236, 0,134,169,158, 5, 63,244, 20,106, 55, 34, 82, 21, 29,165, 56,167, 82, 2, 22, -180,183,204,210,189, 25,241,187,233,237,225,100,220, 3,152, 80,112,253, 92, 57,166, 99,153, 70,182,130, 10,152,234,164,119, 86, - 89, 18, 33,201, 5, 97, 70,145, 87,153, 52,237, 25, 88,195,132,133,228, 42, 7,154, 94, 3,127,179,211,197,122, 79, 17,114,220, -207,136,233,166,203, 50,220,174, 70,250,249,233,164,165,141, 17,213,163,121,155,158,193,230,117,141,219,151, 5, 58,200, 30, 82, -133,230, 72,149,201,211,219,222,171, 18,185,121,221,181,168, 8, 8,131, 86,185,107,149, 40,105, 74,121, 64,139, 58,167, 42, 76, -127,132,143,135,244, 78, 35,167,207, 77, 71,183,193, 83,207, 4, 92, 7,166,161,226,120,232,185,171,137, 62, 46,121,194, 5,131, - 73,240, 82,160,174,160,134, 66, 7,221,173,145,216,173,173,169,238,230,227,208,109,120,108, 60,170,120,148,204,234,252,180, 33, - 69,184,116,136,238,161, 82, 57,156, 72,194, 30,120,132,178,214,123,173,224,113,202,149, 17,210, 31,105, 23,179, 6, 31,180, 15, -107, 54,119,111,211,186, 82,118,157, 59, 83,112, 85,238, 6, 95,131,103, 71,187, 17, 86, 21,122, 52,122, 72,130, 99,187,113, 83, -133, 57, 44,166, 58, 86,149,165, 78,133, 5, 20, 20, 12, 5,107,144,127,217,239, 11,228,156,117,155,248,159,196, 50, 53, 6, 69, - 81, 49,167, 14, 35,118, 89, 36,209, 81, 36,238,145,198, 25,217, 98,121, 98,141, 74,171, 13, 82, 58,223,200,246,236,191,246,140, -186,241, 7,135,185, 87,133,124, 53, 18,230, 60, 67, 79, 0,168, 49,153, 35, 86,142, 62,101, 52,112, 70,242, 72,200,138,210,199, - 20,210,176,118, 83,166, 56,218,223, 88,151,102,125,130,112,118, 42,169,192, 62,220,155, 3,248, 58,253,211, 14, 69,121,189,216, -141, 20,197,250,250, 61,248,229,122,168, 93,114,229,109, 39,197, 75,206, 82, 17, 78, 84, 37, 57,240,170, 2, 88, 75, 71, 8, 80, - 17,173,246,250, 13,156, 87,180, 78,224,103,100, 28,162, 63, 88,110,202,179, 25,220,245,218, 78, 69,118, 49,221,175,121,170, 25, -141,184,237, 53, 69,181,220, 41,161, 42,215, 76,222, 83,227, 38, 98, 92, 68,140, 74, 75,192,117, 38,227,250, 54,119,189,161, 79, -164, 73,216, 46, 46,110,123, 78,180,253, 25,154,101,232,154,149, 18,165, 73,135, 95,154,143, 16, 72,168,192,114,215,185, 18,237, - 62, 19,168, 82, 1,129, 35,223, 2, 20,149, 45, 50,202, 86, 27, 67,243,193,111,209,227,219,173,146,220,107,127,118,119,231,112, -164,239, 85,205,109, 84,218,174, 81,173,207,169, 81, 69,178, 35, 87, 35, 60,153, 16,234,149,118, 37,204,149, 42,232,125,153, 9, - 75,205, 33,229,199,142, 93, 0,191, 29,240,156, 31, 80, 50,110, 36,240,255, 0,133,248,167,136,120,250,159,140,167,206,102,204, -197, 81,139, 47, 20,147,199, 51, 60,242, 9, 52, 75, 52,159, 86,209,161, 80, 35, 44, 16, 5,210,199,204,186, 91,202,188,243,133, -252, 73,226,222, 17,225,159, 14,106,120, 26,159, 34,131, 42, 52,130,108,204,214,211, 75, 2,165, 60, 92,190,100, 48, 71,245,171, - 35,134, 38, 64,165,201,109,106, 60,175,173,120,101,186,226,227, 30,216,222, 31,145,113,169,212,222, 13,238, 7, 6,204,215,213, - 43,196, 18, 19,114,181,106,109,123, 85, 19, 47,197,202,132,164,212,146,231,141,205,215,196, 74,201,235,211, 90,121,178,118,150, -251, 86,248,244,118,209,176, 55, 14,149,181, 28, 67, 63,187,123,137, 77,165, 94, 87,124,150,160,183, 79,191, 68,251,137,138,172, - 71,101, 79,167,202, 75, 85,121,111,253, 99, 25,144,182,148,167, 95,150,150,144,124, 71, 18, 12,191, 55,139,216,145, 27,114,184, -246,164,241,181, 23,126,103,210, 85, 77,220,141,186,220, 36,237,202,118,242, 36,168,229, 86, 2,232,107, 69, 32, 92,230,240,109, - 65,169, 66,136,128, 94,247, 2,166,125,229, 68, 33,194,145,159,188,127,251, 8,246,135,139,155,230, 86,246,237,181,237, 81,216, -221,230,170,248, 18,174,153,244,186, 83, 85,171, 78,238,170, 68,109,180, 49, 90,169, 81, 81, 50, 35,244,171,136,165,166,146,236, -232,146,128,119,194, 75,143, 69,117,254,103, 75,214, 91,226,215, 8, 67, 22, 85,150,205, 86, 35,138,175, 35,134,138,121,205, 36, -147, 69, 73, 85, 26,176,229,203, 3,162,251, 69, 57,230, 48, 97, 30,180,109, 10,167,202,197,149,139, 52,240,103,141,106, 37,205, -243, 72,104,140,147, 80,241, 4,245,244,244,226,182, 40, 37,173,163,149,163, 60,200,170, 35,145,189,154,161,121, 42, 80,203,203, -117,214,204, 6,181, 8,220,174,226, 71,130,207,107,101, 91,105,167,218,220, 83,113,207,179,208,246,122,238,169,208,173,233,177, -183, 54,243,164,208,173,170,181,102,101, 69,135,109,234, 98,103,201,178, 88, 45,207, 85, 69,134,150,209, 67,168, 82, 61,221, 78, -173, 73,109,181,173, 58,117,197, 87, 1,155,253,192,167,179,178,235,160,238,229,199,101,215,173,141,200,226,147,102,174,107, 61, - 22, 93, 90,117, 86, 35,117, 8, 59,103,187,240,170,243,222, 92,168, 76,160, 38, 69, 61,202, 40,109,109,115,248,137,137,146,174, - 80,141,116,161,143,163,193,196, 46,228,213,168, 20,254, 34,120,219,187,111,155, 38,221,113,180,211,233, 77,199,185,174, 25,241, - 97,167, 8,114, 37, 29,203,202,228,122, 53,190,165, 48, 57, 82,234, 35,200, 8, 29, 60, 21,142,154,234,183, 19,126,200,187, 31, -124, 56, 36,218,238, 11,108,125,198,175,109,125,165,181, 87,181, 22,242,163, 87, 39,211,158,220,106,188,245,210,168,215, 85, 46, - 68, 42,129,170,215,224,171,196,147, 34,233,147, 37,110,182,234, 91,105, 81,195, 44, 70,109,146,148, 54,214,158, 34,228,185, 53, - 87, 15, 81, 71,196,212, 85,249,107, 87, 71, 81, 94,180, 57, 43, 81, 65, 18, 68, 85,227,149, 89,109, 43, 77,170, 53, 86, 9, 12, -154,144,144, 89, 2,128,238,210,120, 95,158,231,148,156, 75,152, 73,194,149,249,118,106,153,124,148,217,123,102, 25,242,215, 84, - 77, 36,193,146, 72,157, 90,240,164, 26,100,118, 66,243, 71,165,192, 96,175,172,152,216,127,163,207,182, 54, 85, 63,129, 26, 5, -213, 18,131, 1,186,245,225,121, 94,117, 27,146,168, 35, 51,239,213,105, 84,250,195,212,170,127,190, 73, 8, 11,121,152,244,248, -205, 54,202, 20, 74, 90, 10, 95, 32, 5,107, 39,133, 62,218,203,122,129,108,123, 96,109,245,210, 41,177,105,109,213,209,195,221, -118,176, 97,180,134, 12,218,147,149, 56,208,159,168, 62, 91, 3,158, 81,133, 78,134,130,179,241, 17, 25, 57, 61, 53, 47, 47,103, -175, 7, 75,224,115,135,139,127, 97,141,234,237,254,138, 5, 74,189, 81, 77,202,253, 13,187,113,201,102,185, 84,122,164,166,141, - 41,170,164,208,194, 90, 47,114, 3,239, 11, 42, 8,230, 56,206, 53,160, 92,119,251, 21,218,227, 43,139,138, 79, 20,201,223,169, -214, 59,244,232, 27,125, 4,217,141,109,212,106,251, 11, 22, 36,247, 38,120,191, 94,185,121,196, 82, 76,164, 44, 39,151,221, 15, -128, 83,205,151,129,228, 17,110, 24,227,108,134,131,196,238, 46,226, 60,195, 51,120,242,140,217, 51, 4,134,110, 92,238, 92, 77, - 42, 52, 0,198,177,153, 20,104, 81, 96,232, 2, 5, 0,233,176, 24,151,241,111, 0,241, 22, 99,225, 63, 5,112,190, 91,148,164, -153,214, 76,249,107,207, 8,150,157, 4,109, 4, 46,181, 12, 36,105, 22, 38, 58,216,234, 40,236, 92,177, 35, 85,201,196, 94,166, -255, 0, 4,227,251,102,171,138,226,141, 80,145,106,127, 43,106,227,151,155,183,111,130, 40, 41,134,253,197, 45,203,106, 77,100, -206, 72,103,248, 45,250, 74, 26,201, 88, 17,189,203,148,159,208,106,118,219,255, 0, 77,225,202, 23, 11,155,155, 59,120,151,101, -141,146,115,108, 43,142,220,242,235, 79, 83, 77, 2, 85,186,237, 13,231, 25, 76, 37,173, 94, 28,153, 78, 35,192,250,189, 49,242, -243,146, 21, 28, 67, 5,242,214,185,225,237, 10,246, 37,236,223, 28, 51,160,110, 93, 50,230,159,180,155,231, 14,139, 6,141, 84, -188,169, 20,168,245,170, 53,231, 14,149, 20, 69,166, 34,238,183, 93,151, 24,202,168, 48,195,108,176,204,230, 36,178,250, 35, 54, -134, 94, 76,166,217,142,134,185,163, 99,253, 27,221,214,159, 80,165, 91,187,205,197,181,110,187,181,116,121, 33,246,109, 11, 90, -155, 92, 73,125,180,171, 33,152,105,184, 43,142,194,160,169, 67,169,117,184,146, 84,156, 20,165, 25, 60,195,123, 59,206,248, 23, -142, 41, 56, 79, 52,204, 56,182,110, 23,174,225,202,104,160,154,140, 82, 79, 49, 38, 34,167, 93, 35,197,104,209,156,173,149,152, -146, 20, 70, 93, 84,165,153,191, 32,200, 60, 65,240,254,183,140,178,156,183,130,224,226,234, 14, 40,171,154,162, 10,227, 91, 4, - 0, 9,129, 81, 29,108,114,131, 35,162, 6,187,162,128, 11, 25, 66, 51,137, 46,188, 20,224,130, 37,122,161,107,241,207, 22,205, - 68,229,213,151,193,189,253, 34, 59,113,121,149, 53, 84, 40, 55,206,223, 79,185,147,150,134, 72, 22,172,106,177,123, 29, 60, 36, - 57,159,135, 58,112,125,151, 27,107,197,206,231,238,109,253, 66,224,219,124,109,173,154,220,132, 90,144,164, 85,209, 87,159, 18, - 13, 86,231,182,219,170,182,183,153,164,123,205, 6,114,159,102, 44,244,195,114, 64,108, 32,164, 58,218,149,148,246,148,183, 0, - 30,195,186,103, 4, 59,219, 95,221, 41, 91,210,238,236, 81,174, 43, 18,191, 97, 78,179,235, 27,115, 6,133, 5,234,101,126, 92, - 7,229, 25,178,149,117,212, 19, 61,159,118,131,224,173,133,199, 8,117, 50, 23,206,113,240,235, 95,184,128,250, 57, 52, 5,238, - 92,237,211,224,251,126,238,109,132,155, 34,168,253, 90,157,107, 61, 18,125, 66, 21,175, 38, 90,150,227,236,218, 87, 93, 26,179, - 18,165, 71,166,165, 75, 33,152,239, 9,107,109, 10, 40, 18,121, 2, 82, 39,213,158, 45,112, 93,125,119, 19,229,145,230,113,193, - 73,155,199, 76,244,245,181, 20, 18,212,211,115,163, 69, 71,134,162,150, 72,214, 70, 81,203, 66,172, 80,165,217,219, 82,178,174, -170,226,135,193,142, 59,203,114,254, 18,205,101,202,100,158,183, 36,150,174, 58,154, 26, 92,198, 42, 74,174, 68,178, 51,199, 61, - 45, 92, 82, 52,106,228, 72,225,215,152, 30,200,138, 85,149,155, 79, 63,120,152,246,113,123, 73,247,246,235,219,109,167,226,139, -140,141,138,188,175,178,213,122,187,181,118, 29,241,126, 64,166,221,115, 99, 73, 93, 54,159,112, 78,182, 41,145,237, 56,210,106, - 13, 56,228,106,115,110, 33, 60,254, 41,132, 84,218, 23,238,207, 41,173, 31,246,169,108, 70,229,240,207, 70,224,147, 98,119,114, -163, 71,170,222,187,125,195,213,118,150,252,234, 12,137, 18,233, 70,139, 43,118,239, 89,244, 56,177,164,203, 97,167, 29, 12, 68, -146, 91, 60,200, 72, 79, 32, 74, 71, 40, 26,238, 94,204,253, 30, 26,228,253,212,164,238,167, 22,156, 77, 94,219,207, 82,164, 79, -131, 56,192,167, 63, 93,167, 79,170,174,154,224,118, 27, 85, 91,234,181, 93,149, 83, 76, 20,173, 8, 10,106, 34, 99, 59,203,144, -220,182,137,206,183, 63,218, 81,236,103,137,199,254,225,237,141,254,141,242,159,182, 63,197,206,219,177,183,108, 80,227,216, 76, - 93,200,157, 30, 61,114,165, 89,102,162,106, 82,110,248, 10,142,176,154,138,153, 45, 22,157,230, 12, 37,207, 23, 42, 41,211, 54, - 91,226,118, 67,149,113, 15, 14, 82, 84,113, 37, 61,110, 65,151, 37, 76,179, 61, 46, 80,244,112, 67, 83, 36, 82,198,139, 2, 70, - 26, 87, 71,230,182,191,169, 81,168, 7, 46,218,138,163,238,105,225, 55, 17,103, 28, 53,197, 21,180,220, 43, 85, 67,196,121,172, -148,176,195, 29,102,117, 29,117, 68,244,145,205, 12,142,213, 15, 41, 72, 99,120,249, 43,203,250,242,218, 47, 24,141,116,134,125, -234,246,125,236,206,223,237,103, 9,155, 11, 64,179,173,250,125, 38, 3, 59, 97,100,212, 92, 17,163, 54,202,230, 85,234,214,237, - 54,167, 88,172, 76, 82, 19,151,234, 82,234, 82,100, 72,125,213,100,173,199,207,100,132,164,111, 48, 24, 24, 29,135, 65,166,203, -102,236, 37,237,126,216, 88,187,122,185,202,169,155, 50,212,183,173,113, 82, 83, 9,138,169,233,160, 82, 33,210,147, 53, 81,146, -234,196,117, 58,152,129,101,176,181,132, 21,242,133, 40, 12,150, 11,143, 78, 49,236,142, 6, 56,109,189,119,206,237,247,106,133, - 98, 35, 63, 80,109,189,164,235,165,183,175,125,198,171, 71,147,252, 28,183,209,200,180,173, 16, 18,168,242, 38, 84, 93, 65,230, -143, 77,165,203,121,176,183, 80,219, 78,115,121,134,183, 63,207, 30, 26, 53,122,250,236,222,165,132, 99,114,242,188,210, 27, 18, - 91,123,146,215, 98,214,176,185,107, 0,113,212, 98,122, 30, 27,225,232,231,174,100,203,178,252,150,145, 76,135, 96,145, 71, 12, - 64, 48, 1,118,178,133,178,170,222,230,193, 65, 36, 12,113, 23,233, 10,251, 69,127,139,219, 56,240, 51,180,149,207, 14,246,220, - 58, 76, 90,158,253,213,105,238,225,251,107,110,170, 45,166, 69, 35,111,195,236,175,154, 61, 90,224, 64, 68,138,131,100,165, 72, -161,165,182, 28,109,216,245,192,166,197,250, 63, 62,207,199, 44, 27, 45,238, 46,247, 46,142,166,111, 45,207,164, 38, 30,218,192, -168, 71, 90, 31,183,118,209,231,218,148, 43,105,105,228, 15, 10,125,126, 68,104,146, 26, 88, 10, 34,147, 18, 26,217,112, 38,161, - 37,189,113, 27,217,255, 0,195, 62,227,251, 81,184,218,174,223,155,197, 50,161,115,219, 13, 92,234,221, 61,253,186, 37, 37,214, -218,174, 63, 83,168,185, 34,149, 99, 68, 49,148,129, 0, 85, 37, 71,114, 43, 76, 50,166,145, 6,141, 74,151,238,188,134, 52,102, -151,250, 18,218,182,237, 58,213,161,211,168,148,168,145,160,194,167,196,143, 18, 60, 88,140,183, 30, 52,118, 35,180,150,153,143, - 29,134, 82, 16,203, 8,109, 41, 74, 16,144, 18,148,164, 37, 32, 0, 53,117,113,253,101, 39, 0,112,165, 23,134, 89, 44,193,243, - 42,197, 90,140,226,116,234,236,225, 88, 67,126,160, 61,151,202,108, 86,153, 34, 86,213,206,123,208,254, 27, 80,214,248,145,198, - 53,254, 44,103,208, 52,121, 85, 11, 61, 54, 73, 76,251,132, 68, 44,166,123,116, 38, 59,183,152, 92, 53, 84,146,178,149,228, 32, - 25, 10, 82, 18,144,148,140, 4,128, 0,244, 3,160,215, 62, 61,164, 30,208, 29,190,246,125,108, 68,221,193,174,166, 21,195,185, -183, 74,103,208,246,111,110, 92,144, 91,126,238,186,153,142,218,156,168, 84,144,203,169,118, 61,155, 75, 18,162, 72,171, 73, 65, - 65, 8,121,152,108,172, 76,155, 21, 42,223,186,157, 78,157, 69,167, 84, 43, 21,138,132, 42, 77, 34,147, 10, 85, 74,169, 84,169, - 74, 98, 13, 58,155, 78,130,195,146,166,207,159, 54, 83,137,106, 28, 38, 99, 52,235,142,186,226,146,134,208,218,150,181, 4,130, - 71, 9,184,174,225,239,128,223,109, 5,235,103,196,178,120,186,133, 90,187,118, 26,145,116,193, 93,191,180, 87, 53,159, 80,147, - 34,153,115,212,232,158,253, 88,147, 10,183, 72,146,245, 74,148,212,218, 52, 38,155,157, 7,154, 22,102, 37, 42,117, 74,117,156, -212,252, 35, 69,149,207,156, 82,213,241, 20, 21, 13,195, 52, 45,174,178, 72, 34,146, 64,163, 75, 24,163,145,145, 78,133,154, 64, -177,177,184,109, 37,180,144, 64, 34,228,227, 92,195, 55,166,201, 42,232,248, 98,122,101,226,188,193,116, 80,199, 81, 52, 81, 22, - 98,202, 37,146, 53,145,135, 49,160,137,154, 69, 91, 50,235, 85, 12, 10,155, 24,223,112, 43, 69,217,158, 45,184,165,187,120,165, -246,138,241, 35,182,116,170,123, 23, 91,119, 61, 74,223,220,203,198,221,164,212,247, 82,240, 90,154,145, 18, 4,155,122, 83,169, - 76, 13,179,165,195,106, 27, 94,232,150, 88,134,243,109, 69,164,194,109, 80,163,204,105,153,125,220, 94,209,127,103,156, 61,184, -186,232, 52, 94, 47, 56,125,117,247,237, 26,244, 24,113, 99,110, 45,186, 93,145, 37,234, 60,166, 35,176,203,104,151,241, 45, 78, - 41, 9, 74, 64,234, 84, 0,215, 43,127,189,146,225,251,255, 0,151,141,236,252,108, 47,255, 0,212,117, 98,186, 62,141, 70,193, - 80,109,171,134,184,206,250,111, 75,206,209,168,117,106,171, 77, 58,108, 79, 9,215, 41,240, 31,150,134,220,228,180,193,240,212, -166, 64, 56, 32,224,156, 28,234,227,226,156,231,194,238, 48,205, 41, 42,234,248,179, 49,165,167,161, 88,226,165,164,134,136, 37, - 61, 52,107,164,104,141, 76,102,218,138,130,204,119, 54, 10, 44,136,138, 40,222, 15,200,252, 93,224,124,162,178,142,139,131, 50, -202,202,154,247,146,106,202,201,235,245,213, 85, 72,218,137,121, 92, 72, 47,160, 51, 4, 81,176,187, 49,187,187,179,241,151,216, -125,188,123, 87,177,188,108,155,223,120,111,251, 87,109,173, 15,226,150,243,164,127, 8,239, 10,196, 74, 37, 35,235, 57,181,155, - 69,248,144, 61,246,107,137, 71,189, 56,212, 57, 74, 66, 51,149, 6, 20, 64,192, 58,156, 37,241,179, 92, 40,241,203,106,237, 46, -225,220,246,214,221,239,165,175,107, 85,218,191,118,150,241,196,122,245, 54, 52,165,184,202, 93,157, 69,169, 68,120, 38,161, 71, -146,245, 54, 31,189, 67,112,189, 2,106,233, 81,140,168,239, 42, 43, 5,184, 0,123, 51,184, 59,180,120,227,226, 73,123, 35,122, - 92,215, 45,167, 72,254, 47,238, 75,185, 21, 91, 80,210,133, 79,223,104,181, 43,126, 19, 17,149,245,197, 62, 75, 62,234,182,234, -239, 21,254,143,159,153,164,114,168, 12,131,250, 11,240,185,177,214,207, 9,155, 29,181,187, 7, 78,186,100,213, 41,118,141, 53, - 54,133,175, 62,230,151, 77, 98,183, 95,122, 59, 21, 90,234,227,165,168,172,176,212,202,144,167,198,170, 72, 83,113,218, 4, 70, -167, 60,241, 64,109,167, 22, 49,227,201,203,105, 56,158,154,191, 47,204,234, 97,226,113, 20, 74,241,160, 40,145,211,114,230, 28, -196,153, 44,218,218,229, 29,117,125,130,110, 45,140,253, 29, 23, 52,173,225, 42,188,187, 50,202,105,103,225, 38,158,102, 73,100, - 43, 36,146, 85,137, 41,207, 41,224,123,174,133, 0, 58, 57, 91,243, 2,216,220, 12, 63,180,219,118,145, 74,138,212, 72,144,152, - 67, 77, 33, 40, 72, 13,164, 97, 41, 24, 0, 0, 58, 12, 1,168,214,125, 36,238, 26, 44,170,175, 15, 59,113,196,205, 42,137, 14, - 22,224,216, 59,137, 73,176,171, 53,136,200, 98, 51,213, 75, 2,242,167, 86,221, 76, 42,145, 5, 42,168, 46, 29,213, 78,163, 42, - 16, 60,230, 50, 42,243,249, 18, 18,251,170, 18,111, 4, 30,160,228,122,141, 71, 19,233, 42,111, 69,183,107,112,145,182,219, 37, -239,241,156,189,119, 91,118,169,119, 3, 20,143, 17,179, 37,155, 43,111,169, 53,105, 85,170,210,208, 57,148,210, 5,199, 87,180, -163, 53,144,128,239,189,200, 40, 89,247,119, 16,170,219,194,167,174, 95, 16,120, 99,216, 11, 9, 94,160, 7,211,125,224, 42,220, -240,214,234,188,157,100,223,109,175,219, 22,175,140, 41,151,191,134,156, 91,250, 68, 41,133, 41,137,143, 85,182,168, 14,158,207, -166,253, 27,157,160, 45,183,222,221,240,212,253, 25, 45,199,171,212,118,115,136, 29,176,151, 33,247,169, 54,142,229, 80,110,122, - 75,110,168, 41,184,138,190, 45,181, 67,159, 26, 49, 42, 42, 67, 62, 61,152,135,139,120, 8, 14, 76, 91,137,202,221,112,234, 82, - 58,139,207,209,155,219, 90,149, 31, 99,247,187,115,230, 71,118, 60, 91,231,115,160,208,105,106,117,183, 80, 38,192,177,109,214, - 20,185,241,212,165,114,187, 24,213,110,170,156,110,100,164, 31, 22,152,242, 20,163,202, 2,101, 13,163,120,178,105,219,196, 78, - 41, 52,214,229,243,208, 27,116,230, 8, 34, 19,125,252,208,250,189,247,193, 60, 25, 90,149,240,199,132, 5, 93,249,190,206,228, - 95,175, 40,212, 76, 97,251,185, 38, 61, 63,225,181,182,194,210,210,210,213,119,139, 59, 11, 75, 75, 75, 67, 3, 11, 86,231,168, -244,137, 50,219,159, 34,151, 78,126,123, 74,105,109, 77,122, 12,103,101,180,182, 20, 20,202,155,146,182,138,208,164, 40, 2,146, - 20, 10, 72,200,193,213,199, 75, 89, 4,141,193,177,247, 96, 98,222,186, 77, 45,198,165,199,114,155, 79,113,137,239,123,196,230, - 87, 14, 50,154,153, 32, 41, 11, 15,203,109, 77,226, 67,220,237,182,121,150, 10,178,128,115,144, 52,195, 92,219,245,176,182,149, -122,185,103,220,245, 58,117, 38,177, 14,165, 62,137, 88,166,205,183,100,165, 18, 94,180,182,226, 54,233, 43,153,126,224, 91,159, - 5,155, 45,232,238,197, 88, 82,208,167,241, 10, 62,100,128,214,182, 39, 90,175,186,220, 34,237,174,239, 92, 87,189,203,114,202, -174,179, 62,249,180,173,155, 70,114, 96, 73, 97,182,233,177,104, 55, 4, 90,205, 74,117, 39,196, 97, 70, 44,234,189, 58,155, 70, -165,212,213,146,151,233,244,134, 89,229, 24, 36,239,229,230,133,166, 97,152,203, 44,112, 21,216,197, 98,193,245, 40, 4,130, 13, -194,173,216,141,137,210, 0, 32,219, 9, 75,204, 10, 12, 42,165,129,253,111, 75, 29,135,199, 97,247,227,225,226,159,135, 84, 56, -170,163,213, 95,119,172, 38, 13,219, 88,247,105, 22,125, 85,171,145, 66,203,155, 66,162,214, 18,136,138,166,123,195,149, 5, 46, -227,166, 8,173,167, 43,148,194,220,113,158,102,153,112,164,250, 39, 17,220, 62, 92, 21, 58, 93, 58,145, 81,141, 34,185, 94,151, - 97,212,226,211,133,167, 80,106,170,170,149,249,112,215, 45,203,118, 92,198, 28,166,133,197,168, 51, 86,164, 85,125,241,199,121, - 87, 1,181,165,233, 10,109, 15,161, 74,182,220, 60, 32,109,125,201,123,215, 47,185,174, 86, 27,170, 87, 55, 43,109, 55, 45,216, -204, 61, 29, 48, 33,205,219,106, 84,138, 75, 84, 24, 49,212,193, 12, 91,213, 70,167, 84,156,170,176, 58,201,118,122,151,204, 20, -134,139,116,232, 92, 31,109,165,187,120,209,239,138, 92,218,235, 53,202, 30,226,110,142,227, 66,113, 79, 68,117,145, 63,115,169, -177,233,206, 81,214,211,177,136, 85, 10,144,168, 20,183,233, 12,118,138,245, 57, 11,202,185,222, 14, 56,145,195,220,178, 86,106, -161, 46,139,128, 74,144, 27, 78,161, 30,201,246, 67,125, 94,175,251,237,109,176,143,246,189, 67,202,133,111,239,189,175,107,245, -235,111, 53,190,235,247,192,151, 23, 20,214,213,149,120,238,245,161,112, 90,149, 90,123,118, 93,223,110,218,116,155,146, 37, 34, -165, 34,213,175, 92, 87,142,216, 91,119,181, 10, 5,199, 93,102, 0, 98,139, 83,155, 86,172,154, 91, 40,230,144, 74,145, 17, 79, -169,147, 50, 58, 23,100,166,241,143,176,110, 91,118,252,155,150, 60,202,122, 85,111, 48,244,196,211,236,186,197,114,218,166, 92, -206, 88,209,239, 59,138,199,163,207,137, 73, 87,214, 85,120,214,244,153,202, 90, 88,103,194,117, 48,100, 69, 14, 42, 91,110,197, - 77,226,167,194, 53, 62,224,168,214,164, 92,187,177,184,117,202, 93,207, 86,176,238,171,166,132,252, 75, 34, 52, 75,138,247,219, -171, 22,218,178,232, 23,101, 70,124, 75, 81, 19, 90,146,100, 90,180,154,171,241, 99, 73, 98, 19,149, 8,201,195, 8,139,207, 29, -204, 89,174, 3, 54,230, 28, 89, 84,218, 93,213,112, 83,169, 85, 8, 13,183, 62, 50,109,173,179,153, 84,126,170,109,166, 45,137, -213, 38,111, 9,246, 59,149,202,124, 73, 44,199, 68,199, 96,199,169,183, 24, 77, 91,133, 9, 76, 55, 93,134,181,227, 28, 52, 99, - 65, 52,210, 44,161, 35,212, 99, 50, 88,176,141, 85,236, 90, 50, 67, 23,214,214,210, 86,214,179,139,144, 10, 77,101,201, 85, 4, - 92,245,183, 75,220,116, 61,133,133,239,123,246, 56,201,110, 78, 45, 54,210,143, 71,187, 69, 26,206,190,106, 23,221,159, 10,239, -174, 77,176,164,109,229,114,157, 93,162,200,181,109, 26, 5,194,253,122,230, 66,160, 17,111,208,220,164,222, 86,170, 68,245, 41, - 75, 91, 85,192,134, 91,117,109,188,218, 1,107,139,222, 30, 41,208,160, 38,182,212,154, 96, 81, 98, 34,164, 83,236,138,173, 86, -132,229,233, 73,143, 2, 77, 86,210,160,202,167, 82,150,229,102,224,167, 57, 85,155,240,177, 28,130,105,117, 4, 48,181,191, 26, - 67, 73,200,239, 78, 20,232,247, 93,227,184,151,181, 59,113,239,187, 58,175,186, 16,107, 20, 59,177, 20, 6,109, 25, 81, 38, 91, - 85,235, 26,194,177,234,148, 36, 49,113, 91, 83, 67, 13,174, 54,221, 80,228,162, 75,124,147, 24,118, 76,180,176,251,104,120,114, - 97, 71,129, 29,185,102, 75,134,157,116, 87,233,212,215,107,237,221,142,192,102,217,219, 23,234, 46,220,107,153, 26,125, 70, 66, -175, 41, 86, 50,235,200,165, 73,156,220,169, 11,130,138,162, 26, 67,243,150, 16, 68, 68,166, 32,196, 67,134,204, 81,243,102,154, - 55, 96, 25,172, 90,225,180,141, 75,126, 89, 22, 86,190,141,141,197,203, 50,155, 12, 6,246,205, 70,202,164, 3,177,176,251,143, -218,190,227,175,167, 96,112,231, 92,188, 65,108,253,156,237, 21, 85,234, 37,205, 77,117, 54,204, 75,162,127,188,109,197,114, 52, -173,190,178,220,185,255, 0,131,148,235,130,242,141, 38,152,219,246,149, 21,117,198, 37, 41,160,227, 97,192,213, 50, 76,191, 5, - 44,199,113,212,227,232,226,211,100, 21, 21,169,244,186, 61,249, 82, 97,202,109,126,252,241,169,187, 81,118,165, 40,183,173,245, - 24,119, 77,250, 28,149, 70,101, 47, 81,162,201,144, 35, 61, 61,165, 56, 94,122, 73,102, 57,144,174,112,155,149,235,194,253, 54, -254,147, 62, 77,127,114,247, 1, 75,185,109,201,150, 53,252,136,169,180, 27, 69,243,183,234,190,107,183,181, 30,208,169,151,173, -119, 21, 76,139, 79, 23, 21, 86,150,196,154,122,162,203,114,155, 49,212, 72,121,217, 74, 76,164, 52,251,165,194,237,235, 26,209, -179,173,109,147,172, 76,141, 81,133,182, 87,238,208, 87, 46,106,213,219, 71,163, 71,122,208,188,167,211, 39,166, 53,106,131, 47, -109,107,104,172, 50,153,222,250,242,158,167, 46,147, 80, 97,184,166, 59, 47,172,204, 15, 66, 37, 60, 57, 12,220,152,228,168,144, - 77, 35, 16,197,159, 68,106,161, 88,234,102,104,191,104, 88, 1,114, 84,173,192,114,193,114,237, 84,161,152, 32, 33, 64,176, 2, -228,155,141,128, 13,233,248,131,216, 12,110,107,245,216,236,216,210,174,155,102, 19, 51, 24,254, 12, 74,185,104,144, 74,126,174, -102,127,139, 76,118,175, 5,151, 65,108,123,159,142,181,183,206, 74,121,146, 94, 82,148, 50, 14,180,215,116,165,219,144, 32,213, -182,215,234, 10, 53,122,167, 42,135, 42,149,118,221,213, 70,214,169, 21,107,134,188,202,229, 86,106, 18, 4, 96,219,174,148,212, - 36,135,144,147, 32, 54,202,144, 24,109,164, 55, 29,160,157,199,135,107, 57, 22,193,139,100,166,162,160,236,107, 61,139, 88, 85, -154, 99,195, 80,113,154, 42,105, 34,162,212,101, 58,174, 69,115, 39,197, 74, 10,206, 14, 19,204,123,235,144, 59,209, 19,116,167, - 75,115,110,234, 52,115,107,213, 46,219,210,159, 99,220,151,204, 58,236, 73,212,214, 41,117,135,213, 18,124,250, 47,142,152,243, - 99,207,171, 72, 8,129, 8,201,140,219, 77, 59, 90,111,154, 74,212,166,148,189, 76,174, 26,121,106,106, 29,239, 34, 68, 9, 80, -110, 46, 9,181,201,219,183, 91,237,190,248, 60,236,234,136, 7,148,183, 95,203, 29, 10,217,141,236,135,113,237,133,155, 34,137, -104, 94, 55, 7,131, 64,143, 79,110,109, 18,136,236,138, 4,185, 20, 96,229, 38, 91, 17,174, 7,228, 6, 36,186,204,216, 18, 99, -188,239, 63, 35,146, 34,186,166, 84,235, 74,109,197,229,117,203,231,113,228, 81, 38, 76, 27,115, 80,181,169, 66, 35,130,109, 86, -161, 91,167,203,170,192,109,238,102,132,198,233, 52, 53, 63, 33,184, 44,146,133,204,125, 1, 82, 99, 70,241, 95,139, 22, 83,173, - 37,181,115,182,167,188,183, 37,129, 6,159,182,219, 79, 95,118,221,177,236,232, 45,208,224,166,152,212, 39, 19, 54, 68, 95,130, - 92,184,146,164, 69, 83,145,233,254, 40, 83,113,195,107, 72,113,182, 68,151, 7,140,251,152,109,170, 91,157,184,213,165,133, 85, - 47,171,178,127, 33,230, 75,114,171,213, 23, 35,250,156,199, 84,159, 15,147, 25,200, 41,229,229,200, 61, 52,228,156, 45, 83, 33, - 46,213, 9, 12,109,184,184, 98,214, 61, 46, 54,177,183, 93,246,239,141,118,204, 17,118,208, 89,135, 93,192, 23,247,125,248,187, -241, 61,191, 16,171, 20,120, 91, 43,100, 59, 38, 45, 50,223,155,227,110,163,143,165,182,103,212,183, 14, 41,104,204,160,206,247, - 98, 91,122,157, 79, 90, 99, 41,149, 50,183, 97,190,216,132,184, 46, 57, 2, 52, 39,156,210, 5, 41, 40, 66,220, 89, 66, 27,109, - 42, 90,220, 95,192,219,105, 72,202,150,226,212,112,218, 7, 82, 73, 32, 0, 59,247,214,204, 79,218,105, 60, 77, 67,171,238, 54, -206,186,245, 31,112, 40,173, 83,169, 53,218, 12, 24,116,183,153,221, 11,113,130,220, 51,122, 91, 76, 85, 22,150, 26, 76, 26,164, -146,195, 50, 28, 10, 83,241,203,235,111,199,134,228, 45,102,150, 23,179, 43,113,174,103,163, 78,220,186,172, 10, 83, 3,192,117, -104,185,234,127,195, 25,237, 41, 32,164,174, 53,175, 72, 83, 84,104,143,114, 21,146,164,150,212, 20,190,185,198, 4,179, 46,173, -203, 50,156,190, 58,121,100, 74, 87,131,103, 86, 97,169,159, 98, 92, 0, 11,184,125,138,176, 91,105, 32,109,107, 6,154,136,106, -106,106, 25,213, 76,161,250, 16, 54, 3,176, 36,216, 2, 58, 17,126,183, 62,252, 48, 60, 43,109,125, 79,127,119,214,218,118,158, -185, 44,218, 22,100,195, 85, 21,152, 78,173,176, 24,129, 33,164,215, 46, 72, 51, 89, 87,232,220,113,192,221, 34,148,242, 50,174, -121,115,101, 55,205, 29,104,115, 82, 78,211, 25,177, 59, 3,102,236, 21,187, 50,139,108,185, 46,165, 62,173, 33,153, 53,170,245, - 73, 17,145, 54,114,162,180, 89,135, 17,150,162,180,148, 67,165,176,133, 61,224,176, 57,202, 21, 37,197, 41,197,149,100, 62,122, -131,113, 6,106,185,165, 96,104,175,236,208, 11, 33, 34,197,137,182,166, 35,168,189,128, 0,244, 85, 23,220,156, 61, 80,210,154, -104,136,127,239, 28,220,251,189, 7,243, 39,212,156, 45, 45, 45, 45, 48,227,119, 11, 95, 8, 4, 16, 70, 65,232, 65,215,221, 45, - 12, 12, 83, 67, 45, 53,146,219,104, 65, 61,202, 82, 1, 63,128,213, 77, 45, 45, 12, 12, 51,123,215,177,246, 78,250, 90,142,219, - 55,132, 15, 17, 77,169, 82, 41, 53, 88,229, 45, 85, 40,211,185, 57, 19, 46,159, 36,164,248,107,198, 2,208,160,166,221, 72,229, -113, 10, 24,199, 21, 55, 95,128,189,229,176,101,201,126,218,136,213,251, 65, 75,139, 49,164, 82,249, 99, 86, 27,103, 36,161, 50, -233, 82, 22, 57,221, 9,192,203, 14, 59,205,140,242,163, 60,162, 65,250,242,180, 33,192, 82,180,165, 96,247, 10, 0,143,219,170, -147,196,127, 5, 56, 23,196,226,149, 89,229, 28,148,121,204, 74, 17, 43,169, 25, 98,168,208, 62,202, 73,169, 94, 41,209,127, 84, - 75, 27, 50, 11,136,217, 1, 55,183,188, 54,241,191,143, 60, 47, 87,165,200,171, 99,172,201,165,114,239, 65, 86,173, 45, 54,179, -246,158, 61, 46,146,192,237,250,198, 41, 21, 92,216,200,174, 64,180, 88,213,177,251,198,219,222, 2,182,186,252, 11, 10,228,255, - 0,246, 90,178, 91,207,151,233,189,211,147, 31, 62,108,117,239,167,207,108,248, 36,222, 91,238,100,115, 87,165,127, 3,105, 10, -113, 62, 60,170,176,241,106, 37,172,142,111,119,166, 48,172,135, 49,156,120,203,100, 12,103,174, 48,100, 58,105,148,245, 30, 99, - 13,130,123,231,195, 26, 33,168,236, 50, 48,211, 77,182, 63,217, 72, 31,208, 53, 83,100,223, 67,239, 15,232,107, 82,167, 52,206, -115, 28,238,154, 50, 15,179,179, 69, 4,111, 99,246,100,120, 99, 18,149, 61,249,111, 17,244, 97,139,115, 58,250, 99,248,133, 95, - 67, 37, 46, 85,146,229,217, 29, 76,128,143,104, 85,150,162, 68,184,251, 81,164,210, 24,131, 14,220,200,229, 95,240,156,107,150, -193,112,227,103,236,125, 9,184, 52,136,161,218,131,220,143, 84,106,146,130, 29,168, 84,101, 37, 56, 15, 74,120, 32, 14, 80, 10, -130, 27, 64, 13,182, 9, 8, 72,201, 39,100,244,180,181,212,185, 94, 87,151,100,153,125, 38, 85,148,209, 71,151,101,180, 40, 35, -134, 24,148, 36,113,160,232, 21, 70,221,110, 73,234,204, 75, 49, 36,147,142, 85,205,115, 92,203, 59,204,106,243,108,222,182, 76, -199, 50,175,115, 36,211,204,197,228,145,207, 82,204,119,233, 96, 7, 69, 80, 21, 64, 0, 0,180,180,180,181,191,134,252, 45, 45, - 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12,104, 15, 16,151, 95, 24, 54,239, 17,123, - 83,103,109, 12, 84,212, 54, 75,118, 69,182, 47, 27,216,219,148, 90,131,187, 24,189,180,184,101, 92,219,132, 23, 42, 76, 82, 37, -139,234,202,151, 77,160,210,125,241,138,135,213,181, 58,116,137,140,248, 9, 90, 64,231,117, 43,136,239,106,117,199, 89,185,105, -117, 10, 52,219, 42, 68,189,220,218,235, 50,177, 79,135,177,151,213,106,118,216, 64,186,248,146,182,109, 10,197, 94,196,168,220, - 27, 33, 79,182,247, 3,109, 33,236,132,171,166,163, 88,171, 53,117,221,106,132,229, 62, 29, 72,212, 41,241, 36, 73,106, 28,131, - 84,132, 47, 28,201, 10,199,108,140,227, 84, 76, 88,197, 69, 69,150,202,143,115,203,215,203,250,134,165, 20, 60, 69, 77, 73, 4, -113, 75,195,212, 85,111, 18,196, 57,143, 18,150,102,142, 70, 98,238, 24, 50,182,184,244, 70,234, 2,130, 99, 89, 13,218, 73,249, -209, 44,195,134, 42,235,106, 36,154, 46, 37,175,163,142, 87,148,152,210,102, 8,171, 36,106,161, 35, 42,200,203,203,148, 73, 42, - 49, 44, 87,154,209,139, 36,116,252,158, 18,111, 54,228,113,174,250,120,178,217,207,122,222, 77,206,102,216,218,235, 50,169,182, -183,141, 11, 96,170,118,165,187, 86,174, 81, 46, 93,174,102,187,109,151, 87,181,116,241,125,223,117,200,235,187,229, 59, 34,206, -174, 87,232,109, 83,149, 52, 24,150,188,232,144,226,189,121,221,222, 37,189,160,182,229,237,191,208,108, 59, 58,250,169,203,183, -173,190, 38,157,179,108,216,155, 3, 85,170, 88,180,107, 78,206,216,154,213,197,195,166,226,216,251,164,154, 35,177,247, 99,117, - 46, 45,225,139,109,211,166, 90,113,234, 19,223, 67, 85,233,113, 87,111, 66, 52,228,205,149,220, 51, 22, 58,149,204, 89, 65, 80, - 24, 4,167,168, 30,131,211, 95, 12, 72,196,133, 22, 91, 42, 29, 1,229, 25, 3,211, 75,197,197, 20,136,176,163,240,229, 36,235, - 18,176, 33,145, 44,210, 60, 84,241,180,133, 86, 48,170, 73,131,152, 2, 42,144,206,124,197, 76,130, 93,105,120, 70,177,218,103, -143,138, 43, 96,121, 93, 72, 43, 36,132,172,105, 45, 76,169, 24,102,149,157,128, 21, 28,178,100,103, 82,136, 60,129,132, 70, 29, - 28,224,214,249,226, 54,181, 83,222,219, 55,136, 39, 43, 85,241,100, 94,246,107, 27,119,127, 86,246,245,141,190,145,120, 91, 23, -102,204,109,181,247, 91,109,168,212,184, 17,169,213,150, 40,215,245,201,118,208,253,234, 19, 64,161,116, 5, 67,154,165,207,141, - 37, 70, 41, 62,217,106,175, 29, 60,104,113, 79, 93,164, 80,248, 84,226,128,108,102,199,212,235,214, 38,211,193,135,178, 27,169, - 46,147,113, 46, 44,255, 0,115,185,183, 61, 15,199,182, 20,196,245, 87, 38,211,216, 92, 23,154, 60,130,143, 6,156,148,254,148, -200,113,217,206, 33,150,155, 57, 67,105, 73,237,144, 49,211,211, 67,187, 77,128,242,138,221,136,195,139, 61,212,180, 5, 19,247, -157,111,240,175, 28,175, 11,103,243,113, 12, 25, 5, 53, 85, 91, 66,177, 70,164,152,227,133,180, 34, 75, 44,105, 26,133, 87,155, - 75, 19,164, 5, 65, 35,170, 0,166,216,110,227, 15, 15,159,139,248,110, 14, 25,168,226, 74,186, 58, 36,153,165,149,192, 89,101, -157, 4,143, 36, 48,202,242,146,204,144,234, 80, 53, 18,206, 99,141,156,150, 92,126,116,252, 63,207,246,190,240,179,111, 84, 45, -109,128,218, 78, 44,118,210,133, 86,172, 61, 95,169,195,163,240,195,113, 77,114,125, 93,248,145, 32,174,108,185,213,189,175,149, - 33,245,136,112, 98,182,132,169,210,134,210,214, 16,148,229, 89,216, 95,229,123,244,129, 63,242,126, 52, 63,251,173,204,255, 0, -254, 61,169,231,253, 81, 76,255, 0,200, 99,127,246, 73,254,173, 47,170, 41,159,249, 12,111,254,201, 63,213,169,173, 79,140,244, -149,147,203, 85, 89,225,206, 77, 85, 85, 49,212,242, 73, 10,188,142,118,221,157,162, 44,199,110,164,147,211,211, 16, 58, 95, 2, -107,104,105,226,164,162,241, 71, 60,163,164,128,105, 72,162,157,227,141, 23,246, 81, 18, 80,170, 58,236, 0, 27,226, 37,155,115, -253,212,126, 49,125,153,188,113,237,174,247,198,222,153, 59,193, 46,175, 96, 72,219,250, 22,228,109,202,182,202,225,187,172,138, - 21, 82,137,114,222,246,157,180,203,246,205, 29, 85, 20,205,129, 74,154,216, 8, 67,198, 83,220,180,197, 40, 34, 90,211,174,108, -123, 29, 56, 93,226,149, 28,122,109, 85,237, 78,219,189,198,219,219,123,106,234,245,201,187,145,114,220,214,181,114,217,129, 10, -149, 34,223,173, 81,102, 90, 18, 69,110, 36,113, 58,173, 81,126, 98, 97,251,154, 2,223,101, 46, 57, 49, 77,165, 17, 22,226, 63, - 64, 22, 96,195,143,159, 6, 51, 45,115, 12, 43,145, 0,100,124,245, 69,170, 85, 61,151,140,134,162, 50,135,137, 36,184,148, 36, - 40,147,243,198,154,161,241,114,174,151, 42,226,204,162,135,135, 40,168,169, 56,157,157,130, 68,186, 35,166,230,211, 71, 75, 40, - 72,213, 66, 72,165, 35, 14,129,130,132,145,152,182,181, 58,112,239, 63,130,212, 85,153,191, 6,103, 85,252, 79, 95, 95, 91,194, - 43, 26,151,149,181,201, 87,201,170,146,174, 18,242,179, 23,141,131,202, 81,202,150, 47, 18,162,175, 45,134,178, 91, 28,254, 11, - 94, 39,235,248,104,231,255, 0,249,185, 70,127,110,177,109,192,143, 34, 93,135,122,196,136,195,210,165, 74,180,238, 40,241,163, - 71,105,111, 72,145, 33,234, 68,198,217, 97,134, 91, 73, 83,175, 45,197, 37, 41, 74, 65, 82,148,160, 0, 36,235, 46,210, 35, 32, -131,216,244, 58,169, 35,115, 27,163,129,114,132, 31,220,111,139,166, 68, 18, 35,161, 54, 14, 8,253,226,216,132, 15,176,167,134, -142, 35,182,159,142,131,114,110,159, 15,251,217,182,150,232,218, 43,214,152,107,251,129,181, 87,213,153, 69,250,202, 85,110,207, -118, 45, 59,235, 91,142,131, 25,143,127,113,168,178, 84,219, 62, 39,136,180,199,112,165, 36, 33, 68,117, 47,219,205,195, 55, 28, -251,238, 54, 30,243,225,142, 29, 70,225,177,182, 89, 85,139,166,109,187, 96,220, 82, 40,155,167, 77,220,121,146, 24,110, 13,239, - 72,138,151, 99, 46,172,220, 26, 44, 70, 24,129,245,108,167, 42,145,159,169,206, 83,113, 11, 78,151, 83, 34,132,192,132,135, 60, -100,198,101, 46,147,146,224, 64, 11,207,219,162, 84,132,172, 20,173, 41, 82, 79,112,160, 8, 63,113,213,149,152,120,159,153, 87, -113,173, 39, 27,140,170,149, 43,105, 34, 16,136, 36, 15, 44, 37,116, 73, 27, 19,114,172, 24,164,140, 1, 7,202,108,119,232,106, -156,179,194, 76,171, 47,224, 42,222, 1,108,226,174, 74, 26,217,140,230,162, 50,144,206,175,174, 41, 20, 11, 43,161, 85,120,148, -144, 65,212, 46, 54,216,136, 25,208, 61,170, 30,218,237,168,164, 39,110,107,112,119, 42,161, 86,167,180,154,124, 73,123,145,195, -123,147,175,152, 73, 79, 52,102, 82,236,185, 86,131, 14,213,229, 7, 80,172, 61, 80,106, 99,238,173, 39,196,113,206,163, 77,149, -151,192,119,180,211,218, 97,189, 44,110, 46,255, 0, 64,220,170, 74,107, 38, 36, 90,246,237,239,133, 26, 85,175, 26,139,111, 48, -234,221,106,157,101, 88, 47,198,128,235,144, 71,143, 49,200,112, 41, 20,248,116,144,252,135, 28,117,248,190, 58,222, 95,232, 6, -237, 2,142,250,185,220,129, 29, 74,245,240,211,253, 90, 50, 61, 62, 20, 79,251,222, 43, 45, 99,205, 8, 0,254, 56,212,132,120, -202,153,122,212, 79,195, 92, 13,149,240,246,109, 84,165, 90,170, 40,213,156,106,234, 81, 86, 56,128,223,205,165,153,208,176, 5, -209,237, 99, 26, 62, 5,190,100,244,176,113, 87,136, 57,191, 19,100,212,110,174,148,114,202,202,135, 79, 64,238,210,202, 78,215, - 82,200,169, 32, 82, 66, 58, 94,248,215,190, 20,248,114,178,184, 89,217, 43, 15,102, 44, 56, 70, 37,191,100,208,163,210,163, 45, -222, 85, 76,168, 74, 82,220,153, 87,173, 84,156, 72, 1,218,172,250,188,153,211, 37, 41, 41, 74, 21, 34,123,133,180, 33, 28,168, - 78,200,105,105,106,151,168,168,158,174,121,234,170,101,105,234, 42, 93,164,145,216,221,157,220,150,102, 98,119, 44,204, 73, 39, -185, 56,189,233,169,169,232,233,169,232,233, 97, 90,122, 90, 84, 88,227,141, 5,149, 35, 69, 10,136,160,108, 21, 84, 0, 7, 96, - 48,180,180,180,180,142, 23,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194, -210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,214, 53,117,217,246,213,239, 67,171,219,183, 69, 34, 21, - 94,149, 91,165, 79,163, 84, 24,146,195,107,113,112, 42,113, 93,135, 45,182, 95, 41,231,142,178,203,206,114,173, 5, 42, 66,136, - 82, 72, 80, 7, 89, 46,150,178, 24,169, 5, 77,136,238, 48, 8, 7, 98, 46, 49,196,171,235,133,221,241,219,202,252,170, 5, 5, -186,133,255, 0,110, 54,227,142, 91,183, 24,180, 43, 87, 5, 89,218, 66,156, 34, 28, 91,130,109, 22,174,210, 93,171,176,128, 27, -113,199, 24,105,215,249, 3,170, 47, 40,169,247, 49, 56,124, 52,111,189,235, 81,137, 67,173, 91, 85,184,244, 57,175, 52,212,250, -127,240, 58,177,105,211,231, 52,181, 0, 89,174,220, 21,122,163,202, 77, 11,186,164,199, 97, 13, 46, 66, 17,224,173,197,178,183, - 24,123,188, 58, 90,146,167, 20, 85,172, 74,141, 2, 59,168,182,162, 91,115,107, 92,168, 54,223,184,232,119,216, 13,176,222,114, -248,203, 92, 57, 11,126,155,126, 7,249,225,157,217,141,156,160,236,245,178,138, 85, 60, 53, 50,183, 53, 12, 57, 94,173,134, 82, -202,230,190,210, 57, 90,139, 21,176, 63,193,105, 44, 36,169, 17,217, 29, 0, 37,106,202,214,163,167,139, 75, 75, 81,233,166,150, -162, 87,154,103, 50, 73, 33,185, 39,231, 96, 58, 0, 54, 3, 97,182, 55,149, 85, 20, 42,139, 42,244,194,210,210,210,210, 88, 54, - 22,150,150,150,134, 6, 32,111,253,251,111,253, 25,127,246,206,255, 0,117, 13, 84, 31, 77,167, 61,189,153,157,251,127,142,111, -251,168,234, 6,201, 25, 61, 71, 79,216,116, 66, 7, 92,227,160,237,253, 29,191, 61,180,202,213,149, 2,195, 94,231,220,191,150, - 52,249,178,126,215,224, 63, 44, 79, 25, 63, 77,151, 39,255, 0, 6,119,218,127,150,103,111,251, 41,107,223,247,236, 95,244,103, -255, 0,219, 47,253,212,245, 4, 4, 2, 7, 95, 63, 47,223,170,169, 25, 61,186,122,250, 31, 81,243,210,126,219, 83,255, 0, 19, -240, 95,203, 24,230,201,127,181,183,192, 98,119,163,233,176,103, 24,246,104, 30,163,167,248,229,121,231, 24,255, 0, 53, 62,250, -168, 62,154,225, 35,175,179, 71, 31, 47,229,149,254,234,154,130, 42, 65,207, 67,215,212,255, 0, 96,209, 9,238, 1, 57,207, 66, -113,249,198,136,213,245, 67, 97, 37,143,253, 43,249, 99, 60,217, 45,187,126, 3,242,196,238, 7,211, 87,201,199,247, 52,251,255, - 0,207, 39,240,255, 0,146,174,190,171,233,171,114,130,127,185,167,159,151,242,200,255, 0,117, 93, 65, 69, 9,235,159,151, 79, -207,231,190,171, 4,115, 15,151,207,215,229,233,211, 26, 76,230, 21,118, 63, 93,254, 85,254,156, 37,237, 18,245,215,248, 15,203, - 19,165, 79,211, 89, 73, 4,159,102,170, 83,233,158, 50,135,207,254,106,191, 45, 18,215,211, 80,241, 19,205,253,205, 94, 80,123, -127,142, 62,115,255, 0,101,109, 65, 56, 67,100,168, 18,128,163,223,185,239,242, 25,237,223, 87, 54,211,203,202, 0, 0,118, 29, - 49,229,158,131,238,210,103, 49,173, 22,250,254,191,225, 79,233,198, 13, 68,189,155,240, 31,150, 39, 74,159,166,146, 79,127,102, -191, 47,111,249, 99,122,255, 0,213, 99, 85, 71,211, 69,207,250, 54, 71, 94,199,249, 98,244,199,175,249,172,106, 11,137, 0,145, -159, 63, 79,199,240,209, 41, 7,203, 0,118, 57,237,143, 77, 96,230, 85,191,241,191,202,159,211,140,123, 76,223,183,248, 15,203, - 19,158,254,253, 11,254,141,175,251, 98,127,186,206,189,143,166,127,144, 15,247, 54,241,159,249,225,255, 0,186,214,160,208,144, - 8,234,123,244,199,237,253,218, 36, 39, 29,124,250,119, 29,189,116,145,205, 43,199,251,255, 0,242, 39,187,252, 56,199,180,205, -109,218,196,123,135,229,137,201,143,166,116, 79,250, 55, 15,111,252,240,187,127,217,107, 94,199,211, 56, 39,191,179,119, 29, 51, -254,120, 95,111,127,241, 91,233,219, 80,111, 66,135,111, 60,254, 7, 24,209, 8,238,125, 72,239,223, 31,119,231,182,138,115, 90, -253,254,190,214,255, 0, 10,127, 78, 11,237, 51,116, 50, 88,250,233, 31,150, 39, 26, 62,153,166,112, 71,179,131, 57,237,142, 48, - 63,221,115, 94,135,211, 49, 57, 0,251, 55,241,156,227,252,112, 51,219,254,171,154,131,194, 82, 70, 48, 64,232, 51,143, 33,242, -252, 52, 66, 49,158,191, 96,244,255, 0,142,136,115,108,195,114, 42, 46, 7,248, 19,250, 48, 95,107,159,246,255, 0, 5,252,177, - 56, 65,244,203, 15,159,179,135, 31,245,191,207,255, 0,149,221,122,254,252,175,166,127,185,197,246,143,229,127,219,211,254, 75, -218,132, 10,112, 10,114,160, 9, 29, 7,168, 61,127,167, 94,243,144, 72,238,122,100,244,207,207, 69,253, 47,152,255, 0,204,127, -146, 63,233,198, 13, 93, 64,255, 0,121,248, 47,229,137,189,127,126, 89,255, 0, 71, 16,255, 0,239,127,229,235,254,107,186, 95, -223,150,127,209,197,255, 0,107,255, 0,247, 93,212, 32,130, 70, 78, 83,156,121,142,227,167, 97,235,175,129, 39, 36, 96,158,227, -228, 15,174,116, 63, 75,230, 63,243, 31,228, 79,233,198, 61,174,163,175, 50,254,235, 47,229,137,191,255, 0,126, 86,112, 79,247, - 56,187, 99, 63,227,127,235,216,255, 0,154,238,144,250,101,100,228, 15,103, 9,200, 56,255, 0, 59,241,143,159, 95,228,189,168, - 65, 28, 19,201,158,160, 12,125,189, 71, 93,124,228, 56, 61, 58,142,199,215,215, 67,244,190, 96,127,246,143,242, 39,244,227, 34, -170,163,188,157, 61,195,242,196,224, 26,250,101, 42,117,105, 66,125,155,238,173, 74, 90, 16,134,216,226,229,114, 31,117,110, 45, - 45,180,204,120,237,112,184, 87, 34, 67,142,173, 8,109,180, 2,183, 28,113, 40, 64, 42, 80, 26,145,125,139,237, 28,187,106,123, -107, 97, 92,219,161,195,163, 59, 99,184,215, 61,173, 2,228,186,182,189,141,220, 55,106,172, 25, 85, 68,137, 81,173,154,141,204, -118,206,154,106, 53,248,244,231,225,154,131,105,167, 50,136,178,214,252, 70,220,146, 35,151,215,249,251,123, 18,120, 79,167,111, -111, 18,114,247,186,251,163, 49, 85,218,222, 24,163,210,111, 53,194,156,128,245, 62,228,222, 74,163,175, 29,169,183,157, 96,172, - 9,108, 83,222,131, 80,184,101, 52,174,132,209, 41,225, 89, 75,196, 25,105, 85,110, 39,101, 73,126,161, 41,197,174, 75,239,169, -114,139,171,241, 63,239,176,162,251,170, 86,121,157, 65, 89,113, 67, 7, 35,169, 4, 18,115, 82,113,247,137,217,238, 79, 87, 22, - 91,147,230, 34, 26,136,198,185,156, 69, 79, 33, 23,221, 80, 44,145, 56, 6,222, 98,116,157,153,122,110, 71, 99,125, 27, 60, 13, -161,241, 3, 47,175,226,174, 50,162,122,236,146, 71, 48, 81, 64, 36,150, 14,107, 70,214,150,114,244,239, 20,133,117,222, 36, 93, - 65,110,172, 77,203, 45,186,186,215,180, 61,151,139, 72, 78,210, 40, 56,230, 50,147,125, 47,149, 37, 77,151, 65,231,254, 5, 97, - 72, 9,229,201,242,231, 29, 51,240,235, 38,139,199, 80,146,160,145,181,193, 5,104, 75,168,255, 0,223,202, 78, 90, 39,195, 82, -214, 13,164, 11,120,116,164, 96,142,161, 65, 94,120,215, 37, 97,212,227,199,149, 78, 9,151, 17,105,146, 42, 43,109,228,184,158, - 66,150,152, 96,162, 49, 81, 60,133,229, 15, 16,124, 93, 73, 25,192,198,117,127,135,119,198,133, 85,181,154, 92,152,232, 50, 28, -186,224, 45, 77,133,168,134,145, 77,106,160,134,156, 25,228,241,210,136, 43, 91,107, 60,205,168,199, 90, 80, 50,188, 26,248,120, -191,199, 91,223, 62,222,224, 91,217,168,122, 27,111,255, 0,163,123,205,183,183,173,183,183, 70,215,125, 26,252, 47,211,253,139, -131,216, 17, 28,143,189,110,104,215, 17,164,174,118, 53,123,111, 17, 95, 80, 78,224,219, 29,102,143,198,144,125,124,131,109, 74, - 72, 74, 85,145,120,165,105,198, 84,135, 7, 50,109,142,133, 46,164,167, 31,102,112, 78, 53,145,195,226,200, 74,117, 13, 42,195, - 67, 36,164, 41,197, 27,185, 11, 13, 21, 41, 73,194,147,252, 30, 10, 94, 8, 28,197, 41, 32, 5,103, 39,166,121,115, 2,240,167, - 70, 20, 80,180,187,134,229,185, 73,145, 29,134,150,242,101, 73,157, 30, 64, 97,134,152, 42,230,117,245, 61, 19,152,140,164, 39, - 42, 42, 1, 32,105,211,165, 85, 16,235,177,228, 37,200,205, 55, 48,170, 47,130,211,169,144,168,175,186,194,157, 76, 57, 13,129, -240,203, 11,104,243,140, 39,147,168, 74, 84, 64,202,195,197,222, 56, 99,182,126, 45,113,183,178,209,131, 98, 7, 66,105,253,247, -233,115,110,128, 3,138,247, 55,240, 35,129, 40,195, 21,225,118,129, 72,107, 19, 85, 94,119, 82,194,219,213, 27,146,171,175, 96, - 71,152,124, 11,113,237, 58,246,213,110,191,179,158,220,176, 55, 74, 7, 3, 3,126,182, 34,238,121,155,106,229,220,202, 87, 17, - 78, 89, 19,118,199,113,165,190,239,212,246,205,239,105,183,176,245,193, 6,220,171, 67, 74, 62,167,174,138,129,141, 46,106, 28, -166,201,143, 6, 89,138,153,124,121, 63, 76,188,131,211,217,192, 8,233,212,113,129,228,124,255, 0,205,115,211, 93,240,187,108, - 11, 23,121, 44, 27,215,104,183, 62,212,167,238, 22,218,110, 61,183, 91,177,239,203, 66,160,208, 85, 46,224,160, 85, 98, 2,253, - 61,213,161,121,131, 48, 56,162,244, 73, 72, 34, 68, 57,212,248,242,227, 45,183,153,109, 73,252,231,120,230,246,106,239,183, 6, - 60, 82, 94,220, 62, 83,108,205,193,221, 91, 81,182, 13,241,179, 87,213,187,104,220, 55, 36,155,231,104,106,242,164, 10, 21, 78, -166,154, 13, 41,239, 10,232,165,186,219,212,154,235,124,169,228,168,210, 87, 32, 1, 30,100,114,171, 79,131, 60, 72,204,115,136, - 37,165,205, 43, 2, 87, 83,141, 66, 67, 28, 72,146,161, 61,172,129, 53,165,192,178,216, 50, 16, 84, 54,151,115,201,126, 41,240, - 67,240,133, 90, 87,229,108, 70, 77, 84,193, 66, 19,169,160,115,246, 86,238, 90, 66,143,111, 41,114, 72,109,181, 29, 64, 44,156, -255, 0,191, 47,234, 71,247, 56, 71, 65,159,243,192,245,237,255, 0, 37,221,124,254,252,192,255, 0,251,184, 58,127,233,129,251, -191,146,230,161, 89, 94,176, 47,187, 81,114, 17,117,216,247,149,174, 99,171,195,147,252, 35,181,171,244, 20,198,115,152,128,219, -235,171,211, 88, 13, 56, 84, 8, 9, 81, 4,144, 64, 7, 88,123, 74, 75,159, 19, 69, 14,164, 21, 0,180, 45, 46, 36, 20,146, 20, - 9,109, 68, 2, 15,124,246,212,249, 51,218,185, 55,142,181, 92,123,132,103,248, 46, 42, 15,110,150,246, 51, 0,111,208,133,191, -238,181,241, 56, 81,244,203,137,239,236,225,192, 29,201,226,255, 0,215,254,171,186,248,126,153,120, 29, 15,179,135,175,203,139, -254,159,143,242, 93,212, 32, 71,158, 48, 9,235,223,204,253,191,118,188,167, 39,161,193,199, 83,242, 36,159,221,165,127, 75,230, - 63,243, 31,228, 79,233,193,189,170,162,223,222,111,255, 0, 72,252,177, 56, 1,244,203,201, 56, 30,206, 14,191,250, 95,255, 0, -186,238,190, 43,233,152, 4,128,127,185,195,159, 80, 56,191,234, 62,223,241, 93,212, 32,142,124,128,239,248,116,243,251,245,224, - 2, 84,115,211, 3,186,122,117, 63,111,200,157, 15,210,249,143,252,199,249, 19,250,113,159,106,159,254, 39,224, 63, 44, 78, 11, -251,242,241,128,127,185,197,247,127, 43,254,191,183,133,221, 47,239,203,198, 79,253,206, 35,129,231,252,175,186,125,255, 0,226, -187,211, 80,130, 66, 58,149, 12,115,116, 4,159, 63,159,111,206, 53,240,167,226,206, 58,142,135, 29,189, 58,232,126,151,204,127, -230, 63,200,159,211,129,237,117, 31,183,248, 47,229,137,190, 15,166, 96, 9, 35,251,156, 36, 99,204,241,125,223,236,255, 0, 21, -237,123, 31, 76,184, 28,127,220,226,239,156,127,141,247,167,127,249, 47,106, 16, 24,207,151,108,247,244,199, 92,126,124,181,244, -117,192,232, 61, 63,183,166,135,233,124,199,254, 99,252,145,255, 0, 78, 49,237, 85, 23, 31, 89,248, 47,229,137,191,143,166, 88, - 79,250, 56,122,245,233,252,175,255, 0,163,252, 87,122,235,233,250,101,100,119,246,112,227, 63,243,191,235,248,127, 37,221, 66, - 19, 3,190, 50, 71, 94,159,213,159,150,190,247, 32,249,119,193, 25,253,190, 93,244, 63, 75,230, 63,243, 31,228,143,250,112, 61, -170,163,254, 39,224,191,150, 38,238,126,153,113, 31,232,224, 56,245,254, 87,248,253,159,201,119,166,169, 43,233,153, 17,254,141, -252,140,227, 63,203, 3, 30, 93,255, 0,205,115, 80,137, 32,156,156, 0, 51,142,224,117,245, 61,123,245,213, 5, 32, 17,128, 51, -158,253,127, 63,145,172,254,151,204, 44,127,180,111,255, 0, 68,127,211,140,251, 84,255, 0,183,248, 15,203, 19,121, 63, 76,212, -130,113,236,221, 39, 7, 31,231,129,248,255, 0,201,111, 95, 15,211, 55, 35,183,179,120, 30,153,255, 0, 60, 47,217,254,107,125, -245, 7,245,128, 51,129,133,119,198, 14, 62,255, 0, 77, 10,172,140,244, 29,122,244,245, 31,111,111,237,209,151, 54,175,239, 83, -123,255, 0,129, 63,167, 25,246,169,251,191,224, 63, 44, 78, 33, 95, 76,228,167,253, 27,185, 30,191,203, 11,253,214,245, 72,253, - 51,220, 28,127,115,115, 63,245,194,255, 0,117,175, 77, 65,216,247,233,128,113,149, 30,227, 30,127,111,150,188, 16,112,114, 0, -207, 92, 14,248,249,244,232, 59,232,227, 53,175, 32, 30,127, 95,240,167,244,224,235, 81, 49, 23, 50,126, 3,242,196,226, 85,244, -208, 57,127,209,181,145,235,252,176,255, 0,221,103, 84,207,211, 67, 35,253, 27, 63,135, 24,191,238,177,168, 57, 45, 35, 56,193, -193, 29,252,191, 31, 95,234,208,235, 73, 57,230, 30,125,255, 0,163, 74, 46,103, 90,127,223,127,149, 63,167, 0,212,205,183,155, -175,184,126, 88,156,137,250,105, 24,200,254,230,199,108, 99,252,113,123,255, 0,217, 99, 84,213,244,210,249,127,209,175,159,250, -227,126,239,228,175,168, 52, 41, 61, 72, 62, 89,255, 0,142,168, 41, 56, 62,164,103, 31,126, 58,232,227, 50,173,255, 0,141,127, -251, 83,250,113,145, 81, 41,232,255, 0,128,252,177, 57,179,244,211,113,219,217,173,147,233,252,177,255, 0,221, 95, 94, 15,211, - 80,198,127,238,106,246,242,254, 88,253,127,254,213,181, 6, 5,142,164,147,229,220,116,200,251, 71, 97,211, 84,150, 6, 51,159, -179,211,246,104,227, 48,172,218,243, 94,253,244,175,244,227, 62,209, 55,237,254, 3,242,196,231,207,211, 85, 32,103,251,154,121, -199,252,242,113,255, 0,229, 87, 84,149,244,214, 72,255, 0, 70,150, 71,254,153, 61,191,236,169,168, 45,169, 56,237,219,247,143, - 95,191, 67, 44,117, 35, 3,175, 92,104,195, 48,171,190,242,237,255, 0, 74,254, 88, 56,158, 75,253,187,253,195,221,238,196,233, -215,244,215,249, 15,254, 13, 12,143, 95,229,149,251,191,146,159,174,168, 31,166,202, 57,185, 71,179, 56,159, 60,255, 0, 44,190, -159,179,133, 62,250,130,147,205,243,116, 35,207,203,167,159, 76,103,203,250,244, 42,153, 60,221,200, 3,183,150, 62,206,158,154, - 88, 86,212,216,125,109,255, 0,237, 95,203, 6,231, 73,183,159,240, 24,157,183,247,236,196,140,143,102,104,199,110,188,102,224, -231,211, 31,201, 71, 94, 15,211,105,229,239,236,204,199,253,115,191,221, 71, 80, 71, 82, 0,206, 51,208,227,167, 94,222,154, 25, -105, 72, 7, 35,174,124,242,122,252,243,246,104,235, 89, 57, 27,203,191,192,126, 88,199, 58, 77,183,189,253,195, 19,188,254,253, -183,254,140,191,251,103,127,186,134,150,160,120, 80, 60,142, 63,111,239,210,209,253,170,163,254, 39,224,191,150, 13,205,147,246, -191, 1,249, 99,234, 65, 0, 3,249,235,162,146, 15, 64,123,244, 31,156,106,138, 70, 79,203,207,243,246,232,132, 12,159,179,175, -223,157,105, 22,185,191, 75,116,194,120,174, 1, 61,189,113,249,249,106,176, 0, 96,121,121,254,253, 83, 70,122,244,200, 36, 12, -231,183,231, 58,174,144, 14,115,158,131, 61, 52, 76, 12,123, 74, 74, 73,234, 49,249,252, 52, 66, 7, 76,250,254,204,106,130, 50, - 71, 92,224,158,153,235,223,231,231,253,154, 41,180,246, 7,203,169,252,253,186, 65,141,205,241,131,176,191,166, 43,163, 29,135, -197,143, 79,159,217,162,144,140,142,131, 3,207,237,253,231, 84, 17,208,244, 3,175,125, 20,140,253,223,191, 68, 98, 69,192,194, - 36, 91,248,227,210, 7, 98, 79, 83,230,122,244,253,253,180, 72,193, 3,207,211,167,159,110,218,164,145,147,246,117,209, 9,237, -140,128, 1,200,251, 71,223,219, 73, 49,185,233,108, 99, 21, 18, 0,193,193,235,223, 61,241,233,162, 83,140, 14,157, 60,134,124, -191,118,168,164,115, 31,219,247,116,237,162, 80,158,163,167, 65,235,162,147, 97,115,219, 4,244, 23,177,255, 0,199,207,250, 98, -170, 64,242, 3,229,162, 82, 9,192,249,119,249,252,245,118,183, 45,171,130,238,172, 83,173,203, 86,135, 85,184,238, 26,180,164, -196,164, 80,104, 52,233,117,122,213, 90, 99,129,106, 68, 58,109, 46,158,203,143,206,146,164,161,100, 33,180, 40,242,182,165, 16, - 2, 73,213,222,187, 99, 94,182,156,151, 98, 93, 54,117,215,108, 74, 96,148, 63, 30,227,182,235,180, 39, 90, 90, 78, 20, 28, 77, - 82,158,215, 41,230, 7, 90,109, 60, 43, 32,137,165, 81, 43, 11,133, 36,106,181,237,123,117,183,107,224,250, 36,229,180,162, 54, - 49, 41,179, 56, 83,164, 27, 94,197,173,164, 27, 88,218,247,182,248,198, 80,144,123,128, 8,207, 65,220,156,249,122,157, 86, 70, - 62, 33,143,179,215,239,252, 63,110,188, 32, 18, 50,217, 14, 1,220,161, 73,115,211,185, 65, 56,237,162, 27, 73, 86, 58,128,125, - 7,127, 95, 61,101,136,223,126,191,127,195, 26,250,131, 11,131,127,120,239,138,168, 73, 56,233,212, 12, 30,190, 64,234,179,125, - 79,108,128, 65, 3,191,221,251, 53,245, 40,236, 58,103,190,122,253,191,187, 85,144,140, 43,169, 3,207,228,114, 15, 95,217,164, -240, 49, 84, 39, 42,193,232, 59,129,129,148,140,118,207,225,175, 74,108,245, 4,242,143, 47, 81,233,175,160,149,103, 24, 10,245, - 30, 99,243,231,175, 67,174, 2,178, 51,230, 48,123,121,159,195,246,235, 24,199,195,174, 40,165, 56,206, 85,212,156,142,157,254, -204,246,215,148,164, 2, 50,163,223,238,235,242,243, 58,172,224,201, 29,122,122,142,157, 51,140,159,151, 93, 92,168,148, 58,189, -195, 84,167, 81, 40,116,202,141,102,177, 88,152,213, 58,145, 73,165, 65,153, 85,171, 85,170, 18, 20, 16,196, 10, 77, 42, 3, 46, - 72,169,206, 90,136, 8,101,134,214,226,179,209, 58,195, 50,162,150,118, 10,171,185, 39, 96, 48, 91,133, 2,231, 97,181,254, 54, -183,239,197,153, 93,240, 57, 64, 30,106, 3,174, 51,128, 61, 53,233, 88, 67, 69,215, 84, 27,101, 56,241, 29, 89, 8,105, 40,238, -165, 21,172,129,140,103, 82, 39,224,247,232,242,113, 5,186, 44,209,175,126, 45,110,120,252, 41,109,245, 65, 45, 76, 98,212,168, -192,137,115,111,205,126, 34,210,167, 80,219, 22, 95,189, 38, 13,132,167, 80,143,133, 85,151,221,152, 18,178, 69, 47,152, 99, 82, - 25,217,126, 4,125,158,220, 32, 70,111,248,177,225,226,214,187,174,202, 84,112,204,221,208,222,132,198,220,171,212,205,121,104, - 12, 72,241,238, 54,151, 77,163,211,164, 45, 56,103,220,169,241,154,109, 74,229, 79, 82, 64,134,103, 28,115,148,101,101,145, 24, -213,204,187, 89, 14,215,247,144, 9,248, 27, 91,212,226,216,224,191, 5,184,251,142, 12,111,150,229, 38,134,142, 80, 8,158,164, - 20, 4, 18, 0,100,140,217,216, 94,195,204, 99,185,176, 23, 36, 3,170,254,203, 46, 26, 46, 77,165,224, 39,102,233,180,203, 98, -123, 55, 94,240,135,247,210,247,144,229, 50, 82, 28,149, 42,249, 17,191,130, 80, 39,169,184,229, 79,197,133, 96,194,183,154,100, -100, 99,197,117, 73, 37, 43, 81, 86,234, 87,236,203,238,132,204, 33, 46,221,170, 32,138,139, 45, 45,243, 6, 98, 99, 20,165,137, -143,123,195,179, 60, 34, 27, 65,240,249, 15, 57, 79, 42,214, 17,130, 72, 35, 99,155,223, 42,234,221,136,202,101,194,143, 66,171, -184,105,112,211, 76, 5,132,211,101,181, 28,123,180,100, 71, 82, 83,238,168, 82, 80,227, 9, 67, 73, 8, 14, 54,132, 97,180, 20, -130, 37, 39,125, 42,234,171,170,153, 34,124,151,131,206,170, 19, 32, 54, 57,101,207,141,200,137,172, 48, 57,190, 37, 8,222, 27, -165, 60,170, 39, 42, 9, 10,109, 42, 35,158,243, 89,104,243,106,250,186,249, 38,156,203, 86,236,231,104,202,139,157,149, 87, 85, -236, 1, 10,190,110,130,198,230,248,244,231,129,168,248,183,129,184,107, 38,225,202, 14, 30,163,155, 47,200,105, 99, 77, 38, 89, -121,146,114,215, 68,146, 59, 8,236,178, 22, 87,121, 1, 82, 69,181, 95, 73, 7, 26, 81, 90,169, 61, 79,168,208,167,204, 91, 44, -184,170,148,168, 83, 66, 11,141, 70,124, 78,167, 84, 35, 51, 29,198, 66,130, 11, 8,121,168,165, 36,146,181, 41, 14, 44, 21, 40, -224, 88,100, 92,178, 84,252, 41, 12, 58,134,169,236,223, 20, 56, 17, 31, 91,158, 31,213,209,106, 45, 85,162,212, 38, 53,239, 67, -159,220,194,222,100,171, 9, 37, 41,111, 45,133, 37,120,214,238,238, 21,145,110,110,237, 53,104,141, 18,147, 65,187,160,213,226, - 84,226, 75, 44, 52,154, 77, 70,163,111,200,247,152,240,235,208,227,114,167,192,113, 14, 20, 25, 44,164, 59, 28,191,226, 56,135, -145,206,141,115, 74,240, 69, 70,139, 58,226, 93, 94,157, 42,151, 38,217,171,209,163,191, 18, 75, 72, 91,241,167,211,107,148, 86, -235, 13,120,141,225, 15,143,117,147,200,218,176,158,118,242,164,158, 78,241, 42,202,121,105,230, 69, 46, 37,138, 83,229, 96, 54, - 39, 96, 53, 11, 27, 48,191,217, 61,150,247, 32, 99,163,184, 11, 53,202,248,178,154, 72,228,131,244,126,105, 66,170,147,211, 72, -202,218, 17,229, 26, 94, 18, 8, 15, 27, 23,116, 14,187, 34, 6, 89, 17, 67,170, 54,206, 82,238,185,177,160,198, 76,229,153, 13, -208,110, 74, 4,198,235, 44, 56,149,128, 69,106, 35, 41,155, 33, 8,201, 46, 37,233,173,153, 1,226, 91, 60,203, 41, 39,176,223, -221,171,219,215,238, 40,178, 42,213,233, 10,163,209,233,181, 8,142, 38,114, 84,251,110,185, 54, 35,209, 31, 13,197, 91,138, 79, -143,206,150,212, 57,242,124, 38,229, 16, 84, 73,240,213,204, 75, 50,143, 87,173, 84,164, 89, 20,181,168, 46,225,151, 26,159, 71, -109, 65, 14,184,229,111,223,226,166, 53, 41,224,179,148, 64,114, 79,132, 90,113, 73,200,104,184,146,174,118,146, 79,101,175,201, -205,219,204,155,102,128,180, 26,125, 18, 28,150, 98,195,105, 10, 14, 85, 92,139, 49, 44, 74,113, 69,160, 66,149, 34, 98, 36, 58, - 20, 83,202,178,235,104, 56, 3, 26,125,225,170,120,167,231,215, 85,141,112,211,105, 68, 66,108, 25,200, 98, 1, 35,204, 2,129, -118, 32,139,221, 73,211,171, 88,164, 60,112,168,124,170,167, 38,200,178,103, 72, 51, 44,237,231,149,166, 81,253,213, 50, 10, 79, -172, 10, 67, 42,201, 44,175, 42,128,126,168, 90, 67,176, 82, 27, 44,157,124, 91, 86,163,172,210, 40,209, 33, 66,112,182,149, 48, -228,143, 4,186,243,202,144,134,136, 71, 50, 71, 59,195,196, 43,253, 81,128,121,143, 54, 9,213, 9,123,191, 49,153,245, 55, 35, -206,109,168,116,233,113, 41,236,173,165,115,203,126,108,150, 24,126, 66, 34,165,149,164, 32, 41,215,163,182,233, 78, 22,166,155, - 90,143, 48,108,145,165, 85, 75,154, 37, 70,161, 46,164,219,243,155,165,183, 95,162, 83, 41,204,184,183, 31,120, 38, 3,190, 45, -101,232,203,231, 40, 76,115, 83, 50,127, 74, 20,164,143,112, 40,242, 9, 31, 98, 92, 79, 79,129, 78,140,203, 11,121,138,245, 72, -215,101,185, 49,196, 39,158, 19, 18, 21, 36,165,158, 84,115,163,196,105,234,116,116, 44,252, 60,143,172,114,249,234,105,237,243, -234, 88,226,151,149, 96, 84, 34, 93, 22,215, 29,128, 4, 3,181,141,183,216,168,177,185,166,163,240,166,136, 67, 12,245,145, 53, - 84,238, 0,153,166,177, 96,204, 18, 87, 55,144,155,186, 70,146, 43, 45,216,107,212, 1, 59, 91,122,169, 91,167, 70,186,227,184, -197,203, 10,131, 87,163,189, 10, 69, 85,214,171,148, 90, 69,113,166, 35, 70, 56,136,137, 81,234,204,184,151,100,173,214,164,200, -104, 6,254, 24,254, 26,193, 30, 33,214,177,238,127, 2, 62,206, 30, 34,208,151,119,167,131, 14, 31,170, 51,171, 76, 70,150,170, -189, 2,208,133,100, 93, 16,152,156,135, 92, 15,166,232,176, 13, 54, 74,101,165,135, 57,220, 33, 69, 97,249, 39,169,192, 0, 26, - 93,210, 95,153, 46,142,195, 48,212,207,240,138, 76,170,188,247,144, 86,212,166, 41,209, 88, 17,109,147,200,217,240, 91,113,230, - 10, 86,128,162,166, 98,165, 96, 97,201, 9, 78,178,250, 69, 65,249,177,152,150,228,245, 53, 78,141,239,234,159, 40,211,220,125, -234,189,102,123,128,204,166,210,121, 79, 70,152, 89, 40,114, 90,121,185, 11, 65,166,199,232,221,121,189,200,179, 42,152, 93, 92, - 75,230,181,135,235, 18,204, 69,152,107,221, 75, 2, 72,234, 69,174, 46, 14, 32, 60, 65,225, 38, 67, 80,102,246,156,185, 96,142, - 64,186, 65, 26,216, 43, 6, 40, 6,149,221,157,212, 46,150, 93, 69, 68,110,116,131, 41,199, 40, 55,231,232,175,112, 39,186, 52, -233,149,158, 27,247,143,120, 56,116,174,173,153, 18, 34,210,174, 57,144,247,130,194,102, 74,185,149, 26, 52,200, 23, 10,162, 86, - 96,176, 86,182,130,146,213, 93,197,161,183, 1, 8, 39,149, 38, 53, 60,110,123, 1,189,162, 92, 20, 64,171,222, 82,246,226, 47, - 16,123, 65, 75, 15, 72,127,116,120,126, 77, 82,239, 20,202,115, 40, 46,174,117,219,183,111, 65, 69,126,215, 97, 8,232,243,169, -139, 58, 27, 74, 74,185,166,114,142, 99,250, 18,209, 46,181,183,224, 68,113,102, 52,106,107,177, 37,200, 76, 89,105,113,113,218, - 56,118, 12, 55,101, 50, 10,230, 23, 86, 85, 37,215,208, 22,167,192, 67, 77,169, 69,206,125,108,205,177,123,137, 81,132,228, 77, -240,230, 79,154,105,244,170, 68,172, 70,170, 45, 44,243, 23,229,205,128,165,133,198, 42, 67,110, 60,176,176,144,220, 86,155, 75, -156,175,184, 82, 37,249,111, 22, 85, 64,218, 42, 36, 46,150,235,171, 86,247,176,186,185, 5,172, 47,228,140,198, 46, 44, 72,234, -121,147,139, 60, 39, 92,176,153,168,117, 68,140,198,218, 71,144, 3, 98,138, 64,212,159,103, 84,140,214, 0, 32, 12, 28,131,124, -126, 50,105,198, 21,146, 20, 2,150,143,132,228, 7, 26, 81,109,214,212, 65,248, 92, 74,194,146,164,156, 20,169, 37, 42, 0,131, -165,219,161,234, 58, 18, 58,228,124,254, 71, 95,166,111,180,163,216, 17,194, 7, 31,240,238, 45,193,218,248,212,110, 26,248,173, -144,137, 82,206,229, 89, 52, 54, 25,176,183, 2,186,219, 40,113, 49,183,135,111,169, 74,106, 53, 73,215,223,228, 75,245,122,111, -187,214,152, 50, 20,235,206, 84, 2, 61,217,127,158,255, 0, 24,156, 20,241, 33,192,134,239,206,217, 30, 38, 54,238,125,139,118, -182,211,245, 43,118,166,211,159, 90,217,123,137,109, 53, 37,113,155,187,182,234,235,101,180,177,115, 80,148,226, 64,116, 0,220, -200, 46,171,221,234, 49, 34, 72, 30, 25,177,178,252,214,159, 48,137, 36,141,135,159,161, 6,234, 78,231, 77,251, 48, 0,221, 90, -199,202,197,117, 32,214,105,170,234, 26,172,186, 65, 29, 84,101, 65, 54, 87,177, 10,215, 32, 13,141,138,150,236, 14,199,245, 75, -111,141, 87,232, 7, 78,223, 46,186,240,164,147,156, 28, 3,215, 4,145,249,235,175, 68,129,142,189, 7, 76, 99,191,151,125, 32, - 65, 39, 61, 71, 76, 36,140,103,167,252,116,233,141, 78,248,166, 18, 9,199, 92,122,143, 95,234,239,175,161, 36,250,244,200, 30, - 93,115,158,191,142,170,121,127,171,248,116,215,196,144, 1,202,147,156,231,167, 92,228,232, 96,111,143,129, 56, 33, 89,201, 25, -230,243,242,215,164,117, 4,143,135, 25, 61,115,251, 63, 29,125,233,140,254,206,216,252,245,215,209,215,246, 12, 1,220,121,253, -253, 52, 48, 58,123,176,136,207, 68,245,233,231,142,164,103,246,106,130,219,198, 9,242, 61, 70,124,244, 78, 14, 58,140,121, 2, - 70, 49,246,252,191,175, 84,207,110,131, 39,246,103, 63,212,127,167, 88, 6,255, 0, 17,140,224, 37,160,224,249,103,215,184,207, -168,252,247,208,170, 64, 0,231, 36, 18,123,250,252,190, 90,184, 57,205,158,184, 61, 58,231,190,125, 58,121,245,208,238, 32,242, -231, 4,117,232, 58,231,175,203,236,214, 65,232,122, 99, 32,158,221, 78, 45,197, 1, 39, 32,245, 29, 49,158,152,199,174,188, 20, -231, 36, 28,121, 28,159,179,207,240,209, 42, 73,234, 20, 7, 79,245,123,146,126,126, 67,174,168,242, 12, 40,100, 99,166, 0,243, -235,158,231, 75,169,184,235,131,168, 34,219,109,243,243,111,195, 3, 40, 3,212,147,129,248,125,186,160, 70, 70, 63, 35, 70, 41, - 35, 56, 30,153, 63, 44, 13, 12,180,144, 73, 3,167,246,126,206,186, 81, 79,108, 24,216,116, 23,254, 71, 0,184, 0, 32,116,206, -122,159,217,215, 31,158,154,162,160, 78, 58,100,103,175,175,221,163, 20,147,230, 7,221,216,158,250, 25, 89,201,230, 56, 39,183, -207,211, 31,119,244,105, 92, 1,208, 95,113,129, 22,128,114, 64,199,200,249,250,140,104,117, 35,166, 6, 1,239,246,103,200,244, -209,138,206, 65, 56,207,160,242,208,199,169,200,207, 95, 92, 14,221, 63,118,149, 7,160, 39,167,207, 95,158,248, 54, 5, 87, 76, -228,103, 25,253,159,187, 66,172,116,206, 15, 78,216,253,164,244,237,211, 70,172,100,142,152,235,220, 30,253,124,255, 0, 62,122, - 25,196,228,156,100, 1,208,227,182, 79,228,104,248, 50,250, 91,127, 92, 91,215,128,112, 14, 73, 39,167,161, 29,123,232,115,223, -168,235,158,191,184,104,199, 19,144, 83,211, 62,126,189, 61, 63, 13, 12, 80, 70, 78,114,125, 15,225,223, 58, 89,122, 97, 81,107, - 3,210,216, 29,105,243, 25,206,133, 90, 72, 39,183,153,251, 62,223,150,116,105, 25,251,186,250,103,228,126, 90, 25,105,206, 73, -200, 62,126,125, 59,253,250, 85, 79, 91,157,176, 69,216,144,119,183,250, 96, 34, 48,113,165,175,107, 73, 39, 35,175,224, 52,180, -174, 15,113,220,216,227,234, 49,143,233,209, 40, 24, 3,231,215,243,247,106,128,198, 6, 1, 31, 35,223, 85,211,204, 59,128, 49, -233,223, 61, 58,233, 18,118, 3,231,221,140,226,178, 60,250,253,223,191, 85,209,220,253,157,189,127, 63,191, 84, 81,143, 33,215, -204,234,178, 6,122,231,177,237,249,242,254,173, 16,157,137,190, 6, 8, 78,112,112, 70, 7,124,143,196,244,243,233,162, 27,234, -126,239,234,213, 4,125,189,188,191,126,189, 18, 64, 86, 14, 8, 30,125, 1,207,244,255, 0,102,181,216,133,193, 78,224,142,199, - 7, 54,115,211, 61, 62,206,158,126, 99, 69,164, 14,128, 16,123, 15,151,236,213,189,146,233, 74, 78, 19,142,153,251,112, 63,171, - 71, 55,223,162,122,140, 28,224,246,249,233, 34,215,194, 71,174, 43,165, 61, 65, 57,232,123, 99,191,167,237,209, 9, 0,142,169, -249,103, 39,175,175,217,170, 64, 18, 71,145,233,231,230,123,231,229,170,232,200, 36,116, 29,135,203,168,243, 62,103,182,176, 73, - 61,123, 96,167, 21,209,156, 1,208, 14,195,241,243,249,104,148, 3,216,156,228,224,103,250,117, 65,160, 72, 29, 58, 3,231,163, - 16, 58,231,175,203,211,211, 73,191,175,207,108, 99,107,145,181,206, 58,159,236,114,180, 36,215,120,223,178,238,166, 92,121,134, - 54,178,207,191,175,249, 50,154, 42, 65,101,248,212, 39,104, 52,196,151, 17,213,181, 46,101, 96,132,144, 65,248, 62,103, 82,170, -147,119, 79,171, 52, 99,214, 12, 27,130, 56,200, 92, 43,154,147, 73,175,197,113, 32,149, 96,181, 85,136,238, 83,215,166,114, 61, -117, 30,111, 98, 93, 13, 12,206,226,110,249, 80, 74, 93,129,102,217,118,147, 11, 61, 22,147, 89,172,205,170, 73, 66, 84, 58,128, -180, 66,104, 17,242,215,110, 85, 89, 62, 34, 74, 78, 18,162, 18,178, 78, 2, 72, 24,243,252, 53,207,158, 33,214, 52,188, 67, 60, - 91,218,146, 56,163, 6,254,160, 73,191,190,242, 16, 55,233,143, 67,190,140,252, 57, 24,240,222, 10,185, 97, 89, 6,113, 87, 87, - 57, 12, 1, 4, 44,130,152, 2, 8,181,138,211,143,223,140, 91,113,184, 80,224,223,122, 90,127,248,197,225,195,111,141, 78, 74, - 74, 28,185,236, 6,100,109,189,210,202,149,255, 0,194, 25,155,109, 45,182, 30,116, 14,184,114, 58,193, 35, 36, 29,114,235,126, - 61,136,232,153, 30,101,195,194, 78,234, 11,142, 74, 18,167, 81,180, 59,192,184, 84, 27,145,224,126, 38,225,219, 27,129, 13, 41, -129, 85,124,254,171,109, 79,106, 42,220, 56, 5,240, 78, 79, 93,141,126, 51,110,161,151, 93, 72, 82,213,250, 21,147,128,162,159, -242,172,156,116, 75,192, 96,143,245,128,214,109,101, 34,179,125, 87, 98,219,150,188, 73,117, 58,171,235, 8, 75,113, 88,113,228, -190,130,160,148, 6,130, 7,194,176,163,212,158,137, 41,207,108,226, 37, 67,197, 89,254, 85, 44,107, 65, 92,242,128,109,202,127, -172,140,251,130, 53,244,131,234,154, 77,174, 21,133,241,105,113, 79,128,254, 26,113,109, 13, 76,249,182, 65, 22, 83, 80, 16,177, -174,164, 11, 73, 52,123,127,120,210, 70,162, 57,108,123, 78,146,165,250,169,223, 16,133,191,246,226,251,218,171,186,173, 97,110, - 77,165,112,216,183,165, 5,229, 49, 86,182,110,106,115,212,202,172, 69, 5, 40, 7, 80,219,163,150,100, 37,129,150,164, 48,167, - 88,117, 63, 19,110, 40, 29, 97,233,193,243, 24, 29,250,143,184,116,215,232,143,190, 62,204, 45,147,226, 95,110, 34,219, 28, 90, - 85,225, 64,173,211, 34, 4,217, 87, 45, 7,192,123,116,108, 57, 14, 35,197, 13,193,172,182,131,239, 52,194,172,248,180,249,101, -232,171,201,194, 80,172, 40,106, 85,157,236, 48,246, 94, 89, 49, 96, 11,150,111, 16, 59,185, 80, 43, 83, 18, 93,168,222, 84,251, - 54,159, 41,214,155,241, 92, 81,129, 64,166,133,196, 36,117, 74, 67,170,207,108,116,206,173,202, 63, 17, 40,214,142, 55,205,233, - 13, 21,112,217,227, 87,141,135,185,128, 46, 29, 67,117,210,202, 74,244,212,246,213,142, 20,207,126,143,124, 95, 14,119, 61, 31, - 6,200, 56,195, 36, 55,104,107, 68,114, 83, 2, 59,199, 46,168,204, 70, 69,177,250,200,100,120,157,124,223, 84, 73,137, 96,225, -130, 70,121, 22, 8,237,202,133, 96,250, 28,227, 72,168, 32, 0, 58,146,113,140, 31, 63,151,222, 53, 61,230,125,146,190,201, 76, - 62,208,225,254,252, 87,128,217,112,248,251,193,118,173,197, 4, 39,152,242,173, 11, 29,115,211, 32,117,193,211, 69,186, 94,193, -159,103, 5,247, 75, 55, 6,222,220,187,247,177,170,142,168,178, 84,212, 27,150,141,124,210, 39, 70, 74,144,228,182,226,199,187, -233,222, 60, 23, 11, 1,196, 7, 82,242,195,107,113, 42,240,151,142, 83,177, 77,226, 46, 75, 83, 47, 41, 81,193,177, 55,242,216, - 0, 46, 73,185, 22,183,223,238,190, 25,235,190,143,254, 42,229,177,123, 69, 87, 14,170,171, 21, 80, 22,161, 11, 51, 57, 1, 84, - 2,160, 93,137, 3,114, 63,142, 35, 1,192, 79,179,155,127,248,252,190,165,208,246,210,151, 26,220,219,219, 90, 68, 49,185,187, -209,119,179, 45,157,189,219,184,210,112,227,112,228, 57, 29, 33,219,162,244,145, 27,153, 80, 40, 80, 57,165, 61,128,236,151, 33, -196, 10,146, 38,173,194, 71, 5, 92, 32,251, 61,109,198,127,137, 11, 71,248,111,187,134, 47,186, 92,156, 68, 95,208,233,213, 77, -203,169,188,166,210,220,230, 45,176,210, 20,198,221, 91, 60,222, 42,147, 78,163,161, 14,132, 16,169, 50,102, 40, 41,100,251, 2, - 70,221,108,222,222,208,118, 35,135,219, 98,141,182,187, 99,183, 80,221, 22,253,169, 5,240, 28,175,120,202,109,117, 43,158,224, -172,168, 42, 69,193,113,212,166, 35,154,109, 86, 73,117,239,122, 88, 75,220,172, 22,219, 70, 15, 39,112, 35,202,153, 34,108, 9, - 83, 16,228,242,167, 30,167,205, 67,209,101, 60,247, 40, 75,203,132,133,184, 16,103,115, 6,213,204,193,117,183,249,130, 73, 35, - 5, 53, 87, 20,120,131, 91,154, 84, 73, 73, 68,198,158,137, 73, 10, 65,221,198,214,239,181,250,134,185,234, 8, 61,113,217, 30, - 12,253, 20, 41, 50,184,169,243,158, 45,133,115, 76,244, 44,114,114,236, 90, 10,109,118,101, 69, 7,109, 69,110, 68,166,247, 32, -244, 91, 5,122, 46, 93,207,151,112,185, 82, 84,201,237, 85,196,152,174,184, 88,241, 23,239,197, 8,146,129,239,112,210,195,217, -143, 82, 97,220,134,151,240, 7,148,160,230, 82, 64, 42,108, 46, 11,170, 52,200,142, 42,108,229, 75,154, 25, 10,128,251,176,220, - 69, 62,231,164,248,160, 73,129, 34, 43, 32,148, 79,109,191, 21,101,149, 97,198,164, 54, 36, 52,149, 5,184, 19, 97,136,251,117, -212, 9,207, 47,222, 75, 83,204, 70,166,198,109, 84,203,178,149, 49, 96, 25, 28,237,178,132,166, 28, 66,181,167, 45,188,144, 84, -217, 47, 45,181,163,161,199,231,178,168,238, 61, 67,174,165, 50, 30, 68,210,138,101, 69, 41, 66,226,214, 24,154,175, 18, 68, 23, - 25,200, 16, 43,237, 53,206, 89, 40, 41,101,229, 18,227, 11, 67,153,107, 85,228,149, 94,103,214, 88,177,181,218,251, 49,190,198, -219, 19,126,194,199,107,117, 59, 14,220,202, 56,115, 41,161,100,166,134, 46, 65,164,220,199, 24, 80,202, 6,149, 99, 29,208, 93, - 86,200,179, 38,148,109, 12,205,160, 36,107, 36, 87,151,170,161,165, 46,223,113,167,151, 78,170, 42, 43,148,218,139,143,133, 60, -212,244, 50,100,136,203,150,242,135,136,250, 60, 22,164,198,112,144,183, 19, 29, 76, 58,165, 45, 0,185,112,131, 94,118, 83,239, - 68, 41,110,145, 84,110, 85, 61, 77, 75,109,178, 94,166,215,169,104, 8, 67,209,226,188, 8,118, 28,136,175, 69,146,129,147,227, -180,167,144,130,160, 73, 24,237, 74,148, 41,180,184,241,225,200,118,224,181,231, 71,136, 98, 84,161,159, 30,183,110, 75,101,207, -122,101,135, 67,139, 34,171, 78, 67,173,161, 72,116, 98, 92, 85,128,204,132, 60,193,241, 18, 44,199,101, 84, 85,252, 43,112,177, - 42, 84, 4, 52, 95, 52,245, 4,179, 84,167,160, 46, 60,163,202, 84, 82,137,173,158,119, 35, 43, 36, 50,180, 41,160, 2, 22, 0, - 48,114,196,178,177, 80, 55,211,178,238, 64,223,114,118,234, 70,226,196,234,190,160,112,250, 40,232,234, 98, 13, 29,180, 72, 74, -135, 58,129, 51,142, 88, 77,113,191,149, 76,133, 66, 76,142, 54, 49,137, 46,240,201,115,180,187,121,113,159,112,167, 74,168,126, -134,164, 39, 75, 21,246,192, 76,150, 24,152,101, 59, 6,160, 22,251,164, 23, 22, 86, 34,169, 37, 64, 41, 77,186,215,114,156,150, - 43,139, 43, 97,169, 85,218,101,105,162, 25, 69,219,106, 92, 52,234,159, 51,106,114, 59,213,187, 98, 11,114, 96,186,162,129,133, - 58,105, 47, 71, 91,228,165, 74,112,210, 83,241, 18,146, 11,135,106,214, 98, 78,172, 73,102, 43,177,164, 67,184,105,116,249, 76, -184,164, 4, 42, 59,240, 23,245, 98,155,113,151,208, 49, 37,216,174, 66, 88, 82,250, 45,200,200,202,137, 72, 26,161,196, 82,249, - 44,237,191,114,123, 77,202,228,191, 13, 50,108,176,183, 27, 75,109,213, 41, 83,161, 73, 7, 42, 42, 37,230,219,111,224, 71, 41, - 82,129, 72, 56, 26, 82,178,211, 80,176, 96,117, 33, 87, 27,130, 65, 15,123,139,250, 43, 17,247,133,176, 59,154,251, 35,230,229, - 30, 34,101,181, 84,209,154,121,115, 5,168,137,162, 38,222, 89,169,228,145, 35,177, 23,211, 13, 74, 42,128,222, 98,209, 33, 93, -247, 45,207, 13,114,155,103,122, 54,250,161, 33,214, 94,250,215,234,202,139,111,115, 54,235, 9,117,115, 33, 84, 25,247,117,161, - 36,186, 75,171,142,226, 92, 32,132,169, 8,234, 2,250,244,178,232,151, 46, 85, 85, 97, 46,180,218,152,141, 41,185, 10, 82,146, -133, 56, 87, 49,135, 28, 75,206, 54,128, 82,149,182,149,114,148,252, 73, 40, 42, 25, 63,173,202,173,165,149,245, 27, 59,105, 37, -133,198,106, 75, 46,199, 11,153,201,226, 56,179, 68,204,101, 51,206,133, 4,148,184,138,122, 64,229,229,233,145,221, 56, 61, 81, -185, 75, 51, 27,159, 80,109, 41,125,186,148, 24,239, 53, 37,180,135, 92,106, 52,136,171,113, 78,165, 68,140, 37, 16,223, 89, 4, -156,167,195, 25, 30,171,240,236,165,105,234,169,128, 26,161,150,226,251, 18, 25,116,220,216,131,250,167,125,192, 39,222,113, 12, -241,161, 4,252, 89,144,102,166, 63, 45, 69, 19,211,173,192, 32, 52, 53, 5, 73,183,217, 0,172,167, 96,196,253, 93,251,227, 89, -170,116,137,115, 41,150,180, 88,239, 52,228,155,128,190,219,171,105, 45,132, 20, 84,125,242,101,110, 97,109,192, 60, 15, 6, 4, -169, 41, 7,205,101, 42, 4, 30,100,235, 48, 98,100,183,170,109, 55, 77,129, 26, 53, 90, 77, 38,159, 64,165, 69,109,165, 59, 30, - 52,118, 31, 90,205,199, 80, 1,144, 68, 88,139, 74, 3, 44,182, 0,117, 80,218,100,243, 23, 20, 81,245,170, 20,128,229,191, 57, -231, 18,227,180,170, 21, 94, 83,170,231,105, 13,211, 41, 41,129, 19,194, 45,180, 74, 72,152,162,162,165,171, 24, 90,155, 91,121, - 64, 1, 10,190, 89,208,106, 49,147, 38,123,140,190, 42,215, 59,205, 63, 4, 41, 77, 7,232,116,248, 77, 39,221, 90,229, 3, 45, - 60,220, 25, 11,121, 77,164,169,180,203,154, 2,178,180,171, 50, 56, 55,242,106, 47,163,123,251,137,182,215, 39,127,128, 23, 32, -147,183, 70, 90,252,198, 22,163,102,103,142,115, 15, 52,168, 39, 72, 47, 37, 68,133,131, 88,139,196,145, 68,178, 49, 42, 54, 4, - 38,158,106, 17,126,147, 14,157, 74,146,213, 34,214,106,160, 3,145, 23, 72, 93, 65,214,154,147, 60, 45,214,208,171,150,181,227, - 40,145, 58,176,135, 20, 0, 88, 40, 71,191, 85, 50,133, 16,199, 40,204,233,149,217, 16, 81, 74,106,213,167,196, 41,166, 68, 93, - 61,218,202,202,222,163, 83, 36,180,202,163, 63,224, 83, 73, 82,235, 51,209, 30, 63, 41, 12,169, 45,248,223, 4,213,169, 74, 90, - 53,128,211,101, 42, 82,164, 55,109,135, 89,147, 41, 74,163,196,152,181, 2,229, 14,132,196,169,105,114, 84,194,235, 37, 15,213, -165,203, 74,222,142,144, 8, 75,184,116,146, 25,235,123, 77,126, 53, 26,159, 50,222,163, 82, 34, 87,170,209, 34,199,165,211, 98, -196,145, 42, 52, 27, 97,182,148, 76,169,143,206,119,244, 45, 5, 21,254,145, 74, 46, 58,167, 16,167, 2, 71, 51,139,214,220,104, - 21,172, 65, 37,238, 69,201, 58,119, 82, 55, 23, 34,254, 81,127, 40,177, 82, 54, 23, 48,154,250, 57, 42, 21,105,164,129,171,170, - 20,141, 98, 87, 0,144,254, 73, 38,170, 44,234,129, 19, 88,176,146, 78, 89, 34,103,179,171,162, 77,157, 81,164,143,123,163, 8, - 73,114, 60, 56, 14, 56, 25,153, 92, 82, 27, 64,113,230,129,159,116,212,234,141,165, 30, 35,232,150,149, 34, 26,138, 67, 35,195, -229,195, 64,160,161,215,163,214,229, 61,114,193,118, 3, 18,169,144,234,116,244, 83,105,213, 73,128, 42,170,162,244,180, 53, 84, -173, 73,139, 52,114,195,114, 72, 17,209, 13, 46,130, 91, 66,252, 80,144,164,132,233,150,102,139, 89,170,162, 58, 42, 11,109, 2, -156,194, 86,221, 33,181,251,181, 38, 42,218, 67, 77,174, 97,127,153, 78,214, 92, 14, 2,191, 29,239, 13,182, 62, 55, 80,210, 57, -121,206,113, 74,153, 54,127,189, 8,203, 67,140,225,184,143, 85,220,123,222,211, 87,121,197,162, 59, 80,232,138, 96,225,196, 37, -231, 93,231,158,158,124,173,226,166, 18,183, 1,113, 59,104,206, 7,217,212,166,214, 54, 39,125,193,177,184,189,190,201, 2,219, -129,115,109, 36, 64,115,202, 58,106,133,145,131,199, 51,172,111, 27,220,150, 84, 18, 57, 32,181,236, 38,119,102,187, 2,172,173, -245,138,161,227,115, 42,109, 53,183, 89,113,151,211, 75,165,167, 49, 32,171,220, 30, 90, 20,243,205, 83,164, 33,100, 75, 87,189, -190,190,121, 21, 18,250, 71, 48, 94, 91,105, 75, 43,121, 74,230,229, 45,103, 23,124, 32,112,213,237, 11,217, 74,166,193,241, 37, -103,179,117, 80, 93,247,138,133,163,115, 83, 94, 17,183, 11,108, 46,100,165,216,113, 47, 43, 30,236, 12, 41,116, 27,141,183,211, -202, 18,144,184,181, 22,208, 98,204,139, 46, 18,220,104,135, 30,225, 76, 56, 81,105,212,133, 48, 41,180,229, 70,162,206,126, 38, - 92, 98,148,206, 66,164,193,166,164, 45,105,171,200, 68,140,120,203, 37, 97, 47, 60,174,114,244,144, 80, 29,171, 42,165, 30,155, - 49, 51, 37,181, 81, 79,132, 15,185,196,151,151,234,114, 30, 44,248, 41,113,104, 4,248,238,184,148,190,180,184, 74,188, 52,182, - 16,234,154, 81, 58,124,203,115, 9,169, 39, 2, 57, 12,104,246, 82,172, 26,204,163, 72, 34,253, 44, 52, 92, 91,236,149, 12,133, -109,183, 62,241,103, 9, 69, 81, 77, 83, 52,208,150, 44, 27, 66,145,121, 36, 63,181, 37,206,204,250,129, 61,116,169,212, 89,131, - 43,201,249,104,123, 74,253,155,155,225,236,203,226, 10,102,204,110,202, 63,132, 86,125,198,138,149,127,100,183,134,155, 1,112, -237,173,219,177,225,202, 67, 75,152,211, 60,203, 77, 6,247,167,123,204, 54,107,180, 85,184,167, 33, 62,251,114, 35,170, 69, 54, - 84, 73, 46,115,200, 36,167, 25,234, 60,137, 61, 71,217,242,198,191, 92,191,104, 95, 2, 27, 99,237, 47,225, 82,247,225,235,116, -208,197, 6,191, 47, 55, 54,209,110, 43, 17, 27,149, 84,218, 45,211,165,197,120, 90,215,101, 56,171, 11,149, 13, 70, 66,225,214, - 96,115,165, 21, 26, 85, 74, 92, 66,166,214,227, 79, 55,249, 64,239, 46,206,238, 55, 15,155,187,185,155, 17,187,212, 5, 91, 27, -163,180, 55,157,106,194,190,104,165,101,216,241,171,116, 57, 30, 18,166,211, 37, 16, 5, 70,131, 54, 18,226, 79,167, 74, 70, 81, - 42, 5, 78, 52,132, 18, 28, 26,183,178,186,229,171,129, 84, 73,169,212,119, 35, 85,129, 0,134,181,188,202, 72, 5,128,210,110, -164,121,139, 34,115,126, 99,150,201,150, 78,208,177,215, 21,236,173,125, 91,218,250, 75,126,181,187, 55,113,190,246, 44, 91, 95, -135,148,129,156,147,147,205,212, 31,144,244, 3, 58,243,202,158,132, 96,121,118,234, 51,223,167,152,213, 84,132,144, 83,212,144, -122,231,250, 71, 93,121,229, 7,168,206, 61, 58,103,231,212,233,216,126,242, 48,223,133,202,123,243, 12,118,207,203,183,111, 61, - 32, 14,126, 17,140, 14,161, 90,245,202, 0,199,235, 2,114, 60,191,110,190, 5, 15,139, 57,201, 32,114,253,216,239,161,239,192, -233,108,123, 39,162,135, 78,189, 62,195,246,249,106,136, 10, 78,112, 73, 80, 61,113,230, 62, 64,254,122,234,166, 18, 83,202,122, -103,184,207, 81,130, 49,223,236,215,174, 80, 6, 9,201,199, 47,111, 46,189, 71,203, 89,192, 63, 27, 96, 53, 1,149, 31, 49,140, -143,183,211, 84, 10,122,103,152,159, 49,204,115,211,229,233,253,186, 57,109,140, 0, 0, 42, 35,161, 61,188,137,207,221,161, 86, - 58,145,216,118,198, 58,231, 30, 93,116, 48, 63,158, 1,112, 96,228,246, 63,119,203, 84, 21,220, 28,101, 35,160,235,242,245, 31, -102,138, 90, 22,121, 72,232, 51,231,247,231,247,104,117, 39, 61, 58, 2, 59, 96,249,104,234, 64,191,160,198, 65, 55,247,255, 0, - 60, 14,160, 50, 60,137, 24,206, 58,103,203, 61, 58,234,146,135,124,156,121, 99,160, 31, 51,219,236,252,116, 73,206, 49,128, 51, -231,231,251,123,106,130,209,216,142,152, 32,159, 63,195, 75, 14,184, 84, 94,215, 29, 79,250, 96, 55, 19,215, 9, 7,190, 79,166, -113,212,157, 10,180,231,174, 51,219, 30,163,230, 61,124,245,112, 94, 8, 35, 56,199,150, 58,254, 63, 97,208,174, 36,246, 79, 78, -132,250,231,203,175,160,237,165,148,155, 11,141,240, 1, 23,176,233,128,148,158,253,122,158,192,247,206,126,126, 93,116, 42,219, - 61,126, 33,142,248, 29,128,238, 64,251,180, 98,130, 72,235,144,115,140, 99, 39,215, 61,190, 90, 29,105, 56, 32,252,142,124,190, -223,195, 58, 58,223,238,254, 95, 39, 6,192,106, 72, 24,199,207,169,245, 30, 90,160,176, 6, 79, 92,227,183,145,249,118,249,104, -165,167, 61,148, 78, 62, 93,254,239, 93, 12,179,220, 30,157, 60,198,115,242,249,127,110,150,193,148,246,192, 42, 80,207, 64,115, -230, 7, 95,188,250,119,213, 21, 12,100, 99, 63,179,231,162,150,129,220, 12,103, 57, 35,191,246,104,101, 2, 7, 81,158,249, 35, -174,127,183, 74, 39,124, 40,187,129,129,212, 62, 68,122,250,125,199, 84, 23,140,143, 92,117,213,117, 19,215,184, 4,231,175, 66, - 79,245,106,130,251,142,158, 93,255, 0,118,149, 29,122, 95, 24, 34,198,227,107,126,239,159,158,216, 20,140, 18, 59,227, 75, 95, - 85,250,199, 75, 75, 13,192, 56, 53,129,222,221,113,224, 31, 34, 70,125, 6,170,115,117, 4, 36,146,112,146, 71,252, 62, 67, 84, - 57, 57,156, 74,190, 46,131,167,126,189, 72,198, 14,138, 73, 72, 0,249,103,174,123,247,243,198,181,201, 39,189,191, 44, 27,238, -190, 43,164,129,129,211, 63,236,245,233,243, 58, 32, 97, 35, 36,140, 31, 65,231,246,249,232,100,242,133, 16, 14, 78, 58,158,157, - 7,144, 58, 37, 4, 36, 28,167,155, 7,168,239,223,182,147, 44,119, 29,113,140, 86, 9, 88, 80, 33, 67,148,142,189, 58,147,229, -223,183,125, 16, 27, 14, 36, 37, 73,206, 14, 71,113,233,215, 84,146,114, 59, 96,121,126,113,162,219, 33, 61, 20,122,227,203, 61, -135,228,105, 51,107,111,211, 4, 38,221, 6,253,190,126, 24,172,132,132,167, 25,192, 31, 46,167,238,209,141,168,114,132,252,186, - 31, 95,234, 58, 17, 41, 24, 32,168,146,115,128, 59,159,179,174,138,108, 18,115,203,216, 12,131,215, 0,103,174,144,194, 71,174, - 42,227,160,207, 92,117,206, 62,223, 33,242,209, 40,194,176, 79, 64,124,186,245, 61,190,239,236,213, 16, 1, 81, 29, 64,242,237, -249,245,209, 45,130, 6, 1,237,228,113,147,251, 59,104, 99, 7,241,193, 13,224,100, 14,158,159,183, 68, 33,125,121,112,122,103, - 36,117, 25,207,111,219,170, 8,237,156, 12,250,116,207,217,159, 61,101, 86,165,169,113,222,213,218, 85,175,104,208,234,151, 29, -199, 92,154,205, 58,143, 67,162, 64,145, 83,170,213,103, 62,174, 86,162,193,129, 17,181, 57, 37,226, 79, 92, 12, 36, 30,101, 16, -144, 78,144,150, 68,141, 93,157,130, 34,110, 73, 54, 0, 1,212,158,192, 96, 14,194,219,159, 78,228,237, 97,234, 73,216,119, 56, -239, 95,177,184, 52,198,205,241, 34,250, 82,145, 37,219,203,111,154,116,243, 97, 74,140,138, 52,229,161, 36,121, 36, 56,165, 99, - 62,127,102,186,125, 58,178,168,165,224,240,108,180,227,106, 45,243,168,133, 3,219,224, 41,253, 99,156, 28,124,181,130,123, 43, - 61,153,123,231,176,246, 46,230, 76,226, 66, 69, 19,109, 99,238,172,123,102, 85,189,105, 61, 82,102,161,115, 83, 77, 53, 47, 41, -114,110, 56,241, 22, 91,166,201, 83, 79, 37, 41, 96, 41, 78, 35, 7,156,131,211, 91,183,187, 60, 21, 87,216,164,202,171,216, 55, - 44, 43,172,211, 80,185, 34,157, 13,254, 73,133,108,167,153, 73,110, 58,212,124, 76,167,200,119,206,185,175,140,211,219,115,250, -250,186,121,150,106, 87, 41,102, 86, 4,217, 99, 69, 62, 95,180, 64, 96, 69,237, 98, 6,161,177, 7, 30,160,125, 30, 51, 92,167, - 42,240,231,133, 50, 92,240,205,148,102, 10, 42, 3,172,240, 74,138,188,202,201,222, 50,206,202, 2,106, 70, 70,243, 90,193,183, -223, 26, 33, 89,187, 38, 56,211,173, 73, 82, 68,134, 29,100, 33,180, 43,195,241,146,165,129, 30,115, 42, 79, 82,234, 84, 82, 20, - 61, 53,220,158, 22,104,113,246,115, 98,169, 87, 66,163,180,230,226,223, 48,159,157,245,162,217,109,215,233, 84,130, 15,134,212, - 53,167, 42, 99,197, 78, 84,181,167,226,199, 98, 53, 30, 10,163,245, 54,234,111,196,144,202,209, 82,166, 75, 80,109,137, 72, 83, - 78, 49, 38, 59,153,147, 79,146,210,250,165,126, 35,100, 96,227, 24,215,127,118,138,242,164,110, 62,192,109,157,106,149, 47, 30, -229, 76, 54,197, 89, 17,150, 68,186,101, 86, 23, 51,106, 97,104, 7, 45,130, 23,217, 88,202,117, 28,118, 20, 81, 23,136,105,153, -198,204, 58,139,149,189,143,111, 45,236, 65,254, 3, 29, 5,199,185,104,158, 14, 29,203,164, 80,217,101, 77, 86,170,133, 93,209, -180,199,170, 20, 96, 14,241,187, 6, 37,127, 93,148, 45,136,181,242,106,229,223, 42,176, 31,122, 91,235, 11,114, 43,173, 63, 43, -152,169,199,159,143,135,153, 45,243, 30,101,243,182,162,159,187,215, 88,194,171,109, 42, 52, 22,155,105,229, 73,168, 62, 22,203, -206, 5, 45,198,219, 49,203, 37, 62, 31, 54,124, 70,223, 9,248,135, 92, 47,174,172,242, 97, 74,133, 54,150,235,136, 92,152,237, - 58,252, 89, 13, 45, 92,139, 46, 50,219,136, 74, 20, 9,248, 28, 41, 32,143, 62,190,122,188, 83, 18,164, 54,242,101, 71, 65,114, - 44, 22,132, 53, 40,114,187, 30, 75,239, 23, 82, 65, 72,234,224, 65, 70,125,121,117, 30, 87, 45,172,129,168,158,155,237,126,135, -115,211,189,187,236, 62, 56,127,142,130,130,138,154, 49, 79, 24,120,134,234,170,193,123,180, 96, 91,169, 10, 66, 18, 15,151, 77, -128, 4,226,231, 71,140,106,110,203,144, 95, 44, 50,131, 42, 92,249, 46, 56,161,202,196, 32,136,201,141, 24, 96, 36,190,183,201, -194, 51,149, 21, 28,117,214,187,111,102,251,181, 33,243,106, 81,228, 61, 14, 37, 33, 97,130,251, 50, 21, 30, 63, 51,105,194,152, - 98,106,148, 82, 95, 81,200, 60,195,245,138,142, 20, 14, 19,125,222, 75,250, 78,218,216,238,219,180,169,142, 42,187, 85,231,169, -204, 91,107,109, 14,183, 50,106, 86,182, 24,105,167,112,133,173,168,202, 43, 80,230, 79,199, 45, 56, 33, 67, 58,228,228,187,229, -250,132,217, 47, 75, 67,178, 96, 58,242, 83, 61,164, 56,226,208,226,208,181,175,198,125, 46,167,157, 35,226,117, 68, 43,152, 40, - 32, 32, 40,140,101,246, 58, 73, 18,147,146,135, 76,211,128,242,145,107,170,177,186,198, 9,237,250,205,184,185,216,218,219,233, -112,238, 72, 56,183, 63,169,204,229, 28,252,143,135,165, 49, 82, 40, 35,235,170, 18,203, 36,204,173, 96,202,132, 24, 98, 13,183, -146, 66,118, 56,218,122,181,245, 81,114,145, 37,110, 60,103,198, 97,207,125,165, 84, 31, 79,131, 90,163,190,219, 97, 10,108, 48, - 26, 9,169, 66, 90, 80,227, 47,128, 80,181, 33,204,169, 42, 79, 34,145,144, 27,238, 36,202, 77, 46, 61, 71,146,158, 91, 77, 34, - 80,129, 80,121,196,192,149, 37,107, 67,234,250,134,230,105, 96,211,223,104,169, 92,205,169, 77, 58,128, 83,145,140, 41, 90,141, - 75,174,173, 77,251,204, 9, 44,170,156,220,176,219,244,224,164,200,165, 79,117,183, 20,184,138, 75,160,173,218,100,118, 89, 33, - 75, 40,230, 73, 95, 94, 82, 7, 38,179,218,117,105, 35,154,151, 61,164,211, 34, 50,180, 74,121,186,147,237,205,163, 21, 60,162, - 29,110, 35,204,164, 37,216,238, 48,180,134,146,248, 5,180,189,243,232,211, 62, 92,169,112,162,228, 27,221,109,123,121,123, 16, -109,110,225, 46, 44,215,186, 62,199,161,242,220,190,156, 36,113,114, 47,203,109,107,162,234,192,145,231, 26, 47,177,110,190, 75, - 27, 13, 65,145,137, 24,220,138, 82,100, 86,167, 67, 85, 85, 5,217, 21, 54, 83, 26,153, 91,143, 41, 84,218,173, 77,175, 19,157, - 16,100, 78,167,184,142,105,169, 96,169, 46,243, 41,104,121,178, 22,223, 34,202,155, 23,250,140,137, 20,138,148,138,125, 82, 20, -234,253, 56, 69,122, 35,244,247, 86,135, 43,244,199,152,112, 33,197, 60,228, 96,159,173,226,132, 50, 84,121,113, 53,165,176,135, - 82,167, 71,194, 53,242, 20, 11,121, 84,166, 35,198,155, 38, 4, 37,169, 19, 41,142,209, 42, 19,225,165,233, 62, 34, 25,142,226, - 80, 30,113, 17,157, 66,149,252,196,164, 18,216, 82, 84,115,167, 38,148,205,126,152,227, 49, 97,220, 38,171, 81, 86, 91, 68, 26, -187, 13,248, 14, 69, 97, 62, 35,143,138,156,112, 22,101, 41, 15, 18, 22,226, 10,194,136,230,230,233,134,127, 42, 6, 37,206,199, -117,101, 43,181,186,143,180, 75, 2,110, 73, 96, 5,128,176, 42, 44,157, 77, 28, 1,181, 71, 86,166, 56,195,160,133,227,150, 34, - 10, 48, 60,200,165, 70,147,146,168,163,204, 71, 45, 85,148, 2,193, 25,163,195,167,111,214, 86,203,172,196,137, 45,186,155,174, -161, 10,167, 73,203, 62,227, 94,136,211,232, 33,202,160, 82,127,192,238, 54, 24, 88, 10,120, 37, 1,208,149, 43,151,151,153,182, -170,166, 34,105,117, 25,181, 40,161, 79,194,159, 53, 78,221,148, 2,130,244,202, 62, 11,173,203,168,196,140,210,177,239,188,139, - 79,188, 52,148,143, 25, 25,113,159,210,140,171, 8,167, 26, 85, 94, 65,131, 35,235, 11,102,226,130, 87, 49,132, 48,166, 27,155, - 34,167, 24, 20, 49, 81,133, 37, 81,151, 26,170, 90,112, 31, 21,124,188,252,170, 13,201, 72, 73,201,204,105,149, 74,157, 57,200, -147,110, 38,154,139, 18, 67,205,195,153,115, 70,104, 51, 79,155, 83, 70, 23, 21, 85, 85, 0,161, 70,146,242,249, 2, 78, 76,126, -101,128,219,173,128,148,235, 34, 80,196, 0,231, 83, 92, 1,220, 90,204, 10,145,112, 0,185, 42, 1, 2,236,108, 45, 99,136,197, -109, 57,134, 90,147, 78, 60,243,173,165,136,149, 15, 48,189,215,148, 86,241,202,190, 93, 81,152,134,165,148, 13, 11,202,242, 35, -169,110,248,110,177, 16, 67, 42,158,104,128,170, 20,215, 22,194,141,110,142,176,131, 25,131,225, 54, 11,133, 84,196,180, 99,164, - 18, 82,252, 36, 58, 2, 73, 90,181,243,137,137,169, 94,219, 91, 8,140,165,159, 30,241,143, 84, 66,139,156,202,240, 96,192, 62, - 18,156, 82,206,124, 78, 89,140,129,203,241, 21, 30, 76, 19,163,109,106, 99,148,203,129,215,161, 22,149, 70,170, 36, 45,108,171, - 31,224, 53, 5,243, 58,217,101,215, 79,193, 25, 79,185, 33, 32, 39, 1,165,190, 66, 50,135, 15, 45,187,123,227, 46,167, 87,178, - 45,198, 26,115,194,143, 66,171,214,144, 26, 91,156,200,171, 26,148,118, 84,145, 31,151, 10, 8,167,198, 11, 4, 31,135,197,207, -235, 37, 39, 74,201, 56, 20,179, 48,220, 2,160, 89,137, 27, 48,218,251, 92,218,224, 27,108,182,181,237,189, 90,213,112,199,197, -185, 37, 66, 63, 50, 26, 82,245, 33,186, 21, 2, 41, 29,149,214,224, 41, 89,127, 85, 64, 0,155,129,164,168,195,121,106,210,157, - 49, 16,180, 67,123,221,105, 23,132,151, 98,143, 8,133,181, 9,233, 2,160,114,132,149, 41,152,202, 77, 80, 0,122, 20,224,133, -140, 19,174,145,216, 85, 22,174,139, 58,117, 20,167,255, 0,116, 45,215,218,183, 92,253, 48,116, 59, 66,168, 71,135, 84,162,201, - 91,137, 33, 46,115, 83,165, 76,101, 96,101, 41, 92, 44,103,200,106,117,145,110,169,112,231, 15, 1,196,123,195, 84,153, 12,178, - 20,148, 41, 94, 28, 38,226,200,119,157,100,120, 95,165,138, 1,112,228,146,114,114,161,173,186,219, 8, 70,145, 86,150,137, 9, - 45, 70,158,138, 76, 55,148,216, 65,109, 45,150, 86,152,239,128, 57, 65, 12, 75,229,234,122,225,213,148,244,209,114,119,104,171, - 4,128,125, 92,254, 87,191, 96,110,192,158,223,104, 2,109,189,142,214,189,197,123,226,102,115, 14,101,151,130,175,170,167, 41, -126,116, 54, 59,220, 24,181, 41, 23,243, 93, 94, 65, 97,177,125, 39,160, 56,182, 92, 20, 69, 77,185,225,210,208,218, 12,121,177, -214,245,101,132,175,147, 20,200,207,169, 77, 67, 12,161, 64,187,239, 14, 55, 24, 58, 82,112,164,176,232,229, 32,231, 94, 29, 77, - 69,138,133, 70, 29, 29,163, 30,174,236, 24, 12, 74,171,176,182, 29, 93, 18,157, 80, 46,135, 10, 99,172, 22,209, 86,126, 34, 28, -247, 86, 74,249, 90, 42, 50,212,149, 37,164,133, 61,149, 74, 50, 96,174,108,231,227,148, 73,104, 70, 98, 34, 90,232,251,142, 52, -174, 65, 30, 63, 46, 28,230,126, 90,201,119, 25, 60,138,113, 64,225,189, 82,183,173,152,148,155,102,178,203,203, 68,215,166, 72, -114,183, 95,156,227,173,149, 84,171, 51, 30, 74, 27, 67, 12,173, 36, 52,203, 81,219,102, 60, 68,130,144,203,109,165, 36,133,120, -138,212,193, 31, 77,212,144, 72, 34,198,251, 27,245, 44, 15,154,214, 6,230,224,239,182,149, 3, 21, 18,113, 76, 43, 65, 3, 50, -137,214, 49, 12, 40,135,117,121, 29,209,158, 71,223, 75, 42, 46,136,204,108, 8,145,132, 74,193,144, 72, 75, 74,213, 54, 21, 45, - 76, 91,246,218, 94,139, 17,193, 28, 86, 29, 14, 46,115,208,212,249, 67, 77, 64,167, 72,144, 20,185,149,135,226,180,158,101,145, -202,195, 40, 83,141,144,227,200, 2,245, 21,216, 52, 92,248, 96, 70,161, 83,252,103, 98,197,145, 15,156,115, 78,109, 49, 66,157, -109, 1,110,205,152,167, 16,175,119, 65,203,206,130,172,229, 69, 42, 23, 85,184,213, 38,116,122, 77, 49, 30,243,112, 48,191,122, -156,175, 0,120, 52,218,131,205, 97, 18,106, 83,146,149, 4,194, 76, 0,146, 91, 88,241,164,101, 41,109,188,184, 10,126, 34,216, - 84, 0,137,213,234,155,149, 73,236,160, 76, 76,164,176,212,104,116,198,150,183, 7,131, 18, 42, 93,229,167,198,253, 69, 23,214, - 76,149,151, 57, 71,195,200,157,109, 69, 33, 82,243, 60,133,180,234,176,248,250,244,211,107, 91,226, 72,211,167,112,188,181,209, - 76,160,213,204,197,106, 0, 96, 24,179, 79, 82,204, 72, 51,121,144,128, 10,249, 98,149,218,225, 28,149, 89, 27,152,205, 94,144, -220,249, 80,209, 79,171, 70, 91, 20,181,184,135, 92,141, 50, 72, 14, 84, 76,118, 19, 36, 34,177, 25,151, 21,138,119,187,114, 19, - 21, 68, 12,117,150,149,132,150,213,150, 54, 98,220,136, 16,188,119,163, 67,101, 5,113,196,105, 72,165,185, 82,119,197, 5,126, -248,228,114,219,144,233,141, 70, 67,104,106, 56, 82,124, 82, 79,136,218, 88, 9,105, 88,156,247,222,169, 82,227,191, 45,232,212, -218, 11, 78, 71, 98, 59,143,161,113, 39, 84, 75, 46,153, 13, 76,172, 45,229,243, 37,135, 29,104,251,180, 52,101,110, 6,210,236, -148,169, 74, 12,138,140, 74,153, 50, 51,206, 33,177, 76,164,162, 59, 73,171, 73, 72,104, 78,168,197,125,231,124, 63, 6, 48,109, -102,142,200, 60,234, 28,229, 82, 93, 7,244,104,105, 39, 91,241,105,141, 99, 37,254,169,195, 11, 90,214,220,144, 53, 30,151,233, -216, 2, 62,226,207, 81, 79, 37, 64, 53, 1,150,150,100,144,129,164,144,145, 57, 33,117, 0, 73,102,157,197,144,162,146,201,229, -185, 91, 7,133,199,163,200,101, 79,198,131, 70,106, 76,183, 83, 33, 17, 40,212,166, 60, 24,241,189,234, 27,101,247,106, 85,121, - 13, 51,138, 77, 9,190, 85, 34, 58,146,217, 82,185,213,225,182,227,202,108, 33,244,163, 51, 30,132, 13,122,179, 61, 46,206,167, -178,218,106, 21, 83, 17,198,105,113, 16,255, 0,130,203, 84,152, 48,121,220,112, 58, 60, 70,144,219, 72, 14,202,154,226, 91, 75, -137,117,229,164, 37,133,166, 84,233, 54,205, 18,152, 42, 78, 72, 74,100, 38,109, 70,157, 75,167,176,101,215,110,185, 45,168,183, - 26, 21, 45,132, 58, 22,233, 81, 25, 47, 73, 45, 70,101, 9, 42,121,228, 37, 28,165,217,183, 32,206,171, 85,105,149,250,165, 82, -149, 14, 75, 94, 12,218, 69,174,167, 26, 93, 42,136,182,199, 51,171,157, 33,213,135,234, 53, 63, 17,100,187, 57, 41,104, 33, 40, - 8,142,218, 24, 74,121,221,169, 86, 22, 72,193,212,205, 96,202, 46, 67, 48,184, 22, 31,101,130,133,184, 4, 88, 49, 35, 72,181, -216, 86, 28, 81, 1,116,150, 73, 25,169,242,225,205, 66,229, 73,146,164,163,105,104,209,130,181,131, 0, 76,135, 75, 68,143,118, -149,228,145, 98,129, 95,138, 36,233,202,152,138,141, 93,169,141, 69, 80, 30,227, 5,244, 43,222, 82,165, 36,243, 74,171,176,208, - 41,106,160,226,222, 82, 83, 28,169, 98, 40, 10, 73, 90,220,201, 68, 52,254,150,111, 2,144,225,187,179,158,209,187, 10,132,211, - 79,213,165, 82,118, 15,137, 25, 20,246,210,148, 75, 91,140,190,246,200, 95,117, 36, 32,115, 57, 41, 10,102,175,109,202,146,122, - 41, 18,232,108, 40,225,134,134,166, 17, 71,172, 75,173,183,254, 28,202,224,136, 19,125,223,220,189,237,247, 37, 21,179, 37,214, - 81, 80,121,191, 1, 45, 16,166,130, 31,105, 33,106, 75, 76,149, 56,163,206,177,200,205,113,141,195,133, 51,141, 78, 12,248,147, -225,150,176,148, 59, 23,119,182,166,230,182,237, 57, 15, 97,150,105,151,140, 70, 87, 85,176,107,200, 50, 27,253, 3,177,111, 58, - 93,191, 49,181, 28, 41, 2, 57, 60,193, 74,200,158,100,149,102, 22,210,191, 88,166,198,203,123,107, 2,250, 84, 17,179, 17,170, - 37, 36, 88, 6, 45,176, 1,135, 60,241, 94, 80,210,197, 55, 50, 52,167,146, 27, 38,149,177,141,119,250,189, 44, 46, 13,254,219, - 16,222,117, 4,220,220,223,242, 16, 41, 10, 0,121,103, 35, 29, 63, 35,174,144, 0,146,129,231,232,122,252,251,246,242,213,103, -105,213, 58, 52,201,244, 90,252, 69,192,174,208,170, 53, 26, 21,114, 3,128,135, 96, 86,232,211, 30,166, 85,233,238,115, 96,133, -177, 82,139, 41,165,103,205,147,175, 33, 3, 57, 79,194, 14, 78,124,199,203,236,212,253, 72, 96, 25, 78,160, 70,198,251, 27,216, -220, 31, 76, 83,251,247, 22, 56,241,142, 65,215,160,207, 76,143, 35,229,243,210, 78, 79,144, 72, 39,250,186,145,142,218,250, 74, -136, 25,198,115,208,129,220,124,245,247, 36,146,124,191,217,244,236,126,205,103,127,191, 3, 30, 72,200,230,229,206, 58,121, 15, -199,215,251,117,236, 5, 31,245, 72,242, 7,190, 62,223, 76,233,114,133,144,114,164,245,198, 7, 65,219,215,238,215,190, 92,127, - 56,224,103, 31, 47,191,211, 67,221,233,129,138, 43, 71,124,156, 15,196, 14,221,186,244,208,171, 3, 3,191,166, 64,201,249,119, -249,234,232,212, 41,147, 22,132, 71,105, 74, 46,186,134, 91, 32, 16, 29,125,194, 18,211, 12,249,188,250,213,209, 40, 72, 43, 89, - 56, 72, 39,166,186, 71,195,191,178, 43,142,110, 36, 99,196,171,219, 27, 61, 83,178,237, 25, 97,151, 26,188,247, 98, 90, 54,206, -131, 38, 59,229, 63,225, 52,182,171,241,205, 66,178,148, 52,175, 16,166, 60, 5,115, 36, 97, 43,202,147,157,121,171, 41,169,236, - 37,148, 43, 55, 69,234,199,224,162,228,159,112,198,205, 37, 29, 93,124,188,138, 26, 89, 43, 38, 29, 86, 36,103, 32,122,182,144, -116,143,123, 88,123,241,204, 5,140,156, 36,231, 29,252,135,224,124,251,232,117, 0, 14, 70, 1, 7, 7,183,159,203,207,166,117, -177,124, 80,240,223,126,112,157,189,183,214,195,110,107, 49,211,119,216, 53, 54, 96,207,155, 77, 84,151,104,213,200,115,224,199, -169,209,174, 75,118, 76,184,204,185, 50,223,157, 79,148,219,177,157,113,166,212, 74, 28, 66,144, 20,218,181,174,203,234, 48, 7, -159, 79, 94,255, 0,111, 83,141,108, 83,203, 28,200,146,198,218,163,144, 2, 58,142,190,160,216,223,220, 69,240,155,199, 36, 18, -203, 12,200, 98,158, 22,100,116, 59, 50,178,157, 44,164, 14,132, 16, 65,247,140, 12,160, 58, 18,122, 12,253,253, 63,179, 67,171, -168,200, 61, 58,140,249,227,207,167,231,182,138, 63,173,208, 17,223,167,203, 25,201,252, 53, 69, 64, 1,142,253,115,246, 15, 67, -173,144,108, 65,244,198, 70,227,125,199,254, 48, 26,129,245, 28,189,186,140,125,224,250,245,208,171,192,201, 25, 7,255, 0,104, -122,103, 69,184, 70, 72, 57, 0, 30,195, 29,124,186,126, 31,179, 66, 47, 62,163, 30,158,121,249,116,210,202, 73, 23, 56, 0,108, - 61, 54,192,202,193,193,193, 4,247,206,116, 58,199,159,175, 67,233,162, 87,235,229,140,122, 96,250,252,244, 58,129,201,200,200, -251,113,131,219, 56,209,199,198,216, 54, 6, 88, 0,100, 39,175,203,167,231,251, 52, 43,131, 39, 36, 2, 64,236, 58,254, 63, 61, - 22,231, 76,100,244,201,251, 60,134,132, 80, 30,188,221,127,104,193,245,251, 52,170,155,223,107, 91, 25, 22,223, 2, 44, 12, 18, - 70, 49,219,212,117,237,161, 87,243,234, 15,111, 44, 31, 92,249,249,232,197,140,103,249,222,127,105,251, 6,133,115, 24,236,123, -246,244,239,223,229,165,147, 10,139, 27,123,190,126,126,252, 12,188,246,199, 76,103, 62,152,254,142,154, 13,206,249,201, 78, 51, -156,140,231,211, 31, 46,250, 49,194, 2,122,244,243,207,151, 79, 93, 90,212,167,148,162, 20, 50,159, 34,158,248, 35,184,244,210, -152, 2,247, 55,232, 48, 59,171, 82, 85,220,156,231,177,199, 79,179, 75, 84,137, 89, 82,129, 64,192, 61, 9,238,125,123,157, 45, - 11,159, 92,102,195,211, 7, 1,145,228, 49,230,115,215,175,153,251,245, 85, 41,199, 65,212,158,255, 0,159, 77, 82, 78,114, 7, -145,207, 79, 35,223,203,237, 26, 37, 0,231, 61, 49,231,219,242, 53,130, 1,198,113, 85,164, 37, 39, 24, 29, 70, 51,230,123,121, -232,129,156,245, 31, 8, 29,193,235,233,231,223,190,169,163, 29,176, 58,117, 7, 26,244,121,242, 2, 82, 20, 60,250,224,142,189, -251,246,210, 76, 0,248,223, 3, 5, 39, 29, 51,146, 59,252,240,123,103,174,138, 64,206, 8, 35, 31,183,240,208,109, 54, 70, 78, - 78, 73,235,147,144, 6, 78, 6, 51,215, 70,163, 57,233,142,157,199,203,229,162, 27,218,255, 0,203,124, 17,187,155,224,134,240, -161,156,231,174, 64,235,211, 29, 63,164,104,132,168,143, 60, 14,199, 24,243,245,249,127, 86,168,160, 96,103,207,203,243,246,141, - 16,132,224,228,245, 7,174, 63,160,231,215, 73, 16, 5,253,223, 39, 9, 28, 86, 71,127, 62,223,143,231, 58, 44, 1,220,122, 99, -160,192,252, 52, 58, 82, 7,219,143,207,238,213, 86,242,162, 60,134,112, 57,142, 0,243, 42, 62,128, 12,232,167, 5, 97,182,231, -108,101, 54,149,175, 93,188,238, 42, 37,171,108, 82,103,215,174, 43,142,169, 10,139, 68,162,210,216, 92,170,133, 82,169, 80,121, - 49,225, 64,134,195, 96,151, 31,113,229,164,118,194, 70, 84, 72, 0,157, 78, 55,217,195,236,235,180, 56, 5,219,136,183,189,229, - 6,143,114,241,101,120,210,144,245,197,112,186,195, 83, 99,109,101, 38,115, 41,113, 22, 77,152,167, 82, 66, 42, 9, 66,147,245, -132,212, 0,227,174,130,132,144,210, 64, 58, 65,236, 48,224, 78,145,183,150, 91, 28,115,238,229, 25, 47, 93, 23, 10,101,211,120, -127,163, 84,163,165, 73,163,211, 57, 87, 30,165,184, 46, 48,226, 73, 76,201, 4, 45,184,107, 35, 40,101, 37,105, 33, 78,103, 93, -206,171,207,168, 77,158,242,214,234,165,120,206, 45,240,239, 57, 83,188,203, 36,252, 62,157, 9,239,170, 51,196, 46, 48,105, 37, -147, 42,160,151, 76, 16,146, 37, 96,109,169,129, 27, 92,118, 83,208,119, 32,181,143,145,135,112,125, 25,188, 13,143, 54, 16,113, -223, 19, 82,137, 17,172,244, 16, 72, 60,170,157,125,165,213,191, 93,246, 49,126,194, 16,247,212,254, 92,102,175, 95,155, 82, 46, -162,100,151,208,236,151, 84, 86,135,157, 83,143, 45, 96,146, 94,142,181, 28,149, 31,231, 39, 61,245, 66,141,115,205,137, 57,175, - 1,247, 75, 76, 35,195, 76,148, 41, 72,125, 46, 37, 67,149, 50, 80, 63, 89,178,122,100,246, 29,245,245,218, 59,147,164, 45, 78, - 62,215, 50,202,148,134,101,254,133,244, 62,145,140,180,188,124, 11, 56,232, 71, 67,171, 83,148,233, 49,170, 13,190,247,248, 44, -245,182, 90,104, 56,144,150, 39, 33, 63, 10,154,125, 67,225,241, 20,158,202,245,193,243,213, 56,106, 88,146,193,203,105,235,239, - 59, 19,191,201,199,127,158, 23,202,218,157,233,146, 24,236, 81,136, 80, 46, 1, 43,107,143, 46,174,130,197,183, 3,169,212, 47, -102, 23,138, 45,142,166,222, 16, 42, 27,183,108,211, 81, 10,232,163, 70,247,155,186,155, 13,174, 83, 92,132, 0, 8,170,165,134, -192, 6,115, 39, 5,106, 72,203,136, 86, 73,233,166,207,131,205,208,115,108,174, 89,118,133,206,234,163,216, 59,146,166, 20,169, - 42, 82,136,161, 93, 77,252, 49, 42, 33, 4,225,182,215,204,148,185,216, 20,171, 61,198,186, 27,110,114,132,166, 53, 69,148, 59, - 30, 90, 23, 25,101,236,171,154, 43,201,240,223,133, 36, 17,241, 35,145, 74,229, 39,161,215, 63,238,253,167,145,106,238,109,193, -110,177, 27,154,158,103,166,165, 71,109,208, 75, 65,135,207,188, 66,117,149,227,252,159, 41,228,233,219, 3, 75,181, 66,188,109, - 27,157, 72,221, 61,223,199, 99,123,219,220, 65,219,108, 51,192, 88,210, 85,228, 53,174, 76,116,104, 30,157,201,185,229, 35, 0, - 2, 19,125,224,147, 75, 37,239,101, 33, 13,213, 69,250,103,114, 80, 10,102,173, 46, 58,164,199,113,180,212,163,184,159,141, 18, - 38,180,144, 27,150,219,136,255, 0, 40,194,218,193,244,234, 52, 13, 53,152, 76, 85,228, 75,126, 75,175, 83,218,112,212,170, 11, -111, 28,170,135, 77,132,169, 78,242,115, 15,209,175, 45,242,143,153,236,117,227, 97,231, 85,171,148, 38,109,155,155,154, 91, 20, -248,232,126,139, 84, 87,199, 38, 34, 85,134,223,163, 74, 82,186,185, 28, 40,126,141, 95,205, 7, 30, 67, 69,110,125, 33,219, 19, -109,119, 58,172, 90, 66, 93,116, 66,166,211,214,225, 63,160,250,214, 82, 3,169, 64,233,241,150, 27,112, 39,168, 3,155, 62, 88, - 58,244,144,243,106,233,148, 11,197, 35,128,123,129,109,205,246,238, 6,199,184,235,108, 71, 42,184,155,216,242,188,198,154,162, - 95,237,180,208,232,140, 11, 90, 66,236,136,172,189,245, 3,160,145,212, 16,122,249, 73,227,159, 17,187,137, 50,231,190,101, 63, - 18,112,228,140,252,162,176, 30, 62, 10,228, 73, 82,164, 22, 95, 72, 63, 2, 91, 10, 66, 22,112, 8, 82, 66,185,126, 28, 29, 79, -145, 81, 80,168, 42, 68,213, 63, 12, 37,188, 63, 45,130,209,128,132,156,150, 26, 75,203, 73, 74,254, 39, 10,138, 92, 67,124,164, -229, 42, 25, 25,186,221,245, 35, 87,185, 43, 18,155, 90,227, 77,126,164,251,143, 7,129,118, 51,188,178, 11,120,144,148,242,135, - 91,232, 71, 50, 10, 92, 36, 36, 39,211, 88,139,213,131, 77,117,196,212, 27, 16,219, 83,220,225,196,169, 47,211,101,161, 71,194, - 11, 92,133, 4,174, 9, 66,203,105,113,183,145,240,248,193,124,202,108,130, 38, 34, 59,179, 29,137,125,253,230,246, 63,127,165, -250, 13,186, 11,218,248,225,108,186, 60,159, 36,202,104, 33, 80,239, 79, 18, 6,232, 36, 44,108,206, 88,216,171,134,102, 58,137, -189,193,232,183,182, 51,138,107,197,167, 35,145, 32,194, 75,137, 45,162,170,204,129, 26, 59,172, 0, 57, 16,250, 88, 42, 67,173, -168, 44,132, 33, 97,105, 81, 89,194,193,192, 15, 21,183, 34, 93,189, 17,133,173,196,213, 88,150,133,188,239, 51, 44,199,149, 29, - 45,142, 86,210, 82,135, 2, 38, 68,112,144,144,148,168, 41, 39, 32,133, 0, 2, 89,200, 80,154,117,109,186,212,100,199,139, 80, -101, 13, 33,216, 78,199,114, 51,238, 37, 74, 91, 78,189, 27,148,178,231, 80,164,172,130, 9, 41,201,238, 14,179,250, 11, 83,227, -182,194,154,145, 2,161, 25,212,187, 44,196, 66,213, 18,124,111, 5,107,100,166, 20,148,169,198,211, 12,115,175,153, 42, 74, 80, - 70, 78, 78, 51,166,186,192,172,178, 6,109,136,220,117,189,189,227,117,177, 30,160, 27,119,233,139, 14,158,162, 39,142, 0,101, - 66, 93,128, 10,247, 70,216,130,108,214,176, 96,108, 65,243, 95,175,187, 27, 7,111,210, 27,168,182,211,116,199,151, 78, 75,232, -110, 83,209,169,177, 26,125, 10,125, 72, 91,143,187, 34, 34,142, 34,172, 0,129,128,132, 45, 73, 72, 9, 43, 56, 80,206,163,202, -184,216,125,223, 26,158,154,225, 56, 80,114,142,180, 69,150,162,178,150,227, 46, 61, 62,106,200, 76,129,146, 74, 91,146, 28, 87, - 54, 67,121, 73,211, 37, 69,159, 9, 83, 19, 42,175, 34,171, 13,106, 74,227,154,156, 84,200, 79,185,120,108,229,135, 25,169, 81, -213,250, 96,176,134,208,128, 65, 64,248,130,145,141, 58,116, 74,219,236,148,159,175, 97, 86, 33,180,182, 20, 87, 17,108,199,169, -180,216, 91,106, 47, 79,130,128, 61,245,230,208,113,204,207, 34,215,156,148,247,212, 94,170, 25,163,109,148, 76,140, 5,245, 41, -218,254,142, 8,213,107,116, 44, 47, 97,229, 55,198,205, 75, 85, 29, 71,255, 0, 73, 68, 85, 96,178,164,159,111, 98,202,179, 71, -229, 98, 69,134,130,202, 77,238, 0, 83, 96,239, 82,107, 84,106,164,152,205,214, 16,245, 17, 75,247,101, 22, 43, 1,232, 83,105, -203,136,165, 50,229, 98, 34,151,202, 17,226, 61,202,145,202,178, 48,162,146,142,250,216,251,105,128,186, 36,170,100,211, 22, 67, - 77,176,209,122, 60,214,153,145, 30,167, 10, 65,240,214,164,164,158, 79, 13, 73, 45,115, 37,224,181, 33,120, 81,230, 79, 42,131, - 59, 69, 16,106,201,139, 50, 64,129, 87,142,243,161,150,146, 80,211,168, 90, 71,134,148, 54,236, 25, 3,150, 43,129, 5,101,229, - 41, 92,199,162, 51,130,112,245,208,236,136, 14, 52, 88,165, 63, 50,139, 34, 51,197,246, 98, 51,239, 14, 83,216, 91,139,113,121, - 76, 73,110,172, 58,223, 48, 72, 13,160,134,135,112,144, 6,154,194, 70, 23,117,229,143,129,216,236, 71, 80, 47, 96,118,184, 4, -222,231,114, 6, 41,222, 44,205,105, 4, 73, 28,205, 45, 7, 45,193,177,250,212,141,149,187, 31, 44,137,107,144,124,172,109,102, -184,117, 1,243, 59, 82,158,154, 90, 88,167,200,142,181,210,164,169,181, 70, 81, 89,144,237, 61,164, 97, 8,142, 95, 89, 89,114, -156,227,128, 6,143, 58,148,202,185,146,172,161, 73, 41, 58,230,163,187, 82,190,163,190,164, 15,240, 15,170, 97, 12,245, 79, 47, -184,169, 46, 41,174,193, 14,169,111,140,231,161, 40,198,122,227, 89, 5, 18, 3,176,154,143, 6,166,202, 9, 1, 73,143, 61,174, -116,199,117, 99, 11,126, 47,134, 18, 84,193,229, 10, 37, 10, 37,180,225, 64, 40, 28, 13,100,168,166,120,245,217, 15,133,120,168, -146,220, 87,219, 46, 28,171, 6, 52,112,158,128,225, 60,175, 70, 87,197,205,140, 40, 16,112, 64,214, 42,193, 90,101, 10,126,211, -169,184,233,123, 31,188,110, 72,220, 3,125,207, 67,138, 55, 49,206,155,219,234, 42,132,129,216,197, 32, 46, 15,145,195, 50, 2, -235,191, 86, 80, 85,250, 18, 70,227, 86,166, 57,149,157,109,178,148,183,224, 71, 1,183, 35,200,142,217, 40, 25, 72,109,212,201, - 82,185, 20,122,144,165,158,100,158,128,171, 25,198, 50,253,209, 40,136, 75,137, 56, 90, 16,244,102,139,216, 60,229, 92,174, 20, -160, 14,224, 59,241,225, 62,105,200,244,214, 51,107,195,108,165,151, 16,146, 22, 20,133, 20, 2, 74, 64,121, 60,138, 65, 87, 76, - 96,117,207,114, 8,243, 3, 79, 5, 53,182,146, 64, 57,193,111,145, 35,178, 84, 80,226, 28,232,165,126,162,177,219, 31,234, 19, -220,105,223, 44,132,121, 88,223, 77,198,253,250,119, 62,253,247,252,113, 75,113, 30,119, 60,175, 32, 4,249,186,239,191, 91,252, - 54,176,222,214,184,191,174, 50, 89, 20,195, 81,143, 72,144,180,173, 79,134, 84,226,176, 3,206, 10,131, 10, 49,156,120,149, 12, -182, 3, 33,100, 31, 37,188, 73,238, 14,172, 46, 81, 36,215,106, 78,136, 82, 13, 46,159, 29,244,173,218,140, 98, 3,147, 86,130, -148, 42,159, 79,101,212,148,184, 90, 82, 9,117,242, 64, 39,157,182, 86, 64, 39, 89,163,142, 4,210, 26,113,106,112, 18,169,104, -109, 13,148, 32,151, 20,219, 9, 95, 85,156,163, 43, 88, 5, 64, 16, 3,157, 50, 73,215,199, 43, 45, 65, 83,113, 91, 14,161,136, -145, 25, 84,196,198, 1,231, 22, 91, 74, 20,150,219,107, 33, 42,116,156, 18,165, 16, 57, 84, 58,142,131, 82, 86,141,140,129, 80, - 14, 99, 42, 29,250, 93,128, 39, 98, 55,238, 64,233, 99,214,219, 98,176,130,186,186, 61, 66,153, 3,200, 12,138,151, 0,172,107, -174,228,216,130, 24,139,170,168, 32,128, 73,218,246, 35, 9,159, 71,167,209,161,120, 20,248,236,194,134,100,203, 91,178, 29, 95, -186,251,203,202, 90, 28,149, 81,118, 76,215,143,188, 39,196, 74,202,151, 33, 97, 35,155,151,196, 40, 72,195, 37, 84,174, 73,169, - 84,154,106,129, 77, 18,105, 49, 10,229, 68,157, 80,241,218,102,167, 32,224, 55, 84, 90, 25,111,222,102,198, 15, 5,251,154, 64, -109, 11,229, 46,180,231, 39, 33, 15,133, 74, 59,117,246,189,234,168,242, 95,136,212,199, 36,199,182,218,105,167,105,241,249, 74, -146,211,181,151, 92, 73, 53, 87, 2,149,206,150, 9, 76, 54,221, 64, 80,109,197, 32, 43, 88,189, 94,149, 6, 43,205,191, 86,230, -247,217,135,221,162,211,216,142,170,140,185,124,205,173, 45, 70,131, 10, 58,124,106,140,226, 75,124,160, 0,202, 50, 8, 82, 18, - 57,198,220, 72,224,134,210, 45,176,191, 96,122, 95,208, 6,189,206,219,216, 29,247,196,207, 33,174,134,153,155,219, 85,171,171, -156, 48,220,187, 89,207, 83, 96, 67, 75, 32, 91,221,193, 17, 45,216,175, 48, 50,178,224, 84, 74, 44,154,236,184,109, 72,113,234, -237,116,165,197,177, 54, 82,143,185,194,138,164,184,249, 16,105,241,143, 44,103,208,121, 50,164,146,226,240,182,220,119, 4,235, - 37,164, 65,153, 92, 80,137,106, 70,139, 82,125,151,164,197,155, 93,168,123,196,123, 46,150,251, 8,240,252, 17,238, 40, 42,185, -170,222, 34,155, 80,141, 16,150, 88,230, 75,114,101, 51,130,141,103,113,118,222, 84,228,199,126,232, 95,240,106,136, 16,215,189, -218, 86,235,201, 53,185, 52,220,146, 81,114, 92,236, 97, 49, 90,112,128, 36,194,166, 1,146,181, 52,236,199,138, 84, 53,147, 85, -149, 73,182, 92,129, 6,223,109, 81,169,207,198,147, 79,163, 83, 41,232, 5, 82, 81, 29,145,152,108,180,165, 54, 91,134,211,156, -200,113,210, 18,218, 3,193,103,153, 99, 39,101,145,165, 85,144, 39, 49,211,208,128,187,218,251,146, 58, 53,134,171, 94,215, 4, - 88,173,147,175,226,120,170,103,246,122, 6, 21,149, 44, 27, 66,168,189, 44, 37, 67, 23, 6, 68, 33, 36, 54, 58,210, 58,127,236, -202,171,173,165,149, 12,145, 11, 77, 10,223,167, 90, 47,203,153, 93,154, 39,203,117,178,229, 86,225,153, 22, 43, 10, 90,217, 97, -108,173,148, 73,109,194,197, 34,138,149,128, 98,176,158, 86, 18,160,180, 32,169,197, 18,171,243, 12, 71,188, 39, 42,174,205, 61, - 18, 45, 72,169, 45, 52,144,181, 82, 30,158,238, 86,184,179,219,134,160,218,163, 82,146,160,225,109, 14, 58,219,178, 20, 76,135, -249, 18, 91,109, 56,227,176, 25,153, 75,137, 81,185,166,184,212, 78, 68,193,165, 81, 33, 56, 20,195, 85, 39, 10, 11, 82,165, 48, -193, 47, 87,234,137,240,209,202,128,158, 72,168, 70, 91, 66, 74,214,240,187,209,162, 25,147, 29,241, 80,243, 20, 40, 45,185, 21, -234,107,146, 57,170,243,146,235,172,178,227, 19,125,225,132, 36,196, 91,197, 42, 68,112,151, 28, 82, 94, 80,113,210, 62, 13, 58, -210,106, 66,183, 75, 35, 17,168,117, 97,109,198,228, 16,111,212,237,190,224, 90,197,113, 23,172,103,117,158,190, 74,182,147, 48, - 80, 99,105, 64,211, 10, 1,101,209, 78,168, 99, 38,107,105,141, 52, 17, 20, 68,221,110,162, 55, 14,212, 81, 18,171, 73, 69, 54, -151, 80,170,193,183,229,135,231, 85, 42,149, 41, 47, 79,143, 80,247, 20, 52,203, 16, 98,229,240,126,168,115,170, 31,125, 39,149, -208,202, 26, 10, 40,231,230,113,232, 15, 68,139, 87,166, 53, 26, 60,198, 94,122, 51, 68, 71,148,250,148, 25,103, 63,162, 83,229, - 41, 41, 99, 37, 69, 44,160, 37, 60,201,103,152,129,206, 20, 27,135, 43, 8,141, 22,153, 2,220,110, 28,171,174,170,134, 89,142, -153,169, 66, 35,209, 88,108,174, 57,126, 80,125, 99,220, 96,135, 91,113, 92,141,161, 33,199, 27, 75,101, 92,216, 34,241, 2, 53, - 62,152,134,101, 34,161, 49,233,206,169,137,117, 56,178,156, 90,231, 45,245,190, 29,112,130,215,199,159, 17, 9,113, 10, 64, 72, -240,130, 80, 82, 83,212, 76,105, 31,217,222, 25, 64,230,104, 8,110,162,224, 1,102,223, 85,193, 99,246,172,183, 96, 73,103, 47, -101, 81, 84,230, 84,205, 52, 18,164,134, 72,163,156,202, 35,140,221,164,118, 98, 85,165,150,214,109, 39, 74,162, 72,246, 71,229, - 5, 65, 26,139,159,203,207,219, 83,176,204,240,223,237, 79,227, 35,111, 41,204, 69,139, 67,175,238, 80,222, 59, 98, 36, 38,195, -113,161,208,183,162,149, 7,112,132, 52,182,144, 3,101,170,213,102,182,215, 40,232,148,176,158,221,135, 48, 73, 36,100, 96, 99, -184, 61,250,246,212,159, 62,150, 45,137, 6,222,246,135,108,254,224, 66, 67,137,123,117, 56, 94,183,220,168,135, 22,209, 74,230, - 88, 87,181,215, 66,109,109,161,180, 2,209, 52,250,172, 0,176,165, 45, 68,165, 61, 64, 1, 34, 48, 64,228, 21, 18, 15,251, 56, -236,115,211, 86, 37, 3,171, 82, 68, 23,236, 70, 90, 53,182,195, 76,108,209,131,111, 66, 22,227,189,136,190,247,199, 60,230, 49, -152,171,170, 80,253,162,193,143,184,200,162, 66, 62,237, 86,255, 0, 76,120, 41,206, 48,160,113,145,142,217,207,150, 15,125,123, - 0,227,148, 14, 92,116, 63,209,247,244,215,220, 39, 25, 35,191, 83,230, 71,159,125, 87,109,178,242,146,134, 70, 92, 87, 96,172, - 36, 4,128, 84,165, 45, 71,162, 80, 0, 36,146,112, 0,201,233,173,195,210,228,218,223,187, 26, 93,174,118,199,134, 90,117,213, - 33,166,208,167, 28, 90,185, 80,132, 2,165, 40,158,192, 1,174,165,240, 33,236,163,226, 11,141,133,195,187,161,181, 31,108, 54, - 57,185,170,102,161,188,215,148, 9, 46,210, 42,138,140,234, 81, 54,157,182,214,243, 78, 53, 39,113, 42,232,234,133, 62,203,140, - 81,226,186,164,251,205, 65, 68, 45,141,111,127,178,155,217, 11, 7,117,232,244, 30, 38,184,174,161,203,107,103,231,248, 21,109, -173,218, 73,190,241, 78,168,239, 51, 13,168,169,155,182,242,228, 90, 36, 81,246,136,186,131,238,144,210, 90,151,113,134,203,171, - 91, 20,149, 36,203,150,181, 2, 36, 72,241, 41,180,202,125, 62, 5, 42,149, 74,131, 14,149, 68,162, 82,162, 70,166,209,168,180, -168,109, 37,152, 52,202, 93, 50, 19, 72, 98,155, 79, 98, 58, 66, 90, 97,150,208,219,105, 24, 66, 83,166, 25,243, 9, 42, 36, 48, -211, 63, 42, 59,216,200, 44, 75, 90,215, 17,131,112, 7, 91,187, 2, 54,178,171, 92,178, 89,124, 43,192, 18,102, 49, 69,153,103, - 74,240,208,200, 3, 69, 2,157, 18, 76,166,196, 60,141,179, 69, 19, 15,178, 22,210, 56, 58,131, 70,186, 89,244,203,132,143,102, - 23, 8,220, 37,199,165,207,176,182,222, 37,237,184,240,218, 71,188,239, 38,234, 68,167,221, 55,203,178, 8, 5,199,104, 48,157, -143,245,101,141, 16,184, 57,155,143, 75,138,210,217, 36,230, 83,228,243,158,151, 69,160,187, 49,126, 36,133, 58,235,129, 35, 46, - 60, 86,226,143, 94,131,153, 68,246, 24, 3,200,118,213,202,135, 74,248, 27, 28,132,168,164, 41, 71, 3, 60,167,178,137,239,204, -123, 15, 64, 52,232,211,232,248, 74, 64, 64, 35, 29, 71,146, 73,235,146,113,212, 96,254,205,107, 90, 40, 75,114,198,159, 86, 38, -236,109,251, 76, 73, 38,219,253,162,109,208, 91, 22,226, 81, 83,208,192,148,180,116,233, 71, 78,189, 18, 53, 84, 94,219,144,182, -187, 30,236,110,205,212,155,226, 36,191, 73,131,133,184, 14,237,254,198,241,107, 70,166, 37,170,205, 10,172,246,199,238, 12,230, - 90, 72, 51,232,213, 6,101, 92, 59,127, 50,122,210, 50,227,241,167, 51, 87,134,218,213,158, 86,166, 6,193, 0, 1,168,116,169, - 41, 33, 39,204,245,237,215, 39,203,251,117,250, 82,251,111,182,226,159,122,123, 47,248,158, 68,212,183,205,103,209,237,109,192, -166, 56,164,149,248, 53, 59, 98,234,166, 45,165,183,223,145, 74, 98,100,132,103,253, 85,145,219, 95,154,217, 61, 0, 4, 2, 74, -134, 8, 61, 7, 49,198, 52,227,147, 73,255, 0,165, 66, 15,216,112,195,220, 36, 0,159,222,225,201,223,169,197, 33,199,180,137, - 77,196, 45, 34, 0, 5,116, 17, 74, 69,250,190,167,136,155,109, 98,194, 32,222,246, 36,247,192,206,116, 56, 35,174, 1,207,238, -253,186, 25, 65, 61,243,212,246,243, 7, 26, 53,192, 0,199, 55, 83,220,158,189,254, 95,142,132, 88, 87, 83,128, 65,237,142,152, -192,193, 56,199,174,159,241, 15,192, 46, 18, 50, 66,124,241,246,227,185,249,232, 98, 58,147,216,252,251, 39,236, 30, 90, 53,207, - 47,191, 65, 58, 65,207,175,110,189,250, 16, 14, 52,178,244, 30,252, 20,218,254,159,207,182, 5,112,227, 39,190, 51,142,131, 31, -120,199, 78,154, 17, 68,242,243, 31,159, 40,251,126,126,154, 37, 72, 61,249,137,198,122,121,118,238,122,245,213, 5,161, 68,100, - 16,191, 34,124,135,231,247,232,227,183,207,254, 48,111,134, 5, 42, 36, 16, 71,124,114,231,182, 61,126,122, 29, 68,103, 25,234, - 1,232, 6, 0,235,229,162, 84,147,145,215,246,116, 0,106,130,240, 62,121,237,229,142,217,251,124,180,162,141,133,183, 31, 63, - 61,177,144, 1, 62,151,192,138, 73, 25,229, 57,201, 57,255, 0,103,240,208,221,251,232,197, 2, 50, 70, 0,235,156, 30,227, 61, - 50, 61,116, 50,192, 29,129,245, 39,203,236,252,116,170,117,249,219, 10, 40, 4,116,183,200,197,185,230,249,199, 41, 42,198, 70, - 82, 58,103, 25,238, 71,150,116, 51,141,184, 1,235,202, 2,112,144, 0, 36,143,159,167,158,174, 42, 0, 30,132,158,249,207,174, -132,121,178,164,158, 85,169, 7, 39, 24,254,119,219,234, 51,165,176,110,158,235,226,222, 82,148,255, 0,148, 36,147,212, 99,211, -208,244,239,165,175, 69,181,182, 0, 82,148,225, 61, 73,192,233,242,239,165,161, 99,233,140,227,210, 7, 92,249, 15,233,252,157, - 20,130, 49,129,223,185,251,245, 65, 32,224, 12,117,234, 63, 19,255, 0, 13, 86, 64,238,124,199, 76,122,104, 96, 96,148,167, 3, -175, 66,127, 28,126,227,253, 90,168,210, 0,200, 56, 61,207, 79,158, 58,231,243,223, 84,210, 73,233,142,131,166,126,239,219,162, - 91, 73, 57,233,223,215,207,166,147,112, 55, 61,255, 0,241,129,143, 96,121,224,159,199,161,251,180, 91, 63, 23,113,203,215, 25, -238,123, 13, 83,109, 35,160,235,215,175,223,141, 18,148,131,208,116,233,158,223,102,147,193, 77,141,238,118,193, 72, 79,216,122, -118,249,250,227,203,207, 85,146, 1, 56, 61, 61, 49,251, 7,109, 14,216,230,198,125, 50,122, 99, 68,160, 2, 64,198,125, 63,225, -164, 90,192,144, 62,122, 97, 28, 86, 29, 14, 58,140,121,159, 62,158,186,218,174, 11,120,121,159,197, 23, 18,123, 87,179,145,130, -147, 79,185,110, 40,206,220,178, 66, 73, 76, 27, 74,150,164,207,184,229,172,143,213, 6,158,202,219, 7,253,105, 35, 90,172, 1, -206,113,144, 59,143,159,245,234, 71,254,193,173,178, 98,146,141,245,226, 34,165, 22, 63,188, 82,169,144,118,234,211,150,250, 66, -158, 98, 93, 83, 19,235,142, 70,200,253, 26,253,223,221, 91, 42, 24, 61,198,152, 56,151, 50, 57, 86, 77, 91, 84,173,166, 80,186, - 80,142,161,155,107,143,122,130, 91,254,220, 76, 56, 7,134, 79, 24,113,142, 65,195,218, 75, 67, 95, 58,243,173,255, 0, 2, 48, -101,152, 92,116,213, 26, 20, 7,179, 48,196,149,103,214, 45,203,102,139, 77,179,109,136,172, 83,237,139, 54,149, 2,215,182,224, - 65, 9,106, 37, 62,145, 72,142,136, 76,165, 49,147,211, 5, 45,100,145,212,231, 39, 86,118,235, 42,143,200,227, 47, 37,210,234, - 18, 24, 83,124,167, 5,120, 37, 7, 39,169, 39, 31,142,154, 22,235,241,228,173,213, 7, 98,188,149,229,164,178,233,228, 89, 82, -186, 30,101,122, 21,107, 39,167, 33,181,182,204, 85, 70,113,109, 7, 2,195,161,204,169,167, 50, 20, 18,130, 15,196, 61, 53,201, - 85,114,187,206,236,205,119,148,147,111,221,239,252,122, 91,240,246,231,132, 50, 26, 12,191, 43,166,165,142, 30, 84, 80,168, 93, - 32, 13, 58, 85, 84,105,177,176, 1,109,176, 91, 3,211, 99,135,136,196,145, 38, 52,105,210, 76,121, 79,186, 10, 76,117,169, 45, -200, 65, 31,170,160, 65,233,140,104,132,199, 66,144,161, 62, 50,221,107,148,150,150,164,248,168,109, 67, 33, 74, 86, 6, 71,200, -131,160, 41,209,224, 56, 99,202,116, 72, 15, 50,217, 66,222,125, 75, 64,192, 24, 0,163,205, 35,215,229,172,162, 35,108, 56,218, -125,222,104, 97,121,193, 42, 81,113, 50, 18,162, 73, 1,181,118, 3, 58, 69,199,148,148, 66,227,107,244,216,237,190,219,127, 28, - 18,170, 83, 9, 43,230,178, 30,161, 74, 4,185, 54, 11,164,181,128, 27, 95, 77,200, 59,139, 97, 81,169,202,247,134,228, 67, 90, - 39, 71, 36, 55, 34, 19,199, 15, 6,193, 24, 91, 89,234,160, 7,109, 86,220,221,191, 69, 90, 85,181,115, 68, 96, 46, 68, 6,140, - 7,138,147,149,150, 82,160,166,208,188,140,168, 39, 39, 25,242,233,167, 58,137, 71,166,201,142,194,201,142,212,216,196, 6,229, - 50,121, 11,153, 61, 65, 3,161,199,207, 78,207,240,125,201,244,162,195,141,165,106, 65, 67,236,188,216,248, 92, 90, 48, 74, 84, - 7, 98, 83,144,126,221,106,152,228,100,145, 44, 64,101, 22,223,184,183, 79,141,173,235, 98,111,138,187,136,120,137, 99,171,130, -101, 58, 30, 38,100,109, 86, 82,202,195, 78,228, 88, 56, 32,141,236,172, 58, 16,109,124, 91,182, 90,193,101,183,152, 82, 35,165, - 30,248,200,113, 65, 41, 9, 79,140, 82, 57,198, 49,211,152,245,251, 78,155,223,104, 77, 33,251, 91,135,122,140,200,202, 44, 42, - 69,199, 77,109, 75, 9, 39,197,247,120, 85, 7, 27,105,208, 6, 86,128,176,147,145,219,151, 56, 58,220,141,174,167, 53, 29,232, -216, 70, 58, 14,152,232,133,143,214, 72, 31,205, 26, 97,253,170,148,143, 23,133, 86,229, 70, 46,101,187,202, 15, 56,105, 57, 89, - 75,148,154,162, 84, 79, 78,191,171,143, 92,159, 93, 75, 50, 90,104,205, 42,203,166,242, 70,111,241,189,135,243,239,235,142,124, -204,184,154,105,248,255, 0, 33,161,119,211, 75, 85, 83, 4,100,118,176,147, 86,254,237,133,254, 24,136, 5, 65,227, 38, 82,145, -202,226, 39, 41,110,184,151,185,156,241, 27, 46, 17,149,180,210, 23,200,250, 75,169,109, 32, 45, 42, 64,235,207,202,174,244,225, - 84,213, 6, 69, 67,223,225,189, 84,158,167,131,113,207,129, 29,150,216,138, 80,148,182,153,212,240,151, 19, 0,248,133,126,240, -180,243,120,152, 79,110,128, 7, 61,166, 95, 74, 93, 83,147, 93,247,105, 92,175, 73,101,190, 69, 71,105, 74,202,153, 10,108,130, -212,142,100,163, 40, 88,230, 36,130,160, 83,202, 52, 77, 26, 68,232,229, 30, 27, 79,123,184, 37, 79,205,166,196,101, 85,116,182, - 73, 71, 35,108, 72, 90, 68,166,220, 46, 4, 56,180, 23, 84,209, 5, 97, 7, 3,149,225,214,234,123,129,216,253,221,239,113,176, - 23, 3,174,219, 95,167,161,116,245, 3,200,177,221,159,162,132,176, 97,182,229, 73, 27,128, 53, 11,223,179, 1,176, 39, 14, 61, -179,110, 49, 87, 92,138,164, 73,146,233,178,165,150, 16,227, 84, 69, 42, 50, 94,109, 10, 71, 71, 96,168, 22, 37,159,133,105, 75, -193, 9, 83,132,168, 41, 95, 14,158, 74, 45, 26,235,147, 34, 76,184,244,134,171, 40,104,204, 83,146, 41,175, 68,162, 76,140, 26, -117, 76,161, 51,233,207, 31, 0,115,161,149,165, 62, 10,135, 57, 87,234, 12,157, 54,148,138,123, 5, 81,133,159, 38,108, 39, 22, -195,242,231, 68, 66,152,157, 2, 68,128,208, 83,174, 57, 5,247, 3,144, 18,140,142,105, 41, 91,107, 89, 89, 79,134, 84,158,109, -108,157,156,170,253, 2, 24,110, 77, 1, 74, 65,106, 28,151,106, 52, 57, 77,206,132,236,118,255, 0, 72,150,159,167,169, 41,148, -219,202,116, 37,124,170,241, 18,165, 16, 50, 10,136,212,110,190, 89, 0,102, 91, 57, 54, 10,173, 96,125, 45,246,150,247,176,217, - 88,139,245,185,184,195,137,205,164,100, 34,153, 99,169,146, 43, 14, 92,202, 82, 66,118,230,106, 62, 73, 25, 71, 75,134,111, 41, - 23, 70, 4, 1,238,148,138, 91, 79,179, 2,163, 42,161,107, 43,221,217,145, 13, 23, 52, 5,211, 28, 76,196,148,190, 35,243,188, -223,129, 37,188,163,195,105,198, 94, 1,193,212, 37, 68,105,199,141,108,212,103, 60,153,146,233, 80,100,164, 73,113, 42,158,134, -163,128, 66,210,128,223, 59,193,178, 90, 87, 40, 29, 82, 74,185, 79, 84,231,174,179,235, 33,170, 93, 82, 77, 65,154,147, 17, 46, - 76,178,176, 41, 85, 40,140, 45,104,144,248, 64, 74, 13, 62,115,105,115, 41,101, 46,164,185,225,171,144, 31,132,142,153,120,104, -155, 91,103, 58,196,127,118,165, 59,108,201,150,211, 50,140,139, 86,167, 83,165,188,209, 10, 66, 17, 17,112, 22,243,140, 60, 16, - 72, 81,231, 97,105,115,147,153, 93,245, 22,146,172,134,180,138,209, 72, 58,244, 55,189,174, 71,217, 35,212,143, 54,251,139, 30, -173,181,252,117, 14, 86,239, 28,240, 77, 72,225, 81,117, 42, 44,182, 50, 45,220,171, 22,130, 84,251, 42, 72, 28,237, 90, 65, 85, - 58, 66,227, 1,178,236,216, 17,129,148,194,170,116,121,146, 79,188, 38, 93, 38, 95,133, 10, 82,217, 78, 91, 18, 24,229,114, 60, -196,167,194, 87,134, 28,105, 10,115,149, 65, 71, 7, 26,218,107,126,109, 90, 10,162,154,132,152, 21, 33, 32, 55,133, 48,201,165, -212, 26, 80, 33, 63, 20,102,159,113,167,222, 82, 65, 82,130, 11,105, 73, 39,225,199, 46,172,180, 45,177,175,198,113,230,233,151, -117, 62,124, 98,178,148,183, 92,183,144,196,137, 9, 81,248,202,103, 82, 28, 65,109, 73,194,146, 20, 24,229, 74,149,158, 83,170, -151,157, 90, 22,218, 91,117,139,187,113, 17, 73,181,172,155, 85,134,101,215,110,181,213, 99,253, 77, 72, 98, 68,134,161, 70, 15, -171,149, 18, 12,199,165, 63, 30, 59, 44, 48,211,146,228, 58,240, 75, 8,112,149, 16,164, 80,243, 60,247, 50, 62,199,125,199,193, - 73, 23,219, 99,125,143, 82, 0,239, 80,241, 39, 21, 71,196,149,209, 83, 82,212,174,107, 81, 80,226, 56,226, 80,230,162, 70,147, -234,226,138, 33, 50, 71, 80,238,238, 21, 99,138, 13,122,152,170,128,194,195, 15, 28,122,147,162, 40,105,244, 58,132, 37,223, 18, - 3,231,194,234,242, 86, 28,114, 59,165, 43, 30, 26,249,214,164,228,128,219,188,202,202,185,192,213,242, 37, 81,151, 30,143, 37, -197, 57,226, 48, 3, 43, 43, 9, 11, 44,184,174,102,157, 83, 95,206, 90, 22, 66, 70, 64,200, 86,124,137, 13, 21,189,112, 82, 46, - 11,114,151,114, 91,117,216,119, 21,175,113, 83, 33, 86,232,117,120,238,174, 76,106,173, 26, 82, 67,145,101, 66,125,192, 11,141, - 45, 4,130,146,128,164, 41, 37,183, 57, 92, 66,210, 3,147,114,251,147,205, 46, 54, 83,202,178, 2, 20,226, 80,132,161, 96,169, - 73, 10, 36,120,173,129,204,140,147,204, 20, 64,198, 59,150,162, 37,117, 42, 5,134,194,253,108, 65,216,110,125, 71, 75, 11,250, - 92,139, 85, 45, 11, 75, 83, 85, 72,209,180, 51,196,206,140,172, 25, 25, 24, 29, 14,146, 35, 0,209,184, 32,134, 82, 46, 24, 18, - 55, 26, 78,240, 90,213, 31,208,130, 86, 9, 4, 18,130, 72, 73,229, 80, 42,230,108,126,177,199, 46,112, 65, 25,207, 93, 58,209, - 39,130, 16,145,159,214, 81, 60,157, 65,194, 72, 0,114,156,158,128, 96, 14,165, 71, 30,128,234, 46,217,220,212,153,116,202,237, -193,112,215,105,214,197,177,108, 64,126,171, 91,175,213, 37,166, 53, 46,151, 79,136, 18,100, 76,145, 41, 67,244, 76, 39, 45,163, -148, 5, 41,199, 22,134,154, 11, 82,210,147,121,177, 56,210,225,140,221, 20,202, 80,185, 43,180,231, 43, 85, 4,209,236,251,142, -240,181,165,219, 54,109,110,224,123,244, 52,198,233,213,121,111, 56,150,164,191, 39, 34, 8,154,220, 70,223,145,203,133,133,114, - 37, 82, 44,159, 40,174,158,140, 87,178, 8,168, 83,237, 72, 72, 38,202, 69,200, 91,220,219, 97,125,133,250,145,136, 77,103, 11, -113, 14, 98,249,179,100,188, 59, 93,159, 12,160, 94,161,169,105,165,154, 56,137, 78, 96, 87,150, 53,100, 83,203, 28,198, 91,150, - 88,129,148,174,133, 36,110,229,114, 79,128,205, 58,148,133, 31, 26, 20,100, 59, 45, 60,196,132,212, 39, 20,202,122, 50, 84, 70, - 84, 27, 10,142,218,188,129,109, 73,206, 70, 5,137,201, 14, 46, 63, 35,110,172, 30, 98,236,137, 60,136, 43, 66,208, 65, 73, 5, -196,225,111,114,171,166, 73,229, 9, 25,193, 3, 88, 95,215,200,158,183, 30, 67,206, 41, 43,116,248,202,117,107,231, 82,249,143, - 62, 86,165,101, 75, 43, 42,230, 4, 2, 9, 87, 55,198, 14,178, 38, 92, 98, 67, 32, 20,251,201, 8, 88,240, 16,146,164, 41, 67, -178,192, 65,194,147,145,216,231, 10,198,125,116,226,139,237, 51,153,109,101,216, 45,137,176, 85, 0, 40, 38,219,249, 64,243, 91, -246,186, 2, 70, 32,113, 80,251, 44, 81, 44,131, 83,130, 89,141,129,187, 49,212,196,131,181,139, 18, 64, 38,192, 90,228,140, 52, - 23, 71, 18,155, 27,182,247,133, 23,109,175,221,230,219,141,180,184,238, 72,209,228,209,169,247,213,194,220, 10,181, 86, 20,201, - 78, 65,135, 62, 60,103,163,251,172, 38, 37, 75,102, 75, 81,164,214, 36, 66,142,250,153, 91,141,169,214,146, 84,119, 30,147, 66, -165, 80,195,147, 41,232, 38,166,235,108, 25,149,121, 74, 76,250,173, 65, 50, 26, 67,141,184, 37,252, 94, 36, 34,194,208,182,218, -140, 81, 20,180, 82, 89, 10,109, 73, 89,131, 15,180, 99,113, 31,190,120,217,226,105,247, 21, 37, 48,237,189,193,122,201,132,220, -231, 27, 90,216,183,172, 58, 52, 11, 98, 37, 40,182,149, 41, 9,140,210,225,202, 12,167,155,149,105,150,162,177,158,154,222,143, -101, 55,180,158,109,129,120, 91, 92, 38,241, 1,118, 84,165,108,197,201, 83,133, 67,218, 59,194,177, 84,117, 3,105,238, 58,130, -145, 22,145,102,215, 42, 78,168,190, 54,130,167, 53,198, 99,180,128,239,129, 65,155, 33,153, 40, 74, 41,207, 76, 66, 18,163,204, - 18,106,169,105,103,136, 44,113,146,169, 37,205,135,152, 11, 55, 64, 21,137,251, 98,218, 65, 1,129, 26,156,119,103,137,223, 65, - 12,230,155,192,222, 23,241, 67,129,120,142,163, 57,207,166,202,105,115, 92,243, 34,120, 80,201, 36, 83,210, 71, 89, 57,203, 94, - 45, 47, 81, 37, 18,146,173, 69, 62,179, 89,161,231,164,145, 39, 16,209, 79, 40,202,229,206,203, 50, 92,167,210,208,107, 18,249, - 17,239,226, 44,119,234, 17,224,182,163,206,183, 36, 8,104, 87,141, 37, 68, 5, 37,149,169, 33,190,156,196,116, 73, 21, 52,233, - 79,123,195,137,167, 34,158,186,130, 89,101,234,213, 77, 81,234, 87, 35, 64,168, 41,152,136,167, 35, 45,198,233,144,132,186,180, -161,158,159,161, 42, 57,214,118,211,109, 82,144, 99,162, 60,122,107, 81,146,184,210, 98, 6,209, 25, 12,173,165,168, 41,185, 13, -180,145,149,165,224,224, 89, 57, 61,193, 61, 53,141, 63,114, 33,233, 11, 85, 22, 2,170, 6, 42, 84,212,185, 46,120, 80,168,201, -117, 77,148,182, 88,156,160,181, 73,125, 4,163, 41,105, 11, 32, 40,146,226, 20, 64,212,177, 40,249,104,218,136, 93, 29, 1,247, -238, 71,235, 92,237,232, 58, 18, 54,181,252,231,165,168, 98,130, 44,186,134,201, 24, 5,166,121, 54, 99,112, 87, 94,233, 10,130, -202,186, 81,249,136, 78,144,193,201, 44, 84,122, 5, 38, 28, 86,234,113,156,144,169,205,161,212, 57, 82,170,201, 76,201, 45, 60, -163,153,137,113,197,182,159,113,143,202,130, 20,219, 0, 33, 33, 33, 36,173, 0,232, 37,215, 92,148,250,153,181,195,113, 24,204, - 83,252, 40,144,178,220,218,116,212, 96,205, 77,188,203,169,196,146,181,168, 6,221,112, 41,150,139,220,205,165, 69, 32,139, 44, -136,107,113,106,122,179, 49,215,100, 48,241,113, 20,248,234,113,186,107, 6, 70, 20,166,155,136, 28,230,125, 10, 89, 0,151, 66, -148,164,164,149, 30,184, 24,253,199,122, 66,165, 47,234,152,208, 81, 88,170, 60,133,169,134,151, 37, 17, 89,142,182,144,160,195, -138,116, 16,184,175,115,146, 26,228, 35,152, 2,144, 10, 70,182, 97, 64, 14,163,229,113,223,173,246,245,220,141,236, 46,119,233, -208,144,112,239, 75,150, 79, 93, 50,162,150,205,103,109, 68,106,254,230, 52,186,181,201,144,170,200,168, 55, 28,194,177, 0, 89, - 74, 58, 49,195,130,197, 46,151, 71,143, 89,156,136, 50, 16,226,147,239, 45,220,146,230, 75, 91,181, 22,228,134, 85, 46, 53, 65, - 42,116,169,215, 27, 81,116, 21,143,136, 56,176, 83,223, 69,209,101,194,118,104,120,212,188,105, 41,116,182,242, 25, 83,206,149, - 54,218,214,160,181,186,242,194,131,168,108,182, 83,205,250,200,108, 3,147,240,233,134,126, 83,142,181, 21,235,160,213, 20,137, -105,109,136,245, 1, 33,149, 69,131, 86, 73, 74,228,162, 18,225, 47,194, 98, 66,176,143,133,208, 29, 73, 36,133, 44,128, 52,237, - 91, 17,157, 91,145, 84,244,169,143,180,227, 68, 21, 75,109,133,243, 33,111,129, 20, 74,114, 56,241, 39,182, 84,174, 82, 70, 20, -165,173, 69, 57,239,167,120,101, 42,241,198, 6,146, 55,181,138,219,126,164, 14,187, 16, 5,245, 16, 5,201, 45,115,133, 51, 76, -165,169, 40,229,154,170,189,170,102,150,227, 88, 37,145,130, 42,169, 88,221,140,154,183, 83,169, 71, 40, 43,236,138, 6,155,195, -227,233,107,174,155, 39,136,190, 10, 30, 97,107,118,164, 56,127,220, 70,158,146,160, 16,217,132,155,246,143,200,210,154, 35,155, -222, 4,191,120, 37, 71, 9, 82, 86, 10, 64,235,168,152,132,228, 28,164,164, 19,215,231,143, 77, 73,155,233, 79, 95,204, 87,248, -240,217,189,185, 66,217,147, 47,105,120,111,164,154,148,182,157, 83,138,126, 70,226,221,245,186,220, 86,150,133,146, 80,148, 83, -104,144,212,158,249, 18,186,147,129,168,234,237,246,223,222, 27,165,119,219,150, 21,133,110, 86,174,219,186,237,172, 68,160, 91, -118,213,189, 79,122,169, 91,174, 86, 39, 44, 34, 53, 58,153, 1,128, 75,239, 43,226, 82,212, 74, 91,101,180, 45,231,150,219, 72, - 90,211, 98,229, 79,202,203,150, 89, 92, 34,171, 76, 88,147,176, 28,199, 55,185,216, 11,111,185,252, 49,198, 60, 76,139,250,126, -189, 32, 28,197,102,132, 46,145,114,196,195, 16, 0, 0, 1, 44, 73,181,128, 4,182,214, 7,108, 96,193, 42, 89, 72, 66,114, 71, -100,165, 36,149, 99,176, 0,119, 58,237,167,177,211,217,215, 3,138,221,197,169,239, 54,241,210, 85, 43,135, 45,155,171,194, 77, -122,148,248, 83,108,110,166,227, 37, 13, 84,169, 27, 94,149,140, 21,219,145, 99, 42, 44,251,145, 77,156,169,135,162, 82,185,144, -185,207, 4,246, 39,129,175,163,187,181, 22, 69, 46,141,184, 92,116,214,164,223, 87,121,101,186,140,141,132,177,171,110,211,108, - 90, 17, 41, 14, 34,153,125,223, 20,181,162,117,229, 60, 3,201, 42, 45, 53,216, 84,224,161,200,151,229, 4,149, 43,177, 76, 91, - 27,113,181,244, 24,150, 14,210, 88, 54,166,216,237,189,188,185, 31, 81,216,214, 37, 26, 21, 6,221,166, 25,110,243, 75,144,204, - 24,141,132,174,107,238,225,201, 18, 29, 43,126, 67,129, 42,121,215, 23,130, 27,243, 44,205,164,167, 43, 26, 24,161, 39,118, 99, -165,220,118, 10,191,105, 84,157,152,182,150,181,202,117, 86, 19,158, 18,240,238,182,106,218, 90,236,242, 5,138,150, 59, 56,166, - 62,103,145,133,180, 9, 71,217, 84,185, 12,200, 75, 22,182,135, 80, 11, 12,100, 74,154,169,242,176,132, 54,203,109, 54,195, 44, - 71,140,203, 81,226, 70,137, 29,164,179, 10, 4, 72,236,165, 45,195,134,212,102, 91, 75,109,182,148,182,219, 76,161, 8, 74, 80, - 18,144,232, 90,112, 2,249, 93,117, 25, 66,146,209, 71, 66, 22,162,163,134,241,211,245,150,177,159,152, 58,106,104,113, 92, 82, -188, 39, 22, 57,159,117,107,144,172,114,134,208,144, 20,235, 77,249,242, 37, 62, 27, 96,249,156,159,144,217, 59, 62,158, 23, 33, -162,160,146, 26, 67, 60,168,236,129, 33,209,134,130,134, 48, 2, 26, 35, 31, 51,211, 77,180, 46,116, 52,199,224, 54,176, 30,128, - 14,214, 29,134,219,219, 98, 14, 47,113, 78, 21, 72, 3, 87,123,254,238,135,222,126,240, 59, 91, 14,157, 22,158, 26,105,164,172, - 5,168, 4,243,159,213,231,121,125,145,208, 99, 30, 93, 60,129,211,139, 26, 35,109, 54, 49,133, 17,220, 16, 79, 83,232, 60,250, -246, 31,187, 86,138,100, 68,165, 73, 8,229, 81,142, 64, 42, 86,112,183, 22,144, 21,130, 15, 85, 36, 19,242, 28,218,203,218, 78, - 49,240,169, 41, 70, 66, 74,122,165, 68,142,170,207,160, 57, 72,251,254, 88,216, 14, 90,230,251, 15,244,249,254,125, 48,211, 87, -166, 54,210, 5,205,133,251,123,192,239,235,247, 3,211, 99,142, 83,123,105,234,144, 40, 62,204, 78, 45,213, 56,172, 10,158,223, -193,161, 68,109,166,214,234,222,168,213,110,106, 44,120, 49,210,219,105,230, 42, 83,161,103,253,144,131,228, 53,249,148, 74,163, - 86, 33,178, 31,157, 73,168, 68, 97, 73, 37, 15, 75,136,244,102,150,130,114, 10, 29,117,176,149,119,242, 39, 7,166,117,250,228, -239, 21, 54,139,113, 81,162, 91, 21,234, 77, 58,187, 2,167, 53,185, 83, 41, 53,168, 81, 42,144, 36, 71,167, 16,227,102, 68, 9, -141, 45,167,146, 37,173,178,146,164,171, 5, 25,232, 70,154, 39,182,131,105, 43,148,145, 68,173,237, 86,217, 86,168,230, 58,226, -138, 93, 86,195,181,102,211,147, 24,131,204,194, 99,191, 75, 41,109,188, 19,219,175, 94,132, 30,186,205, 29,108,244,181, 21, 13, - 12,113,200,178,104, 7, 83, 48, 55, 91,237,178,176,177,213,114,119, 55,218,198,215,196, 43,137,120, 6,163,136,230,167,205,151, - 49, 90, 53, 72, 22, 32,134, 2,250,180,203, 43,106, 45,205, 75, 41, 46, 64,178,159,179,125,239,183,228,250,227,101, 60,188,224, -140,142,128,244,207,144,199,168,198, 48,126,122, 21,192, 0, 3,155, 35, 57,233,215,215,166,191, 65, 78, 47,125,129,220, 19,241, - 21, 2,167, 90,218,170, 35,252, 48,110, 99,233,144,252, 74,205,131, 29,202,134,222,212,103,172, 18,132, 92, 59,119, 53,242,134, - 99, 45,220,115, 59, 76,122, 43,169, 25, 41,109, 88,229, 48,230,227,131,217,183,196,255, 0, 1,119, 35,112,119,146,205, 19,108, - 74,180,247, 33,217,251,193,104,151,171, 59,105,118,144,165,248, 44, 49, 88, 13, 5,219,245,162,132,229, 84,234,138, 35,202, 73, -200,108, 58,145,204,100,244,217,164, 82,178,199, 50, 26,105, 9, 0, 92,221, 24,250, 43,250,158,193,130,177,236,164, 11,226,164, -206,184, 91, 56,200, 65,146,174, 1, 45, 32,219,159, 17, 47, 24,222,195, 93,194,188,123,216, 93,212, 33, 36, 42,187, 28,115,229, -210,158,163,169, 24, 62, 96,119,253,255, 0,215,160,212, 66,187,167, 24,232, 58,249,116,198, 49,219,174,141,117, 3,152,133,229, - 39, 56, 41,199, 80,122,227, 65,120, 97,165,169, 73,201, 43,238, 14, 79, 41,235,146, 61, 52,244, 14,192, 1,182, 35,160, 31, 92, - 14,231, 32, 73, 74,186,231,203, 24,251,137,244,208,101, 3,148, 32, 40,165, 57,236, 60,201,209,133, 63, 26,186,168,231,201, 71, -225, 29,187,121, 13, 81, 86, 50,122, 16,115,246, 12,124,177,163,142,222,236,103, 3, 40, 3,211, 29,186, 30,189,241,215, 57,208, -203, 24, 36, 15, 67,140,252,199,207,203, 69, 47,208,103,166,115,229,147,129,215, 62,186, 25, 64,244,230, 29,124,143,175,113,215, -212,233, 85,189,129,245,235,243,240,198, 69,172,126,125, 48, 42,129,193, 30,127,147,161, 85,246,156, 17,215,204, 2, 8,199,217, -162,148, 58,146, 20,122,103,207,167,159, 83,161, 92, 42,235,233,230, 71,159, 95,232,210,139,215,173,176,170,143, 95,157,176, 50, -206, 15, 76, 31, 80, 71,224,126,220,104, 85,168,227, 28,189,125, 61,126,206,154, 37,100,103, 3,200,156,244,243,249,232,117,227, - 57,235,233,242,251,180,182, 50,126, 54, 56, 25, 99,175,159, 81,231,229,242,210,215,178,172,119,200,244,198, 14,127, 31, 61, 45, - 40, 47, 97,229,191,200,255, 0, 79,155,224,126, 56,162,144, 64, 30,191,143,158,170,163, 62,125,137,232,115,220,250,106,159,236, -213, 69, 35,156,131,204, 71,166, 63, 63,156,233, 54,219,160,220, 99, 35,227,108, 20,131,208, 14,228,121, 99,231,251,116, 80, 56, - 35,184,249,250,104, 22, 57,146, 8, 81,234, 59, 31, 80, 60,243,247,232,209,216,117,207,207, 68,223, 77,200,244,254, 88, 24, 45, - 24,207, 92,231,203, 69, 35,207,183,239,208,173,124,207, 92,126,127,118,138, 64,232, 79,221,249,252,249,105, 44, 16,142,190,251, - 15,145,130, 80, 58,103,215,250,244, 66, 49,140,129,215,212,247,207,245,106,146, 48, 57, 79,150, 7,252,116, 64,193,232, 49,223, - 31, 97,210, 44, 79, 91,236,127,211,253, 48,153,183, 97,138,128, 40, 5,103,208,224,119,235,169,123,123, 41,104,112,173, 78, 2, -173,121, 73,134,167,220,191,111,139,158,183, 80,116, 97, 14, 1, 26, 65,131, 29, 41,199,146, 91,142, 0, 58,136,106, 65,193, 4, -140,224,156,227,211,175, 77, 75,111,217,163,113,199,172,240, 9,183,233,105,231,146,187, 86,241,187, 45,249,133,131,143, 9,213, - 78,114, 75, 97,196,121, 2,219,168, 32,158,224,244,213,121,226, 65,147,244, 28, 33, 13,148,206,186,191,254, 57, 45,142,131,250, - 49, 71, 12,158, 42,209,137,118,101,162,169, 41,214,225,249,148,226,226,196, 27,233, 45,211,181,251, 99,118,128, 83,114,214,210, -153,146,220,116,144,235,125, 10,212,129,205,144, 20,161,156,249,105,224,180,100,161, 50, 35, 25,130, 74, 80, 57, 85,206, 20,176, - 26,230,198, 22,164, 30,253,198,153, 40,181, 49,238,232, 92,122,195, 47, 73, 82,210,211, 81,100, 39,149,110,184,178, 82,218, 1, - 61,252,180,248,219,242,107, 80,222,162, 71,155, 77, 98,169, 61,192,124,102, 35, 56,130, 91,108,254,170, 94, 72,254,110, 58,245, -215, 54,213, 70,193,217,152,217,148,130,111,182,219,117,233,112,127, 28,123, 9,151,215,172, 84,113,194,236,164,181,215,237,232, -114,116,222,246,144, 11,142,228,222,194,248,216, 58, 84,210,135, 89,145,227, 49, 81,108,184, 26, 12,189,132,132,180,123, 21,146, - 58,249,103, 78, 29, 49,216,145,157, 46,202,141, 0, 50,165, 99,153,162,151, 0, 10,255, 0, 80, 14,216,207, 93, 55, 22,253, 58, -116,249, 14,180,186, 68,194,162,227,110, 41, 40,100, 22,154, 72,236,208, 41,238, 63,167, 78,237, 50,222,105,197, 50,210,160,203, - 5, 43,248,209,238,139, 82, 16,172,254,170, 84, 6, 15, 64,123,246,209, 97,137,100, 58,121,100, 21, 38,219,129,125,253,251,159, -203,124, 66, 51,202,138, 53, 13,169,202,221,119, 10,203,112,189, 71,216, 96, 1, 27,139,233,177,239,124, 60, 54,123, 86,252,196, -161, 45,162, 50,155,229, 7,170, 74, 10,129,238, 6, 71,112,116,252,211,104,240,209, 29, 41,140,174, 68, 20,228, 53,207,204,217, - 24,234, 19,232,174,250,105,109, 74, 83,112,209, 24, 57, 24, 70, 14, 44, 8,200,152, 24,136,167,206,112,124, 36,200, 90, 75,189, - 71,243,115,233,167,174,148,195,204, 73,247,101,182,182, 20,172, 18,219,237, 41, 33, 67,200,161, 67,203,168,237,167,136,114,230, -101,187, 11,252, 13,192,191, 66,125,255, 0,150, 57,147,139,234,195, 84,202, 96,169,114,138, 75, 0,206, 26,224,108, 77,134,219, -119, 54,216,237,113,131,109,233, 2,149, 48,165, 68,165, 30, 38, 65, 7,177,206, 58, 19,172, 11,142,250,104,187,248, 72,189,156, -100,243,201,160,212,173,234,211, 33, 37, 75, 0, 55, 52,196,120,156,116, 8,228,153,212,158,131, 26,214,142, 52, 56,200,162,240, -178,104,182,149, 18,205,170,110, 30,239, 93,144, 68,251,106,214,167,179, 37,200,145,162, 56,240,138,204,250,159,186, 52,167, 29, - 74,229, 97, 13,180,210, 74,150, 65,201, 72, 25,215, 24,110,255, 0,109,214,236, 89,181,169,123, 63,196,206,212,209,225,216,219, -139, 33, 54,133,121,152,140,200,163, 86,236,207,172, 95, 67, 44,213, 92, 50, 29, 90, 28,247, 39,220,142,243,241,228,161, 37,109, - 48,160, 22,133, 16,160,237,150,210, 77, 74, 30, 57, 24, 4,148, 29, 42, 55,123,122,233, 0,155, 3,252,176,190, 77,224,151, 30, -113,173, 21, 7, 27,228,116, 52,241,195,151,149,172,136, 84,213,193, 77, 53, 92, 16, 72,162, 73, 41,163,149,129,100, 44, 12,107, - 36,134, 56,222, 75, 34,185, 39, 28,240,171, 81, 92, 18,235, 15,189, 50, 83, 15,182,251,205,242,193, 1,135, 11,172,188,227,129, -215, 90,116, 41, 15,167,152, 55,128,160,127, 87,190,113,171,197,186,251, 84,199, 27,110,231, 91, 11, 8,109,105,102,164,211,204, -152, 75, 4,120,205, 50,166, 93, 67,142, 51, 33,194, 84,147,146,190, 85, 0, 82,178, 59,103,187,207, 96, 84,168,155,135, 92,164, -148,251,168,139, 80,118, 74,101, 49,206,195,115, 26, 83,165,196,200, 97,164,164,165, 44,172,160, 41, 39, 56, 83,110, 36,144, 0, -213, 45,183,165,251,180,225, 57,214, 41,211,231, 46, 59,134, 32,155, 57,137, 75, 47, 56,165, 48,251,207, 7, 20,216, 97,211,207, - 28, 22,210,121,212,147,204,148,242,228,105,122,137, 21, 98, 46,198,247, 22, 0, 1,112,118, 0, 3,218,222,150,216,220,157,247, -199, 91,101, 89,173, 61, 78, 87, 77, 84, 36, 38, 42,136, 21,215, 65,180,182, 96, 28, 89,154,203,123,157,181, 30,246, 5,126,214, - 30, 11, 94,207,114,229,117,201,237, 69,164,202,120,197,143, 54, 85, 82,157, 37,183,147, 22, 59,235,108, 65,134,165, 70,194,224, - 61,226, 33, 45,144,231, 55, 47,196,226,209,149,116,219,107, 39,110,107,207,161,154, 43, 53, 69,192,105,220, 59, 45, 51,224, 51, - 86, 64,151,226,135,152,104,200, 64, 67,211, 90, 7, 24, 74, 94, 41,111, 9,230, 0,233,156,176,182,201, 77,169, 18,170,137,115, -223, 42,193,152,112, 99, 91,243,158,143, 35,199, 74,144,226, 36, 74,147, 13,192,137,144, 80,224, 4,151, 2,137, 82,194, 64, 37, - 56, 27,217,102, 90,215,133, 41, 49, 27,133, 84, 98,165, 57,224,159,142,189, 5,146, 26,113, 35,153,236,152,138,109, 46,169, 69, - 25, 87,137,133,140,117, 36, 18, 53, 10,175,145,203, 5,138, 80,109,208, 48, 59, 17, 96, 8,190,160,123,246, 0,108, 20, 27, 91, - 12, 57,247, 17, 10,106,116,134,130,190,154, 78, 89, 80,156,196, 87, 1,193, 91, 30, 97, 18,163,152,205,238,197, 65, 6,218, 88, - 22,108, 90,237,237,189,152,234,185, 95,164, 89,245,210,228,149, 56,245, 82,107, 53, 74,100,246, 35, 52,164,165,243, 25, 77,135, -115,204,242, 70,121, 29, 74,177,211,148, 96, 43, 79, 29,187, 98, 95,172, 58,106, 17,164, 80, 67, 45, 56, 12, 74,109, 70,100,217, -240, 85, 24,171,153, 44, 69,113,113, 82,236, 53, 20, 4,149, 21, 41, 69, 5, 39, 41, 86, 6,179,123,118,157, 92,141, 29, 16,156, -183,161,203,117,169, 45, 41, 85, 8,181, 70, 27,109, 47,173,212,248,236, 71,106, 84, 99,132,175, 36, 36,133,242,100,225, 68, 4, -141, 58,241, 37,169, 36,181, 81,162,206,163,163,196, 75,109,173,245,177, 34, 3, 69, 39,152,189,239,177, 10,146,225, 89, 79,232, -208,128, 73,194,129, 72, 61,117,169, 79, 70,103, 39,152, 2,179,118,234, 61,230,215,211,210,196,129, 98, 64, 29,141,241, 79,103, -220,101,153, 30,114, 70,144, 85, 43, 2, 13,228, 73, 14,130, 64, 58, 33,230, 2,133,252,192,233,140, 21,185, 0,130, 72,108,110, -143, 14,191, 8,188, 39,209, 80,234, 30, 65,115,252, 6,171, 17,212, 71, 73, 7,149, 40, 68,198,155,113,192, 74, 65, 61,137, 39, -175,124,235,131,126,216,205,247,152,111,141,190,225,194,146,243,176,233,118,141, 10,155,186,215,228, 17, 33,165,138,133,245,119, - 54,244,107, 38, 20,208,210,212, 86,213, 50,201, 6, 83, 77, 44,254,130, 77,220,242,193, 10, 9, 34, 68, 98,167, 69,113,239,115, - 98,162,209,150,227,169,100,164, 50,250, 30,142,153, 10, 67,104, 47,161,113,185,149,250,217,193,234, 7,124,117, 58,132,167,180, - 11,114,157,191, 56,207,226,110,235, 91,220,193,123,191,119, 82,161,167, 35, 13,210,109, 57,205,218, 52,134, 80,174, 65,250, 54, -233,246,252,102,210, 48, 48,150,250,247, 58,147, 81,229,101, 16,136,212, 49,107,111,110,151,247,223,215,107,145,238, 29,206, 45, - 63,161,246, 88,153,247,139,149,156, 79,155,208, 8,233,184, 47, 46,150,174, 32,203, 38,147, 89, 80,241, 82,211,189,164,119, 95, - 36, 18,213,200,157, 74, 75, 28,114, 11, 50,130, 59,157,236,172,221, 24,215,231, 13, 23, 37,147, 81,118, 25,168,236,189,253, 46, -152,218, 93,144,151,101, 53,102,223,141,191,116, 91,190, 19,107, 28,209, 97, 71,172, 69,186,152, 65,253, 80,165, 4,167, 7, 26, -218,107,158,228,161,191, 61,218,125, 49, 94,245, 40,172, 37,210,202,148, 67, 42, 11,229, 81,117,224, 57, 60,114, 15, 92, 2,160, -149, 14,100,228,234, 49,124, 2,239,229, 79,110, 55,233,155, 77,234,234,233,116, 45,237,130,141,181,173,200,114, 66, 99, 70,106, -181, 46,104,159, 98, 79,117,194,147,225, 52,221,203, 17,152,171,112, 17,134,171,110,142, 96, 9,204,138,108,186, 50,226,248, 65, -230, 94, 18,210,234,138,218,116, 40, 56,144,201,253, 42,228, 2,144, 82,232,125, 39,155,155,185, 24,199,163, 70,113, 75, 61, 53, - 66,211, 24,192,102, 80,250,173,177, 4,158,128,236,109,107, 27,244,244, 55,216,120,245,195,212, 92, 51,226,119, 20,241, 60, 83, - 51,208,241, 68,223,164, 41, 96, 4,170, 44,179, 42,251,111, 53,134,197,189,176, 77, 41,141,108,170,146,160, 98, 5,181, 97, 28, - 75,220,181, 26, 38,200,211,104,247, 69, 74,235,183,182,170,177,190,251, 65, 11,117,110,107, 14,159, 10,179,117, 91,182, 75,207, -220, 78,183, 82,133, 14,168, 4, 79,171,216,186,153,183, 21, 41, 82,210, 98, 36, 41, 9,115, 46,170, 58, 78,196,185,236,244,224, -218,187,107, 59,115,220,156, 71,239,126,228,237,173, 2,138,187,170,107, 84,230, 45, 75, 86, 5,193, 65,109,135,229, 52,252, 91, -142,223,106, 82,213, 70,114, 67,192,198,106, 35, 40,154,243,242, 91,140,151, 91,112,244,112,233,245, 17, 14, 44,120,174, 52,203, -140, 76,104,179, 45,183, 16,135, 25,122, 52,130,142,120,210,155,117, 36, 60,203,137, 64, 5,181,165, 73, 88, 7, 57,232, 53,131, -111, 20,122,181,183,183, 23,101,181,105,248, 52,138, 5, 74, 76, 74,251,148,250,116, 97, 1, 16,222,167, 60,106, 47, 70,165, 53, - 21, 77,181, 6,159, 41,244,182,244,150, 67,100, 56,236,116,184, 10, 10,220, 42, 89, 95, 56,135, 46,142, 10, 39,138, 88, 81,180, -202, 38, 14, 74,164,134,226, 72,138, 50,168,146, 61,200, 73, 86, 72,223,161, 85,177,213, 91,112,255, 0,139,220, 97, 77, 6, 89, -195,156, 53,196, 21, 60, 22,207,152, 77, 60,242,208,138, 52, 21, 75, 82,148,144,150,121, 38,162,154,174,158,178, 4,129,185,117, - 52,245, 41,169, 36, 80, 81, 94, 4,118, 96,232,187,243,188, 52, 58, 53,183, 22,179,113, 84,169, 53,196, 81,160,251,245, 41,201, - 62,244,245, 37, 30, 24, 17,105,181, 9, 10,121,208,245, 77,152, 9,140,153, 37,110, 58,225,146,151,148,235,139,112, 41,106,217, -189,151,227, 46,253,131,118,219,180,250,252,122,125,201, 79,118,165, 17,114,150,164, 24,178,216,166,197,117, 15,212, 36, 41,109, -252, 46,145, 13,149,146, 84,156, 16,146,163,211, 58,229, 18,107,239, 62,242,147, 37,199, 31, 91,206,242,186,241,117,192,165, 58, -115,211, 39,155,149,210,121, 78, 15,117, 43,161,198,175,245,237,208,133,180,123, 77,185, 27,181, 83,195,175,211, 41, 12,109,245, -155, 17,197,165, 15, 85, 55, 47,117, 95, 93,149,109, 82, 48,149,164,169,198,162, 73,174, 84, 86, 89,234,134,109,247, 20,190, 92, -115, 20, 34,161,174,138,166, 35, 73, 52,177, 73, 35, 11, 42,177, 35,177,251, 38,224,129,110,227,176,216, 3,139, 63, 49,225,124, -159, 58,137,168,171, 50,122, 67, 83,155,200,176,199,104,150, 37, 89,170,228, 17, 68, 21,129,214,136, 36,145, 64, 37,137, 84, 80, - 88,147,124,113, 55,116,247, 70, 69,253,187,251,165,124,248,206, 6,183, 3,113, 47,219,205,230,124,103, 29,108, 53,115, 87, 43, - 21, 40,234, 47,172,146,232, 75, 18, 90, 9, 39, 39, 13, 39, 9,232, 14,172, 14,214,153,120, 48,183, 78, 92,152, 57,157, 10, 37, - 43,109,167, 26, 13,184,150,207, 80,131,206,176,172, 30,169, 9, 5, 24, 32,105,155,145, 77,159, 79,177, 55,214,248,122, 99,102, - 14,214,238, 37, 54,195,167, 33,244, 45,181,207,144,221, 5,213,204, 44, 21, 16,151,138, 88,241,164,244, 32,167,198, 64, 82, 64, - 41,200, 53, 27,141, 40,118,147, 76, 15, 45,169, 62, 12, 25,243, 2, 86, 20,234, 16,197, 62, 19, 65,165,164,117,229,247,167,138, - 73, 61, 22,177,202, 7, 66, 69,171, 7, 12,211, 48,141, 68, 97,196, 42, 34,118,176,243,125, 68, 82, 27,237,230, 26,101, 64, 77, -183, 59, 94,221,125, 38,200,188, 76,203,114,202, 54,165,142, 67, 20,116, 65, 22, 8,217,183, 68, 90,250,204,182, 21, 7,236,171, - 60,153,116,228, 2, 70,148, 58,202,134,186, 15,209, 95,217,213,187,149,126, 36, 56, 44,216,253,206,187,174, 26,157,110,227,126, -218,126,193,186,149,240,199, 84,155,163,109, 39,191,101, 84, 39,204,125,144, 23, 80,149, 50,149, 75,163, 76,121,231, 85,202,227, -245, 23,148, 15, 58,213,173,192,169,181, 57,184,233, 69, 62, 75, 17,217,117,148, 54, 25,157, 8, 41, 77,184, 20, 57, 18, 85, 21, -196, 40, 55,148, 36,167, 33,106,235,158,185, 26,226,103,176,146,232,171, 73,224,105,202, 90,107, 52,248, 49, 97,111,182,232,183, - 25,185,145,221,148,239,233,169,118, 36,151, 91, 74,223,144,136,236, 44, 74, 46, 41, 40,108,169, 68,173,101, 73,230, 86,187, 41, - 49,154,218,209,205, 42,173, 52, 52,180,165, 74, 68, 70, 98, 69,116,182, 9, 42, 83, 15,150, 84, 82,172,173, 43,228, 0,100, 3, -231,140,166,170, 86,154, 21,107,179,160, 10, 88,238,110,160,139,147,114, 77,254, 59,238,122,227,195,207, 25,248,114,151,135,188, -100,241, 27, 44,203,158, 10, 60,158,155, 59,204, 26,142,156, 69,166, 56,105,158,169,228,130, 24,163, 88,121, 65, 97,137,146, 53, - 32,147,100, 5,141,201,182, 5, 94, 69,230, 10, 94,145, 46,158,251, 79, 45,104,148,212, 6, 23, 14, 74,219,229, 12, 45,182, 36, - 58,225, 37,149, 97, 25,231, 83,121, 7,151,152,115,103, 88,171,145,168,116,244,134, 97,194,115,222,240,219,142,210,234,106,145, - 26, 99, 65,211,209,246,222,146, 74,159,116, 16, 64, 41,113, 93,130, 80,224, 61, 53,146,220, 18, 42,169, 71,189, 65,175, 23,224, - 43,196,110,100,138,180, 52, 73,141, 20,132,150,219,121,201, 49,146,211,140, 32,184, 66, 20, 84, 8, 65, 74, 73,198,117,138, 87, - 28,148,234,162, 34,187, 74,117,192,134,195,141, 85,221,124,204,165, 74, 66, 64, 8,106, 33,105, 1,113,212,225, 81, 86, 31, 66, - 49,205,221, 67, 11,214,189,142,171, 48,185,237,109,186,218,221,251, 94,219,220,117, 0,118,198,190, 89,205,228, 83,161,104,226, -136,234,212,180,224,194,199, 64, 4, 7,140,136,249,140,128,157,144,137, 21, 72,107,233, 54, 57, 45, 21,111, 50,239,128,212,167, -155,106, 99,237, 53, 50, 5, 82, 58,170,112,130, 22,133,248,114,226,201, 82, 20, 84,194, 84,162, 75, 79,133, 20,150,202,144,180, -144, 70,158,219, 70,151, 29,231,155,118, 60,104,204, 22, 63,193,222,142,151, 20,169, 10,146,203,194, 58,208,195,190, 63,232,220, - 83,255, 0, 26, 27, 64, 12,165, 9, 10,230, 9, 32,105,148,162, 91,141, 33,248, 83, 89,126, 99, 48,230,182, 20,180,198,150,244, -129, 79,113, 60,188,170,101,153,170,115,222, 32,173, 37, 93,149,240, 99,149,124,169, 9, 89,109,184,249,226, 98, 31, 5,220, 21, -239,191, 17, 15,200,136,155,150,213,178,166,210,246,246, 59, 73,141, 4, 86, 55, 54,239,228,181,236, 42, 83, 8, 90,185, 31,124, -220, 21, 40,178,202, 18,149,144,213, 45,220,101, 41, 86,157,232,209,181,169, 10,100,111, 40, 23, 59,177, 54,181,129, 23, 4,146, - 58, 1,212,220, 92, 98, 11,198,117,212,212,212,243, 58,213, 20, 77, 12,210, 54,146, 52,132, 30,109, 96, 29,244,170,155,187, 57, - 42, 0, 96,197, 77,204, 4,253,172,219,203, 47,139, 95,105,175, 18,183,101,176,204,138,245, 61,141,200,141,179, 22, 18, 41, 9, - 93, 86, 93,102,147,182,162, 46,222,210,152,166, 51, 24, 19, 62,108,219,142, 29, 80,176,134,211,151, 87, 57, 0, 2, 78, 76,168, -189,147, 30,205, 59,119,129,141,189,137,185,219,145, 71,167,212,120,177,191,168, 72,110,225,150,239,131, 57,157,155,182, 42,104, -109,241,183, 54,188,132,130,150,171,238,183,225,154,253, 69,162, 22,251,224,192,105, 98, 36,114, 29,230,127,176,159,128, 53, 76, -144,190, 60,247,198,152,229, 94,166,106,149, 39, 54, 34, 21,106, 58, 84, 43, 87,116,135,159, 77,209,188,211,162, 60,140, 58,227, - 18,159,150,197, 29,103, 9, 19, 37, 74,154,140,150,153, 34, 80,232,121,231, 86, 94,194,151,206, 84,165,229, 89, 83,132,156,149, -100,255, 0, 59,169,238,117, 52,214,174,144,192, 15,246,106, 75, 42,129,210, 73, 19,102,115,254, 20, 96,116, 95,171,221,172, 52, -163, 53, 11,192,252, 48,106,170,102,226,204,206, 29, 53, 57,147,188,180,145, 48,254,234, 41, 9,101,148,237, 96,238,166,209,126, -196, 86, 97,188,158, 91,213,199, 90, 49,104, 79,128,238, 30,144,121, 9, 61,192,192,201, 10,245,242,251,181,174, 71,196,148,241, -192, 74,219,247,143, 25,101,101, 88, 83,109,158,100, 32,143,231,159, 20,183,140,231,245,116,231,222,179, 3,236,178,194, 18,160, -158, 67,240,159,214,231, 63, 8,200,245,230, 7,246,107, 16,183,233,171,125,220,148, 41, 94, 26,193, 82, 72, 56, 30, 24, 42, 25, - 7,182, 93, 82,127,254,159,144,211, 69, 97,106,138,152,227, 83,176,254, 38,222,238,150,252, 15, 81,139, 78, 53, 68, 46, 72,176, - 83,107,124, 58,253,247,191,243,198,113,108,211, 19,227,169,194,215, 63,134,203, 99, 5, 93, 27,101,146, 22,246, 14, 62, 37, 45, -242, 7,255, 0, 71, 91, 55,104, 83,196, 88,200, 91,141, 21, 62,226,125,225,196,142,201,144,233, 1,182,178,161,208, 1,200, 7, -158, 18,112, 52,218,218, 20, 34, 11, 72, 82, 48,167, 29, 66, 86,162, 9, 37,168,227,198,115, 36,249,169,100, 15,158,126,122,216, - 74, 93, 56,165,176,160, 48, 80,160,230, 79, 96,234,193,228, 24,207, 80,150,250,245,243, 58,216,145,194,132,133, 59,122,123,247, -233,252, 61, 58,123,176,171,188,113,197,169,205,134,223,126,214, 23,251,250,216,250, 19,223, 23,184, 45, 45, 45,164,250,130,146, - 81,130,165, 58, 79,198,161,205,211,205, 71, 39, 29,135,217,171,242, 82,161,202,146, 14, 66, 64, 79, 92, 18,112, 18,132, 16, 7, - 82, 71,151,110,167,174, 79, 64,225, 49,204, 6, 74,148, 8,194, 60,151,142,203, 80, 0,244,206, 50, 62, 95,110,173, 87,197, 93, - 84, 74, 17, 76,101,242,212,170,171, 93, 62,154, 51,254, 77,126, 25, 50,166, 56,148,245, 8,102, 57, 81, 78, 59,184,180, 13, 2, -252,184,139,157,194,142,158,167,111,226,127,215, 17,237, 18, 87, 87, 69, 75, 8, 13, 45, 67,233, 30,130,251,146,127,194,160, 22, -111, 64, 9,233,134, 94,191, 60,214,174, 57,178,155, 80, 92, 88,138,250,178, 34,146, 73, 75,205,197, 89,247,133,181,215,245, 87, - 40,172, 41, 93,185, 91, 30, 93,117,113,101,178,148, 36, 20,167, 60,185, 33, 32,115,124,125,242,123, 32, 17,235,228, 58,103, 58, - 6,155, 5, 49,217, 1, 3, 41, 72, 72, 43, 80,202,251,124, 13,167, 57,231,230, 87,116,142,188,202,202,181,122,119,157,164,242, -182,128, 48,114, 74,210, 29, 82,148,174,231,149, 4, 14,112,122, 96,156, 36, 12,232, 82,130, 20, 22,181,207, 83,241,235,252,127, -134, 38,117,241,198,136,144, 66, 60,145, 40, 65,126,182, 80, 5,205,187,158,167,191,125,177,107,145,209, 56, 56, 42,192, 31, 7, - 50,136, 81, 39,245,114, 6,113,145,215,212,143, 62,186,109,183, 18,195,178,183, 58,203,185,118,235,114, 45, 74, 13,245, 98, 93, -244,185, 20,123,178,204,185,224,179, 84,161,215, 41,210,208, 90, 83, 50,227,188,143,209,202, 66, 15, 51, 50, 26, 45,202,140,234, - 80,244,119, 91, 90, 65, 46, 20,133,132,149, 18,121, 66, 82,146,158,167,227, 3, 9, 11,231,233,205,133, 28,116,233,240,231,231, -171, 4,167,130,146, 70,115,130, 7, 41,230, 1,190, 97,133,140,168,119,230, 25, 87, 47,167, 66,115,128,228,164, 50,233, 32, 21, - 35,161, 23, 7,226, 15, 81,234, 45,238,196, 78,170, 0,218,129, 93, 72,247, 12, 8, 22, 32,141,193, 7, 98, 10,220, 16,110, 45, -112,118,216,254,127, 62,215,111,101, 5,107,129, 75,173,157,208,218,223,173, 46,126, 22, 47,170,217,166,219, 21, 73,139,114,161, - 95,218,219,154, 98, 29,148,206,220,223, 83, 66, 63,194, 24, 91, 77,191,245, 45, 81, 88, 76,246, 99,150, 29,196,198,148, 28,226, - 11,202,192,207,250,185,206, 65,252, 7,207,183,227,175,213, 99,121,118,187,111,119,183,109,239,125,163,221, 75,114, 53,215,183, - 27,137, 66,147,110, 93,212, 9, 73, 66,132,168, 18, 70, 89,155, 1,197, 28,211,235,208,230, 33,137,116,249, 72, 41, 92,105,113, -154, 90, 84, 7, 50, 85,249,178,113,225,194, 13,235,193, 55, 17,215,238,197, 93,238,191, 80,167, 82,159, 69,111,111,238,242,201, -110, 45,251,182,117,197,186,245,165,117,196,233,203,239, 75,138,218,226,212, 26, 24, 84,122,141, 58, 75, 74, 74, 64, 71, 51,238, - 85, 86,192,138, 57,152,176,223,150,204,110, 72, 29, 81,137,234,203,216,159, 51, 46,237,118, 86, 99, 65,113,143, 12,174, 75, 50, -215, 81, 41, 25,101, 83,105, 43,215,145, 46,237,160, 27,127,116,226,230, 50,126,201, 86, 67, 97,203,213,166, 30, 57, 89, 86, 50, - 57, 63, 91, 35,175,110,154,250,115,156,144,122,249,254,255, 0,158,190,132, 99,161, 63, 14, 7, 46, 51,204,122,121,244,234,117, -245, 72,229, 29, 50,113,234,114, 6,127,226, 52,254, 46,118,196, 36, 11, 11,116,192,142, 40,231,160, 24, 29,207,175,231,166,135, - 82,137,238, 64,232,124,241,143,179, 68, 44, 19,211, 24,237,156, 99,160,245, 31,126, 52, 50,128,235,212,121,128, 78, 49,215,207, -246,105, 68, 59, 91,211, 6,181,253,109,251,240, 59,128, 1,240,171,174,122,121,121,246,207,159,246,104,101,244,200,243, 35,246, - 1,147,162, 21,140, 28,140,254,113,161,148,112, 8,235,215, 56,237,248,125,154, 85,112,176,189,136, 39, 3,168, 0, 15,145, 62, - 99,204,143, 35,249,242,208,203,229,235,235,211,242,126,225,162, 87,140,117,249,224,122,159,158,135, 88,233,231,247,118,251,254, -237, 44, 58,142,248,193,237,183, 67,243,247, 96, 69, 12, 31,183,175,217,165,175,171,198,113,140,126,255, 0,187,241,210,210,202, - 77,133,197,207,221,131, 99,202,112, 72, 7,242,117, 92, 15, 35,128, 60,190, 67,250,245, 69, 3, 39,236, 25,209, 40,239,246, 15, -207,219,164,143,175,174, 6, 42,164,124, 64, 14,131,166, 15,207,236,243,242,209, 35,215, 56,198, 62,220,124,191, 62,122,164,143, - 51,208,255, 0, 72,235,253, 31,213,170,160,100,227, 56,233,145,243,252,254,237, 17,175,109,186,223, 3, 4,160,140,231, 62, 93, -207, 79, 77, 22,130, 49,143, 63,233,251, 52, 26, 72, 30, 64,143,179,183,217,162, 1, 74,146, 72, 61, 65,252,115,142,159,159, 93, - 35,140, 48,184,235,108, 20,140, 18, 1,239,158,135,203,239,209,169, 7,166, 14, 79,145,253,186, 1,158,132, 17,149, 14,196, 19, -140,124,243,251,180,122, 72, 79, 76,145,211,160,233,147,164, 9, 36,220,225, 54, 29,199,206,216, 33, 4,224,142,153, 29, 85,219, -183,166,164, 73,236,110,220, 31,173,246,111,125,182,170, 68,175, 13,251,106,189, 68,191,169,177,199,196,183, 33, 84,227, 24, 21, - 2,134,250,229, 41,151, 17, 57, 35, 63,229, 6,117, 29,198,252,179,144,122, 1,230, 79,219,211, 93, 44,246, 85,110,228, 13,175, -226,214,210,164,215,229, 24,246,198,234,192,168,237,157, 95,227,228,108, 75,174, 32, 59,111,188,224, 39, 4, 38,172,195,104, 4, -246,247,157, 70,120,186,135,219,242, 26,232,130,234,146, 37,230, 46,215,221, 14,166,255, 0, 32, 97,247,226,198,240,131,136,227, -225, 95, 18, 56, 87, 54,157,180, 83,123, 64,167,148,237, 97, 29, 72, 48,220,223,107, 43,186, 57,255, 0,166,248,146, 36, 30,101, -188, 76,200, 92,160,148,190,196,228, 14, 82,218,114, 10, 92, 8,242, 87, 93,108,205,136,136, 94, 60,105,208,170, 83, 26,151, 9, -191, 29, 82,222, 74,157, 92,231, 64, 7,195, 90, 79, 64,192,244,244, 26,103, 63,131,149,104,117, 26,148, 68,184,195,109, 83,228, -173,134,209, 44, 2,226,202, 22, 82, 16,178, 79,234,114,242,159,179, 79,213,149, 33,113, 88, 77, 61,112, 27,121,229,248,106,149, - 58, 39, 41,101,148, 19,213, 63, 32, 79, 66, 62,237,115, 51,211,150,121, 6,155,219,175, 91,109,181,133,253,226,219,123,241,235, - 75,241, 11, 79, 76,188,137, 11, 48, 93,149, 89,118, 13,107,151, 89, 1,176, 11,212, 3, 98, 79, 75,219, 27, 67,183,181, 74,244, -214,231, 56,229, 74,158,135, 38, 41, 14, 18,160,166,156, 74, 16,156, 36, 32,118, 65, 62,159,191, 89,190,241,113, 11,110,112,191, -176,215,206,245, 95, 6, 20,202, 61,145, 74, 92,138,101, 45, 18,130,100, 92,247, 68,212,150, 40,116, 70,185,198, 84, 94,156,164, -120,132, 3,202,211,110, 40,118,198,137,219,165, 83,139, 76,133, 80, 28, 90,114,210,212,240,109, 10,241, 74, 15, 76,167,253, 94, -159,126,117,202, 47,164, 21, 92,174, 69,225,135,102, 32,209,169,178,160, 90,181,125,216,152,229,206,180, 71, 8,142,167,224, 81, - 11,148,102, 36,173,177,132,143, 17,201, 42, 66, 85,208,148,156,117, 26,113,203,168, 3, 58,157, 54,103, 33,125,118, 36, 94,196, -237,222,227,213,182,195, 70, 89, 79, 69,197, 92, 91,144,112,245,125, 61,168, 43,234, 1,157,252,177,147, 20, 49, 60,207, 26,149, - 58,245, 75, 28, 77, 18,149, 55, 93, 87, 27,139,227,130,123,191,198,175, 16, 27,247,184, 53, 45,208,191,119, 70,231, 85, 90,163, - 41,199,233,180,154, 61,106,117, 46,133,107,211, 84,247, 52, 26, 77, 22,153, 17,228, 34, 20,118, 27, 40, 72, 87, 47, 57, 41, 37, -106, 42, 36,235,167, 28, 15,251,109,119,107, 98,106,116,123, 7,136,169,179,119,107,102, 31,113,136, 72,172, 74, 90,101,223,214, - 83, 75, 33,180, 78,165,212, 93, 60,213,120,109,143,137,113,159, 82,138,146,217, 13,173, 11,198,163,142,186,235,108,188,164,169, -213,165,121, 56, 0,143,231, 19,148, 16, 58,242,145,159, 46,186, 6,109,204,220, 84,151,229, 73, 75, 76,165, 69, 13,186,181,124, - 13,149,252, 65,167, 20,122, 32, 43,175, 41, 61, 51,208, 28,156, 25, 60, 92, 63, 80, 37, 67, 1, 49, 19,208,129,189,141,182,255, - 0, 21,246,184, 55, 7,184, 56,236,142, 32,151,195,140,255, 0,133,223,133,248,147,134,104, 42, 50, 10, 88,196,113,162,172,112, -123, 24, 69,210,178, 83, 74,129,100,164,145, 7,247,111, 27, 39, 75, 54,164, 44,167,244, 98,220,125,244,218,109,207,181, 44, 93, -211,218,219,134,218,187, 42, 87, 53, 36, 51, 69,220, 10, 51, 17,100, 76, 69,191, 35,149,215, 40, 82,159,113, 5,234, 52,228, 57, -209,198, 86, 27,121,151, 16,161,243, 44, 38,219,240, 59,195,109,247,187, 50,119,219,118,236,200,251,153,118, 75,170, 65,173, 67, -182,174,118,154,153,103,210,171, 16,188, 32,197, 90, 69, 61,192, 77,102, 97, 83, 13, 41, 94, 54, 91, 36,117, 74,129, 58,135, 95, - 6,188,107,223,252, 45,110, 43, 52,233, 52,170,149,203, 96,222, 20,101,215, 83,103, 60,250,190,174,187,227,193, 5,199, 38, 91, -143, 44,148,196,174,178,208,123,149, 72,234,165, 37, 41, 87, 50, 84, 70,166, 95,193, 71, 19,251, 57,196,190,221, 82,183, 35,102, -111, 8,119, 37, 13,224,211, 21,170, 59,206,165,155,154,207,170,129,201, 34,143,114, 82,138,185,226,186,219,193, 72, 75,184,240, -221, 9,202, 85,215, 26,134,231,185, 70,123, 75,158, 38,105, 42,145, 71,202, 88,163,146, 50, 90, 29, 18, 16,197, 88, 92,133,119, -146, 38,219,245,140,108,190,102, 70, 11,198, 92, 75,194, 16,120, 95, 13,105,224,204,246,176, 46,111, 21, 85, 20,213, 74,239, 79, - 89,200,142, 74,121, 30,138,165, 99, 8,209,242, 82,106, 70, 89, 32,229,195, 52, 53, 48, 77, 24, 84,168, 68, 26,105,237, 7,217, - 19, 64,220,153,215, 20, 88,210,156,133, 88,145, 38,124, 79,119,101, 69,163, 18,166,128,243,109, 37, 40, 1, 44,161,169, 41,117, -174,100,245, 74, 25, 74, 0, 3, 3, 90, 51, 69,177,226,173,138, 60,234,204,122, 85, 38,221,129, 41, 51,103,211,161,176, 94,110, - 91,208,250,114, 84,204,148,115, 56,210,150,121,194, 65, 70, 22, 18, 73, 35, 82, 72,226, 42,210,160,110,117,160,197,162,168,115, - 29,188,213, 74,168, 86, 45, 9, 77, 65,126, 76, 10,156,120,126, 17,171,208,229, 78,105, 60,176,167,150, 84,151,226,161,194, 60, -101, 71,113,182,200, 89, 26,226, 82, 54,226, 82, 43,245, 56, 55, 19,146,165, 82,168,173,189, 53,234,122,121,219,167,174, 92, 53, - 21,161,215,162,173,172, 60,148, 33, 24, 82, 73, 88,113, 92,185,201,201, 27,117,108,244,241,194, 26, 80, 4,200,175,177, 5,212, -177, 33,144,129,246, 88,144, 74,234,211,113,184,242,225,135,128,248,146,174,159, 42,143, 44,172,115, 72,249,120, 15, 20,146, 35, - 63, 50,152, 72,218, 26, 20, 93,164,179,172,144,173,201, 8,234, 67,105,179, 12, 29,182,244,136,190,236,139,162, 43,211, 44,218, - 8,144,234,232,245, 56, 11, 17,235, 21,134,156,116,152, 20,134, 80,176,164, 56,209, 72, 43,143,200,135, 22,133,101, 74,113, 57, -214,238,237,187,251,130,203, 76, 67,151, 72,167, 84, 98,133,170, 91,213, 42,148,233, 12, 76,138,192, 82,148,219,210, 68,113,202, -170,138,219,193, 89, 73, 67,106, 72, 42, 40,200,248,181,222,133, 7,252, 38, 61, 94,168,236, 48,218, 34,198,106,222,121,215, 12, - 42, 5,177, 73, 72,109,202,131, 44, 54,165, 4,166,172,236,131,241, 5,128, 23,219,155,149, 1, 39,109, 54,169, 47,214,159,141, - 78, 48, 42, 53, 11, 73,106,126, 99,142,173,244,196,145,119,169,196,182,166,100,201, 84,167, 3,137,162,161,194, 72,100, 6,202, -154, 9, 82,143,134, 60, 50,195, 58,115, 25,121,138, 2, 2, 5,250,155,236, 2,134,216,220, 95,168,238, 13,133,186, 73,115,220, -216,213, 80, 74,207, 75, 13, 76, 72,128,234,144,106, 49, 40, 80,161, 99,149, 74, 52,149, 4,141,198,181, 87,112,116,142, 90,187, -151,130,212,169,221, 85,192, 81, 71,162, 69,143, 17,233,177, 66,234,213,121,210, 29,109,249,104, 83,136, 47,211, 99,197,142,149, - 42, 58, 27, 13,132,100,161, 42, 4, 36, 14,234,214,192, 82,168,207, 6,100, 72,146,243,115, 36,115, 37,223,120, 83, 66, 40,134, -150,151,200,182,225, 67,103,224,109,191, 19,152,143,214, 95, 97,205,166,202,221,175,203,122,100, 42,117, 14, 27, 48, 96, 45,217, -109,187, 93,144,132, 73,164,149, 65, 11,113,200,212, 8,170, 80, 21,149,224, 37, 41,120,242, 70, 10, 10, 9, 83,160, 99, 78, 43, -116,232,146, 18,162,237, 86,169, 54, 43, 79, 52,133, 63, 42,172,182,163, 42, 83,190, 32,120,165,166, 16,210, 27, 75, 65, 69,178, - 18,158, 64,162, 82, 50, 81,157,111, 81, 68, 21,129, 8, 22,227,101,189,237,123,109,114, 1,185,236,109,232, 47,107,226,137,226, -141, 77, 41, 30,203, 30, 87, 20,158, 96,168, 26,121,138, 19,111,172,118,118,179, 18,159,221,137, 20, 88,110,150, 85,193, 53, 73, -145,226,170, 46,101,196, 76,164,184, 28,240, 12,134,153, 95, 43, 10, 74,155, 46,181,207,144,121,194, 7, 62, 9, 82,143, 47,108, -234, 4, 62,210, 58, 72,219,158, 58,184,155,183, 37, 40,183, 29,237,225,189,234, 44, 58, 57,127,200,220,181, 35,117,198, 37, 8, - 56,229,118,159, 89, 74,128,242, 87, 67,131,157, 78,142,170,138, 83,209,158, 69, 30, 52, 6,160, 54,228,136,114, 46, 38, 99, 50, -181,206,146,133,248, 78, 67,166, 72,113, 37, 82, 16,149,149, 37,199,134, 91, 66,242, 26, 11, 88, 90,147, 16,207,164, 3,178,234, -161,113, 5,183,251,173, 73,167,134,104, 59,189, 97,210,168, 85, 9, 52,211,200,236, 43,223,109,162, 38,218,168,185, 41,231, 21, -137, 21, 23,168, 70,202,152,128, 87,226, 56, 92, 95,235,114,171, 51, 28,157, 98,150,190, 8,100,110, 92, 83,221, 79,199, 69,239, -185,177,177, 27, 15,128,189,142, 45, 63,163,127, 17,212,112,127, 20,113, 29, 53, 38,185,106,243,156,177,196, 81, 58,133,230,212, - 82, 85, 83, 84, 44,108,169,172,160, 52,166,171, 97,169,163, 3, 91,114,200, 24,226, 4,154,196,244,219,106,220, 88, 18, 36,123, -230,213,238,117, 58,151,184,116,120,110,184,212,168,118,117, 66, 76, 20,196,186,144,180, 43,157,136,145,234, 12,197, 91,146, 81, -132, 70,114, 83, 75, 43, 75,110,100, 74,151,217,207,198,213, 39,137, 54,238, 61,133,221, 10,180, 42,127, 21,123, 72,167,219,169, -193,146,168,241, 90,223,139, 2, 44,118,170, 52, 45,207,178, 66, 74, 81, 80,184, 88,183,166,211,141,199, 76,103,157,106, 33, 53, -232,129,216,210,102,162, 20, 59,161,215,121,234, 81, 43, 84, 91,170,177,103,222,204, 45,171, 98,241,138,155,114,161, 89, 69, 74, -148,180, 59, 78,143, 92,122,151, 17,151, 83,112, 82,132, 69,184,196,200,129,133, 59, 38, 25,125,133,176,243,141,180,149,244, 87, -132,222, 13,248,140,184, 47,203, 39,113,120,121,171,199,191,238, 93,185, 98, 53,251,111, 91,251, 99, 85,166,215,175, 87, 41,240, - 42,241,155,165,214,182,154, 47,191, 41, 91,145,104,211,234, 42, 83, 92,148,103, 83, 85,163,199,117, 84,250,197, 33,136,225, 97, -185,206,113,194,121,109,101, 27, 45,125, 80,163,171, 2, 95, 99, 38, 41,121,134,115,162, 78, 66,144,133, 38,141,138,205,202, 84, -102,150,120,231,139,150,134, 90,104,163,158, 75,196,249,142,105,226,180,212, 89,118, 93,165,163,138,170,138, 74,220,202, 74,236, -184,209, 80,208,200,239, 65, 46, 97, 87, 27,213, 71, 85, 72,252,182,203, 23, 53,133,225,134, 42, 12,195, 41,170,210,211, 69,154, -203, 85,150,205,166,227,165, 61, 6, 5, 54, 97, 74,156, 18,227, 69,110, 35,140,180,165,169,249, 82,156, 67, 13, 71,138,218, 85, -241,185,226,184,218, 91, 31, 9, 82,214, 50,122,244, 11,114,111, 27,114,131,182,251,199, 34,255, 0,136,154, 45,247,176,245, 58, - 22,218,111, 22,216,181, 81,143, 85,184, 45,221,195,188, 89,183,161, 89, 20, 42,100,159,117, 96, 92,148,187,141,187,194,223,118, -133, 84,102, 59,113,170, 72,126, 72,105, 41,114, 12,164, 55, 75, 99,119,122,224,174, 51,245, 7, 19,219, 89,112,112,215,186,220, - 60,220,144,175, 61,215, 77,193,108, 87,174,237,159,151,101,211,226, 77,189, 33,110,173,151, 93,162, 70,144,154,221,142, 81, 76, -164, 63, 80,165, 60,241,153, 77, 68,215, 72,114,100, 8,147, 31,135,146,113, 71,183, 59,103, 34, 92, 13,253,110,235,173,110,165, -205,184,176,173,202,147,143,193,221, 91, 86, 92, 45,209,191,156,186,104, 59,129,181, 86,205,199,245, 20,121, 48,102,109,181,175, -123,214, 32, 86,104, 82, 40,181, 28,208,209, 13, 52, 53,191, 38,135, 86,101,109,214, 19, 84,229,188, 53, 74,207,159,161,161,167, -175,150, 56, 86,121,140,113,211, 67,100, 55, 51,107,101,157, 73,146, 72,180,145, 11, 42,168,147,153,162,197,146,162,201, 56,112, -210,113,141, 46, 79,196, 20,245, 18, 53, 58,173, 84, 67, 46, 95,106,106,245, 73, 41,170, 2,208,207, 24, 52,245, 80, 86, 80, 37, - 72,165,150,158,114, 90,122,170, 9,135,212,151, 87,227, 20,104, 45, 87, 24, 85, 86,218,241, 42,148, 71,110, 43,170,211, 76,212, - 52,150,132,106,245,151,114, 85,109, 11,162,129, 84,104,168,251,149,106,157,112,209, 42,113,229, 48,188, 58,218,227,142,108, 33, - 77,169, 90, 21,237, 94,168,222, 22,133,223,195,254,202, 10, 93, 82, 93,177,180, 43,183,183,154,236,164, 81, 20,153,146, 98,238, -125,229, 73,129, 91,163,213,175,116, 52,191, 22, 53, 66, 29,188,253,173, 71,167, 81, 57, 76,150,133,213, 81,149, 33, 81,220,148, -211, 74,150,182,225,218, 92, 50,112,247,195,165,153, 77,165, 90,219,117, 99, 91,150, 60, 43,174,244,174,223, 49,109, 27,134,228, -218,202,205,255, 0,107,212,149, 18,116,251,243,114,104,207,201,168, 51,121, 72,220, 7,211, 38,169, 13,184,115,170,215,251,244, -217,244, 88,238, 70,155, 37,169, 49,121, 20,212, 93,185,118,222,225, 46,203,225,223, 98,183, 23,120,253,160,252,116, 84, 55,118, -117,213,191, 91,223, 72,247, 69,219,219,105,184, 23,221, 98, 20,254, 44,230,237,204, 42,236,138,109, 42, 84,217,212,251,153,118, - 17,144, 93, 52,138,101,143, 85,175,174, 58,252, 58,125, 67, 79,254, 28, 54, 93,153,214,174,113, 79, 20,121,133, 44, 97,185,112, - 9,150,105,100, 73, 41, 86, 94, 92, 38, 35, 21,167, 43, 81, 29, 57,169,144, 44, 20,142, 37,170,101,154, 49, 70,106,111,238, 14, -168,151,137,248,115,244,207, 19,210,215,101,116,144,212,140,186,131, 48,134,146, 36,164,139, 59,164,121,107,219, 53,204, 26,181, -229,163,139, 38,160,162,201,235, 36,205,169, 85,235,234,125,154,190, 36,140, 9,162,154, 90, 72,169,213, 45,253,208,118,151, 97, - 90, 91,181, 38, 13,167,103, 94,215,213,102,231,174, 55, 49,215, 31,172,238, 77,247, 17,216,119, 14,228, 45, 49,233,233, 9, 77, - 46, 21, 66, 69,159, 70, 41,134,135, 99,193,140,211, 84,180,200,231,102, 82,155, 18,155, 83,131,120, 85,111,219,154, 3, 50,105, -148,169, 19,160,193,160,214,170,113,194,103,214, 98,211,229,168,183, 62,159, 72, 66,178, 89,147, 84, 14,152,173,252, 45,248, 13, - 54,178, 84,149,147,169,133,123, 64,189,146, 86,255, 0, 13,187,109,182,187,145, 64,219,248,219,185, 14,215,178,234,116, 13,218, -222, 42,148,217, 2, 53, 42,184,204, 22,226,237,117,131, 14,206,132,240,114,194,225,222,157, 83, 53,138,149,106,161, 29, 14, 73, -171, 86, 42,171,153, 89,124,169,230,121, 34,177,182, 91, 65,116,111, 46,243,196,218,253,171,247,251,206,183,116,213,106,146,228, -110, 45, 77,182, 89,136,139,118, 28,148,197,186,119, 9, 54,243, 47, 6,109,107, 54,152,143, 26, 45, 38, 35,139,255, 0, 5,141, - 9, 78,190, 85, 41,232,140,170,115, 83, 86,212,245, 25,140, 21,212, 63,162,231,161,141, 36,125, 43,202,166, 45, 35,172,211, 73, - 10, 63,152,169, 40,176, 6,149,220,186,195,120,162,104,238, 34,191,184, 15, 62,224,252,219,132,178,206, 51,225,190, 45, 60, 75, -193,102,174,190, 55,168,174,180,249,164,116,185,109, 52,249, 86, 93, 75,153, 84,195, 32,246,103,141,107, 43,115,158, 82,101,249, - 74,150,205,227,150,183, 49,167,173,118,253, 35, 52,143, 98,189, 5, 54,159,179,243,109, 77,101, 98, 4,221,196,190,119, 71,112, - 90,102,181, 21, 8,139, 91,164,212,174, 88,182,196, 10,140, 85, 56, 18,219,240,220,254, 9,200, 41,115, 33, 74,231, 82,146,146, -218,155, 42,234,187,209, 27,163,184,237, 90, 72,168, 42,130,200,240,165, 64,143, 38, 82,158,160,173, 74, 13, 9, 84,182,157,124, - 46, 93, 57, 73, 90, 10,152, 73, 43,100,172, 41,160,180,115, 32, 49, 27, 9, 77,177,109, 93,139,217,139, 99,111,227, 72,143,183, -214,214,217,218,118,173,163, 6,173,153, 19, 88,131,108,210, 99,208,101, 65,174,135, 83,148,212,157,159, 79,150,244,181, 20,148, -123,204,229, 43,177, 57,114,208,124, 17, 57,202, 83, 14,170, 36, 5,137, 85, 10, 36,185, 75, 84, 55, 96,202, 71, 42,132,120,171, -113,106,241,219,116,146,219,173, 15, 11,186, 85,148,168,114,194,132,136,200,173, 31,158, 54, 80, 65, 3,168, 34,224,129,232, 65, -213,184,220,116, 23,199, 0,113,150,101, 55, 20,241,127, 20,113, 19,235,165, 25,245,125, 85, 67,198,196,108,179, 84,182,152,185, -133,129, 73,145, 89, 34, 14,220,203, 72, 8,103,229,150, 86,247, 81,110, 91, 49,167, 78,161,215, 37,212,219,113,213,165,218, 85, - 69,240,244, 26,132, 54,129, 11, 49,228,181, 29, 46, 66,168,140,245, 75,156,193,124,161,183, 27, 28,201, 86,190, 81,155,125,104, -135, 34, 12,114,220,121, 41, 40, 98,157, 53,228,170, 35,114, 20,230, 86,221, 26, 80,200,167, 40,169,103,158, 59,169, 8,202,112, -128,131,144, 60,211,163, 71,152,183,230, 83,229,191, 4,133,169,153, 76,134,179, 60,198, 89,109,232, 14,212,225, 62, 86,221, 65, - 13,185,148,165,196,101, 78, 32,243, 37,209,130, 19,153,208,146,134, 81, 41, 19, 11, 49,214, 86, 24,121,165,178,165, 69,168, 40, - 31,135, 1, 64,169, 46,149, 41, 36, 40,254,144, 5, 36,146,188,100, 38,134, 48, 25,152,141,172, 46, 77,136,220, 27,250,141,253, -222,226,122,130,193, 89, 80, 41,169,164,139, 72,146, 84, 43,112,200, 85,236, 84, 40, 87, 84, 1, 94,219, 21,144, 93,244,155, 22, - 69,101,209,125,183,168,209, 97,190,250,204, 70,152, 5, 64,200,140,166,150,203,176, 87,241,151, 94,136,160,178,134,218, 89,230, - 82,128,202,114,162,164,100, 2, 53, 28,111,107, 60, 59,251,143, 63,104, 23, 11,126,205,170, 3, 53,106, 46,201,109,173, 53, 27, -255, 0,189,117,166,249,216,137, 90,147, 49, 18,105,172,202, 66,146,174, 71, 98, 81, 45,102,106, 49, 24, 42,193, 53,155,189,229, -160, 5,197, 73,215,123, 47,141,211, 98,142,167,173,155, 89,193, 42,229, 25,106, 76,148,165, 47, 71,180, 91,112, 5,120,181, 23, - 14, 83, 34,182, 58,174, 44, 18,162,180, 43,149,249, 92,173,165, 40,113,184,160,218,118,243, 51,158,189,219,161, 64, 93,228,170, - 58,109,137, 55, 99,177,210,229,194,253,186,103, 61, 86, 93, 46, 69, 85,196,248,174,194, 85, 90, 68,169, 42, 65, 86, 20,243,235, - 89,234,113,167, 76,190, 73, 36,154, 36, 66, 2,174,204,196,216,168, 96, 86,235, 97,187,142,171,113,179, 0, 79, 96, 43, 78, 39, -200,167,207,168, 64,172,169, 48,195, 60,176,243, 35, 59,153,169,213,129,145, 9,184, 40,178,128, 35,189,201,120,217,238, 72, 33, -152, 74, 45,191,110,218, 20, 10, 5,159,104, 82,163, 80,109, 43, 50,145, 78,182,173,138, 20, 36, 37,152,116,202, 37, 38, 58, 33, - 65,136,219,104, 24, 24, 97,176,165, 43,186,214,165, 45, 89, 82,137,214, 66,192, 44, 56, 50, 64, 66,255, 0, 84,246, 74, 22,174, -188,167,230, 79,109,121, 92,114, 87,226,132,243, 5, 16,162,145,156, 45, 62, 69, 56,238,161,231,246,106,239, 2, 58, 29,109,109, -140, 45, 4,158,231,170, 65, 29, 58, 31, 49,251,181, 41, 93,150,200, 52, 42,216, 5,236,161, 64, 0, 1,233,167,107, 95,107, 15, -118, 6,132,133, 20,133,242, 45,129, 0, 88, 1,181,128, 29, 5,187, 14,150,219,160,198, 15, 92,140,185,115,138, 64, 42, 71,192, - 48, 51,148,245, 42, 81, 7,237,199,237,198,179, 75, 74,130,162,174,110, 64,124, 66, 48,124,213,215,155,149, 64,142,249, 35,240, -215,148, 83, 60, 73,124,161, 36,156,132,103,190,121, 71, 64,125,124,254,243,173,128,177,237,177,134,150,166,134, 7, 42,186,224, -143, 44, 12,121, 14,154, 67,202,160,201,111, 49,218,255, 0, 63,127,239,196,120,213, 0, 90,237,117,185, 55,251,239,238,249,252, - 47,182,197,185,224,181,226,148, 36, 57,202,148, 5,148,228,167,152, 5, 58, 79, 79, 76, 14,157,180,226, 8,126,236,203,104,229, - 60,234, 39, 41, 0,168,144,160, 20,178, 64, 31,173,203,129,242,206,178,138, 93, 27,145,148, 5, 35,225, 35, 39, 61,212, 7,196, - 78, 60,251, 1,143, 61,123,145, 19,153, 69, 69, 4, 41,106, 8, 66, 83,212,227, 32, 37, 32,103,190, 59,159, 85,124,134,144,177, -221,137,249,239,127,225,134,106,140,228, 77, 49,141, 79,213,198,127,211,243, 54,237,139, 84,118, 89,109, 14, 61, 41,212, 70,139, - 13,135, 37,204,148,176, 18,212,104,172, 36,184,227,206, 40,246,108, 37, 56,249,146, 7,158,181,250,179, 86,126,239,172,200,171, -165,165, 49, 78,105, 40,133, 70,101,239,129, 48, 41,109,171,225, 88, 0,126,146, 83,234,203,139, 61, 57, 66,130,124,177,167, 30, -243,170, 10,151, 53,173, 13,126, 37, 62, 51,173,185, 94,117, 25,228,155, 49,165, 7, 24,164,151, 19,254, 82, 35, 74, 8, 47, 36, -116, 83,129, 32,146, 1, 26,196,209, 13,152,192,120,189, 72, 36,248,109,160, 56, 2,128, 5, 63,163, 79, 92,103, 3, 39,160,236, - 58,233, 61, 70,161,194,166,241, 70,119, 63,180,195,227,217,127, 22,248, 41,196,175,135,160, 90, 56,228,204, 39, 66,107,106,150, -209, 41, 6,241,194,108, 75, 91, 99,174, 91, 3,191,217,140, 1,191, 54, 69,192, 76, 50, 27,111, 13, 54, 73, 64, 9, 75,139, 82, -155, 0, 43,169, 44,128, 9, 62, 93, 64,193, 61,206,129,152, 95, 41, 82,138,208, 22, 65, 72, 12,164, 32,165, 0, 36,148,163,152, -144,217,234,147,145,223, 36,228, 96, 13, 93,159, 83,174,103,149, 32, 40,182,126, 55, 51,206,132,145,201,240,161, 7, 35, 62, 99, - 32,129,158,249,214, 55, 45,212, 37, 96, 41, 41,120,167,152, 0,148, 0,129,149,167, 39,148,225, 32,224,247, 61, 71,166,116,224, -158, 91,109,185, 27,219,231,253,127,117,240,237, 35,179,146, 77,153,143,253,199,183,115,176,223,225,139, 75,238,163,147,144, 21, - 40, 96,142,116,142,164,165, 71,170,222, 82,187, 31,136, 4,140,243, 1,229,215, 88,252,183, 65, 72, 11, 82, 74,126, 16, 8, 28, -184, 82, 72, 9, 66, 86,188, 18, 18,124,176, 62,100,224,157, 92, 39, 56,224, 82,146, 23,204,162,174, 95, 9, 9, 79, 55, 83,240, - 40,169, 64,252, 33, 36,252, 92,160,245,192,214, 45, 49,208,142,112, 21,241,171,170, 65, 78, 85,128, 50, 82, 74,129,229, 60,160, -143,187,169,234, 53,176,135,175,112, 15,243, 31,187,175,201,195, 45, 82, 13,247,235,252, 62,255, 0,187,182,253,175,139, 84,247, - 82,160,163,130, 9, 39, 36,167,159,175,196, 10,138, 66,176, 19,215,191,145, 57, 25,215, 6, 61,188, 92, 35, 69,226, 19,132,201, - 91,199,110, 82,195,187,161,195, 10,102, 93,241, 28,140,192,126,125,115,105,170, 47, 48,214,226,219,142,184,128, 86,242, 33, 44, -195,173,196, 64,207, 34,224, 76,242,116,235,186,178,222, 24, 37, 41, 81,237,144, 82,160, 20, 48, 84, 0, 3,162,199, 82, 58,245, - 31,127, 70,250,191, 79,164,215, 96, 84, 40, 85,216,173, 79,160,215, 96, 84, 40, 53,232, 14,182,151, 35,203,161,214, 98, 61, 73, -173, 66,121,165,116,117,135,105,115,166, 54, 71,126, 85,224, 28,246,216, 14,203,105, 35, 63, 89, 25, 12,191, 17, 98, 47,238, 61, - 15,184,145,176, 59,197,243, 92,186, 44,214,138,175, 46,156,218, 42,180, 41,114, 7,145,137, 5, 36,183,172,110, 22, 65,210,229, -109,238,199,229,128, 82, 2,137,239,143, 49,212, 31,152,199,126,154,248,172,145,219,166, 51,147,251,191, 13, 61,188, 74,237, 67, -251, 7,196, 22,245,108,212,198, 21, 21, 91,103,185, 87,117,161, 21,133,168,173, 72,164, 83, 42,242, 5, 1, 65, 71,170,194,232, - 46, 83, 92, 10,235,144,230,114,115,146,198,169,106, 88, 4, 43,155,166, 71, 76,119,245, 30,186,153,211,202,179,197, 12,202,124, -178,168, 97,235, 98, 1,254,120,230,119,142, 72,157,226,149,116, 75, 17, 42,227,209,212,233,101,251,152, 17,138, 46, 16, 70, 51, -235,156, 28, 99,251,116, 42,177,142,195,148,103, 30,125,187,147,243,213,117,168, 30,224, 12,142,248,206, 79,217,161, 87,208, 31, - 60,156,126,255, 0,221,173,192, 44, 0,244,192, 29,190, 56, 29, 89,193,233,255, 0, 14,253, 52, 34,142,113,223,207,184, 3,240, -209,107,237,223, 29, 71,231,243,233,161,156, 32, 2, 51,147,231,142,191, 62,154, 85, 7,124, 42, 44,119,192,171, 35,203, 63,126, -113,231,228,117, 69,125,179,147,255, 0, 31, 93, 87, 95, 55,158, 49,229,249,245,208,235,199,207, 62, 94,159,126,149, 2,228, 99, - 29, 0, 3,231,255, 0, 24, 21,103,175,216, 49,159, 93, 45, 37,254,183,221,211, 75, 74,139,128, 0, 31,142, 13,143,168,198, 79, -124,227,238,199, 79,219,162,145,140,118,235,230,113,251,254,205, 8,223, 83,147,145,208,244,251,241,215, 69, 35,177,235,231,219, -247,232,141,107, 47,108, 12, 18,142,199,167,223,235,249,253,250,169,158,221,250,124,254,126, 94,154,164,140,245,233,211,215,247, -124,245,237, 36, 40,144, 15, 99,131,223,161,210, 78, 54,248, 96, 99,223,140,142,249, 24, 0,103, 25,202, 78,139,108,149,129,212, - 0,124,241,215,168,233,211,239,253,154, 16,180, 1, 56, 0, 36,228,159, 79, 44,147,243,254,189, 86,109, 65, 36, 14,184,198, 2, -143,203,212,253,218, 64,155,117,192,193,237, 39,151, 3,175, 66,123,119, 63, 63,144,209, 8, 95, 51,137, 73, 78, 57,115,241, 30, -221, 60,178,126,122, 8, 60,140,148,130, 85,216,224,117, 87,159,124,253,167,240,209, 63, 11,137,248,186, 28,252, 35,168,207,219, -248,233, 22,234,113,131,235,243,233,139,187, 64, 43,162,136, 63, 49,147,235,233,247,106,247, 70,169,212,104, 85, 90,117,110,145, - 41,200, 53, 90, 68,248,117, 58, 92,198,148, 80,236, 90,141, 62, 75, 82,225, 74,109, 67,170, 84,137, 44,180,175,184,141, 88,152, - 10,229, 79, 96, 48, 57,177,219, 35,167, 79,219,162,211,156, 40,118, 30, 71,184,249,245,242,233,162,144, 24, 21, 97,112,118, 32, -239,132, 15,196,169, 30,155, 16, 71,112, 71, 67,137,193,240,233,185, 20, 62, 44,120,124,219, 61,240,167, 76, 71,191, 84,105,140, - 81, 55, 14,155, 5, 64, 73,165,223,148, 54,155,135, 89,139, 53, 8, 57,103,197,121,191, 25, 25,253,100, 72, 65, 4,131,173,161, -180,210,245, 40,183, 10, 44, 52,248, 14,171,153,247, 36, 40,150,208,211,100, 16,181,171,201, 93, 7, 79, 83,168,161,123, 40,248, -226,137,194,214,237,191, 97,110, 76,199, 6,196,111, 20,202,117, 42,239,113,106, 82,155,179,174, 82, 83, 18,135,123,178,146,127, - 69, 25, 42,113, 12, 78,199,254, 43,149,211,158, 67,169,140, 46,220,104,182,207,128,184,210,104, 79,178,197, 70,159, 80,128,226, - 36, 70,171, 65,146,132,189, 18, 92,121, 77,168,165,248,174, 52,182,212, 10, 73, 7,155, 84, 39, 16,240,233,203,115, 25, 99, 88, -201,130, 67,170, 35,216,169, 61, 47,220,173,244,155,247,243, 17,102, 24,239,143, 11, 60, 80,110, 39,225,218, 88,107,103, 15,152, -229,170,144,213, 33, 98, 60,234, 0, 89,236, 55, 34,117, 93, 98,219,115, 3,198, 8,209,135, 82,196,175,212,218,113,133,198, 84, -117, 38, 71, 32, 67, 78,101, 4,182,142,157, 7,255, 0, 22,125,124,255, 0, 13,121,226,147, 97,169,220,100,236, 45,251,195,253, -214, 96, 83, 89,184, 96, 55, 58,221,184,156, 71,138, 45,139,210,151,207, 34,220,169,161, 93,196,113, 36,248, 82,113,221,137, 11, -244,198,172,116, 62,102,100,181, 29,160, 61,231,149, 60,142, 99,224,101,164,246, 3, 29,128, 25,233,173,128,164, 74, 18, 99,198, - 73,116,183, 25,181,114, 60,178, 57, 76,151, 16, 50,162,162, 14,124, 60,129,246,235, 82,158, 2,165,118,210,203, 98, 45,216,245, -190,219, 94,253, 7,223,139, 66,108,214,122, 57,232,179, 76,177, 18,150,182,141,214,104,102,243, 49, 73, 35, 33,209,244,220,171, -217,133,180,176,210,230,225,188,151,199,230,211,196, 86,208,238, 55, 15,155,153,121,237, 22,231, 81,100,219,215,221,143, 82,149, - 79,168, 71,125,106,110, 52,230, 88, 90,132,122,157, 46,106,128, 76,202,124,136,220,143, 71,121, 63, 11,141,186,146, 8, 36,141, -107, 90,238,137,210, 99,242, 84,194, 39,208,228,243, 69,156,165,101, 50, 16,209, 35,156,184, 17,212, 56,158,138, 66,198, 72,229, - 26,253, 19,125,160,126,206, 29,169,246,133, 88,112,226,214,219,129,100,111, 5,191, 18, 68, 91, 19,116,219,132, 28,148,220, 38, -208,181, 53, 65,186, 99,180, 66,170,182,233,119, 30, 25, 39,198,138, 86,165, 50,121, 74,144, 97, 29,196,223,179,219,138,238, 14, -171, 85, 42, 30,238,109, 69,202,253,158,137,146, 26,165, 95,150,229, 61,202,229,149, 91,134,219,133, 41,155, 18,173, 13,165, 6, - 91, 82, 48,172, 57,202,180,231, 5, 26,179,178, 42,250, 57,225, 72,106,149, 86,169, 74,233, 44,116,220, 29,175, 27,118,123,216, -133,216,130, 59,142,146,250,158, 42,173,226,215, 74,204,190,189,178,218,167,133,214,182,141,111, 32, 18,142,242, 68,219, 84,208, -202,162, 69,119,250,199, 68, 58, 38, 17,181,158, 86, 98,205, 98,245,184,155,179,246,190,133,117, 81, 43,212, 69,205, 93,107,111, -171,201,247,180,220, 22,125, 75,170,221,143, 77,172, 67, 70, 41, 51,212, 66,147,225, 62,180,195,146,121,152,117, 41, 82,145,153, - 39,123, 14, 56,116,186,118,163,136, 57,119,139, 91,231,181, 82,105,117, 56,211, 85,187, 59, 81, 50,174,154, 46,225, 86, 41,142, -178,236, 71, 96, 81, 44, 39,154, 15, 79,169,138,138,154,146,169,140,169,198,154,240,202,146,121, 8,214,156,123, 19,246,162,147, -184,219,245,181,214,173, 74,157,114, 91,212, 68, 94,177, 46, 9, 87,209,164, 82, 35,166,152,213, 40, 26,147,148,152, 53,249, 12, -182,135,161, 77, 92,118,163,188,212,150,221, 87, 43,171, 72, 10, 95, 41,212,194,248,217,224, 59, 96,239,203,211,110,184,157,163, -220,219,119,195,142,224,236,189, 90, 53,199,112,238,141,180,213, 54,131, 86,184,173, 90, 80,241,158,162,204,105,137, 44, 68,247, -146,216,120, 38, 83,136, 82,185, 95, 91,106, 14, 36,132,105, 42,177, 85, 95, 69,196, 84,180,235, 13, 45, 13, 59, 8,229, 63, 84, -100,153,228, 44,254,209,101,229, 8,180, 29, 45, 34, 57,120,102, 98,238, 84, 54,248,177,115, 46, 32,224,110, 24,171,225,142, 26, -226,122,217,198,119,199, 25, 21, 76,116,245,242, 71, 93, 93, 67,144, 67, 83, 72,217,122,208,154, 38,146,170, 74,254,122,137, 97, -203,171, 80,123,126, 86, 13, 50,114,230,134, 52, 43,104,160,110, 52,106,229, 82,239,218, 10,165,197, 42,143, 92,155,112, 63, 79, -182,109,170,172, 86, 42, 53, 42,212, 72,110,166, 83, 17, 83, 38, 18,137,166,133, 50,164,172, 60, 85,240,145,228,123, 92,248,153, -225, 90,117,139, 14,223,186,217,144,212,184,247, 13, 37,217,245,234, 50, 30, 68,154,188, 47,118, 5,245,153, 13, 36, 5, 84,225, -248, 64, 45,114, 16,133, 4,120, 5,183,210,145,135, 23,170, 17,120,166,246,122,210,239, 8,251,245, 73,221, 42,108,202,125, 54, - 85,110, 12,136,116, 25,110, 42,164,252,181,186,183, 36, 84,100, 71,157,200,243,176,212,251, 97, 40,154,128, 27, 80, 87, 42, 0, - 73,215, 28,248,248,246,138,238,223, 31, 27,209,100, 13,189,190,175, 61,174,217, 13,133,184,168,247,110,220, 46,215,168, 72,182, - 43, 50,175, 26, 23,136,134,174, 58,133, 66, 41, 14,213, 96, 61,144,143,113,148, 85, 17,198,121,155,117,149,165, 68, 30, 78,240, -151, 41,171,203,168,248,214,139,140,242,218,147, 61, 39, 46,146,154,176, 74, 94, 58,115, 70,238,237,110,102,210,194,237, 49, 74, -101,167,176,152,106,242, 71,253,233, 17,120, 7,226,111,137,188, 85,195,180,126, 29,112,252,188, 55,150, 71, 72,245, 89,147,103, -144, 54, 91, 11,230, 13, 18, 65,236,212,236,144, 84, 78,202,220,184,170, 37,144,199, 57,137, 21,156, 76,199,149, 3,245, 94,101, -153, 14, 91, 11,118,106, 60, 38, 42, 50, 98,248, 52,232,255, 0,224, 76,210,169,176,210, 23, 58, 67, 75, 75,170,196,215, 65, 90, - 66,200, 82,134, 70, 57,121,122,190,116, 74, 93, 58,224,113, 52,104,137,117, 22,180, 38, 41,236, 84,166,201,117,250,127,189,196, -138,202,165, 63, 77,135, 61,213, 5, 70,128,166,194, 12,199, 18,144,165,140,160, 16,130,179,166,155,101, 55,170,133,187,214,166, -214,220, 55, 67, 20, 74, 22,231,223,150, 76, 91,182, 85,181, 1,133, 66,160,215,231,197,159, 82,164,204,170, 90, 80,221, 39,244, - 42,118,154,185, 47,211,155, 89,114, 42,164,175,221,144,228, 84, 39,195,216, 74,124, 72,107, 67,204, 60,133,205, 66,221, 76,153, -140,248,200,105, 21,106,162,212,144,195,107,125, 39,244,116,228, 20,254,149, 32,124, 73, 74, 16, 82,160,149, 5, 73,200, 40,225, - 8, 33,133,138,157,182, 82, 3, 95, 73,181,137,216,116,212, 13,238,110, 49, 90,230,167, 55,225,188,207, 50,225,188,237,100,164, -205,114, 10,186,138,102, 10, 67, 66,181, 20,181, 15, 75, 52,145, 56, 33,102, 11, 36, 14,177,206, 9, 14, 84, 59, 29,188,174, 84, - 59,173,112, 93,143, 85,131, 21,160,229,114, 44, 58, 45,153, 66, 12, 7, 27,139, 74, 91,136,101,170,139,205, 35,148, 83,216, 89, -109, 47,175,160, 45,198, 97,150, 17,149, 40,129,153,191, 33,138, 45, 46, 76, 10,157, 73, 53,234,220,249, 45, 83,233,211, 28,109, - 44, 82,226, 34,114,131, 18, 43, 40,129, 31,153, 48, 97, 70, 47, 36,186,181,120,174, 58,242, 82,209, 95, 50,212, 18,208, 73, 83, - 80, 80,204,199,127,194, 85, 21,242, 79,187, 56,168,170,169,212,221,108, 50, 91,138,234,193,240,227,178,130, 24,101, 57,229,108, - 41, 75, 86, 74, 20, 9,139,172, 74,165, 58,245,126,172,220, 89,142, 26,131,177,226,196,130, 86,202, 30,125,154,122,189,198,155, - 17,167, 0, 8,166,198,149,239, 78, 60,238, 79,139,135, 31, 80, 75,139, 70,183,210, 72,208, 37,152, 14,131,107,157,246,216,129, -183, 77,134,221,141,183, 54,195, 12,185,100, 85,145,194,212,139,125, 68,121, 69,150, 73, 36, 70, 28,168,213,141,221, 80, 38,242, -239,121, 25,155,153,118, 55,137,194,174, 84, 41,148, 85,183, 64,162,120, 21, 9, 84,184, 49,145, 29, 46, 45, 79, 64,165, 64,110, - 50,132,154,165, 69,214,148, 82,194,220, 74,138,147, 28,101,231,150,232,192, 66, 9, 86,185, 17,237, 36,216, 24,156, 79,108, 45, - 91,106,157,145, 17,119,146,170, 52,251,163,110,235,115,214,150, 35,192,191,179, 38, 60, 55, 42, 47,160, 19, 2,219,168,211, 29, -118,157, 56,164, 20, 50,202,227,203, 3,158, 10, 73,232,220,233,143,193,167,180,203, 82, 67,210, 37,192,145, 88,170, 20, 52,150, -230, 54,253, 90,120,113, 41,119,149, 69, 38,115,235, 1, 12,182, 7,193, 25, 9, 82,185,130, 82,117,175,119,139, 85,218,217,157, -245,121, 66, 42,143,213, 32,176,154,170,185, 28,143, 69, 75, 2,115,178,106, 74,141,250,175, 22, 25,108,248, 12, 35, 8, 91,142, - 54,181,252, 5,122, 88,213,203, 28,145, 75, 78,229, 37,167, 97, 34,183,236,148, 33,148,223, 96, 69,197,183,176, 63,102,214,216, - 58,240,190, 68,114,250,243,152, 23, 19,199, 8,114,242, 72, 72,231, 22,188,108,205,176,101,137,213,157,138,160, 37,149,131,121, -245, 2, 96,171,183, 20,137,123, 31,191,149, 91, 47,123,232, 85, 27, 62, 93, 6,181, 34,220,190,237,155,214,132,186,220, 88,179, -217,150,220, 71,128,149, 75,125,138,149,169, 90, 75,203, 96,211,110, 42, 91,143,176,165,184,194,229,195,126, 59,201,121, 83,127, -216,175,102,198,192,241,189,192, 78,211, 93,151,173, 66,131, 11,121,110, 27,122,109, 78,202,226,103,134,152,244,170, 29,255, 0, -106, 75, 77, 80,127, 7,147,118,200,183,170, 81,169, 27,137,124, 65,102, 20, 38,171, 53, 4, 24,110,205,241, 18,226,164,123,227, - 13,202,211, 37,186,124, 33,108, 79, 16, 66,211,103,113,182,182,139,118, 84,173, 7,156,166,216,183, 99,192, 67,187, 32,202, 95, - 52,202,236,231,238, 88,201, 46,213,173,214,193, 83,203,133, 49, 50, 99,173,245,243, 52,203, 11,115,159, 93, 2,225, 42,126,233, -240,185,105, 84,108, 74, 45, 95,108, 43, 59, 35, 69, 97,250,141, 10,138,230,217, 90,251, 48,139, 9,233, 47,173, 83,167, 92, 23, -133,177, 85, 69, 46,182,212,244, 48,183, 86,228,216,112,223, 43,138, 95,241, 29,230,228, 19,170, 78, 41,201,115, 12,218,154,183, - 54,203,228, 66,244,207, 79, 57, 83,174, 48,118,211, 36,113,139, 51,236,182,144,200,197,209, 89, 4, 74, 66, 18,100,220, 71,196, - 25,253, 47,135,176,101, 60, 41,197, 99, 32,207,114, 92,228,102, 52,138,194,116,168,154, 25, 34,146, 41,169,214,165, 68,180,176, -199, 36,210, 6,122, 3, 28, 20,213, 45, 28,143, 83, 37, 84,238, 34,143, 74,120, 89,225,111,121,247,111,121,238, 89,155,225,184, -220, 82,237,142,251,112,146,253, 17,207,229,239, 14,200,188, 40,150,199, 16, 91, 53,100,203,106,223,161,219, 59,177,105,238, 28, - 8,141,191,184, 84,122,123,188,237, 86, 66, 93,102,187, 65,135, 61,155,146,157, 54, 68,117, 85,170, 29, 5,246,132,237, 76,171, - 94,215,181, 54,235,103,182,227, 99,237,219, 50,147,100,221,151,117,186,253, 38,155, 38,143,114, 90, 87, 4,106,212, 53,220,242, -118,242,194,180,160,179, 75,166, 81, 39, 84,235,112, 68,217,140, 61,226, 50,212,247, 22, 89,118, 35, 77,235, 83,184,202,246,199, -112,111, 70,219,122,181, 6,171,108, 65,226,231,125,105,213,122,204, 75, 11,108,236, 27,130,252,141,176,118,155, 98, 2, 33,193, -175,238,213,251, 13, 81, 98,223, 52,197,206, 75,206,187, 71,165, 38,170,196,168,241,155,138, 85, 9,111, 46, 98, 52, 47,111,189, -188,183, 37,209,109, 10,103, 17, 22, 2,110,109,194,146,227,138,131,118,219,246,163,116, 11, 98,132,235,103, 52,122, 75,118,253, -157, 38, 77, 80, 90, 17,210,101,178,248,116,206,118, 75, 83,212, 28,101,175, 1,149,162, 45,226,190, 70,185,231, 0,203,149,228, -121,123,231,153,198,105, 91, 28,230, 88, 16, 36,112,211, 70,154,212, 24, 39,149,165, 18, 74,198, 72, 89, 35,105,100, 12, 41,231, -158,112, 57,145,137,231, 10,100, 94, 51,241, 87, 23,112,111, 30,211,112, 52,153, 38, 73,225,242, 10, 90,124,155, 50,146, 42,116, - 99, 45, 52,112,243,178,218,153, 12, 21, 85, 52,171, 42,205, 88,212,181,201, 75,149,209, 37, 91, 81,100,148, 51, 81, 75, 49, 50, - 6,217,173,183,155,188, 84,118,173,158, 32,172,235, 87,118, 54,166,179,183,149,203,134,222,225,242, 30,215, 80,233, 54,151,241, -165,100,213,106,245,122,156,138,221,227, 2,160,150, 46, 42,164,235,130,161, 57, 86,251,132, 51, 77,169, 64,173,174,167, 38, 59, - 85, 4, 56, 26, 3,109,118,123,135, 41,252, 96,110,135, 23,245,109,254,221,189,165,168,219,173, 91,123, 97, 87,216,251,190,175, -183,219, 85, 99,219,212,155,126,209,183,217,137,183, 10,131, 66,169, 76,169,205,176,225, 70,165,194, 83,180,116,125, 88,219,175, -148,178,243,175,199, 75,173, 59, 29, 61,249,246,206,238, 94,228,237, 61,211,181,155,117, 97, 50,205, 62,247,110,151, 14,183,114, - 57, 71,149,102, 55,111,211, 40,145,161,125, 74,213, 25, 54,141,222,227,180,202,188,130,169, 82, 23, 30,151, 57,136, 16,218, 83, -108, 72, 50, 38, 25, 64,114, 67,110, 47,253,229,176,174, 10,205,199,103,238,253,237, 99, 85,238,119,154,122,231,157, 75,174,215, - 74,238, 7, 25, 46,152,207,214,220,157, 58, 73,170, 74,109, 18, 30, 75,110,190, 29,121,180, 44,165, 42, 9,232, 21,240,162,151, - 56,225, 46, 16,143, 36,205,178, 88,214,186,130,176,206,181, 50,212,206, 37,168,141, 97,228, 37, 63, 46, 9,201, 90, 37, 96,103, -142, 25,155, 74,243, 26,157, 97,150, 33,237, 83,203,114,127,162,199,141,220, 86,188, 75, 85,151,241,125, 31, 2,167, 23,193, 83, -150, 54, 91, 79, 78,166,152,101, 85,109, 75, 81, 85, 61, 59, 60, 98,150,158,166,174,122, 58, 72, 42,106,150,136,102, 51,123, 10, - 85,205,152, 73, 43, 44, 16,206,123,218, 61,196,127, 12, 59,235,177, 53, 46, 29,169, 86,189, 55,136,234,109,215, 88,166, 26,197, - 38, 53,233,116,109,198,223, 91,198,222, 80,171,209,234,119, 5,221, 67,164, 25,151, 10, 5, 85,136, 33,154, 93, 49, 37, 18, 15, -233,100,202, 97,150,139,131,132,251, 87,179,251, 79,179,194,224,147,101,216,244,202, 5, 90,229,159, 17,119,149,211, 72,110, 69, - 46,248,110,163, 29,217, 43,129, 66,171, 79,122,116,167, 35, 90, 76, 72,147, 37,216,236, 37,215, 98,203,117,126,245, 45, 50,100, -114,186,222,133,219, 60, 77,113, 16,220,102, 29,123,136, 11,214,170, 86,194,217,230,148,229, 46, 98, 20,211,128,115, 50,125,254, -146,190,100,228,116,200, 4, 30,163, 7,187,151, 72,226,234,249,165, 72,105,119,173, 54,145,119,199, 91,105,138, 42,209,169,240, -173,203,214, 44,100,188,211,178, 16,205,110,152,208,135,112, 48,176,215,197, 10,171, 13,109,124, 69,109,200, 97, 95, 24,214,226, -126, 46,204,248,131, 53,169,253, 34,207, 26, 53,144, 71, 4, 79, 21, 56, 17,133, 22,229,150,231, 57, 26, 1, 47, 34,187, 2, 44, - 52,198,170,139, 50,202,126,130,126, 47,120,111,192,109,194,252, 57,154,229,220, 65,148, 9,205,116,180,137,154,214, 10,186,170, -162, 10,137,109, 91, 69, 71,150,198,235, 25, 10, 22, 25,169,163,100, 69,105,125,166,116, 70,126,237,240,173,188,242,233, 18,100, -237, 93,235, 42, 60,202,109,114, 92,138,190,220,221,209,196,104,148,181, 76, 74, 16,170,157,149, 92,105,110,132,210, 43,242, 74, - 19, 42,158,164,115,198,158,234, 36, 48,143, 6, 66,144,210,247,177, 85,202,124, 85, 41, 50, 23,238,234, 96,171,220, 84,131,201, - 81,167,186,242, 66,220,103,194,112,116,136,167, 49,204,218,135, 38,114,149, 36,142, 82,142, 24,109,205,249,100,111,109,188,154, -141,169, 87,121,132, 69,149, 25,154,133, 12, 70,102, 35,244,170,162,202,228,211,227,215,160,171,156, 70, 90,220,109,197,198,112, - 60, 25,150,134, 86, 98, 60,242,193, 74, 54, 70, 21,203,185,137, 49, 41,209, 55, 38,242,181,228,211, 26, 17,157,129, 46,114, 42, -180,121, 76,135,128,240,207,214,112,156,148,134, 86, 18, 75, 79, 49, 33, 50,163,165,120,248,146, 57, 73,105,106,159,147, 26, 7, - 37, 20,121, 74,249,129, 29,199, 81,176, 38,192,147,176,176, 11,229, 39, 28,113,196, 92, 57, 81,148,103, 21,249,110,121, 69, 46, - 69,155, 81,200,201, 87, 73, 60,114, 67, 44, 19, 46,155,235,139, 65,117, 46,165, 73, 11, 30,131,175, 80,250,185, 64,199, 74,170, -247,117,187,111, 83,215, 94,171,203,137, 65,135, 79, 67,143,174,161,207, 41, 13, 62,140, 15, 16, 83, 24,105,167, 37, 84, 28, 81, - 82,130,227, 69,105,245, 45, 71, 41, 66,191, 91, 76,133, 87,124,171,187,130, 29,167,217, 76,213,237,251,106, 66,189,205,119,162, - 28, 98, 37,199, 86,142, 16,162,185, 54,235, 12, 41,106,181,161,242, 45, 99,199,119,154,162, 48, 80, 81, 16,158,154,182,205, 62, -117, 86,178,221, 66,238,151, 81,166,214,156, 82,227, 66,168, 73,171, 77,171,198,152, 82,188,180,236, 27,145,222, 95,115, 36,148, -242, 70, 81,136,160, 29, 56, 67,138, 29, 54, 42,202,179,153,139, 37,154,143, 44,138, 93, 90,115, 13,179, 42, 84, 55, 84,228, 58, -130,154, 32,177, 34,167, 76,116,248, 83,164,158, 85, 21, 58, 66, 29,194,202, 84,242,134, 53,191, 74, 37,168,148, 34, 92,139,239, -126,187,219,125,133,150,228,146, 47, 98, 55,179, 1,136, 86,103, 62, 91, 69, 8, 36,153,106, 8, 60,182,111, 58, 40,216,157, 54, - 98, 36, 0,234,243,171, 58, 3,101,229,106,179, 43,139,104, 91, 70, 44,120,176,217, 45, 59, 21,146,164, 50,232, 71, 43,133,111, -117, 90,230,100,144,252,149, 40,149, 41,210, 74,150,181, 21, 44,149,171, 39, 97,160,209,196, 74, 98,138,211,204, 1,101, 39, 41, -232,160, 84, 80, 91, 86,122, 5,117,207,217,171, 93,167, 74,230,109,190,118,227,151, 50, 18, 67, 73, 80,101,207,212, 10, 45,182, -190,169, 65, 32, 16, 14, 72, 61, 50,113,157, 59,206,211,128,167,184,215,134, 84,218,139, 67, 9,202,136, 9, 81,207,134, 79,235, - 28, 17,243,252,113,169,165, 53, 56,166, 68,176, 35, 72, 23,245, 29, 5,183,191, 78,155,254, 24,174,234,171, 13, 76,138,146,157, -228,111, 49,216, 94,228,111,219,173,201, 22,181,250,250,130,207, 61, 76, 83, 78,129,201,136,206, 30,102,214, 63,241, 74, 61,219, - 81,242, 79, 81,141, 92, 33, 83, 11, 11, 43, 74, 70, 79,235,128, 48,146,159, 95,183, 89,187, 48, 16,248,113,190, 78,100,130, 82, -160,176, 65, 32, 28, 5, 99,215,168,252, 53, 65,216,162, 34,146,199,235, 39, 31, 2,200,193,233,215,144,231, 79, 81,206,164,117, -233,252,125,253,240,213, 89,206, 82,241,176,243, 14,190,132,117, 7,227,110,189,143, 94,183,197,134,155, 9, 14, 77, 73, 35,160, -115, 31,105,236,123,140,118,214,207,217,208, 91, 67, 45, 2, 19,212, 36, 12, 14,163,212,156,142,135,247,233,135,163, 69, 10,155, -158, 95,135,196,200, 0,103, 57,200,252,115,173,138,183, 84,150, 18,214, 79, 47, 42, 82, 64,200,200,192, 25, 63, 34, 51,173,102, -107,129,181,255, 0,158, 33, 53,234,201, 4,224,108,194,246,251,207,207,175,124, 57,232,109,180, 51,202, 72,248,130,113,142,248, - 78, 0, 31, 35,235,246,233,191,188, 42,206, 66,108,193,167,132,253,103, 41,181, 0, 71,255, 0, 2,140,174,134, 73, 35,245, 92, - 39, 33, 30,121,235,229,171,141, 90,228,106, 11, 32, 52, 80,236,183, 73, 12, 70, 4,229, 74, 7, 30, 43,152, 63, 3, 41, 29, 84, -123, 28,224,100,235, 5, 13,173,197, 57, 46, 67,138,125,249, 46,120,146, 95, 88,253,117,156, 97, 40, 39,245, 91, 0,225, 35,176, - 29,180,142,179, 80,220,168,205,149,126,211, 15,223,164, 16,122,250,158,195,208,145,134,108,155, 45,116,149,107,106,210,241, 41, -186,161,255, 0,120,194,221, 71,236, 47,127,218, 35, 79, 77, 86,176, 66,163, 8,205,225,197, 43, 56, 37,105, 65, 56, 36,252, 75, - 82,212,174,171,112,149, 28,156,245,207, 93, 15, 45,216,241, 57,146, 57, 27, 56,200, 72,192, 89, 78, 15, 85,168,159,128, 99, 39, -226, 63, 33,223, 89, 20,167,114,130, 10,130, 80, 72,248, 26, 31, 30, 65, 0, 16,165, 3,208,231,174, 61, 61, 53,129,212,188, 52, - 7, 20, 82,214, 78, 74,148,226,186,164,228, 18, 84,181,103, 36,244,238,122, 30,157, 53,185, 26, 44,106,170,160, 1,238,236, 54, -253,214,249,247,206,169,100,122,153, 25,234, 36,251, 71,160,233,212,122,216,124,236,119,197,146,116,196, 43,156, 23, 20,234,176, - 66, 83, 24, 44, 50, 18, 79, 66,235,132,167,159, 61, 50, 50, 18, 9,206, 15, 83,172, 58,116,165, 37, 64, 4,182,218, 73,199, 59, -139, 10, 82, 73, 66,186, 33, 13, 30, 94, 96,174,108,228,231,168,198,123,139,140,202,131, 79, 30, 70,148,227,238, 33, 74, 65,102, - 43, 97,196, 54,147,211,226, 81, 41, 74,129, 0,103,226, 56,236, 70, 51,172, 78,114,228,243, 5, 43,193,100,115,243, 36,120,134, - 75,201,194,128, 42, 71, 54, 17,204, 60,206, 74,114,122, 18,116,112,214,210, 59,223,241,219,240,190,226,251,116,251,158,201,176, - 10, 23, 73, 61,143, 95,141,182, 61, 58, 16,167,226,118,197, 23,220, 24, 42, 82,202,147,250, 50,234,130,146,217, 45, 36,168,133, - 45, 94, 71,175,197,215,174, 49,223,174,177,233, 50,208, 66,131,105, 61,214, 66, 64, 78,114, 64, 32,244, 61, 27, 42, 36,100, 30, - 80, 0, 29,250,232,185,104, 66, 49, 33,199, 21,150,220, 43, 66,158, 90,158, 9, 94, 72,229, 74, 84,180,165, 36,173, 63,234,146, -156,146, 6,173,114, 20, 80,180,165, 72, 80,112, 20,145,206,164, 41, 92,139, 1, 96,182,144,172, 56,130, 20, 14, 50, 0, 39, 56, -233,141, 46,141, 98, 54,244,254, 95, 29,247,198,133, 76, 90,206,166, 58,175,233,178,237, 97,238,254, 93,189,215,178,204, 42, 33, - 93, 64, 42,248,136, 81, 57,235,147,209, 95,205, 61, 51,156,117,229,239,140,107, 16,158, 7, 42,147,206, 74,138, 85,241,171,148, - 17,140, 96,145,216, 96, 12,125,253, 6,178,233, 89, 1, 42, 89, 0,224,140, 40, 16,146,179,204,164, 55,201,216, 60,158,153, 29, -114, 59,100,118,197,106, 10,207, 40, 35,170, 73,230, 36,114,149,103,155,161, 9, 87, 86,241,147,231,213, 88,193, 58, 92, 49,218, -223,135,110,159,187,221,238,253,216,103,145, 0, 34,219,123,186,124,143,147,136, 13,251,114,237,134,237,143,105, 46,242, 73, 13, - 22,133,233,109,109,125,248,227,197, 1, 40,126, 69,118,199,166,197,148,182,249, 0,241, 0,122,146,174,101, 31,136,168,158, 98, - 78,117,200,194,180,168,126,137,101, 88,239,233,246,107,183,127, 72, 24,180,175,104, 99,158, 27,161,215, 19,195,254,205, 37,246, -129,255, 0, 34,180,195,184,124, 52,148, 17,150,202,152, 45,175,169,201, 11, 7, 0, 99, 92, 70, 83,105,199, 81,140,246,229,242, -249, 29, 75,178,155,181, 13, 41, 59,217,109,211,176, 36,116,235,219,242,199, 51,241, 50, 44,124, 69,158, 34,159, 47,181,212, 31, -255, 0,116,172,199,247, 18,113, 76,168, 40,116, 72, 29, 62, 47, 63,188,117,208,235, 35, 24,207, 92,244,254,221, 86, 40, 35, 62, -152,207, 95,232,251,116, 51,133, 67,168, 78, 71, 81,243,251,244,236, 6,194,221, 48,206,160, 29,173,211,161,253,216,162,179,229, -143,191,211,175,217,170, 11, 0,227,176,245,245,199,175,207,160, 58,244,188,254,177,201, 82,124,188,177,231,246, 29, 81, 39, 39, - 58, 93, 70,194,221, 63,158, 20, 24,164,230, 60,136,232, 72,244, 39,183,109, 12,178, 9, 61,242, 59,122, 30,223,214,116, 74,241, -130, 73, 3, 7,167,246,245,213,189,240,234,136,240,212,148, 97, 95, 22, 70, 74,128,236, 58,249,233, 68,235,140, 3,126,155,227, -193, 36,156,254,113,165,175, 10, 63,237, 99,238,206,116,180,125, 62,182,191,207,191, 25,199,180,146, 15, 65,159,151,174,171,165, - 93,142, 58,142,227, 61, 70,135, 31,120,254,145,251,117, 92, 96,245, 30,127, 46,250, 37,188,191, 15,195,231,231,124, 12, 86,241, - 19,156,117,235,231,142,159,126,136,111, 10,193, 74,187, 28, 99, 24,201, 62,191,136,252, 53, 65, 9, 0,131,220,244,251, 58,232, -164,225, 61,178, 7, 94,221,254,236,246,210, 76, 24,139,124,252,223, 25,219,239,197, 69,160,168,119,233,221, 93, 78, 6, 49,216, -125,186, 33,164,115, 36, 40,247, 29, 66, 71,160,233,235,170, 64,133, 15,207,113,215, 69, 36,242,224,244,244, 35,208,105, 34, 0, - 39,190, 49,143,104,101, 42,238, 57, 85,215,168,198, 72,251,188,244,123,104, 72, 72, 24,201, 79, 78,191,187,166,132, 65, 39,226, - 72, 25,244, 39,167,152,251,180, 90, 22,144, 1, 87,195,147,231,252,236,250,124,244,153, 23,216,158,159,233,140, 17,124, 28,214, - 58,114,244, 24, 61, 62, 93,191,167, 70, 32, 12,103, 39,230, 60,137,199, 94,154, 13,178, 23,215,168, 29,253, 59, 99,250,245, 93, - 11, 73, 95, 47,114, 62,127,102,127,103,150,147,194, 39,221,190, 13,108,129,145,140,228, 16,160, 70, 82,164,158,133, 36,121,130, - 9,200,212,133,253,149, 30,214, 40,187, 66,197,191,195, 39, 20,245,169, 15,236,235,143,162, 14,220,110,140,213,189, 54,163,181, -211,100,184, 17, 30,135,114, 58,162,165,203,177,148,226,240,211,164,149, 65,206, 21,150, 70, 83, 30,118,242, 14,122,121,126,206, -218, 33, 39, 37, 68,227,168,229, 32,128, 82, 65,232, 65, 7,184, 56,237,231,157, 55,102, 89,109, 54,103, 78,208, 84, 37,251,171, - 11,106, 86,236, 71,240, 32,236, 71, 81,211, 14,249, 22,123,153,112,230, 99, 22,103,149,205,202,158, 63, 43, 43, 92,199, 44,100, -130,209, 74,160,141, 72,214, 29,195, 41, 1,144,171, 0, 71,233,189, 78,163,199,149, 6, 5,118,137, 50,159, 88,161, 86, 97,179, - 50,145,112,209,228,179, 81,164,214, 32,202, 66, 93,106,101, 62,161, 25, 74,109,214,150,210,146, 82, 66,186,115,105,198,165,210, -220, 45, 54,156, 0,210, 18,130, 16,156,144,132,160,130,113,234,163,215, 63,102,191, 63,142, 13, 61,168,188, 90,112, 88, 35, 91, -187,121,119,179,119,109,106,165, 54,185,123, 83,184, 1,218,213,172,195, 74,112, 25, 31,193,231,222,112,191,110, 58,164, 21,224, - 48,176,215, 49, 7,195,198,117, 59, 45,161,226,130,149,124,109,157,131,126, 59,105, 34, 25,190,109, 42, 53,196,184,241, 30, 15, -198,138,237, 78, 35, 82, 31,140,211,167,245,219, 66,220, 41, 7,190, 19,170,167, 56,203,165,200,101,140, 85,149,104,230,213,203, -101,189,155, 78,155,220,117, 82, 3, 46,198,227,123, 43,181,137,199, 98,248,121,226, 4, 60,107, 28,144, 81,211, 52, 25,134, 94, -168,243,195, 33, 13,165, 88,233, 15, 20,151, 2, 68,212, 8, 23, 84,117,184,212,128, 27,157,174,166,211,138,218,110, 68,166,202, - 12,226,136,177,129,232,166,216, 72,248,148, 83,159,213, 41, 3, 58,199,247,101,136,115, 44,202,189,191, 58, 53, 62,165, 75,147, - 13,232,255, 0, 85, 84,225, 70,168,193,124, 22,212, 1, 92, 57,109,173, 42, 25,207, 92,107, 7, 94,247, 82,222, 44,120, 49, 37, - 54,166,153, 62, 27, 97,162,180,183,147,212, 19,228,122,244,251, 53,166, 60, 82,241,139, 69,219,203, 98, 69, 54,140,180, 86,247, - 30,234,150,139, 66,201,183, 25,149, 29,233,234,185, 42,196, 70,134,169,113,219, 89,247, 70,154, 91,161,107, 46,114,242,132,100, -244,206,153,205, 97,168, 2,158, 4, 44,100,219,125,135, 64, 78,228,219,222, 73,244,222,221,174, 76,131, 35,204,179,124,218,130, -135, 45,164, 51, 85,202,227, 76,106, 62,206,255, 0,109,219,126, 90, 70,190,103,145,136, 84, 93, 78, 72, 23,191, 48,247,123,113, - 54,107, 98,106,146,105, 9,180, 41, 21,123,162,141, 80,151, 62,153,110, 91,228, 81,105,212,218,178,156,241, 34, 77,169, 72,130, -226, 75, 2, 57,229, 90, 91, 71, 95, 19, 25, 61, 49,174,102,239,183, 16, 27,245,196,245, 64, 82,110,171,182,181, 46,217, 96, 6, - 35,218,212,137, 51, 32,219,108,198,105, 92,201, 85, 69,199, 30, 6,166,164,128, 10,220,112,144, 72,251, 53,214,202, 31,178,178, -163,118, 58,154,214,227,110,196,250,141,229, 94, 90,234,215, 82,232,240, 89,168, 70,166, 84,170, 4,190,168, 41,121,249, 0, 76, - 90, 29,119,151, 56, 9,248, 73, 25,214,146,202,219, 91, 51,104,184,161,111,104, 55, 2,101, 83,114, 54,198,194,191,169, 77,110, - 68,221,177,164, 63, 85,175,214,237, 88,241,211, 82,147, 76,141, 78,128, 22, 91, 87,142,150, 98,205, 74, 85,132,248,171,248,142, - 53,173,150, 83, 84, 83,203, 81, 44,142,139,160, 27, 2,160,233, 3,114,117, 16, 12,141,127, 70, 80, 9, 35,125,241,233,239,130, - 41,224, 38,103, 13,117, 54, 67,153,205,226, 87, 28,112,190, 95, 45,125, 92,210, 83, 86,187,242,226, 42,178,174, 80,149,113,165, - 44, 65,229,100,134, 4,141,150,122,141, 81, 51, 73,162,237, 30,168,196,225,210,109,131,180,183,158,251, 93,182,173, 90, 77,131, - 96, 89,181, 75,242,173, 86, 98, 49,102, 9,183, 41, 18, 99, 82,213, 61,169,147, 28,108, 26,115,213,233,208, 41,241,139, 73, 89, -155, 50, 88, 98, 57, 82,144,225, 71, 44,173,110, 47,174,107,174,254, 98, 13, 58,249, 85, 6,131, 87,171, 39,220, 44,241,181,244, -153,180,166, 32, 5,149,154,122, 42,162,227, 19, 75,165,128, 71,188, 56,178,174,115,204, 82,145,128, 36, 3,237,235,223,234,222, -215,112, 55,182,219, 31, 86, 98, 61,181,187,220,112, 95,208,183,126,253,180, 97, 54,220, 21,109,191, 13,155, 89, 33,113, 54, 95, -106,218,165, 50, 18, 40,148,150,231,154,107,198, 55, 42, 67,242, 41,179, 93,113, 42,113, 74, 86,162, 97,177, 48,209, 39,113,161, - 58, 64, 13,211,225, 75,148, 51,140, 36,165,190, 84,143,159, 65,171, 75,135,178,168,107,242, 90,172,214,180, 51, 59,234, 16,134, - 17,190,133, 64, 20, 55,158, 54, 2, 70,146,225,136, 0,174,157, 43, 97,185,243, 63,233, 63,244,231,241, 66,159,196,102,225, 15, - 14, 51, 37,224,188,143,132, 9,142,161,114,156,207, 55,165,122,154,211,180,201, 83, 95,148,230, 89,116,181,212,212,192, 8,224, - 5,150, 25,142,186,190, 84,124,245,138, 25,117,109,141,230,157,201,225, 47, 99,174,184,147, 81, 37,251, 42,185,185, 27,109,239, -116,234,109, 66,219,122, 4,155, 82,247,170, 85, 97,120, 77, 63, 82,121,198, 42, 45, 83,110,106, 65,247,182, 36,165, 14,184,226, -150,194, 25, 9,113, 3,110,182,151,139,125,212,183,132,104, 23,139,113, 55, 18,137, 24, 33, 42,171,202,150,138, 77,231, 10, 58, - 80,148, 41,215,106,105,101,113,238, 23, 2, 0,109, 6, 99, 41,127,224, 0,190, 84,115,174, 89,251, 50,110,182,111,109,161,226, - 3,101, 36, 58,211,149,138, 21, 94,218,222,203, 78, 35,202, 81, 46, 82,231,199, 69,129,126,193,167,180, 63, 93,214,103,194,179, -170, 50, 48, 15, 42,103, 21,168, 17,147,174,130,217,182, 49, 51,154, 91,177,188,102,144,164, 58, 35,144,191,242,169, 25, 99,159, -148,124, 72, 7,226,207, 80, 49,207,131,216, 83, 92, 69, 69, 29, 6, 99, 95, 73, 34,235, 8,250,148,236, 9, 14, 17,197,138,133, - 2,215,210,116,217,110,164, 91, 97,105,119,134, 62, 33,208,248,151,225,118, 89,196, 28, 81, 28, 85,249,213, 91,213,189, 89, 99, - 36,143,237,143, 83, 41,169,117,146, 89,165,169, 6,105,139, 75,170, 73,228,145,245,134,150, 73, 9, 44,122, 97,110,111,221,149, -120, 67,165,189, 58,161, 34,214,201,105,134,233, 55,148, 69, 83, 11, 50,221, 90, 92, 68, 40,213, 72,110,200,135, 46, 73, 41,108, -171, 14,167,245, 84,130, 65,200,211,166, 94,171, 84,102, 51, 47,194,143, 89,131, 9, 5,184,240,105, 85, 40,147,218, 74,222, 40, - 89, 97,227, 2, 67,137, 97, 78,252, 5,254,110, 85,114,132, 39, 9, 72, 32,233, 93, 14,201,122, 65,143, 22,156,212, 69, 86,100, - 46, 44,135, 38, 57,135, 33,219,180,231, 22,234, 83, 60,161,192, 10,170,170, 8,144, 33,178, 71,233, 29, 30,242,191,208,181,133, -191,182,125,129, 22,137, 24,184,219, 16,105,244,122,116,229, 24,172,196,140,227, 51,106, 82, 37,172, 0, 92,153,226, 37,249,213, - 57, 83, 22,165, 18,225, 82,222,113, 69, 74, 9, 71,234, 68, 9,208,198,209, 94,219,218,228, 15, 83,112, 65,184, 62,227,110,189, -109,178,169, 62, 83, 5,218,149,249, 37,181, 42,198, 87, 89, 80,199,253,217, 86, 70, 70, 98,204, 20,146, 89,197,201,101, 22,230, - 59,242, 41,215, 69, 77, 73,128,236, 67, 18, 58,167,154,138,231, 60, 4,102,158,150, 80, 82,130,218,157,115, 45,198,101,174, 84, -165, 1, 68,114, 52,130,156, 99, 89, 45, 34,212,134,228, 73, 16,146,227,205,181, 1,201, 78, 77,171, 38, 42,218,143,227,144, 4, -201, 12,201,115, 36, 71, 12, 32,165, 43, 3,226,248,212,144, 10,146, 53,126,180,172,233, 73,154,154,212,168,202, 93,197, 80, 97, -136,104,140,211,242,100,192,162,196,109,194,166, 41,208,221,148,163,201,135, 23,227, 62,232, 78, 95,127, 36, 0,218, 27, 1,238, -160, 90,138,170,136,112, 34,196,122,116, 24,179, 26, 97,224,201, 66,151, 91,158, 22,121, 26, 8,112, 2,184,136,155,133, 28, 30, - 89, 15, 32, 1,204,132,117,220,138, 25,100, 69,141, 33, 42, 95,185,185, 36,108, 64,216, 41, 3,125, 76,119, 96, 54,234,214, 58, - 53,249,220, 11, 78,232,142,144,194,128, 23,101, 1, 6,175,214, 62,103,112,219,249, 82,197, 84,238,108, 17,110, 52,139,118, 47, - 29,184,225,215,110, 42,187,173,184,204,207, 72, 80, 85,167,183,182, 36, 9,173, 70,184,111,106,192, 66,170,116,219,106,146,227, -200, 80,164, 50,235, 10, 77, 66,191, 84,117, 10,106,153, 79,228, 73,241, 36,174, 36,119,184, 21,190, 59,243,185,156, 69, 84,159, -170,238, 77,125,233,212, 64,224,114,153, 96, 80,157,149, 74,219, 91,113,168,200, 9,139, 79,161,218,173,191,225,204,247,118,130, - 18,103,207, 18,106, 18, 92, 10,125,231,194,214, 80,151,139,218, 61,196, 11, 91,199,196,197,237, 22,149, 81, 84,157,189,217,229, -191,180,182, 2, 88, 11, 17,100, 68,160,212, 84,221,239,112,178,210, 9,241,102,214,111,225, 52,151, 48, 84,168,148,168, 76,161, - 74,109,180,160,115,231,137,235,103,118, 56,127,147,104,217, 55,156,251,107,111,175,235,178,220,141,117, 86,109, 75,154,123,113, -238, 29,183,163, 87, 2, 87,106,211,239, 74, 50,150,145, 64,189,234,148,231, 29,158,154, 36,149,174,165, 75,167,166, 52,138,188, - 24,138,159, 21,133,236, 83,112,252,185,180,169, 8,169, 20,176,234, 0, 18, 88, 7,176, 39, 89,211,114,119, 4, 70,189, 44,161, -148, 22,190,159, 75,188, 43,225,207, 12,190,140,158, 22,229, 62, 49,120,177, 11,207,199,124, 79, 74, 43, 96,166,138,138, 92,199, - 54,166,167,120, 99,153, 50,252,166,134, 37,121,162,150, 40, 36,137,243,154,231,228, 65, 75, 44,172,185,141,117, 61, 12, 49,202, - 64,184,109,119,103,132,181, 74,129, 79,134,194,135, 43,190,237, 21,191, 29,100, 96, 37, 40,117, 73, 82, 99, 35, 32,124, 88, 42, - 63,170, 53,226,221,219, 54,154,144,210,159,144,184,110,188,191, 9,111, 50,130,176,158,110, 80, 84,251,171,202,128, 1, 93, 73, -229, 25, 56, 37, 0,140,233,155,215,238,236,178, 81,245, 6,230,196,184, 38, 72,117,114,146,204, 10,157, 18,124,222, 68, 55,238, -229, 13,192, 85, 62, 51,171,139,134,207, 35, 41,140,233,231,202,146,147,144,117, 96,166,239,230,251, 91, 78,170, 52,187,154,100, -238, 69,175,198,143, 95,161, 83,106, 18,154,101, 79,165,231,152,117,164, 67,133, 45,134,212, 82, 91,194,156, 5, 45, 44,164, 2, - 66, 84,155, 34,147,133,243, 36,165, 20,116,217,188, 35,151,238,126, 97, 4,254,177,125, 68,239,211, 82,223,173,172, 0, 24,167, -179, 47,246,170,125, 30,232,243,104, 31,139,124, 24,227,142, 30,161,169,102,142,147, 50,172,203, 50,121, 41,229, 42, 69,218, 3, - 30,118,241,202, 0,243,200, 41, 94,165,129, 22, 42, 88,227,163,116,203, 17, 8,185, 93,183,106,208,252, 38,221, 75,239, 69, 82, -148,212, 98,226, 86,217,118, 44,165,167, 9, 65,101,223, 60,148,144,181, 96,168, 43, 0,252,174, 91,214,181,183, 10,117, 86,179, - 50,153, 73,166, 83,194,214,252,233, 83,209, 26, 43, 44,162, 64,140,219,206, 58,234,210,112,235,191, 11, 64,100, 44,244, 4,168, -145,172,123, 98,119,186,189,184,148,118,141, 70,148,197, 50,191,111,207, 66,201,167,161,249, 52,249,241, 42,212,229, 7,204, 15, -126, 66, 92,110, 3,140,161, 73,118, 19,202, 81, 97,108,148,161,199, 27, 91, 78,107, 86,119,238,216,221, 43,230,252,250,182, 13, - 58,183, 46,147, 70, 13, 38, 4, 56,116,185,179,162, 69, 46,180,223,141, 81,142,184,140, 41,147, 41,114, 84,242, 75,171, 82, 84, -194, 91, 72,230, 64, 90,214,181, 33,200,201,170, 43, 89, 94,208, 24,128, 15,166, 66, 20,216, 3,112,111, 96, 88,110, 78,159,118, -155,220, 99,160, 60, 98,250, 99,112,207,134,255, 0, 71, 46, 29,250, 64,120, 83,195, 50,248,169,148,241,245, 69, 30, 93,144,193, - 67, 79, 83, 28, 82,215, 85,189,122,153,115, 32,105,154,178,134, 26,105,168,101,163,146,156,211,189, 75,102,130, 44,173, 68,114, - 77,207, 71,110, 15, 18, 59, 61, 18,251,183, 45,234,180,107,233,187, 1,250,171, 17,238,235,214,213,164, 83,170,247, 53, 22,146, -247, 59,114, 43, 22,149,141, 85,159, 17,119,100,134, 63, 68,234,163,187, 34, 18,164, 53,206,152,138,117,244,161,183, 58,193, 87, -225, 15,135,235,154,206,165, 93,187, 71,198, 37,215,186, 16,174, 74, 84,106,197,183,252, 7,217, 27,135,115, 66,233,111,133,248, - 82,110, 88, 27,108,185, 18, 44, 98,226,138,217, 76, 74,176, 98,168,211,208, 31, 14, 67,113, 0, 40,199,138, 77, 58,219,219, 50, -244,105,201,133,114, 94, 12, 56,227, 82,225, 41,246,106, 20,107,126, 74, 1, 10, 21,105,145, 29, 83, 87, 29,105,183,135, 90, 99, - 14, 24,108,168,230,161, 33,210,145, 21,121,134,197,241,157,196,167, 13,119,204,187,239,101,247, 94,228,180,103, 85, 93, 74,238, -122, 27,239, 11,130,196,190, 89, 74, 3, 65,139,247,111,234,106, 52,187,152, 37,129,200,203,193,152,211, 98, 54, 3,112,101,197, -108, 4,133,235, 56, 58, 10,228, 87,202, 71,178,152,134,242, 75,119, 19, 27,222,225, 88,150, 31,254, 96, 54, 34,214,141,213,129, - 30, 77, 63,251, 74,190,146, 28, 63,196,245, 21, 94, 41,241, 81, 90,138,137,238,120,103,135,232,114, 90, 51,145,166,250,161,204, - 42,243, 28,191, 56,115, 80,172, 17, 36,201,106, 30,171, 49,165, 99, 58,215,215,101, 85,180,199, 46,155,165, 84,250,206,231,112, -167,186, 84,202,229, 58, 84, 41,147,169,133,248,238,197,175, 91,119, 93, 18,221,187,232,146, 84,224,168,218,183,125,171,122, 80, -169,146, 69, 62, 91, 77,165,197, 50,182,199,186,202, 90, 37,197,125,153, 76,161,221, 73, 67,102,161,181,186, 27, 75, 97,238,133, -149, 75,174, 53,111,223, 86,211, 87,109, 54,213,185, 35, 77,146,237, 17,137, 14,200,167, 84,169, 77, 86, 23, 24,190,212,104, 85, - 56,114,217, 98, 72, 75,241,159,101,166,228, 0, 16,240, 9,226,206,213,123,125,246,154,253,183, 26,179,248,203,225,125,202,139, - 46,178,168,179,235,251,104,229, 22,255, 0,179,166, 52, 82,164, 41,247,246,211,115,158,110,161, 69,150,180,149,143, 14,155, 84, -150,134,210,172, 54,180,249,236,206,213,123, 69, 61,143,214,236,216, 85,123,123,115, 55,238,195,166,195,122, 53,197, 19,108, 46, - 26, 79, 16, 44,236,253, 26,226,128,250,223,131, 85,141,183, 84,234,188,232,106,173,199, 90,212, 89,142,137, 15, 83, 81,144,125, -209,101, 40,228,141, 47, 10,102,180,149, 86,154,156, 24, 92, 29,108,129,135,154,226,204, 2, 44,137,115,111, 54,226,254, 93,182, - 24,147,120,185,244,188,240,119,233, 7,195,249, 54,103, 93, 17,224,159, 17,114, 33,203,106,209, 45, 37, 92,121,173, 8, 71, 34, -150,170, 58,150,200,101,166,150, 41,220, 61, 44,139, 5, 76,112,171,213, 71, 20,136, 39, 4,118, 6, 29,186,134,194, 27,148,195, -193, 62, 44, 68,187, 21,106,102, 84, 30, 70, 85,205,142, 80,158, 87,201, 81, 7,153,192, 0,192, 80, 64,211,149, 66,165,180,203, -136, 67,104,240, 27, 90,130,130, 17,226, 37,166,148,162, 1, 67, 73, 94, 66, 83,252,227,140, 39, 39,160,215, 35, 46,223,110, 95, -179,178,219,105,233,244,219,195,120, 47,233,139, 89,112, 67,182,118,102,191, 77,247,149, 21,115, 41,196,213,175, 41,244,200,241, - 80, 85,142,139,201,194,137, 9,207, 77,115,159,136,255, 0,164,222,229,137, 30,163, 15,134,190, 13,228, 85,153, 9, 87,213, 91, -165,191, 87,204,167, 45, 40,174, 45, 76,182,204,169, 86, 14,216,198,101,228,255, 0,133,202,109,178,212,219,137,132, 41,194,148, -158, 96,180,131, 37,202,248,118,182, 90,133,138, 42,118,185,221,117,133, 75,133, 32, 29,216,168,185,189,236, 14,163,109,129, 0, -219,143,243, 63, 16,184, 90,150, 55,105,115,232, 42,165, 31,169, 77, 42,212,177, 32, 14,130, 18,226,224, 0, 53, 57, 0,216,238, - 55,196,195, 45, 68, 22,211,205,146,176,133, 54,151, 20,132, 15,133,229,231,144, 40,224, 37, 5, 65, 39,151,155,148, 18,158,152, -235,167, 48, 77, 75,205,166, 35, 10,241, 36,158, 64,164, 52, 60, 79, 9, 9,207, 48, 83,160,114,149,103,148, 96,103,182, 73,215, -230, 7, 43,219,203,237, 79,157,190,246,230,253, 61,196,180,212, 75,181, 94,156,213, 51,101,233,182,221, 22,223,225,210, 69, 2, -168,227, 11,169,218,181,125,167,162,176,212,122,212, 25, 8,142,218,126,176,154,244,170,211, 68, 7, 88,168,182,234, 82,177,213, -203,167,233, 12,113,211,199,133,235,182,188, 54,240, 99,176,227,101,238,251,254, 37, 46,135, 81,183,246,214,113,190,247, 95,112, - 47, 39, 98, 37,203,129, 54,157,199, 86,136,195, 22, 53,140,193,106, 91,252,225,149,204, 98, 19, 75,118, 84,180,165, 7, 18,169, -178, 74,170, 69, 51, 56, 73,209, 23, 81,210,224, 42,219,115,204, 50, 5,109, 34,219,149, 87, 3,115,219, 16, 36,241, 71, 32,204, - 22, 85,167,138,163,219, 12,129, 32,128, 37,228,152,177, 1,116, 88,216, 92,246,107, 17,218,230,195, 19,125,171, 92,246,205, 30, - 90, 32, 84,171,244,168,149, 5, 16, 61,205, 83, 89,247,180,147,216, 56,218, 23,148,121,247,198,178,122,125, 22, 5,114, 40,154, -138,154, 22,210,134, 80, 99,180,183,112, 79,162,136, 1, 95,118,123,235,152,220, 17,123, 63,247, 3,103,237, 26, 77,219,197, 85, -255, 0, 51,114,119,174,160,202, 42, 21, 90, 12, 74,180,170,149,181,104,202,120, 37,197,211,222,171, 73, 81,114,229,171,182,181, - 40, 63, 37, 88,100,184,149,120, 41,228,194,143, 75,153,101, 48,185, 91,107,153,134,155, 1, 8,109,165, 41, 41, 74, 64, 1, 32, - 4,224, 99, 3, 80,103, 78, 51,204,101,157,185,180, 57, 21, 10,146, 34, 81, 20,149, 19,184,236,206, 95,148,177,131,216,104, 15, -110,168,167,108, 60,209,182,123, 57,246,138,169,146,133, 91,117,142, 38,105,152,127,215, 43, 89, 24,145,251, 10, 7,241,197, 84, -154,117, 14, 91, 72, 18,147, 35, 46,114, 97,104, 83,107, 42, 39, 25, 0,249,254,115,167, 66, 11,229, 77,120,141, 0,191,209, 21, - 33, 25,229,241, 84, 82, 74, 83,146, 59,103, 90,221, 94, 77, 82,101,118,154,148,130,244, 86,221,202,228,255, 0, 60, 39,160,229, - 89,254,119,200,247,211,203, 6,164, 88,105,150, 65,236,148,131,147,213, 56, 24,206, 62,221, 45,195,237,153,206, 43,169, 51,119, - 73,100,164,125, 34, 72,211, 64, 97, 96,110, 1,191, 81,243,214,210, 12,210,138, 24, 41, 40,102, 89, 57,178,213, 33,105, 1, 32, -244, 32,111, 96, 45,125,246,219,221,139,140, 97, 48, 58,236,154,131, 46,153, 46,146, 87,204,146, 82,132, 15,242,109, 36,167,167, -132, 6, 59,119,206,190,200,170,100,132,160, 21, 41, 56, 1, 36,134,210,133,100,156,114,158,195,191,225,170,166,170,211,105,248, -149,212,255, 0, 59, 56, 36,156,100, 15, 64,113,246,235, 24,171,213,226, 60, 10,142, 60, 84,244, 75,137,232,164,103,245, 65, 82, - 71, 80, 58,100,117, 7, 79,209, 82,242,147, 69, 59,116,245, 27,159, 93,250,111,240,235,241,195,116, 85,144, 77, 56, 50,195,229, - 27,121,122, 40, 22, 2,202,123, 1,254, 33,247,226,229, 38, 74,212,210,138,159, 75, 96, 2, 2, 89, 3,156,146, 72,192, 46,118, -242,234, 6,176,138,131,208,130,143, 59,105,144,180,243, 97,114, 84,183, 74, 71,117, 30, 85,124, 41, 72, 32,103,160,201,234, 15, - 82, 53,100,169,214,165, 52,218,131, 78,182, 91, 7, 5,229,115, 43, 41, 62,101, 9,253, 85, 99, 29,115,128,122, 16, 53,132, 78, -168,190,250,242,169,137, 87, 33, 4, 48, 26, 80,111, 0, 28,172,132,175,226, 56, 4,128,162, 71,159, 77, 32,237, 34, 54,153, 1, - 86, 59,239,247,110, 15,243,248,219,221, 40,164,162, 89, 84,201, 21, 66,136,191,195,112,122,116, 32, 11,143,131, 90,221, 78,196, - 28, 93,170, 53, 86,220, 45,182,214,121,193, 56, 75, 24,202, 63,156,175,242,120, 8, 79,194, 49,147,208,172,140,107, 28,144,185, - 14,165,196,243, 54,128,227,107, 95, 40, 1,247,148, 10, 82,160,148, 36,114,161,156, 18,146,126, 53, 99, 7,225,193, 26, 21,201, -165,223,209,170, 87, 43, 69,196,145,224,199,109, 32, 21,142, 84, 37, 68,147,135, 50, 73, 61, 7,235, 99, 61,180, 42,150, 9, 83, -110, 45,199,193, 66,138, 91, 83,156,173,178, 57, 84,149, 20,132, 36, 4, 47, 4,158,234, 33, 74, 7,212,107, 34, 85, 36, 91,174, -195,111,187, 14, 2, 4,136, 88, 88, 50,239,114, 9,216,252, 64,239,107,131,210,253,111, 96,106,135, 9,241, 91, 90,152,154,224, - 81, 10,117,183, 66,150,132,132, 32,132,199, 90, 18, 18,211, 62, 25,202,136,229, 86, 80, 71, 55, 78,180, 86,211,138, 90,218,109, -210,132,173, 42, 40,195, 97,226,160,188,146,149, 61,202, 17, 24,252, 7, 4,147,128,148,146,114,179,143,162, 72, 66, 20, 93, 82, - 91, 32,243,151, 0, 13,184,226,121, 87,250, 54,210,216, 3, 57, 40,248,112, 84, 48,188,119,233,112,142, 86,234, 29, 75,124,173, -161,158,235,112,133, 50, 75,156,174, 56,246, 66,135, 48, 3, 10, 10, 0,128, 64, 10, 4, 29,108, 70,250,118,191,227,252,183,237, -110,134,223,125,175,163, 80,140,221,139, 15, 94,194,214,251,186,251,205,239,140,110,108, 82,150,189,228, 33,212, 54,225, 10,142, - 29,108, 40,168, 1,209, 40, 65, 63, 3, 28,169, 5, 42,200,193, 95, 80, 71,124, 14,168, 18,210, 86, 21,203,202, 82,160, 8, 0, -169, 41, 24, 9, 81, 60,184, 87,196,165,224, 12, 28, 28,231,190,156,202,203, 43,100, 60,180,187, 46, 83,142,128, 90, 68,167, 20, - 70, 74,148,144,167, 1,235,149, 35,157, 71,249,216, 72, 0, 37, 61,155,106,154, 76,153, 41,136,149, 4,169,231,163,196, 66,202, -129, 9,117,245, 33,158, 98,160,112, 71,136,224, 32,158,132,126, 26, 84, 48, 2,250,134,223,233,191,126,157,125,253,112,216,241, - 18,202,161, 65, 55, 29, 0,222,246,181,135,238, 29,126,252, 64, 99,219,127,112,181,112,123, 74,183,173,166, 28, 82,255, 0,130, -214,206,212, 89,178, 82,176, 66, 90,159, 67,176,105, 47, 75, 67, 68,147,204,215,137, 82, 24, 35,204, 30,154,228,170,206, 51,216, -231,166, 58, 99,237,251, 53,183, 60,121,238, 60, 93,220,227, 99,138,189,200,132,233,122,157,114,111,133,244,154,114,249,150,180, -154,125, 6,168,171, 94, 25,104,172,228, 50, 89,161,161, 72, 29,130, 92, 0,116, 26,212,101,246, 56, 61, 59, 96,227, 63,241,212, -247, 43,140,165, 5, 18,176,179, 8,144,144,122,130, 84, 18, 62, 32,155, 28,114,150,121, 50, 85,103,185,197, 66, 29, 81,207, 87, - 80,202,123, 21, 51, 57, 82, 15,189,108,126,252, 8,178, 15, 79, 76,232,117,245, 36,142,192,224,252,191,179, 85,214,174,254,137, -207,231,246,104,101,224, 28,231,161,235,248,233,200,126,252,104, 1,220,109,129,221,230,199, 97,142,189,189, 51,215, 63,159, 61, - 14, 64, 0, 96,247, 29,126, 71, 68,169, 89, 62,120,252,245,208,202,238, 79,204,253,154, 92,108, 5,240, 48, 58,192,202,135, 67, -215,243,231,249,198,133, 81, 3, 57,249,224,119,237,229,162, 28, 39,169,249,249,126,125, 52, 26,200,251,199,127,179, 74, 45,198, -227,126,216,200,253,248,160,178, 50, 58, 3,211,207, 63,184,253,186, 90,240,163,147,159,195,236,210,210,184, 24,175,170,168, 61, - 49,215,167,225,161, 16,112,122,156,116,213, 97,248,103,161,251, 51,164,216, 90,227,174,173,255, 0, 60,100,245, 38,214,190, 14, - 73, 56, 0,142,152,239,145,247,116,213, 66,176, 7, 82,172,142,216,249,246,207,222, 52, 58, 84, 83,211, 29, 7,111,236, 58,242, - 80,162,174,101, 47, 8, 61,128,206, 71,222, 7,174,116,131,222,222,236,101, 69,254,127,150, 46,141,168, 96, 0, 57,137,206, 73, -254,145,243,192,215,213, 44,173, 73, 8, 39, 9, 56, 87,124,103,247,245,254,141, 80,105,188,242,146,174, 81,158,128,117, 61, 49, -215, 25,244,209,205,167, 57,192,206,127,164,117,237,249,237,164,172, 79,207,166, 48,109,219, 21, 90, 56, 35, 35, 32,143, 46,221, - 61,125, 15,125, 28, 57, 72, 79,160, 62,127,205,251, 62,125,244, 50,121,112, 0,252,253,190,154, 37,176, 85,142,192,124,135,244, -231,207,166,177, 97,123,227, 24,184,178, 15, 76,159, 82, 63,163,247,234,184, 24, 57, 24,201, 57, 7, 31,135,219,161, 16,175, 35, -231,219,250, 49,162,146,113,220,245,232, 65,198, 59,246,199,175,246,233, 22, 22, 36, 97, 50,187,220,155,223,231,255, 0, 56, 37, - 43, 8,199, 58,186,159, 32, 59,244,249,104,146,238, 70,113,140,249,250,227,183,159, 77, 4,113,144,190,153, 63, 44,227,184,200, -252, 53, 81, 36,116, 32,231, 29,201,251,125, 7,150,146, 98, 58,223,225,130,219,221,123,117,193, 41,119, 24,248,249, 64, 32,224, -227,175, 94,160,122,244,206,167, 39,236,166,220,118,247,115,129,157,165,148,252,148, 73,171, 88, 74,169,237,245, 93, 33, 73, 46, - 54,186, 44,133, 38, 1,113, 61, 74, 65,132,228,126, 92,227, 35,168,212, 42,118,215,108,110,189,211,185, 98,219, 86,181, 49, 83, -231, 73, 5,229,186,227,137,139, 78,167,194, 66,128,145, 85,173, 84, 93, 79,135, 74,164,183,252,247,156,234,162, 66, 26, 67,174, -148,160,203, 23,217, 2,214,215,112,241,106,238,110,209,215,119,102,143, 34,181, 87,151, 2,239,168, 76,172, 75,110,139,108, 53, - 53,136,201,133, 34, 21,179,239,238, 5,184,218, 82,218, 11,139,119,149,215, 15,196, 91, 66,126, 17, 4,227, 9,104,167,142,154, -137,228, 6,169, 95, 86,155, 95, 74, 21, 96, 75,158,136, 11, 5, 3, 81, 26,142,194,230,246,184, 60, 26,124,214,135,136,167,204, - 41,105,100,124,178, 88, 36,167,158, 80, 44,129,137, 73, 35, 0,159,180,193,212, 2, 20, 18,129,238,218, 65, 23,235,214,231, 75, -174,219, 59, 83,184, 21,235, 93,151, 30,184,224, 91,147, 13, 27,193,104,188,236,105,178, 18, 35, 38,162,134, 82, 50,234,163, 33, -213,188, 0,207, 86, 70,181,171,102,120, 8,183,217,222,155,115,124, 46, 59,138, 53,229,105,208,108, 90,123, 86, 21, 10, 66,223, -155, 42,179,121,215, 33,166, 69,211,124,221,210, 95,234,244,211, 45,231, 83, 25,177,128,216,198,122,164,107,107,162,239,150,195, - 32,148, 57,188,187,110,233,193, 75,141, 34,227,167, 60,130,146, 48,180, 45, 33,226, 20, 8, 39, 35,207, 26, 14,226,227, 7,134, - 29,183,182,107,183, 12,173,200,163,213,169,246,180, 23, 39,205,163, 89,141,125,115, 86, 84,102,186,172, 83,169,144,129, 84,133, -127,178,128,126,237, 65,225,142,150,158, 82,226,162, 33,169,116, 0, 89,111,114, 69,200, 23, 59,157,133,183, 61,135, 91, 99,179, -242,190, 62,226, 28,135, 33,205,114,204,161,165,203, 70,109,205,246,202,132, 82, 30, 74, 87,138, 56,249, 76,250,117, 70,177, 5, -155, 76,136,234,116, 85, 84, 45,129,101, 97,144,207,224,179,103,238,181, 56,183, 81,123,208,158,152,250,158,156,245,169,125,220, - 20,116, 60,235,202, 42,121,197, 48,137, 42, 66,150, 73, 60,184, 78, 0, 56,244,208, 91,129,114,240,113,236,166,216,187,155,114, -235, 20,202,117,183, 21,229,201,153, 69,162,189, 37,138,222,236,111, 13,232,227, 74, 84, 26, 29, 62,109, 77, 74,149, 44, 56,247, - 39,140,233, 40,139, 17,165, 41,231,112, 0,207, 27,248,128,250, 66,114,226, 82,170, 52,190, 16,184,115,190, 43, 19, 3, 14, 52, -141,201,220,155,106,174, 41, 84,247,112, 66,100,195,183, 41,209, 86,185, 78,160, 14, 96, 30,113, 8, 56,248,186,103, 81,143,226, - 11,136,157,247,226,127,114,100,238, 30,253,238, 45,126,244,188,158,105,214,162,199,173, 62,168,205, 81,169,238, 40,172,211,168, - 86,223,192,221, 6,154, 50, 7, 43, 76,160,168, 1,206,181,158,186,127,203, 56,124,207, 46,161, 18,211, 34,253,166, 54, 14, 6, -215,180,103,204, 24,247, 50, 42,129,179, 89,197,215, 20,239, 27,253, 36,248,135,244, 13, 71, 12, 80,113, 94, 97,196, 20,179,105, - 38, 7,168,168,108,188, 50,127,118,243,135, 96,181, 38, 34,111, 20, 96, 58,169,220, 60,100, 95, 24, 39,180,115,137,253,201,226, -247,127,170,251,223,186, 82, 27,254, 16, 94, 74,118,124, 26, 44, 87, 92,118,155,105, 91, 81,121,162, 91, 54,141, 31,196, 63, 13, - 58, 13, 59, 9,230,192, 47, 62,243,210, 23,241,186,117,175, 92, 57,196, 97,202,237,211, 57,208,178,252, 42, 34,147, 24, 1,211, - 46,149, 5, 18, 60,253, 6,173,251,228,231, 53,219, 29,128, 65,247, 42, 12, 6, 79, 41,200, 5, 73, 4,129,215,191,174,178, 14, - 26,216,118, 93,122,230,134,202,121,164,204,167, 68,139, 29, 9,238,183,223,119,194,101, 41,207,153,113,104, 31,126,172,212,141, - 41,120,124,197, 24,209, 26, 34,128, 46,118, 28,192,119, 59,147,183, 82, 73, 39,169, 36,239,142, 53, 53,117, 21,115,214, 86, 85, - 74,211,213, 84,180,178, 72,231,118,103, 42,204, 73,176,238,123, 0, 0,232, 0, 27, 98,109, 63, 71,223,128,234,125,203,195, 15, - 16,156, 74,220,244,174,123,199,114, 99,200,218,237,155,145, 45,177,136,116,123, 98, 92, 90,221,217, 83,134,149,167,225, 85, 82, -187, 18, 29, 56,186, 15,197, 30,152,164, 14,138, 57,216,168,246, 17,161,213, 31,142,228,117, 50, 90,146,235, 97, 10,230, 75,225, - 8, 56,228,115,185, 67,169,229, 41,229,239,204,112, 8, 58,236,151, 0,219, 99, 15, 98,184, 76,225,239,107,105,113, 83, 17,187, - 99,109,109,231,167,180,148,132, 41, 85,138,164, 38,234,181,105, 14,116, 28,206,174,124,199,201, 39,174,123,233,168,226, 23,134, -171,150, 93,110,226,220, 91, 38, 61, 58,161, 65,144,255, 0,214,146,168, 44, 62,182, 43,237,206,148,240,247,152, 52,168, 9,103, -146,167,207, 53,197, 58,202, 3,136, 63,166, 80, 94, 2, 65, 52,151, 19,209, 54, 99, 28, 89,138, 38,170,131,118,127, 82,142,117, - 40, 61, 55,137, 74,160,247, 13,239,215, 29,145,225,180,210,240,102, 89, 6, 69, 36,194, 24, 42,163, 73,100,212,214, 95,105,101, - 94,110,228,237,169,174, 22,254,128,108, 0, 3, 82,108,234, 84,116, 52,134,210,201, 41,147, 33, 50, 29, 8,240,203,143,186, 2, - 0, 83,220,201,207, 58, 67, 40, 7, 36, 0, 19,132,156,107, 99,104, 52, 8,210, 93, 98,116,150,210, 36,193,113, 47, 65, 13,129, -225,199,203,101,135,198, 79,235, 74,113,133, 41, 10, 89, 5, 32, 16,148,242,167, 36,170, 87, 15, 59,203, 71, 82, 20,230,223, 76, -148,128,134,151,205, 74,153, 75,168, 33,105,194, 64, 39, 19,144,162, 0, 37, 71, 41, 4, 99, 28,189,244,241,218,123, 83,186, 79, - 41,180, 35,109,238,133, 20,114,133, 45,113,162, 37, 61, 14, 28, 74,221,114,104, 72, 79, 81,147,216,245,198,162, 81,100,213, 74, - 64,146,146, 66, 91,182,134,244, 22,232, 13,237,215,211,210,214, 24,178, 78,125, 70,186,229,108,198, 24,237,177,102,158, 32, 0, - 54, 4, 18, 91, 96, 64, 3,222, 5,177,113,161,208, 12,134, 16,211, 10, 90, 34,143,242,202,115,224,151, 49,158,230, 50, 29, 74, -147,238,236, 18,160, 10,191, 89, 64,114, 35, 1, 74, 86,178,171,163,112,237,237,158, 85,185, 95,170,208,239,234,203,242, 38,132, - 82,227,109,214,216,222,251,153, 34, 51,212,224,196,176,253,106,153, 99,209,229, 46,149, 79, 64,228, 45, 41,208,217,144,176, 88, -142,149,168, 40, 7,150,209,216, 45,211,158,164, 57, 54,149, 73,183,217, 80,229, 46,213,234, 77, 72,113, 41, 0,142,127,114,166, -182,234,138,136, 63, 8,231, 66,124,250,119,214,136,251,111,106,123,151,194, 15,179, 87,116,183, 91,103,247, 82,225,178,183, 81, - 55, 54,223, 91, 16,111, 43,121,168,212,249,212,202,101,201,112,177, 6,177, 22,136,227,168,117,112,106, 47,198, 43, 67,115,185, -253,229,144, 74,152, 83, 75,194,132,166,147,135,179, 55,167,146,177,104,218, 8,163, 49,131, 44,171,101, 82,242, 36,105,101, 37, - 93,174,238, 0,210, 13,137,213,184,190, 34, 25,199,137,124, 27,150, 48, 25,157, 89,207,105, 98, 73,154, 90, 74, 25,209,101,153, - 68, 78,197, 69, 87, 38,162, 8,201, 42, 11,115, 17,137, 23, 64, 22,225,150, 51,124,116,238, 62,206,240, 93,121,221, 53,125,139, - 98,254,183,183,166,236,173,213, 46,123, 18,139,190, 78, 91,107,223,205,183,143,115, 74,157, 85, 27,132,254,217,209, 34,200,137, -176,244,148, 57, 59,154,223,149,118,189, 34,254,168, 6,195,212,202, 37, 1,178,229,101, 17,220,184, 46,123,134,236,174, 85,110, -107,134,183, 87,184,110, 58,228,233,117, 42,229,201, 93,156,253, 74,191, 90,168,206,125,114, 39, 77,169, 84,100,184, 86,235,239, - 72, 90,214,224, 4, 37, 74, 86, 72, 39, 36,218, 42,181, 73,149,138,165, 74,181, 92,157, 58,167, 88,172,212,165, 86, 43, 53,106, -148,217, 85, 42,173, 98,179, 80,115,198,159, 87,171,212,230,186,183,234,149, 55,158, 37, 78,200,125,199, 29,112,245, 90,142, 6, -128,109,101,110, 97, 36, 6,179,241,128, 71, 49, 62,185,242, 26,176,114, 30, 31,163,201, 33,178, 14,117, 76,191,106, 66, 5,197, -194,141, 9,251, 40, 52,128, 22,229,136, 85,214,206, 85, 72,164,252,120,250, 73,120,157,244,128,204,169, 36,227, 28,238, 99,195, -217, 60,113, 67, 69,150,137,165,120, 17, 41,193, 88,102,171,119, 98,213,213,195, 83,191,180, 77,245,112, 73, 61, 64,160,130,138, - 25,228,133,136, 90,148,234, 57, 93, 9,121, 9, 80, 90, 91,144,148,188,144,176,114,149,165, 14, 2, 18,224, 80, 4, 40, 96,130, - 50, 8, 58,204,169,155,143,113,209,211, 21,169,110,192,185,160, 68, 11, 17,232,183,173, 53,187,170,154,198, 82, 82, 61,205,249, -174, 9,212,229, 15,255, 0,131, 48, 54, 63,248,163,211, 24, 96,228, 10, 88,201, 41, 7,162,137,244,238, 63, 57,213, 53,164, 43, - 36, 14,185,200,252,159,150,159, 39,166,130,161, 52, 77, 10,202,163,166,160, 13,137,238, 13,174,167,222, 44, 71, 99,138,111,135, -120,167,136,248, 74,170,106,190, 27,206,170, 50,105, 42,192, 74,133,134, 66,176,213, 68, 13,249, 53,148,230,244,245,180,228,253, -170,106,184,166,129,255, 0, 94, 54, 24,116,231,239,189,238,150, 89,133, 64,254, 15,237,252, 36,248,206,123,141,131, 77, 48, 29, -151, 33,230,210,209,151, 80,170, 84,195,206,184,250, 26, 64,229, 8, 74, 50,160,149, 45,107, 8,109, 8,177,171,117,119, 10,108, - 7,169,170,189,110,207,170,159, 74,208,253, 57, 21,201,173, 71,113, 46,161, 40,144,133, 73, 74,196,165, 54,232, 78, 92,111,222, - 60, 37,149,168,148,124, 74,206, 0,166,219,230, 33,120, 36,117,206,124,251,143,219,175,170, 91, 74, 90, 19,207,241, 32, 19,200, -147,240,156,250,254,205, 37, 29, 21, 36, 32,133,167, 64, 24,223,236,130,111,182,228,145,114, 71, 98, 73, 54,218,248,156,102,190, - 58,120,209,157,242, 99,172,241, 87, 62,130,146,154,148, 80,197, 71, 69,153,213,101,153,108, 20, 34, 40,225, 52, 84,185, 86, 89, - 37, 30, 91, 75, 70,241, 68,139, 37, 45, 45, 36, 84,242,232, 13, 44,108,196,177,172,227,188,193, 37, 92,169, 75,105, 8,109,150, -208, 16,219,109,131,209, 13,161, 0, 37,180,228,147,128, 7, 82, 79,114,117, 72,146,163,205,129,140, 14, 81,216,140,129,158,184, -237,223, 94, 84,177,158,216, 4,224, 31, 32, 73,237,246,107,233, 9, 80, 79, 50,129,198, 79,194, 64, 35,215, 61,126,205,109, 95, -111, 47,109,189,216,170, 85, 2,233, 91,105, 10, 6,221, 0, 3,160, 30,158,131,165,177,229,212,133,160,131,128,125,112, 51,211, -236,243,208,105, 11,230, 60,201, 8,109,191,139,226,248, 78, 71,159,207,251,116,122, 20, 20, 50, 7,145,200, 61,199,151, 95,191, - 67,169, 36, 55,151, 49,215,161,201, 4,252,137, 0,246,233,161,179,111,219, 6,177, 6,221,251,126,255, 0,227,138,110,123,186, -192, 82,130,150, 8,200,194, 73, 3,182, 73, 31, 61, 75,227,232,215,112,195, 99,223,219, 35,198, 38,227,110,133,131,105,238, 13, -175,184,202,183,248,125, 93,173,121, 80, 32, 92, 54,253,118,207, 69, 45,203,170,246,167, 78,131, 84, 97,109,174, 60,137,213,122, - 35, 78,132,242,171, 48, 16,160,164,173,180, 40, 68, 24,149,143, 8, 54,158,138, 74,147,205,144,144,181, 99, 24, 3, 29, 15,109, - 77,123,217,103,184,103,103,189,143,246,187,116, 6,164, 81,171,123,149,186,219,227, 85,173,205, 79, 52,105,170,164, 82,174,168, -214,139, 78,199,144,180,167,195,143, 48, 82, 93, 67, 79,160,169, 10,102, 26,210,135, 57,138,185, 98,156, 99,155,193,146,101, 73, - 89, 80, 12,138, 37, 10,177,139, 6,150, 66,173,201,141, 9,232, 76,161, 9, 36, 16,136, 25,200, 33, 72,197,129,225,126, 86,115, -110, 47,162,164, 72,185,210,136,228,101, 7,117,187, 20,132,234,244, 26,101,111,190,214,223, 28,193,223, 63, 97, 79, 4,115,184, -194,185,209,179, 27,239,185, 54,175, 14,116,135,150, 47, 93,165,163, 83,105,149,186,237,191,122,205, 66,164,162,196,218,237,215, -185, 31,144,220,155, 36, 48,243, 62, 60,137,208, 39,207,167, 56,164, 69,140,229, 65, 78,120,204,111, 6,212,251, 26,125,155,123, -125, 58,216,185,109,203, 55,136,138,110,227, 80, 37,198,122,216,220, 26, 55, 21,119,221,175,121,219,245,200,177,194,145,114, 81, -170, 86,149, 42, 2,105, 21,166,212, 60, 80,227, 40, 75, 45,172,132,134,150,223,194,108, 27, 71,113,203,157, 91,184, 42,197, 34, - 81,147,122, 93, 21, 71, 34,115, 36, 46, 82,152,170, 10,100, 82,181,243,128,150,154, 17, 84,177,200, 6, 11,105, 81, 80, 1, 58, -222,155, 74,229,118,163, 38,164,121, 90,136,212, 8,204, 83, 34,180,202,131,110,158, 98, 36, 84,159, 83, 97, 28,172, 45, 43, 91, -109, 37, 72,230, 95, 43, 74, 4,164,144, 53, 71,103,220, 99,198,175, 58,200,217,245, 68, 48,132, 0,197, 3,242, 22,221, 8, 44, -154,100,147,169, 93, 83,188,174, 86,218,156,144,111,212,220, 79,225, 79, 9,228, 78,100,161,201,225, 89, 2,172,143, 33, 82, 89, -164,178,130,234, 9,180,107,204, 58,149, 35, 85, 80,157, 55, 14,113,212,219, 99,136,234,228,106,101, 18,155, 87, 66, 43,171,106, - 35, 20,230,230,213, 86,165, 86,106, 81,233,145,219,143,245,157, 94,162,202, 82, 39,213,158, 8, 74,228, 72,240,144, 31,125,213, -185,225,160,171,151, 78,181,189,187, 22,141,226,232,140,220,143,169,234, 75,115,193,110, 28,247, 27, 75, 82, 94,236, 27,137, 40, - 30, 71, 22, 72,232,147,202,162,122, 0, 78,185, 81, 30,244,240, 36, 85, 11, 97, 75,143, 66,134,205, 38, 36,144,114,151,170,110, -182,100, 75, 96, 4,171,162,144,234,163,165, 65, 32,245, 74,178, 8, 26, 10, 61,219, 41,136, 17,203,239, 31,124,142,204,154,156, -175, 13,210,158, 95,136, 52,201,108,142,169, 62, 50,148,126, 69,191,150,148,202,184,199, 54,167,208, 37,169, 53,106, 7,153,101, -243, 27, 0,162,250,143,152, 27,234, 59,146, 0,182,199, 21,248,142,186,130, 68, 16, 73,204, 22, 91,197, 37,200, 58,148,200, 0, - 63,105,108,186, 23, 99,179, 29,212,244, 27,233,106,113,119,182,151,183, 20,183,231, 10, 22, 90, 95,184,110,205,174,179, 85,117, -110, 45,213, 17,214, 92,183,173,234,168,126, 51, 38,204, 66,193,230,145, 91,105, 50,153,247,130, 7, 35, 78, 18,214, 74,210,172, -108,130,235,136, 99,157,106, 88,230, 57, 24,206,126, 30,184, 29,122, 99, 35,174,184,239,193,253,153,180, 27, 99,196,214,228,110, -244, 17, 42,218,187,248,132,179, 97,219,181,104, 40,144,201,180,230,222, 73,172,174,167, 38,226,195,235, 46,192,175,213,208,195, -104,125, 33, 94,236,228,180, 23,194, 91,114, 74,129,232,125,205,113, 42, 50,221, 64,113, 73, 41, 74,147,200, 62, 21,165,105, 39, - 60,201, 61,142, 2,178, 62, 90,181,184,106,180,102,212,111, 59, 48, 18, 60,132, 50, 0, 46,130,202, 66,144, 55,247,134, 61, 71, -223,105,215, 25, 75,194, 85,210,100,173,193,144,212,211,209, 46, 91, 68,149,130,172,222, 99,154, 8,239, 94,118,188, 98, 35, 41, - 2, 1, 17,229,242, 66,157,152,184, 14,149, 74,248,109,178, 71,136, 2,123,168,115, 2, 14, 14, 57,186,118, 32,228, 31, 62,191, - 45, 97, 51, 47, 98, 23,151, 29, 87,134,165, 30, 85, 12,144, 73, 56, 9, 36, 28,115,140,128, 50, 48,190,217,242,214,190, 84,238, -181,120,174, 53,206, 10,138, 20,251,121, 81,248,208, 14, 28,111, 62,153, 35,167,145, 94,177,148, 93,188,217,104,175,152, 41, 36, -165, 46, 12,115, 32, 15,137, 25, 36, 18,180, 96,127,181,202,144,175, 93, 74, 99,129, 80,108,110,126, 63, 15,221,249,252,113, 22, -167,164, 88,198,195, 87, 75,254, 23,239,215,227,252,142, 54,149,187,161, 46,158,100,184, 10, 85,203,158,101, 4,148,156,144,121, -194,199,192,114, 21,229,141, 90, 42,114,158, 91,107,145, 76, 8,113,208, 10,213, 17, 74, 45,161,212,100,229, 76, 41, 32,144,224, -234,174, 78,161, 92,159, 14, 20,113,166, 18, 37,213,201,202, 92,120, 40, 0, 57, 92, 36, 41, 65, 39, 56, 67,160,145,146, 15, 76, -158,152, 57, 32, 19,157,102,144,110, 4,175,225, 82,207, 50, 70, 72, 4,148,117, 57,200,207, 83,144, 6, 64,237,203,243,234,149, - 69, 58, 78,154, 36, 23,244, 61,193,236,111,235,211,249,140,110, 67, 81, 45, 20,162,104, 13,237,177, 83,114,174, 63,101,198,215, - 30,253,136,189,193, 83,190, 47,109,215,101,185,200,130,228,102,194, 92, 90, 75,164, 58,231, 42,146, 73,229, 80,113, 35, 60,189, -138,136,248, 74,128, 86, 58,234,234,212,199,221, 1, 78,200, 88, 33, 68, 16,142,102, 27, 82, 21,132,242, 40, 55,146, 82,112, 59, - 17,133, 39, 33, 64,231, 88, 13,198,183, 11, 6,169, 79, 9, 91,204, 2,185,108,130,176,149,181,132,149,201, 71,135,250,206,161, -180,146,226,123,173, 0,158,139, 29,113,232,181,233,174, 28,169, 77,128,142, 71, 27, 45,169,120, 83, 43, 79, 55, 50,121,143,249, - 64, 84,147,211,161, 24,193,202,134, 98,211, 43, 81,204, 98,153,246,107,216,216, 88,131,109,238, 59,250,223,241, 6,248,157, 80, -188,121,165, 42,212, 83, 34, 68,192,217,212,145,169, 24,117,235,185,235,117, 35,175,186,197, 67,227, 22, 64, 10, 60,141,168,243, -128, 10,146, 74,212, 91, 65, 32, 37, 74, 41, 42, 91, 32,227,252,152,234, 9,207, 49, 35, 87,149, 84, 92,140,217, 90, 25, 74, 60, -117, 4, 33, 47,165,213,199,195,201, 42,109,160,129,149,198,144,226,142, 19,206, 49,147,240,163,148,243,105,158,139, 82, 82,138, - 1,113, 92,142, 19,203, 33,183,156,229, 70, 87,204,203,109,242,184,163, 29,174,101,225, 33, 28,203, 82,148,148,148,231, 35, 87, -196, 84,214,134,138,188, 73, 40,112,151,217, 83,209,203,109,180,180,164,252, 94, 34, 22,162,183,100,103, 28,223,168, 83,130,148, -143,136,157, 47, 28,195,190,192, 88, 95,247,119,235,183,190,247,177,191, 77,244, 42,224,209,114, 95, 93,183,232,119,183,196,245, - 29, 59, 16, 63, 12,178,167, 82,117,101,214,158,116,143, 5, 24, 90, 23,206,135,176,149, 30,171, 28,152, 67,133,148, 37, 68,130, - 72, 82,136,233,216,106,111, 20,187,199, 75,216, 78, 31,183,187,123,107, 14, 3, 11,107, 54,178,243,187,194, 90, 57,118, 69, 74, - 29, 37,232,118,227, 17, 80,181, 15, 26, 67,151, 45, 70,140,218, 83,159,252, 98,186,121,105,253,153, 86, 47, 7, 9,115, 32, 43, - 45, 41,124,222, 48,200, 88, 62, 39, 83,200,159,140,117, 57, 42,192,233,231,168,229,253, 33,126, 36,209,101,112,247,183,156, 51, - 81,166, 20,220,123,253,118,139,190,234,105, 14,114,189, 19,107, 54,170,107, 47, 14,101, 54,172, 24,245, 77,192,149, 76,140,166, - 92,229,230,106,223,125, 65, 36, 5, 99,118,157, 26,170,122,122, 52, 39, 85, 75, 0,125, 66,117,118, 29, 62,202, 6, 59,122,116, -190,198, 41,159, 87,166, 83,147,230, 89,163, 16,134,138, 38,100,189,183,152,128,144,169, 29,124,210,178, 41,223, 96, 73,219, 16, -244, 92,153, 82,150,236,202,131,161,234,140,247,159,157, 80,125, 32, 97,234,132,215,151, 38,107,224, 96,116, 92,167, 94, 87,207, -155, 66,172,131,211,207, 61,115,246,127,110,136,115,169, 29,135,115,161, 87,230,174,152,245,239,216,121,254,124,181,105,160, 0, - 11,108, 63, 45,182,199, 34, 42,236, 13,205,207,174,253, 14, 6, 86, 50,113,249, 63, 47,150,135, 81, 10,242,192,235,159,159,204, -250,104,133,250,130, 20, 72,252,244, 26, 21, 71,161, 62,125, 79,223,165, 20, 18, 70, 21,192,234, 32,117,249,224,103,231,246,124, -180, 51,131, 57,234, 1, 4,245,209, 90, 17,194, 14,122,247, 57,199,203,231,165,199, 81,129,129, 85,211,167, 82, 79,115,242,244, -199,166,116, 42,200,207,108,117,199,219,215,207, 68,185,242,238, 7,159,111, 95,223,160,150, 79,126,152, 61,193,243, 61,127, 63, -118,148, 65, 97,210,247,249,255, 0, 92, 12, 82, 36, 2,122,129,247,254,255, 0, 61, 45, 81, 95,235,119,242,252, 62, 95,159, 93, - 45, 31, 3,108, 86, 29,251,103,229,162, 52, 42, 87,219, 61, 15,145,199, 76,131,229,170,129, 68,158, 94,108,116,207,111,159, 94, -190,189,244, 71, 2,221,108, 70, 14,195,173,190, 63,195, 7, 54,123, 21,125,223, 63, 67,162, 7, 95, 35,246,121,232, 38,240, 58, -100,147,243,252,247,254,173, 22,149,245,244, 62, 94,126, 95,102,146,193, 58,116, 56, 41,161,203,212,156, 99,200,252,243,216,104, -214,200,243, 0,253,248, 39, 64,165, 89, 29,191, 17,231,231,131,157, 86,108, 20, 44,168,172, 16,172, 1,159, 47,179,238,210,109, -233,109,135,242,198,113,112, 10,193, 1, 67, 4,249,129,223,237, 35,243,215, 68,167, 3,168,200, 39,161, 29,191,102,122,118,208, -169, 81, 32, 12, 12,140,119,237,140, 1,140,143, 60,232,128,172,100,156,100, 96,228, 96,147,246, 99,229,253, 58, 79, 24,193,141, -168,119, 61,113,211,239,233,131,248,104,132, 28,224,245, 56,235,243,233,235,143, 45, 0,133,103, 3,168, 4,250, 14,255, 0,105, -213,126,108, 17,133, 41, 57,207,234,250,255, 0,195, 72, 55, 94,183,198, 45,251,240, 96,194,212, 65,206, 15, 99,156, 99,167, 83, -223,166,178,107, 86,133, 46,228,174, 83,168, 84,230,131,242,231,203,102, 43, 41, 89,195, 69,215, 20,122,190,224,255, 0, 37, 29, - 13,165,110, 56,175,230,182,210,136,235,140,226,141,149,172,148, 40,242,164,140,243, 0,115,229,231,167, 83,107,106,201,163,215, - 27,102, 59,168,106,161, 80, 68,168, 17,165,168, 14,120,254,244,202,121,148,223, 55,119,212,203,110,165, 63, 53,159, 44,231, 74, -177,164,138,154,105, 34, 0,200,138, 72,248,250,159,147,183, 77,240,231,146,208,195,153,231, 25, 94, 91, 81, 57,166,167,174,158, - 24,157,199, 85, 87,117, 86, 43,125,181, 16,108,183,219, 81, 23,218,248,222,138,101,205,111,109, 53,188,139, 14,206, 6, 92,185, -106, 97,219,158,165, 20, 33,169,181,218,147,105,229, 75,211,229, 39,172,106,107, 74, 42, 76, 88,249,229,105,177,148,165, 78,169, -197,168,202, 52, 58,189,201, 45,107,152,251,134, 43,136,241, 26,136,133, 56,212, 96, 73,206, 22, 82,160,183,187,255, 0, 56,129, -159,230,233,172,181,109,231,101, 77,113,174, 96, 84,151, 11,234, 90,143, 58,214,238,114,165,184,181, 28,173,106, 39,185,234,115, -211,167, 77,109, 61,163, 22, 44, 22, 27, 91,137, 83,171, 74,128, 82, 1,207,234,158,188,201, 56, 29,255, 0, 15,232,173, 43,102, -142,152, 57, 86,230,207, 39,153,152,245, 98,109,185,219,238, 30,131, 97,176,176,238, 92,135,135, 96,160,165,130,158,154,139,217, -233,169,194,164, 80, 40,217, 20, 91,173,247,102, 39,119, 98,117, 51, 18,204, 75, 18,113,157, 88, 27, 77, 6,162,243, 10, 91, 45, -173,210, 17,204,134,249,192, 79, 80, 63,214,237,246,249, 13,116,123, 98,182, 58, 4, 74,205, 30,167, 79,136,195, 21, 8,242, 27, -109,110,132, 5, 41, 73, 87,235,167, 43, 4, 56,130,140,228, 96,131,208, 99, 90,225,182, 40, 67,142, 48, 16,148,176,211,139,108, -165, 13,164, 41,196,146, 1, 0, 28, 0,122,103,200,227, 93, 65,218,186,205,175,107,194, 23, 45,203, 58, 29, 22,218,182, 96, 72, -174,220,149,170,131,237,177, 22,155, 74,165,199, 84,185,211,101,200,116,132,182,210, 35, 52,242,142, 78,112,156, 0, 78, 6,171, - 12,238,173,234,222, 88,228,156,164,106, 9, 35,215,160, 2,195,177, 61,189, 58, 92,224,103,185,230,105,150, 32,167,167,102, 26, -193, 82, 7,165,183, 6,219, 90,219, 1,190, 56,205,197,103,181,207,127,173, 13,203,184,118,215,133,170,141, 31,104,108,203, 18, -227,169,219,114,110, 38,173, 59,114,175,120,222, 85,138, 12,199, 41,181,154,156,153, 53,154,123,241,232,148,133, 84,163, 74,110, - 60, 86, 88, 82,220,105,176,227,238,146,190, 68,232,182,233,123, 64,184,141,223,154, 60,154, 6,249, 57,181,123,167, 78,146, 84, -227, 18,107,187, 67, 98, 81,110, 42,116,165, 0,145, 34,159,117,218,148,120,114, 99,114,227,163,101, 42, 70, 84,115,229,173, 86, -221,155,170, 61,231,185, 27,133,121, 69, 66, 4, 43,174,251,188, 46,104, 37,150,148,210, 87, 78,184, 46,106,173, 86,152,226, 26, - 95, 86,138,160, 76,140, 84,147,241, 37, 74, 32,128, 65, 26,194,202,138, 27, 72, 66, 66,146,164,249,147,216,250,231,207, 87, 69, - 31, 7,240,224,142,134,170,163, 33,165,108,202, 5, 70, 19,180, 17,154,132,144, 1,186,205,167,154,132, 27,219, 75, 46,158,139, -101,216,113, 46,113,196, 25,150,101,152,213,213, 75, 88,211,164,146,185, 69, 33, 74, 4,212,116, 0, 45,109,150,194,253, 77,174, -196,146, 78, 25, 29,226, 14, 57,121,205,113,232,130, 3,142,211,225,184, 35,161,210,251, 60,158, 24,194,153,113, 74, 39,194,232, - 48, 51,240,246,211,245,236,251,162,194,185,248,143,179, 45,121, 83, 19, 21,250,213,203,107,181, 9,165, 71,118, 87,191,186,213, -102, 27,130, 3, 81,152, 66,148,243,239, 41, 41,105, 3, 24, 5,238,101,124, 41, 58,101,247,161,159, 22,181, 69,168, 39, 42,110, -109, 13,166,193,234, 48,228,124, 36,164,245,239,145,174,129,251, 9,174,186, 5,165,237, 66,225,233,203,134,153, 75,169,179, 93, -122,232,183,105,102,171, 29,185, 77,211,107,245, 27,114,161,245, 77, 90, 19,110,130,148, 84,153,121,149, 6, 86, 70, 82, 94, 37, - 63, 16, 4, 76,106,145,166,225,202,216,163,115, 19,154,118, 0,141,244, 17,182,175, 48,111,179,107,216,131,211,124, 55,240,245, - 50,102,121,237, 29, 36,238, 33, 74,218,128,140, 64, 27,115, 13,172,189, 64, 38,246, 91,130, 3, 17,112, 70,216,253, 60,108,203, -170, 61, 38,218,163, 69,169,210,215, 6,123, 52,168, 12, 42, 18, 30, 74,149, 13, 45,197,109, 30, 2,136,232, 84,156, 96,142,195, - 24,211,173, 99,205,135, 95, 67,163,195, 82,216,105,226,174, 71,124,148,149, 2, 51,235,129,141,105, 44, 90,227,175,203,110, 58, -159, 60,234,145,200,227,139, 86,113,133,225, 74, 81,201,236,156,159,187,231,170, 28, 4,113, 50,246,254,220,188, 78,211, 27,167, -174,157, 67,217,253,200, 98,198,160, 62,226, 84,149,213,154,110, 59,134, 85, 65, 74, 80,193, 38, 67, 46,128,145,156, 36,167, 56, -206,171,117,160,130,138,122, 97,237, 82,206,210, 2,164, 74,193,245,233, 0,234, 42, 2,170,144,127,100, 1,189,173,233,213,116, - 57, 94,103,152,229, 89,246,102,140,213, 17,228,201, 12,179, 73, 36,128, 58, 9,234, 18,153, 52, 40,182,162,210, 72,183, 8, 0, - 85, 5,141,128, 24,234, 84, 22, 97,190,160,211,140,160, 37, 73, 9, 37, 39,151, 35,203, 4,118, 61, 53,114,153, 78,153, 71,107, -235, 40, 14, 61, 50,158,222, 60, 88,104, 36,186,207,108, 43,161,248,155, 29, 63, 29, 97, 20,201,202, 47,103,152,116,235,202, 79, -126,158, 94,167,229,242,211,203,110,200,247,142, 86,186, 45, 43, 28,139, 74,199, 69, 36,140, 40, 28,142,185,211,232,142, 26,149, -210,124,143,250,172, 54, 32,246,233,212,123,143,108, 87, 57,193,168,203, 88, 74,126,186, 30,174,140,110, 24, 27, 95,115,186,183, -163, 11, 88,251,182, 38, 90,149,147, 81,103, 43,113, 42, 36,101, 41, 4, 97, 63,236,131,246,106, 57,159, 74,191,116, 98, 90,254, -207, 59, 39,109,189,229, 13,212,183,107,126, 44,232,173, 70, 10, 79,139, 34,151,103,194,170,220, 21, 37, 33, 4,228,182,151, 83, - 3,152,129,211,196, 79, 81,158,178, 30,102,146,109,219,145, 41, 96, 40, 65,169, 43,197,142,145,209, 8,117, 68, 7, 25, 3,237, - 80, 32,127,181,168, 24,253, 41,190, 42,105,187,177,198, 54,217,240,225,110, 85, 81, 54,139,195,101,145, 34,125,214,152,206, 7, - 99,181,184,187,128,182, 37, 59, 9,124,170,199,189,197,183, 98, 83,146,176,122,161, 83, 8, 58, 74, 58,202,145, 17,201,101, 26, -102,168,170,131, 88,244, 90,105, 22,173,158,223,176,226, 5,136,155, 90,243, 32,234,192, 98, 1,158, 71, 76,139, 85, 95, 79,189, - 36,176, 18,155, 91,205, 48,228,232,235,246,147, 91,189,183, 39,148,198,196, 2,113, 23,105, 12,224,142, 92,114,128, 57,115,230, - 60,193, 31,158,218,166,220,116, 96,148,167, 35,185, 0, 30,135,231,131,219, 70, 58, 91,112,228,147,129,219,200,129,212,245, 26, -163,239, 1,162,164,182, 58, 16, 2,148, 48,123,246,233,248,234, 69,123,110, 78,199,253, 49, 95,238,192, 91,182, 41,184,218,146, -112, 2, 85,145,205,128,115,240,232,117,175,166, 2,185, 84,122,144,123,252,146, 48, 58,249,126, 26,246,165,183,205,207,226,242, - 41, 68, 0,146,160, 57,188,186,141, 8,236,164,182,248, 10, 66, 79, 40,192, 24,234, 78, 51,205,246,235, 5,182,178,131,140,233, - 61,206, 62, 37, 37,100,130, 84,143, 85, 20,247,251, 9,215,196, 52,218, 22, 28,108, 23, 20, 73, 10, 73, 32, 16, 58,117, 3, 29, -117,111, 83,203,146,247, 41,116,161,190, 96,162,140,245, 64, 79,113,246,247,209,173,134,220,112, 58,130,174, 68,156, 21, 96,167, - 56, 29,142,124,186,235, 23, 38,226,214,237,108, 24, 0, 8,223,231,108, 84,202, 80,181, 45, 75, 37, 10,236,140, 14, 84, 19,208, - 21, 19,249,206,145,240, 91, 89, 35, 4,168, 2,181, 39, 36, 1,143, 63,207,219,175, 14,180,248, 91,135,225, 44, 44, 19,203,230, -113,158,202, 35,190,147, 72, 75,188,184, 10, 97,180,167,149, 94,101, 68,116,193,200,235,219, 67,113,176,234, 62,253,255, 0,241, -140, 88, 27,158,199,247, 99,223,138,128,176, 16, 74,202,192,200, 64,234, 51,216,159,151,174,144, 56,112,168,255, 0,226,210, 65, - 39,211,169,193, 30,191,219,161,201, 91, 97,101, 11,229, 33,124,169,112,164, 97, 67, 25, 41,193, 29, 62,221, 18,149, 30, 64, 28, - 41, 83,138,201, 81,233,203,131,211, 7,167, 95,158,178,160,129,238,248, 99, 4, 11,219,211,111,159,187, 23, 91,122,216,174,223, -151, 45,171,103, 91, 30, 48,173, 94, 23, 45, 2,211,161,169,134,124,101,166,185,117,214,160,219,116, 71, 18,206, 63, 72,148,213, -170,176,202,135,110, 84,156,234,116,188, 70, 90, 86,214,200,237,141,191,195,253,145, 22, 45, 26,196,217,203, 30,212,219, 59,118, -140,216, 15, 52,105,182, 85, 52,210,220,144,228,146, 7,188, 57, 58,187, 14,173, 81,121,213,101,199,100, 86,221,117,213, 5,175, - 81, 5,246,122, 41,151,120,231,225, 49,165, 45,167, 25, 70,253,237,171,138,109, 68, 6,138,152,185, 35, 72, 66, 58,164,128, 60, - 86, 81,140,142,248, 24,212,167,184,174,185,213, 80,146,133, 73, 46,189, 42,116,101,176,243,171,116,136,206,165, 92,181, 24,242, - 29, 66,122, 56,175,137,244, 12,128,174,102,202,115,202, 19,170, 83,197, 9,101,168,206,184,107, 46, 36,242, 99,215, 57,177, 27, -176, 33,119, 7,246, 0,242,159,241,145,183,126,148,250, 56,229,176,205,157, 87,230, 36, 3, 52, 82, 67, 18,237,186, 42,142,113, - 96, 78,222,114, 22,253,238,138, 65,198,134,236,221,125, 48,227, 85,230, 51, 33,182, 20, 46,139,193, 78, 71,146, 11,172,173, 49, -107,213, 39, 22,218,176, 65,104, 45,181, 17,240, 28,231, 10, 57,192,214,224, 91, 87, 56, 52,186,124, 87, 37, 60,195, 17, 27,114, -181, 86,168, 52,165, 33,208,211,232, 84,135, 35,180, 82,172, 45,194,149, 57,206, 62, 17,225,181,156,149, 19,174,110, 88, 21,191, -119,114,244,165,183,202, 67, 27,155,118,199, 87, 58,178, 4, 89, 50, 96,212,208,176,140,117, 30, 4,208, 18, 6,122, 47,168, 24, -193,216,148,220,233, 17, 19, 8, 58,234,126,185,152,195,115,214,218,208, 94, 77, 49, 13,178,244,133,248,196, 0,223,193, 29,180, - 33, 36,116, 68,133,242,242,101, 71, 81,250,188,185,106, 15, 67,113, 99,239,183,107,245,232, 9,183,107,219,224, 58,227, 63,165, -142,190,158, 48, 77,158,254, 98, 55,217,118, 36, 14,246, 5,200, 7,112, 64, 22, 35,166,219,210, 47,185, 82,233, 80,131,107,114, - 60,217, 83, 30,159, 55, 1, 97, 10,126, 99,143, 59,200, 93, 39, 36,248, 79, 52,216, 74,146, 85,208,149, 28,227, 87, 58,150,229, - 67,154,202, 4, 96, 35, 72,171, 77,110, 44, 73,100, 36,180,229, 58,157,136,136, 91,136, 10,230,111,157,193, 37,215, 17,208,101, -244,168,228,117,214,181, 64,187,158,122, 93, 82, 99, 15, 54,251, 37,214,153,128, 31,117, 72,105,199, 39,177,225, 23,146,164,156, - 48,194, 20,135,157, 91,128,140, 41,148,243,100, 17,156, 82,117,230,220,185,110, 46,150,234,204, 86,210,213, 38, 18,207, 68,178, -246, 20,194,221,232, 57,159, 45, 69, 67,133, 75, 72, 8, 74,217, 4,243, 28,107, 65,114,134, 28,192, 19, 72,150,215,216,116,216, -247, 29,143,240, 35,215, 20,246,103,146, 44,245, 78,252,176,174,237,171, 80, 54,208, 8, 14, 67, 30,182, 4,169, 0,130, 8,141, -150,215, 27,108,165, 82,240, 65, 91,130, 60,226,182,132,167,101,192,151, 29,238, 83, 25, 20,197,120, 81,158, 74,218, 87,253,240, - 30, 74,156, 5, 56, 40, 82,144, 70, 78, 52,237, 90, 94,211,206, 31,238, 61,215, 87, 13,251,187,120,211,246, 99,125,216,166,219, - 53, 27, 46, 70,225,213,169,180,173,188,223,218, 29,126, 20,116,211,238, 11, 14,254,117,214,224,219,183,114,235, 2,165, 77,157, -110,215,151, 5,255, 0,172, 41,143, 26,124,233,201, 95,132,215, 47,235,155,134,253, 49,169,137,139, 33, 17,217, 13,120,112, 82, - 15, 49,240, 35, 44,163,195,112,169, 32,252,110,120,100, 14,255, 0, 6, 84, 78,117,197,111,105,134,220,238, 93,231, 65,219, 45, -247,167,109,213,197, 90,217,251, 58,155,114,237,149,225,186, 16,105,102,169,111,209,111, 26,133,206,237,223, 6,220,186, 37, 68, - 46, 57, 71, 74,105,117,120,239,199,126, 99, 76,195, 90,234,170,101,153, 10,125, 14,182,139, 3,128,178,227, 14,113,200,102, 49, -197, 94,146, 41, 26,186, 58, 14,100, 76, 1, 54,102, 4, 50,105,239,205,107, 48,109,241, 25,226,106, 58,222, 29,225,154,236,230, -154,152, 85, 54, 88,209,177,136, 41, 60,216,218,101,137,193, 42, 24,198,232,143,175, 85,138,168,137,139, 93, 73, 6,112,183, 37, - 78,163, 2, 75,208,150,135,161,212, 82,216,153, 17,169,141,173,151,176,166,195,172,115, 50,232, 25,142,243, 42,192, 88,248, 20, -135, 67,169, 82,146, 1,214, 30,110,102,229, 6,164, 37,229,248, 15,167,153, 14, 21,167,199,131, 45,149, 41,178,218,193,232,133, - 37,208,234, 20,133, 14,138, 74,146,161,200,172,136, 53,240,131,237,106,226,159,133, 24, 84, 59, 53,218,219, 59,239,178, 52,133, -176, 33,109, 62,233,213, 42,115, 87,110, 83,210, 19,207, 27,108,183, 21,133,187, 86,176, 89, 90, 16,222, 98,161, 83,232,235, 9, -248,233, 74,207, 48,145,223, 13,254,212,238, 15,184,152,159, 78,162,209, 47,183, 54,118,249,175,188,219, 14,237, 94,249, 74,164, -218,245, 37, 92, 79,169, 49, 99, 27, 63,112,216,112, 91,183,164,105,106, 74, 80,226, 84,253, 38,123,107, 83, 14,125, 94,162,183, - 66,108,186,204,183, 48,166,102,149, 71, 62,156, 30,169,168,233, 30,174,159,105, 0, 23, 14,192, 50,168, 43,245,131, 77,196, 95, -135,248,215,135,243,244,142, 40, 42,125,147, 48, 63,251, 60,246, 73, 9, 31,170,141,253,220,164,236, 80, 35,107,102, 86, 28,176, - 93, 65,235,149, 54,227,231, 82,252, 98,143,120,111, 30, 50, 3,153, 10, 74,242,148,190,207, 95,141,149, 1,219,201, 64,160,158, -157, 92, 10, 45,120, 41, 72, 30, 42,210,211,129, 60,138, 36, 39,194, 40, 56, 9,201,199, 34, 15,194, 82,125, 71, 47, 98, 51,173, - 78, 57, 42, 4,150,225, 74, 68,136, 85, 24,204, 38, 66, 27,148,194,153, 91,140, 60,112,210,188, 53,165, 42, 92, 71, 18,144, 65, - 31, 2,199, 43,141, 41, 93, 9,204,232,245,213, 45, 41,192, 82, 28, 24, 15, 5,245, 67,125, 1,240,211,143,214, 37, 36, 97, 93, -148, 8, 56, 7, 58,212, 89, 53, 45,155,126,155,250,244,189,247,220,131,214,195,222, 7, 80, 36, 83, 0,111,109,143, 66, 55,176, -233,219,176,244,244,232,113,182,208,103, 41,109, 2,130, 8, 28,170, 10, 7, 24, 72, 25,194,155, 35,170,130,179,216, 16,115,215, - 3, 58,111, 43, 10,114,143, 57, 62, 8, 83,116,247,138,158,104, 35, 42,247, 7, 50, 75,237, 35, 36,226, 62, 87,206, 17,241, 16, - 21,132,140, 32, 1,125,182,231,180,168, 76, 58, 9, 40, 84,116,130,133, 30, 98,133, 5, 4,164,144,145,213, 29,122,131,213, 61, - 0, 36, 29, 13,118, 6,157,142,165,164,161, 74, 66,131,137, 36, 16, 75,137, 11,198, 66, 58, 1,225,133,117, 7,177,199, 76,105, -179, 52,167, 21, 20,206, 20, 94, 88,188,203,247, 14,159,247, 13,175,219, 99,141,204,138,188,229,245,233,172,222,154,164,132,144, -123,143, 71,223, 96, 84,155,244, 59,106, 94,135,127, 84,218,177, 40, 8,109, 77,171,152, 21,173,176,163,224,169, 71,153, 72,125, - 10, 73,232,160, 71, 80,122,228,147,140,224,235, 37,102,160, 10, 82,164,185,132, 45, 57, 74,215,202,149, 96,228, 37, 5, 93, 73, - 30, 65, 68,115, 96,128, 73,233,134, 98,157, 41, 13, 56, 75, 78,101, 30, 32, 41,200, 60,139,109,106, 31,174,223, 79,137, 36, 30, -189,207, 76,140,117,214, 72,221,101, 45,182,162,165, 36, 32,100,243, 41, 75, 81, 70,115,204, 0,245,193,235,219, 60,157,117, 24, -134, 67,166,254,131,225,214,223,195,240,185, 63, 9,141,122, 6,118, 85, 58,239,247, 92,246,191,191,212,255, 0,166, 51, 26,229, -207, 71,161, 82,171, 21,250,253, 86, 21, 10,222,160,210,170, 53,218,245,110,162,164,183, 78,161,208,104,176,228, 85, 43,117,153, -206, 45, 73, 9,137, 18,151, 18, 91,238,228,225, 72,142,160,158,165, 57,252,241,248,236,226,198,175,198,143, 19,187,139,190,210, -211, 34, 37,167, 54, 67, 54,134,209, 80, 36, 40,149, 91,187, 67,106, 59, 42, 29,153, 29,224, 82, 63,247, 86,123, 78,203,172, 84, - 21,128,163, 54,224,117, 10,232,210,117,219,143,110, 55, 31,168,247, 9,220, 13,237, 45,117,106,153, 60, 65,155,196,245,118,153, - 33, 73,250,186,148,129, 22,167,110,108,123, 50,218, 88,204,249,174, 8,181, 59,157,180,158,102, 99, 49, 2,144,247, 42,222,154, -216,140, 58,201, 42, 87, 55, 92,245, 24,242, 62, 93, 51,208, 99, 86, 23, 10,101,174,168,115, 74,133,179,204,161, 98, 4,110, 35, -184, 38, 79,255, 0, 83,109, 63,224, 1,129, 34, 76,115,135,139, 28, 75, 29, 69, 68,124, 51, 69, 46,168,168, 95, 93, 91, 41,184, -105,192,178, 67,126,252,133, 36,200, 55,250,214,208, 64,120,119,164,226,207, 66, 6, 58, 99, 61,253,127,110,168, 40,146, 14, 79, -145, 3,176,234,117,236,175, 32,140,119,245,254,173, 14,178, 50, 7,166,115,251, 53, 54,197, 56, 6,195,215,223,143, 26, 25,222, -163,190,112,127,103, 95,199,190,136, 80, 4, 28,249,117,233,242,208,171,236, 62,223,191, 74,170,144, 55, 30,252, 27, 3,172, 12, - 19,233,219,241, 26, 21,194,122,100, 96, 15, 50,122, 99,167,203, 68, 45, 88, 7,168,198,127, 12,119,207,207, 39,246,104, 39, 14, - 65,238,122,244,207, 92,117,243,209,240, 49, 73,194,122,158,135,167, 78,221,191,225,160,214, 70, 49,230,127,175, 85,214,124,179, -246,254,237, 12,162,115,131,131,230, 15,203, 74,168,176, 3,231,255, 0, 56, 24,164,161,156,124, 57,251,241,165,175, 42, 81, 4, -128,123,105,104,248, 61,215,161,234, 61,195, 9, 4, 17,131,140,142,223,159,183, 85, 65,193, 7,254, 56,208,233, 56, 57,252,117, - 84, 28,245,242,237,243,207,245,104, 16, 14,221,176,115,176,176,216,246,251,173,130,144,113,212,117, 31,209,147,251, 52, 64, 81, - 7, 3, 57,199, 92, 12,227,237,208,169, 35,151, 56,237,220,122,227,174,171,161, 97, 64, 96, 17,233,247, 31,233,206,144, 35,125, -251,225, 50, 15,218,181,186,127, 44, 28,217, 61,137,207, 79,219,211, 69,160,115, 4,228,115, 96,228, 12,227,183,110,191,142,129, - 66,176,164,143, 53, 1,246,117,209,136, 61,199,167, 81,162,144, 13,182,219, 5,193,232, 56,201, 61,187,103,231,233,170,157, 57, -128,201,237,219,190,122,158,195, 61,244, 58, 14, 70, 85,219,229,220,254, 78,137, 78, 6, 9,248,142, 58, 30,199,229,215, 73,176, - 32,251,176, 49, 85,178, 80, 71, 49, 24, 29,179,128,122,159,234,206,170,161,228,172,227, 5, 63, 51,208,106,130,129, 57, 36, 12, - 43,246, 12,103,250, 53,245, 33, 41, 28,169, 39,168,200, 39,169,243, 62,154,215,113,110,214,192,193, 69, 75, 80, 41, 11, 40, 72, -242, 79,235, 44,117,198, 14,142,138, 84,193, 74,208,181,165,208, 82,164,172, 44,165,214,212,133, 5,182,227,107, 79, 84, 56,149, - 0, 82, 71,108,122,116,213,184, 21,116, 32, 12, 36, 16,175, 92,121, 99,240, 58, 41, 11, 82,192,198, 50,156, 1,158,159,143,207, - 73,144, 8, 32,238, 14, 5,200, 32,131, 98, 8, 32,251,198,227,247, 28,108, 53,141,190,213,107,108,134, 43,180,182,171,204,124, - 41, 19, 35, 60,136, 85, 18,145,128, 11,205,175, 13,186,160, 60,210,164,149, 28,156, 13,108,141,181,197, 54,220, 70, 82,197, 66, -151,116,195,121, 72,202,146,221, 49,185,109,229, 32,244, 75,141, 75, 60,221,199, 95, 93,115,201, 4,164,124, 94,189,207, 82, 7, -168,253,186, 37,176, 66,144, 22, 84,164,142,169, 32,227,161,236, 8,243,244,251,245, 28,174,225,188,174,181,153,164,137,162,103, -235,203,114,160,244,191,151,117, 31,114,140, 91,121, 55,141,220,125,147,211,199, 74,107,169,243, 88,225, 80,170,107, 41,214, 89, - 52,139, 90,242,161,142, 87, 35,177,119,115,110,248,235,133,191,199,206,218,219, 45, 52,170,125,157,118,214,229, 55,146,132,186, -136,148,166,213,201,219,244,179,102,224, 18, 71,250,170, 3, 29,180,196,241, 5,199, 86,232,111,197, 1,251, 8, 50,221,147,182, -143, 56,211,211,237, 58, 60,167,100, 74,185,156,140,226, 94,138,213,215, 87, 83,109,251,229, 61,183,144,219,158,226,195,104,140, -227,141,161,111,151,249, 82,145,162, 3,148,130, 92, 5,192, 20, 20,148,231,148, 55,212,227, 4, 14,186, 61,162, 86,176,146,225, - 80, 56,228,194,113,201,219,161,207,235,116, 56,211,117, 47, 5,112,245, 21, 84,117,201, 69,207,170,132,134, 71,149,218, 77, 12, - 8, 33,149, 73,229,134, 82, 46,173,163, 82,145,169, 72, 32, 28, 53,241, 15,138,188, 97,196,116,243, 82,213, 84,195, 69, 77, 80, - 10,200,180,176, 44, 69,212,245, 83, 35, 25, 38, 10,219,134, 85,145, 85,193, 42,192,169, 32,158,135, 75,235,241, 20,165,243,156, -130,149,228,227,191,234,252,191,175, 69, 53,226, 20,169,146, 9, 42, 80, 87, 50,134, 0, 79, 79,192,118,208,142, 44, 52,130, 84, -175,137, 56,248,146, 49,143, 64,122,117,233,170,145,222, 81, 66, 66, 73,248,178, 73, 87, 82, 79,108, 12,246, 29, 53, 36, 61, 54, - 29, 62, 70, 43, 94,183, 35,123, 91,175,205,241,136,238,148, 54,166, 91, 20,250,139, 88, 47,209,166,170, 59,233, 79,254, 76,255, - 0, 80,172, 99,160,230, 39,240, 58,198,120,103,221, 57,187, 25,196,150,199,238,244, 21,134, 94,176, 55, 62,210,175,186,181, 28, - 15,112,143, 87,142,138,146, 84,113,217, 84,215,101, 39,255, 0,165,167,117,218,108,106,205, 62,177, 68, 90, 2, 93,157, 79,120, -165, 71,245, 68,134, 82, 86,218,243,228,123,254, 61,245,167, 85, 38, 11,109,188,210,135,233,152, 91,140,184,160,122,120,145,212, - 83,145,142,255, 0,171,251,117,187, 66, 18,104,170, 41, 36,251, 18,234, 83,255, 0, 68,162,196,254,253, 93,251,227, 20,149, 82, -101,249,133, 45,100, 91, 73, 4,145,202,189, 62,212,108,174, 63, 16, 49,250,180,211,238,200,245, 37, 67,171,211,156, 15,194,174, - 65,129, 89,167, 45, 4, 20,189, 10,173, 21,153,145,214,133,121,160,178,242,122,249,231,190,180,239,217, 89,188,242,168, 28,101, -113,223,195, 53, 74,165, 21,248,241,110,200, 59,151,105, 48,148, 54,212,150, 99, 85, 66, 25,171, 70, 90,211,133, 72, 8,121,198, -149,215, 37, 35, 61,129,214,138,112,241,237, 18,181,246,247,217, 85,195,199, 23, 55,221,185, 92,188, 87,110,170,222,216,155,158, -135, 70,113,168, 85, 74,133,213, 66,154,237,182,137,209,228,212, 2, 90,247, 81, 18, 12,119,150,178,172, 40, 40,165, 36,172, 99, - 92, 76,225,195,218, 43,112,108,191,180, 68,241,163, 87,137, 53,218, 13,213,121, 85, 13,251,109, 69,117, 79, 59,252, 93,220,210, - 61,214, 85, 57,148,140, 9,179,169,240, 12, 87, 90, 24,253, 35,176,207, 39, 85,140,213, 94,201, 95, 89, 89, 81, 50, 68, 88,229, - 41, 44, 77, 97,114,211,137, 33, 50, 70,130,251,177,141, 24, 11,126,210,130,124,216,234, 92,247,139,178,110, 30,135,135, 86, 26, -240,171,156,212, 69, 53, 68, 96, 18, 70, 89, 60, 14, 18, 89, 46, 45,161,102,104,166, 0, 18,247,167,107, 0, 6,255, 0,166, 5, - 42,103, 57, 65, 82,185, 64, 32,133,247,194,134, 58, 28,253,191,183, 79,189,167, 40,130,133, 15,136,130, 15, 48,207, 92,244,234, - 62,127,191, 90,215,182,213,122, 45,249,108, 90, 55,197,175, 49, 85, 11, 94,248,160,211,110, 91,114,123,145,228,195, 92,170, 77, - 82, 51,114,163, 41,232, 51, 90,109,232,174,134,220, 0,165,196, 37, 67, 29,181,181, 22,173, 32,176,218, 22,172, 0, 58,144, 15, - 48, 35,161,232, 51,211,182,149,165,204, 0,210,250,182, 96, 8, 55,216,131,107, 17,234, 8,177, 7,208,223, 12,252,106,244,209, - 69, 44, 79,229,112, 89, 74,158,160,131,165,148,142,161,131, 2, 8,234, 8, 32,216,139, 99, 84,189,166, 92, 73, 94, 92, 36,240, - 71,190, 60, 72,109,253,170,139,190,243,218,251, 81,202,181, 6,152,247, 63,185,197,151, 53,246,105,136,172, 84, 2, 7, 50,224, - 67, 84,180,200,117, 35, 4,165,140, 2,158,227,242,123,220, 13,193,188,183,102,246,187, 55, 70,255, 0,174,202,185,175,125,193, -184,106,119,117,217, 95,154,225, 92,154,165,106,179, 33, 82,165,200, 61,127, 70,202, 74,130, 26, 64,248, 91,109,180, 33, 32, 37, - 35, 95,176,103, 17, 91, 65, 79,226, 3, 96, 55,155,100,106, 73,104,195,221, 29,180,188, 44,162,167,194, 11, 49,228,215,104,147, - 33, 65,146,176,160, 71, 43, 83, 28, 97,207,145,107, 58,252,126,111,173,183,174,109,101,223,114,237,205,200,243, 14, 87,172,107, -134,183,104, 86, 21, 21,196,191, 31,235, 27,118,163, 34,153, 41,108, 62,142,143, 50,181,199, 42, 74,135,250,248,242,211,205, 11, - 23,205,103,169,168,185,146,170,158, 46, 83,159, 68,102, 90,132, 67,211,202, 69, 43,202,122,183, 50, 37, 98,121,105,106, 87, 55, - 74,198,201,233,231,141, 79,232,234, 57,204, 82, 16, 6,132,158, 85, 50, 83,153, 27,174,169, 99, 74,129, 10, 55,149, 68, 19,180, -118, 47, 41, 56, 67,100,168,171,151,155, 61, 79, 95, 60,122, 15, 61, 35,130,164,243, 43,195,200,232, 85,144,149, 30,190,103,160, -235,163,138, 10, 81,148,161, 61, 1, 57,207,196, 1,237,229,215, 58,179, 73, 73,100, 1, 32,169,109,175, 10,108,133,117, 65, 61, - 64, 35,211,190,164, 33, 71, 78,184,138, 6, 12,221,108,127,211,249, 99,203,205, 18,188,146,148,164, 30,157,114,114, 49,212,122, -121,235,227,237, 45,212, 2, 7, 84,167,184, 57,230,251,255, 0,214,210,105,196,231,225,201, 72, 78,112, 71,161,193,239,249,235, -162,163, 54,227,231, 9,229,102, 56, 25, 86,126, 37, 18, 58,142,158,154, 26, 64,223,165,177,147,211,115,112, 58,252,252,223, 22, -213, 70,117,150,146,176,201, 81, 88,230, 39, 35,152, 1,253, 61,115,159,248,104,168,146,144,231,232,202,255, 0, 85, 56, 40,229, - 0, 30,157, 78,124,245,114, 83, 5, 65, 72, 11,202,122,142,131, 4, 30,196,245,208, 41,136,220, 55, 57,130, 80,160,172,229, 74, - 5, 71, 24, 57,192, 61,188,255, 0, 13,102,195,174, 10, 13,246,245,219,231,231,243,194, 75,106, 66,138,139,202,121, 62, 73, 39, - 41, 64,244,249,235,195,175,165, 29, 16,164,129,215, 3,176, 10,244,237,242, 58, 13,247, 86, 20,162,210,241,205,219, 9,199, 76, -118, 57,252,252,244, 57,121,183, 22, 18,162,114, 8, 46, 36,167,166,122, 30,132,122,147,160, 1, 61,122,224,218,109,176, 59,124, -252,244,193, 73, 62, 42,249,210,160,160, 6, 10, 58, 4,243,117,237,215,174,169,202,116,144,148,163, 9, 35, 41,232,112, 73, 35, - 26,244,226,149,225, 44, 52,218, 83,202, 50, 6,112, 73, 3,166, 20, 60,186,106,200, 38, 56, 22,159, 25, 41, 42, 74,136,229, 35, - 39,237,230, 7, 25, 25,253,154,205,172, 79, 99,140,129,115,240,254,120,124,184,115,189,156,218,173,243,217,253,196,140,226,154, -114,201,221, 29,189,186,157,144, 2, 28, 76,104,148, 91,202,137, 62,170,234,144,226,146, 10, 19, 71,106,164, 78, 72,192,235,229, -214, 89,252, 84, 79,135, 38,165, 91,167, 64,144,125,222, 21, 90, 83,212,194, 9,203,148,103,102,202,149, 75,147, 29,226,231,198, -199,134,165,180, 86,174, 83,250, 48, 82,145,204,117, 12,134, 36, 32, 58, 89,144,219,141, 68,148, 28, 97,215, 25,112,135,124, 41, - 13,150, 30, 13,148,156,182,191, 13,197,224,142,160,224,143, 93, 73,106,193,222, 9,123,221,195,158,213,110, 37, 84, 5,220,177, -173,145, 99,221,170, 9, 90, 82,245,211, 97, 33,139, 66,186,235,106,113, 41, 18, 89,144,221, 38,151, 80,109,206,169,241,170, 79, - 3,133,165, 68,213,126, 32,229,133,243, 12,131, 53, 81,228,136,205, 3,157,175,169,213, 36,139,223,107, 71, 40,244, 5,135, 82, -109,142,146,250, 55,230, 49,199,158,230,217, 92,205,165,166,142, 42,152,199,111,171, 99, 12,173,241,188,212,235,255, 0,117,239, -229,177,215, 10, 45,116,211,119, 43,112,233,170, 37,182,230, 76,183, 43,177, 16, 48, 67,141,212,104,203,167, 84, 84,210, 85,250, -200,247,186, 39, 42,135, 76,169,127, 17,201, 25,126, 41,181,229, 37, 94,246,130,227,139, 83, 98,158,134,210,180,160,134,139,132, -169, 8,228,234, 57,157, 60,196,119, 33,160, 58, 3,173, 54,220,106,162,232,187,147, 64,173, 32,128,221,114,157, 86,182,101,168, - 2,112,236, 98,110, 58, 71, 42, 0,200, 82,156,139, 85,108,168, 12, 37, 47, 14, 99,215, 89,237, 42,241,122, 42, 89,121,149,120, -143, 68,240,228, 71, 67,193, 97, 42,112, 20,248,104, 82,146, 14, 81,149, 36, 43, 61,130,149,202, 79, 77, 54,154, 98,201, 79, 48, - 93,157, 23,215,245, 64,140,254,242,183,247, 3,113,214,216,234,185,107, 85, 90,190,153,200,103,134, 73, 8,185,181,196,141,207, - 0,122,217, 95, 77,199,166, 54, 18,161, 94,151, 79,143,238,201, 90,156, 74, 11,144,195, 67, 45,167,222,100,242,185, 41,107, 79, - 47, 68,161,128,211, 94, 17, 4,143,139,237,214, 33, 94,188,163, 65,166, 48,194, 95, 91,117, 54,202,144,132, 54,165,128,183, 95, -199,188,184,162,159,133, 33, 12,114, 39, 3,184,113, 99, 62, 90,108,110,125,200,155, 57,192,243,237, 54,135, 98, 37, 65,105,104, -184, 83, 38, 67,170, 74,157,117,106, 82, 65,231, 43, 42, 36,158,164, 28,103,182,152, 91,179,113, 22,203, 82, 31,144,227,141,177, - 29,133, 60,243,188,138,117,126, 27,202,229, 79,134,132,140,173,213,186,224, 64,230, 35, 28,249, 82,146,156,168,109, 83, 80,180, -133, 70,155,131,247,250, 91,173,253,215,233,123,143,190, 31,153,230, 40,116,234, 94, 76,155, 11, 13,199,112,250,136, 0, 48,181, -193, 30,164,142,215, 14, 21,209,121,205, 91,172,198,128, 37,214, 37,203,151, 18,147, 71,162, 69, 74,158,159, 91,173, 84, 31, 76, - 74, 61, 38, 10, 82, 57,149, 46, 76,199,210,132, 36,116, 79,141,204,122, 13, 72,111,103,182,153,253,140,217, 59, 59,105,234,166, - 43,245,214, 40,146,102,238, 75,165,136,243,169,213, 75,230,241,120, 86, 47, 54, 36,211,230,178,227, 21, 26, 75, 53, 55, 26,167, - 24,207,180,236,119, 35,210, 16, 22,218,146,117, 21, 91, 99,137, 58,134,192,111, 54,211,110, 76,122, 84, 42,181,197,100,221,246, -174,224,205,167, 84,216, 19,169,212,123, 66, 37, 89, 42,151, 77, 97,181, 39,195,159,114, 79,128,212,245,169,240, 22,212,111,116, -105, 13,225, 69, 58,152,173,218,236, 42,179,108, 87,233, 14,186,253, 46,181, 6,157,112, 82, 30,120, 56,211,238,209,110, 10,124, -106,204, 5, 62,219,128, 41, 18, 61,194,107, 60,193, 64, 44, 45, 4, 30,186,117,106,119,163, 48,188,177,253, 92,232,116, 31,218, -177, 26,182, 29, 0, 5,108,118, 44, 24,145,181,142, 35,114,231,116, 85,239,152,101,148,181,162, 92,195, 43,146, 35, 87, 18,135, -188, 13, 42, 22,128, 23, 42, 35, 98, 66,200, 24, 35, 57,137,208,164,161, 30,202,120, 41,197,183,177,147, 96, 55,194,117, 82,245, -225,250,163, 11,134,125,197,158,169, 14,206,182,216,166, 75,169,236, 93,114,190,156,248,141,189,108,196, 90,166,237,169,121,196, -181,250,106, 40,147, 79, 30, 49,116, 81,219, 78,117, 26, 30, 33,248, 90,223,142, 22,238, 53, 90,251,235,183, 21, 75, 77,169,146, -228, 66,162, 92,232, 13, 87,118,250,239,240, 22,241, 75,150,189,233, 78, 11,167,214, 10,153, 99,198, 17,203,141,204,109,181,161, - 79, 69,104,144, 53, 62, 58,210, 27,142,235,239, 21,135, 25, 12,160, 78,108, 32,130, 2, 20,150,218,156,215,108, 60,148,173, 41, - 88, 7, 42, 65, 24, 28,201, 25,193,174,203,122,131,116,219,213,139,110,241,182,232, 55,173,161,112, 70, 84, 43,170,207,186,169, - 84,234,253,183,113,211,152,109, 97, 46, 84,104,245, 86, 28,142,237, 70, 59, 5,226,196,128,132,200, 66, 22,182,154,125,146, 80, -180,201,178,222, 38,170,167,211, 29, 71,246,200, 86,223,104,218, 69, 29, 1, 87,177,189,186,233, 96,214, 30, 85, 40, 0, 56,170, -184,143,195,156,143, 60, 18, 84, 69, 23,232,156,193,247, 18,194,160, 70,237,183,247,176,221, 84,146, 79,219, 83, 27,110, 29,203, -146,109, 13, 30, 23, 61,163, 28,100,240,219, 38,149,107,237,182,228, 73,189,236,148, 58,150,218,218, 61,216, 67,151,221,136,166, -144,210, 25,240, 41, 6,169, 45, 53, 11, 53, 66, 58, 57, 80,186, 76,248, 97,190, 98,160,218,142,164,109,178,158,214,237,167,175, - 65,161,127, 41,109,181,191,248, 74,174, 85,212,196, 72,247,141,118,159, 86,189,184,118,184, 38, 56,243,200, 67, 20,205,205,163, - 65, 92,187,103,244,108,243,134, 42,113, 37,120, 42,121, 41,114,160, 80, 84,117,167,220, 73,251, 19,182,242,247,150,245,217,194, - 29,220,173,162,186,165, 45,185,180,237,176,187,166,214,235, 27,115, 85,154,242,203,141, 53,105,221,169,247,138,213,131, 33,111, - 58, 60, 24,243, 19, 85,132,218, 80, 19,227,198, 71,195,173, 7,218,190, 57,120,161,246,121,238,117,107,135, 46, 42, 54,246,212, -222,125,182, 66,215, 76,220,221,149,190,133,155,115,191, 81,182,165,170, 84, 41, 82,173,155,198,146,212,216, 50,159,240,155,121, -200,241,235, 44, 76, 97,206, 80,135,152,140,178,151, 90,121,170,146, 44,222, 17, 46, 79, 77, 21,101, 90,144,210, 68,210, 26, 90, -141, 23, 26,157, 24, 36,177, 72,226,224,221,193, 66, 60,166,100, 39,106,230,105,184,247,129,158, 20,172,144,102, 25, 56, 96,130, - 73, 11, 77, 13,172, 72, 85,114, 4,208,176, 63,238,220,198, 0, 12,193, 90,219,205,107,111, 55, 22,222,185,109,106, 77,203,105, - 92,212, 27,170,209,172,183,227,209, 46,123, 90,179, 79,185, 45,186,219, 47,160, 44, 55, 78,175, 80,230, 63, 25,215,130, 20, 20, -227, 72,116,188,206, 64,121,180, 19,141,103,175, 87,204,134,148,133, 47,152,148,124, 42, 90,135, 81,202, 0, 79, 42,142, 57,128, -233,159,246, 64, 39, 57, 58,138, 47, 16, 27, 71,120,112, 95, 98,211, 61,164, 94,203, 13,207,174,217,124, 50,238, 29,187,102,110, - 70,229,240,243,119,189, 42, 85,155, 77,162,222,245, 72, 16, 41,117, 22,108,155,169,231, 90,184,109, 7,235, 46,162,151, 58,152, -243,203,175,208,101,130,245, 6,171, 58,144, 89,145, 18, 68,155, 3,127,214,247,155, 98,118,115,120,231, 91,109, 90,114,247, 99, -108,236,173,194,145,108,177, 83, 77, 90, 45,188,253,219, 67,139, 87,122,147, 14,164,243,190, 44,248, 45,185, 37, 98, 59,143,101, -242,194,155, 18, 15,188, 7, 73,143,214,196, 35,167,138,170, 9,185,212,211, 51, 37,153,116, 75, 28,128, 41, 49, 75, 29,205,152, - 95,170,150, 83,177,218,235,123, 43,134,115,213,207,218, 72,189,141,233,170,169,213, 93,148,221,209,145,142,149,120,220, 40,189, -200,177, 4, 41, 27, 0, 8,185,198,215,109,149, 22, 37,219,112, 75,167, 73,165, 92, 21,191,118,183,110, 26,195, 20,107, 85,228, - 68,174, 84,165, 82,105,206,202, 98, 44, 87, 92,162,212, 48,165, 45,180,169,192,152,142,168,161, 4, 36, 36,229, 99, 64, 56,226, -223, 77,219,218,203, 74,243,176,184,111,131,100,212,184,131,106,210,106,188,182,174,237,198,176,104,236,108,117, 26,191,107,238, - 45,231, 67,159,114, 83,238, 42,188, 53,220, 59,203, 46,201,218,125,206,169,219, 54,146, 99,166,100,164,216,146,234, 18,227,161, - 2,157, 2,167,204, 14, 62, 61,170,123,199,195,134,245,239, 23, 13,187,105,102,194,182,165, 83,246,238,171,105, 84,183, 81, 53, -244,170,245,137, 87,220,107, 45,183,233,117,187, 54, 41,166, 73,133, 64,143, 76,250,217,135,130,156, 67,211,229, 61, 20,165, 50, - 32,160,164,235,150,155,127,199,229, 2,218,166,220, 17, 47,141,155,184,239,201,213, 27, 39,106,105,180,122,212,125,229,250,134, -170,214,227,109, 78,199,111,230,200, 68,190,174,249,149,109,181,172,187,121, 82,106, 16, 56,129,184, 42,147, 41, 97,218,124,229, - 79,183,224, 36,215,213, 28,203,110, 70,206, 69,195,144, 85, 69, 5, 70, 98,154,105,203, 23, 84, 82, 9,145, 88, 2,188,203, 43, - 29, 22,223, 64,107,155,217,130, 11,134,211,227, 63, 18,206, 91, 83, 89,150,100, 83,153,115, 5, 2, 9,166,100,112, 41,101, 77, - 75, 50,195,172,141, 83, 43,150, 83, 39, 47, 66,149,186, 60,183, 82,141,110,225,240, 39,196,221,155, 81,191,231,222,141, 89,213, - 55,237, 88,247,245,205,127,221,171,222,173,181,185, 61,226,240,182,175, 86,237, 91,186,211,159, 89, 98,236,113,202,246,245, 75, -190,106,209,152,110,218,100, 61,112, 84, 36,212, 28, 91, 16, 22,220,105,170,139,127,159,236,242,222,186, 77, 26,239,166, 87,232, -112,233,215,213,183,115, 90,106,118,188, 55, 27,106, 92,217,154, 61,128,237, 3,137,199,119, 10,177,114,223, 77,221,139, 75, 53, -122, 53,223,195, 53,253, 73,112, 71,241, 98,181, 54,200,172, 83,221,113,115,223,163, 51, 57,230,147,199, 5,183,187,182,199, 20, -139,188,118,233,203, 98,159, 84,186,183,115,137, 91, 34, 52, 27,238, 84,170,188, 61,236,220, 94, 32, 44,203,171,108, 40,237, 75, -107,110, 95,141, 88,160, 80,145, 95,186, 77, 97,137,205, 83, 25,174,211,162,188, 99, 84, 40,149, 52, 64,143, 46,157, 75,218, 83, -101, 77,186,105, 19,162,236, 45,249,108,218, 84, 43,254,198,220, 58,109, 34,211,226, 14,155, 2,237, 19,173,203,215,141, 77,199, -186,173,217,247,125, 99, 98,170, 16,170,182,125,110,232,227, 78,236,167,187, 2, 77, 5,212,166,211,181,219,161, 84, 87, 88,151, - 81,153, 91, 22, 42,173, 58,216, 2, 66,109,243,176,249,247,227,159,188,172,197,153,181, 23,220,146, 73, 36,158,189,183, 55,238, -119,191, 83,134, 79,133, 94, 26, 54,163,119, 40, 23,245, 15,114,220,191,142,226,213, 56,139,225,227,133,189,165,172,237,181,249, - 97,155, 30,221,191,119,242,131,196, 96,167, 93,151,172, 39,236,250,202, 55, 62,208,102,241,218,107, 53,128,138, 37,126,130,149, - 83,107, 53, 9,204, 84,230, 17, 17,189, 55,212,190, 3,248,146,172,211,160,212,169,214,189,181, 33,186,142,219,211,247, 54, 44, - 95,227, 14,196,106,162,186,125, 98,181,178,180, 58, 45,166,105,207, 92, 9,120,110,100,217, 28, 70,108,107,177,109,190, 79,173, -221, 99,115, 41,203, 76, 94, 97, 37, 17,242,109,137,226,246,211,217,104,251,163, 81,127,101, 62,187,186,171,187,235,180,188, 70, -108,210,237,235,249, 22, 93,137,180,219,153,179, 84,221,245,137,101, 55, 93,179, 23, 99,212,230,110, 13,155, 14,126,244, 71,153, - 30,155, 22,183,110, 58,135, 44,136,172,191, 58, 84,105, 79,178,151,218, 87,181, 90,244, 52,109,183, 49,108, 26,164,171,191,110, - 45, 11, 30,153, 2,181,115,110, 83,149,219, 97,171,198,196,221, 46, 9,183, 14, 21,126,223,177, 98,217, 80,152,183,109,137, 17, -184, 39,182,216,149, 73,247,169,115, 94,157,126,212, 38,174,188,170,109, 62,145, 66,136,100, 17, 21, 93, 71,204, 47,211,227,220, -219,115,111,195,225,108, 1,107, 11,252,252,239,134,106, 63,179,199,115,133,155,125,215,171,187,135,179,118,237,197,106,110,150, -201,109,205, 10,223,153,185,246, 52,250, 21,249, 15,122,172, 61,215,189,169, 23, 85,173,123,210,110, 87,226, 85,161,161,221,180, - 69, 50, 35, 16,154,153,245,133, 70,101, 86, 39,143, 18,101,191, 50, 43,173, 61,131,193, 94,250,238,142,241,110, 54,200, 89,144, -172,105,247,150,215, 94, 63,197,253,209, 54,126,230, 88,150,253,156,245,230,245,238,157,187,165, 91,118,205,231,112, 87,162,211, -175, 26,213, 74,234, 15,179, 73,139, 75,126, 92,138,179, 48,164, 75,167,183, 38, 43, 46, 58,157,172,107,218, 71,106,187,184,205, - 93,151, 6,202,110, 37,197,110,209,175, 29,134,190,172,246, 39,241, 13, 5,253,203,160, 93, 60, 62,109,135, 18,118,213,139,112, - 73,220, 10,142,200, 73,165, 84,170,177,119, 63,136, 8, 23, 60, 70,218,180,225,210,217,143,182,241, 40,114,169,117, 3, 80,155, - 86, 12, 7, 9,252, 89,216,124, 52,223,247, 21,199, 92,217,203,159,115,109, 71,183, 27,106,119, 94,200,183,218,221,216, 86, 93, -205,110,222, 91, 37,184,134,249,219,247, 46, 91,196,109, 93, 86, 53,227, 71, 49,101, 84,161,213,227,179, 69,164, 59, 61,217, 13, - 76,139, 38,154,150, 85, 17,245,109, 21,212, 94,194,230,253,122,118,237,252, 63,118, 51,229,219,231,249, 97,202,188, 61,155,155, -199,118,239,117,185,183,155, 45,111,219, 48,169,151,253,165,181,247, 29,144,197,255, 0,186, 86, 69,154,185,177,175,167, 54,191, -110,233, 53, 41,149, 43,218,189, 9,184,108,215,247,190,249,155, 69,160, 50,234,210,253, 65,250, 53, 77,200,172, 42,159, 74,151, - 45,166,227,134, 30, 29,118,127,120,246,186,191, 46,244, 59,148,198,229, 93, 91,162,198,209,109, 69, 98,214,187, 45,122, 85,145, -109,220,147, 54,155,112,111,218, 69, 66,255, 0,180,170,251,125, 80,157,121, 82,101,220,150,181, 18,154,240,167,215,104, 46, 83, -162, 85, 36,212, 19,245,147,172, 55, 5,237,158,182,189,170,118,111,241,175,183,251,177,186, 92, 50,213, 47,138,213,133, 67,216, - 27,113, 74,181,183,186, 14,223, 84,174,122, 47, 11,119,174,202,223, 59, 29, 14,226,170,191,178,245,148,204,114,158,230,219,222, - 52, 89,210, 61,212, 74,157,109,221,244, 74,100,119,233,207,218,140,207,171,105,175, 15, 60, 86,219, 59, 19,183, 23, 37,185, 55, -107, 42,215,157,246,197,244,141,202,218,155,189,189,196,135,110,218,246, 85,232,222,219,222,187,117, 26,163,120, 88,142,109,229, - 70, 70,225, 69,136,139,192, 85, 33, 71,143, 94,160, 33, 53, 10, 36,116,205, 53, 8, 43,126, 27,135, 2, 45, 74,111,229,107,222, -224,251,173,219,227,235,252,241,159, 47, 99,243,255, 0,140,109,229,209,192, 61,139, 67,254, 54, 13, 55,134, 30, 56,238,159,226, -247,134,189,165,221,155, 88, 82,239, 26, 58,127,141, 58,134,224, 29,184,254, 17,110,133,181,238,252, 37, 74,228,217,202, 39,240, -190,165,239, 17, 99,253,100,191,208, 49,227,221, 17,185, 92,241,117, 46,135,178,187, 35, 81, 28, 31,213, 31,183,183,186,171, 31, -122,172,157,204, 93,241,102,218,215,157,151, 58,233,188,119, 54,204,184,111, 91, 90,206,160,237,157, 94,102,218, 53, 31,110,232, - 55, 5,201, 73,181, 97, 62,229, 82, 21,212,253, 17,170,156,202,136, 53,143, 5,170,122,233,238,255, 0, 21,182, 21,251, 73,221, - 38,109, 61,163,187,173, 42,230,243,109,206,204,217,215,189, 66,226,221,186, 53,235, 74,102,187,180, 15, 88,202,106,225,181, 40, -212,205,160,161, 61, 71,164,207,141,102,114, 42,155, 50,125, 77,232,203,169,120,130,166,250, 89,240,157,111,237,173,252,177, 83, - 70,217,139, 67,114,246,121,205,192,178,182,194,199,221,235, 38,179, 78,133,124, 51,107,215,171,138,221, 10,189,205, 93,167, 93, - 54,173,114, 93,149, 85,143,101, 93, 20, 42,173,118, 11,240,157,147, 78,174, 70,121,218, 70, 95,139,225,190, 91,109, 66, 82,230, -223, 59,143,119,166, 50, 8,184, 3,231,127,135,166, 49, 78, 42,118,162,139,177,156, 68,238,246,208, 80, 63,132, 77, 83,182,246, -242,168, 91, 74,166, 93,239, 65,153,117,219,117, 40, 41,100, 86,172,219,150,169, 75,166,194,137, 94,175, 81, 43, 42,159, 72,151, - 83,133, 10, 28, 42,156,138, 35,149, 8, 81, 34,197,146,211, 13,173, 88,184,129,221,147,190, 91,193,122,238,130, 40, 10,181,162, - 92,146,233,172,210,109,231,107, 47, 92,147, 40,244, 11,118,135, 75,181,237,216, 53, 75,142, 68, 40,170,184,107, 72,161, 81,105, -222,253, 60, 68,134,137,147, 11,242, 90,133, 13,183, 81, 21,165,172, 21, 55, 58, 70,221,186,116,193,180,169,223,215, 31,255,217, -}; - diff --git a/source/blender/editors/datafiles/splash.png.c b/source/blender/editors/datafiles/splash.png.c new file mode 100644 index 00000000000..bbce480ecba --- /dev/null +++ b/source/blender/editors/datafiles/splash.png.c @@ -0,0 +1,2483 @@ +/* DataToC output of file */ + +int datatoc_splash_png_size= 79258; +char datatoc_splash_png[]= { +255,216,255,224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,255,225, 0, 22, 69,120, +105,102, 0, 0, 77, 77, 0, 42, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,255,219, 0, 67, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,219, 0, 67, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,192, 0, 17, + 8, 1, 15, 1,245, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1,255,196, 0, 31, 0, 0, 1, 3, 5, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 7, 10, 3, 5, 6, 8, 9, 2, 1, 11,255,196, 0,103, 16, 0, 1, 3, 3, 2, 4, 3, 4, 6, 4, 7, + 11, 5, 9, 13, 9, 1, 2, 3, 4, 5, 6, 17, 0, 7, 8, 18, 33, 49, 19, 65, 81, 9, 20, 34, 97, 10, 21,113,129,145,240, 35, + 50,161,193, 22, 23, 24, 66,177,209,225, 25, 26, 36, 40, 51, 56, 73, 82, 98,232,241, 72,104,105,136,168, 41, 52, 57, 67, 84, 88, +120,150,178, 37, 38, 68, 83, 87,115,130,135,147,152,181,200,210, 54, 89, 99,114,146,184,213,214,215,255,196, 0, 29, 1, 0, 0, + 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 6, 7, 1, 4, 8, 9,255,196, 0, 80, 17, 0, 2, 1, + 2, 4, 4, 3, 4, 6, 7, 5, 7, 0, 7, 9, 0, 1, 2, 3, 4, 17, 0, 5, 18, 33, 6, 19, 49, 65, 7, 34, 81, 20, 97,113, +240, 8, 35, 50,129,161,209, 21, 66, 82,145,177,193,210, 36, 51, 98,162,225, 9, 67, 83, 84,114,130,241, 52, 56, 68, 85,116,148, +211, 22, 23, 24,115,131,146,147,180,181,255,218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0,159,198,150,150,150,134, 6, 22, +150,150,190,100,122,143,199, 67, 3, 31,116,203,220, 60, 68,108,181,171,123, 70,219,170,254,224,209, 41,183,140,167, 25,101, 20, +135,189,241, 73,101,249, 28,165,136,243,170, 77, 69, 84, 74,116,149,133,163,149,185, 15,180,226,185,211,132,158, 97,151,159, 35, +212,126, 35, 92,108,227, 63,131, 43,145, 85,251,143,120, 54,213, 18,235,236, 86, 37,191, 87,185,237,148,243, 72,170, 67,146,224, + 11,147, 81,162,128, 57,167, 69, 42, 5, 75,143,213,230,242, 75, 94, 34, 50,148, 86,158, 42,113, 39, 27,112,159, 14, 38,119,193, + 60, 55, 23, 19,212, 81,204,173, 89, 4,134, 67, 34,209,128,198, 87,130, 56,138,188,146, 2, 0,242,151, 49,169, 50,114,101, 1, +128,179,188, 40,225,158, 7,226,222, 37,108,143,142, 56,150,110, 23,166,172,133,150,142,120,196, 98, 54,173, 44,162, 36,158, 73, + 85,146, 56,200, 44,124,193, 4,140, 4,124,232,139, 41, 61,145,109,196, 58,132,173,181, 37,104, 80,200, 82, 72, 32,131,243, 26, +247,174, 11,240,211,199, 61,219,180,206, 66,179, 55, 36, 79,186,108,118, 29, 68, 54,166, 58, 92,122,228,181,217, 65, 13, 22,219, + 47, 30,106,157, 61,174, 95,242, 14, 16,243, 97, 37, 45, 44,128,150,181,219,219, 46,247,181,247, 6,129, 2,231,180, 43, 48,171, +148,106,139, 65,216,211, 33, 58, 29, 65,232, 57,219,113, 63,172,203,233, 86, 66,219, 88, 74,208,160, 66,146, 14,147,240,211,197, +174, 19,241, 67, 46, 53, 25, 37, 79,179,102,180,202, 13, 86, 95, 49, 2,166,156,244, 38,219, 9, 97,213,178,207, 29,212,220, 7, + 17,201,120,194,158, 38,248, 69,197,190, 22,102, 66,159, 60,166,246,156,166,165,136,165,204, 33, 4,210,212,142,160, 95,115, 12, +218,119,104, 36,179, 11, 18,134, 72,237, 33,202,244,180,180,181,103,226,173,194,210,210,210,208,192,194,210,210,210,208,192,194, +210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210, +215, 13,125,163,254,220, 13,158,224,130,240,159,178,214, 5,156,238,249,111,173, 45,150, 21,116, 81,219,173,155,110,200,219,199, + 39,194, 98,116, 8,215, 53,192,138,116,167,170,213,245, 68,151, 17,255, 0,171, 32,177,132, 50,233, 76,186,132, 39,249, 26, 91, +214, 67,195,217,207, 19,102, 9,149,228,116, 47, 95, 90,224,177, 85, 42,161, 80, 16, 11,200,238, 85, 35, 64, 72, 5,157,128,185, + 10, 46,204, 1, 98,226, 46, 38,200,248, 79, 45,124,219,136, 51, 20,203,104, 81,130, 6, 96,204,206,237,114,169, 28,104, 26, 73, + 28,128, 78,148, 86, 58, 85,152,128,170,196,119, 43, 75, 80,124, 63, 73,159,141,131, 84, 83,195,103, 56, 94, 20, 82,242,212,138, +127,240,103,117, 13, 77, 44, 20,171,195,105, 85,127,227,115,194, 91,193,101, 37, 75, 16,146, 20, 1, 1,180,147,204, 58,247,192, + 39,183,219,102,184,168,189,173,253,156,222,171, 32,236, 38,233,221, 18,227,210,109, 58,154,110, 6,238, 13,182,188,107,111,132, +162, 53, 29,138,204,184,113, 36,218,181,233,114, 84, 26,131, 10, 91, 82, 88,144,233, 68,118,234,107,152,244,120,206,205,115,175, + 7,248,243, 35,161,151, 49,169,202, 86,166,150,157, 75,200,105,230,142,102,141, 64,185,102,140, 17, 33, 10, 55, 98,138,225, 64, + 44,108,160,156, 64,178, 47, 27,188, 58,226, 12,194, 28,174,151, 57,106, 90,186,150, 9, 16,169,134, 72, 82, 71, 38,202,171, 35, + 3, 26,179, 27, 5, 18, 50, 22, 36, 42,130,196, 12, 72, 35, 75, 94, 80,180,173, 41, 90, 8, 82, 84, 1, 73, 29, 65, 7,204, 29, +122,213, 97,139,107, 11, 75, 75, 94, 29,117,182, 91,113,231,156, 67, 76,180,133, 56,235,174, 41, 40,109,182,208,146,165,184,226, +212, 64, 66, 2, 65, 36,147,128, 6, 78,134, 6, 61,233,107,140, 28, 63,123, 94,236,238, 39,253,160,119,151, 9,219, 61,108,210, + 43,219, 63,103, 88,247, 29, 77,157,231, 77, 86, 91,178,239, 43,178,215,171, 80,169,213, 69,219, 84,214,227,166, 57,178,252,106, +195,236,197,150, 92,117, 83,126,173,247,214, 23,238,178, 89, 3,231,181,219,218,129,127,123, 56, 15, 15,137,177,182,194,209,220, +115,188,169,221, 85, 85, 13,213, 86,172,210,254,165,254, 47, 78,219,136, 94,225,245, 74, 79,188,123,199,240,222, 95,139,226,126, +167,184,183,201,250,202,212,182, 30, 7,226,105,179,220,183,134,191, 71,242,179,156,218, 1, 81, 12, 50, 72,136,121, 70, 41, 38, + 5,203, 48, 17,183, 46, 39, 37, 28,171,130, 52,149, 12,109,136, 92,222, 32,240,164, 60, 61,154,241, 87,233, 46,118, 69,147, 78, +105,167,158, 56,228,145,121,162,104,160, 34, 48,170, 90, 84,230,202,138, 36,140, 50, 48, 58,149,138,139,227,180, 26, 90,134, 23, +247,207,155,251,255, 0,155, 30,209,127,235, 93,227,255, 0,232,210,254,249,243,127,127,243, 99,218, 47,253,107,188,127,253, 26, +152,127,247, 29,226, 55,254,233,139,255, 0,155,166,255, 0,234, 98, 19,255, 0,226, 11,194,239,253,245, 55,255, 0, 37, 87,255, + 0,210,196,207,116,181,166,252, 3,241, 57, 89,226,255, 0,133,157,171,223,235,138,219,165,218, 85,203,250,153, 89,157, 81,183, +232,178,101,204,165,211,157,166, 93, 53,202, 3,109,195,147, 56,120,175, 33,108, 82,154,113, 69,125, 66,221, 80, 29, 0,214,228, +106,172,174,163,168,203,171,107, 50,250,180, 17,213, 80, 75, 36, 50,168, 33,128,146, 39, 40,224, 48, 36, 16, 25, 72,184, 36, 30, +160,219, 22,246, 95, 93, 77,154, 80, 80,230, 84,110,100,163,204, 97,138,120,152,130,165,163,153, 22, 68, 37, 88, 6, 82, 85,129, + 32,128, 71, 66, 47,133,165,165,165,173, 92,110, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105, +105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,107, + 3,168,110, 45, 6, 60,249,116,122, 75, 21,123,182,183, 5,239,118,155, 75,181, 41,174, 85, 12, 9, 92,174,168,197,170, 85,150, +166,169,212,105, 67,194, 32,183, 54,108,117,130,164,229, 32, 40, 29, 12, 12,103,154, 90,104,166,239, 21, 38,143, 91,167,219,119, + 13,169,123,209, 43,245,152, 83, 39,208,233, 9,165, 83, 46,121,213,134, 41,225,159,126, 83, 12, 88,181,170,177,130,134,188, 97, +151, 38,251,171, 42,228, 95, 35,139,228, 86, 47,143, 95, 53, 54,130,157,111,109,119, 6, 76, 70,208, 28,118, 91, 44, 90, 40, 45, +183,221,106, 77, 58, 85,222,220,217, 43, 74,114, 75,108,197,113,213, 99,149,182,214,178, 18, 70, 6, 28, 29, 45, 88,232, 23, 37, + 18,231,136,236,202, 36,244, 76,110, 60,135, 33,205, 97, 77,191, 18,125, 54,115, 56, 47, 83,234,212,201,141, 55, 38,149, 80, 64, + 82, 10,216,146,211, 78,164, 45, 36,160, 5, 2,111,154, 24, 24, 90, 90, 90, 90, 24, 24, 90, 90, 90, 90, 24, 24, 99,120,143,168, +110,117, 51,103,174,233, 91, 65, 29,201, 23,200,138,203,116,255, 0,119,109,167,170, 12, 69,114, 67,104,169, 72,165, 50,240, 40, +118,166,136, 69,226,200, 32,144,175,137, 0,184, 17,174, 20, 60,223, 25, 18, 95,121,199,215,190,238, 72, 83,138, 83,202, 92,139, +187,156,186,165, 18,178,175,210,126,183, 54,117, 36,133, 36, 40, 16,160, 8, 61, 8, 35, 32,253,218,208,158, 40, 56,198,176, 54, + 85,185,246,165,163, 22,151,119,238,105, 66,153, 92, 54,212,151,168,214,187,171, 78, 67,245,249, 12, 43,244,179, 83,148,148,194, +109, 65,206,185,121,108,167,148, 47,157, 60,116,224,190, 27,204, 99,139,140, 56,175,196,124,203,131,114,188,170, 14, 66,193, 75, + 56, 17, 77, 38,167,144,114, 96,182,185, 42,165,190,146, 16, 51, 50, 70,132,233, 84,102,199, 72,120, 15,198,220, 77,151, 75, 55, + 7,112,151,134,185,103, 26,102,153,172,252,246,158,170, 2,101,134, 61, 49,198,121,211,223, 68,116,145, 17,172, 23,210,170,242, + 53,139, 51,170,227,143,215, 53,223,196,133,153,238,191,194,219,167,117,237,195, 59,196,247, 52,214,107,151, 20, 5,201, 13, 99, +196, 83, 45,200,148,149, 45, 41, 42, 0,144, 49,147,140,231, 88,195, 91,199,188,114, 93,109,134, 55, 39,112,100, 60,226,194, 90, +101,171,158,186,235,142, 44,159,133, 40,109, 50,201, 90,179,216, 0, 78,177,155,198,244,186,247, 18,225,151,114, 93,181,137,181, +218,221, 69,209,207, 34, 82,202,131,105, 39, 13, 68,134,194,112,136,145, 17,156, 33,166,210,148, 36,118, 25, 36,157,221,188, 47, + 45,145,246,104,112,186,239, 19, 59,221, 70, 93,217,123,214,159,133, 73,179,173, 8,106,140,213,106,227,187, 42,177, 94,153, 78, +181,233, 18, 37,182,177, 72,167,177, 22, 51,207,212,167,150,214, 25,110, 59,132, 37,229,170, 52,119,121, 7,194,159, 15,120,203, +198,222, 60,159,134,248, 23,136, 51,106,108,146, 23, 75,212, 85,212,201, 45, 66,164,141,162, 37, 49,195, 36, 81, 52,243,178,187, + 44, 97,214, 56,145, 92,188,204,177,150,110,196,241,107,196,110, 10,240, 51,128, 32,226,126, 62,225,252,162,167, 58,153, 28,251, + 61, 37, 52,112,211, 51, 70,161,230, 97, 36,209,203, 42,211,192,172,138,210, 20,105, 37,118,141, 82, 21,105, 2,174,163, 72,218, +189,222,170,162, 69,126, 85,135,123,206, 76,183, 23, 46, 77, 77,218, 13, 81,227, 33,199,137, 91,146, 29,120,199, 37,106, 82,148, + 73, 81,238, 73, 58,203,118, 91,127, 55, 47,135,155,149,114,173,233, 18, 19, 1,201, 8, 23, 5,159, 86, 18, 27,166,212,210,217, +229, 80,122, 50,192, 84, 10,130, 81,144,135,219, 1,196,246, 80, 91,101, 77,171,150, 85, 47,164,143,198, 35,151, 97,170, 81,118, +183, 97,169, 54,130, 37,133,179,102, 61,111, 92, 53, 14,120, 40, 95,195, 22, 93,192,171,133,185, 46, 62,166,176, 22,235, 65,161, +204, 74,144,218, 6, 18, 59,121,195,151, 16, 59, 31,237,121,225,250,232,188,108,251, 74, 62,216,241, 35,181,232,138,205,221,106, + 37,246,165,173,185,210, 97,201,126,152,244, 42,139,108,182,186,213,159, 85, 16,103, 34, 50,222,109, 50, 33,200,136,182, 92, 7, +194, 14,201,234,207, 16,126,128,222, 38,248, 71,147,143, 16,120, 59,138,106, 38,207, 50,127,174,217,162, 46,210, 29,204,124,216, +156,104,105,141,227, 9, 42, 77, 79, 51,176,134, 89, 64,146,237,200,222, 28,127,180, 43,194,191, 25, 51,195,225,207, 24,112,181, + 60, 89, 30,113,245, 32, 50,202, 17, 98, 29, 36, 17, 76,191, 88,176,139, 72,205, 19,193, 81, 10, 35, 77, 20, 76, 99, 32,118, 27, + 96,248,137,177,183,250,218, 21,123,106, 66,161,213,225, 37,166,235,214,228,213,160, 84,232,242,156, 78, 64,113, 41, 56,147, 13, +101, 43,240,159, 71,192,224, 65, 7,149,105, 90, 19,106,226, 39,139,222, 29,184, 78,110,198,145,196, 38,229, 82,246,206, 6,226, +214, 42, 20, 27, 86,171, 91,137, 84, 93, 38, 85, 78,151, 17,153,211, 89,157, 82,131, 5,214,105, 13,162, 43,237,171,196,148,182, + 91, 86, 72, 74,138,129, 26,224,102,199,110,133,115, 99,247, 86,135,116,199, 84,134, 26,129, 81,250,170,231,166, 5,148, 9,180, +119, 95, 17,234,144,223,108, 28, 41,230,185, 75,173,103, 33, 47,197, 65,236, 8, 56,167,210,118,170,198,173,240,251,194, 53, 82, + 35,168,126, 52,237,202,189, 36,178,235,106, 10,109,214,222,179,169,238, 54,226, 20, 58, 41, 37, 10, 4, 31, 67,171, 87,232,151, +199,112,248,245, 61, 22, 67,196,119,203,243,234, 9,141, 61,127,179,133, 66,234,105,230,150, 10,168,209,213,213, 57,175, 11,164, +177,216,133,120,223, 78,133,116, 11, 85,125, 48,120, 26,127,163,229, 30, 99,196, 92, 52, 23, 49,200,107, 97, 90,156,188, 84,150, +112,140, 42, 96,138,162,146, 87, 70, 70,147,148,147, 35,197, 32, 96, 89, 36,143, 86,182, 71, 38, 80,214, 61,247,102,238,101,169, + 68,190,118,250,231,162, 94, 86,117,203, 5,186,157, 2,229,183,106, 17,170,180, 90,196, 7, 74,146,220,186,125, 66, 35,138,110, + 83, 5, 72, 80,230, 66,136,202, 72,238, 8,214, 89,168, 64,112,175,237,189,221,253,134,225,159,102,120,123,225,163,133,105,251, +189, 82,218,155, 26, 53, 58,249,186, 43,172, 93, 53, 88,104,168, 59, 62,163, 61,244, 83, 40, 54, 52,101, 57, 18,156,216,146, 0, +149, 42, 82, 84,242,185,200,142,216, 71, 50,250, 53,193,103,210, 48,176, 55,151,114, 45,253,161,226,123,106,154,216,235,138,230, +171,179,111,210,175,154, 45,102, 69, 70,198, 98,189, 45,246,226, 66,166, 92,208, 43, 49,218,153,107, 54,228,197,120, 94,244,183, +101, 50,219,175, 32, 72, 17,218, 11,121, 61, 57,156,120, 63,198,153,119,233, 74,154,108,168,214, 80, 80, 73, 45,180,205, 3,212, +154,116,102,229,204,244,233, 33,144,107,140, 7,210, 20,181,143,217, 29,185,103, 35,241,187,128,243, 63,209, 20,149, 89,184,162, +204,179, 40,225, 7, 84, 53, 9, 74, 42, 93, 19,153, 2, 84,188, 98, 35,203,145,140,122,139,232,184,251,102,226,253,250,171,113, + 37,195,245, 6,251,107,107,171, 91,211,182, 52,173,200,122,165, 79,163, 51, 98,207,189,104, 17,110,183,106,213,101, 50,154, 93, + 53, 20, 39,167, 9, 42,157, 33, 82, 99,134, 90, 13,243,184, 95, 72, 64, 60,195, 47, 80, 32,128, 65, 4, 17,144, 71, 98, 53, 2, +158, 50, 84,211,191, 72, 26,128,243, 1, 10, 14,113, 65,195,147,232, 82, 80,159,137,193, 34,193, 91, 78,246,248,156, 5, 45,144, +174,224,164, 16,122, 13,118, 87,143, 15,111, 68, 62, 31,247, 89,238, 25,120, 83,218,134, 55,231,120,232,117, 24,214,189,203, 90, +170, 59, 86,145,107, 83,239, 39, 22, 24,122,204,183,168, 86,222, 39,222, 53,230, 36, 56,219, 82, 84,212,136,236,177, 41, 11,138, +145, 33,196, 56, 91, 91, 48,240,167, 51,118,225, 88,120,116,201,154,212,103,249,106,102, 51,243, 57,112,197, 76,172, 19, 86,169, + 89,130, 8,193,123, 6, 98, 25,182, 0, 19,182, 17,203, 60, 97,202,145, 56,190,163,137,196,121, 61, 47, 14,230,178,101,148,252, +190,100,210,213,186,151,211,162, 37, 82,237, 35, 4,185, 84, 5, 84, 92,179, 1,190, 36,133,165,168,139,220,190,218,255, 0,106, +111, 13,237, 80,239,190, 41,184, 29,183,169, 27, 89, 90,168, 69,138,228,225, 66,187,237, 23, 16,167,193,117, 20,246, 46, 35, 90, +169, 70,163, 85,156,101, 14,120, 77, 84, 34,149,172,182,172, 54, 74, 84, 7, 85, 46,223,109,143, 13, 22,231, 5,182, 47, 26,148, +171,102,247,187,237, 43,183,112,233,251, 83, 88,178, 40,166,138,205,225,100, 95, 50, 40, 85,218,228,250, 85,194,221, 66,123,108, +120, 76, 51, 65,115,145,214,150,161, 37,154,132, 89, 13, 39,195,116,242,177,215,248,105,197,180, 35, 47,120,168,226,205,105,243, + 57,189,158, 25,168,170, 33,169,137,167,177, 60,146,241,185, 8,246, 6,193,244,130, 65, 0,146, 8,196,131, 46,241, 91,131, 43, +206,100,147, 87, 77,147,212,229, 48,251, 76,240,215,211, 79, 73, 50,211,220, 14,112,142, 68, 5,227,187, 45,202,106, 32, 16, 72, + 0,223, 29,148,210,212, 92,183, 35,233, 31,162,243,160,209,233,124, 25,112,161,184,187,163,185, 51, 34, 63, 58,227,131,120, 83, +170,147,233,118,147, 44,202,113,150,152,250,163,111,196,153,119, 10,221,142, 27,116,188,153, 48,153, 96,159, 12,248,202, 37, 72, +198,248, 54,250, 69,151,109,251,190,214,214,200,241,107,178, 86,230,220,166,238,185, 96,217,113, 46,235, 45, 87, 21, 53,219, 86, +231,169,204, 77, 62,159, 26,239,181,110,153, 50, 30, 76, 37,212, 94,142,195,174,178,251, 78, 69, 46,135, 23, 29,196,133, 99,108, +248, 71,199,171, 65, 85, 94,249, 46,143, 99, 86,119,128,205, 7,180,136,210,247,113, 0,144,200, 87, 98, 84, 91, 83,129,116, 86, + 4, 95, 68,120,211,225,211,102, 52,121,116,121,233,147,219,157, 99,142,160, 83,212,123, 33,145,237,166, 51, 80, 99, 17,134,243, + 0,198,250, 99, 38,210, 50,144,109, 43, 29,120,113,198,217,109,199,157, 90, 91,105,164, 45,199, 28, 89, 9, 67,109,161, 37, 75, + 90,212,122, 37, 33, 32,146,124,128,215, 14,253,164,222,219,221,157,224, 86,233, 59, 61,101,218, 15,111, 86,249, 34,155, 14,165, + 92,161, 49, 88, 69, 18,210,176, 89,169,199,110,101, 41,155,170,176,220,103,222,151, 90,126, 19,172,190,154,124, 86,130,209, 30, + 75, 79, 63, 37,143, 17,182,220,230, 77,175,244,142, 56,132,142,220,122,222,253,112, 91,245, 86,205, 92,140,191, 79, 85,221,100, + 38,245,165, 74,102, 61, 69,151, 99,183, 46,153, 83,187,226,187, 77,174,184,128,224, 80,100, 59, 27,198, 13,148,165,214,201,230, + 8,229, 94, 22,113,190,113,150, 83,230,244,153, 69,168,170,198,168,121,147, 65, 20,147,169, 23, 6, 24,228,145, 93,245, 13,211, + 97,172, 88,173,193, 4,175,156,120,191,192, 25, 38,109, 81,146,214,231,119,174,163, 58,103,229, 65, 81, 52, 84,237,123, 17, 52, +177, 70,232,133, 78,207,185,229,155,135,210, 65, 2, 71,219, 95,199,191, 8,187,217,187,147,118, 59,104, 55,194,208,220,189,198, +166,208,234, 87, 13, 70,153,102, 59, 46,189, 76,133, 76,164,205,137, 79,158,183,238, 88, 81, 85, 78, 18, 91,151, 54, 58, 11, 41, +148,167, 73, 89, 33, 4, 37, 68,109,254,160, 19,244,127,110,123,126,214,227,115,113,175, 26,237, 82, 45, 14,212,183,182, 43,113, + 46, 74,213,102,160,164,196,131, 73,183,233, 85,139,126,167, 62,165, 57,121, 34, 52, 86, 32, 48,235,174, 30,161, 9,104,247,198, +186,103,185, 63, 72, 83,125,183,147,120, 38,237, 23,179,215,133,198,183, 45,182,164, 77, 98,145,112,222, 16,174, 10,229,197,113, +192,167, 58, 82,245,199, 30,212,183,230, 68,102,215,162, 45, 1, 42, 11,168, 75,116,161,181,165, 79,248, 14, 57,225, 53, 36,226, + 95, 8,115, 26, 94, 38,172,201,120,104, 61, 93, 6, 89, 75, 4,245, 53,117,114,195, 4, 81, 25, 67,146,100,145,185,104,163,202, + 74,160,212,224, 2, 73, 32, 18, 34,220, 41,227, 94, 89, 89,194,148, 57,247, 21,178, 81,102, 57,181,101, 69, 61, 45, 29, 20, 83, +212, 77, 48,132,160, 2, 56,151,153, 35,155,184, 12,231, 66, 18, 85, 64, 4,128,101,135,165,168,156,219,158,223, 30, 44,184,114, +221, 75,123,111,253,161,252, 36, 55,183,244, 42,247,131, 37,117,235, 78,155, 93,160, 92, 80,232,239,201, 68,119,171,244,186,109, +102,169, 54,159,121,211,227, 40, 44, 58,212, 57,113,220,230, 73, 71,139,226, 0,218,186, 89,198, 87,182,211,135, 30, 14,235, 27, + 75, 6,163,102,223, 59,171, 70,222, 93,176,167,238,197,161,117, 88, 18, 40, 31, 82,200,182,106,181, 25,180,248, 5, 70,177, 61, +135,125,225,126,226,183, 10,124, 49,200,151, 18,149,128,224, 82, 83, 20,171,240,211,140,105,171,114,250, 40,178,177,152,182,106, +143, 37, 52,148,179, 67, 60, 19,172, 66,242, 24,230, 71,208, 74, 13,202,146, 26,219,128, 70,248,152,209,120,173,192,245,116, 57, +149,124,217,177,202,215, 39,120,227,171,138,178, 9,169,234, 41,218, 83,166, 46,100, 14,156,192, 28,236, 25, 67, 45,246, 36, 29, +177,217,173,112,163,112,253,133, 28, 55, 95,188,105,212,248,162,173,202,171,215,108,187,186,163, 93,190, 47,125,152,175,202,157, + 87,160,214,183, 90,175, 85,141, 82,118,228,122,179, 46,114,165,201,181,228, 73,126,179, 50,101, 17,245, 57, 25,115, 93,105,180, + 56, 41, 5,116,160,202,240,191,237,190,220,158, 50,248,231,219, 77,158,218, 29,130,147,111,112,189, 93,145,119,193,184,247, 10, +229,165,214,170, 87,151,189,209,182,206,237,185,233,142,205,168,210,100,170,143,106, 52,237,203, 71,166, 71,110, 59,134, 83,174, +180,249, 30, 48,117,228, 33,185, 31,161, 92,200, 74,187,115, 37, 42,199,166, 64, 58, 74,170, 30, 49,240,218,181,169, 26,169,242, + 74,252,226,140, 25, 82, 41, 81,156, 65, 43,200,129, 36, 40, 91,149, 48,104,217,133,136,150, 59,130, 25, 75, 17,133,169, 38,224, +127, 20,232, 22,181,105, 35,207,242,236,146,184,136,164,154, 23, 84, 53, 16,164,110, 94, 33, 32, 83, 44, 44,178,170,155,131, 20, +182, 33,149,130,131,134,126,151,176,123, 71, 74,180, 27,176,226,237,253,162,205,158,136,126,226, 45,102,173,218, 59, 86,224,136, + 80, 27, 49, 69, 13,184, 98, 40,143,200, 0,228, 13,114,224, 99, 24,212, 4,189,180, 92, 57,109,223, 10,156,122, 93,182,174,205, +192,141,105,218,119, 45,169,102,238,133, 50,218,161,145, 14,159,102,213,171,255, 0, 88, 69,169,211,168,140,199,193,165, 66, 53, +106, 19,243,227,176,217, 74, 34,138,178, 89,140,150,163, 54,195, 77,254,136, 21, 90,173, 54,133, 75,169, 86,235, 51,225,210,168, +244,120, 19, 42,149, 90,165, 66, 67, 81, 32, 83,105,180,248,238, 75,157, 62,108,183,214,148, 70,136,204, 86, 93,113,199, 22,160, +132, 33,181, 41, 68, 0, 78,191, 57, 62, 35,175,107,151,218,161,237, 50,184, 37,109,235, 50,196, 29,229,220,202, 77,141,183,190, + 43, 14,184,170, 30,215, 90, 80,163, 80, 97,220,243, 97, 43, 10,140,219,118,133, 14,117,126,160,198, 73,109,217, 50,144,146,162, + 19,155, 39,192, 39,174,139, 62,226, 12,218,122,167,135, 34,160,161,145,235, 29,217,140, 69,217,213,208,184, 38,197,194, 71, 52, +154,236, 88, 42,184,189,156,131, 86,125, 35,211, 47,155,135,120,111, 38,167,164, 73,184,135, 50,204, 35,142,133, 17, 84, 74, 17, + 81,146, 64,132, 0, 66, 51,201, 4,122, 1, 10, 89,144,218,233,113, 61,206, 11,119, 14,189,187, 28, 40,240,239,185, 23, 75,138, +118,228,190,118, 83,107,110,250,243,171, 32,173,202,197,203, 99,208,235, 85, 53,168,134,209,146,102,205,124,159,129, 61, 79,234, +167,176,217,253, 55, 59, 75,100,210,182,231,110,237, 11, 38,133, 20, 65,162,218,246,245, 30,223,164, 66, 7,152, 68,165, 81,169, +241,233,212,232,193, 88, 25, 13,196,142,210,123, 15,213,211,141,170, 34,178, 72,102,172,170,154,158, 62, 77, 60,178, 59, 34,126, +202, 51, 18,171,255, 0,106,144, 62,236,116, 69, 12, 83,193, 69, 71, 5, 76,188,250,152, 98,141, 36,127,219,117, 64, 29,191,238, + 96, 79,223,133,168,165,123,119,125,170,238,209, 91,175,240, 39,195,117,192,235,151, 29, 77, 14, 81,120,135,190, 40, 15,243,187, + 74,135, 49, 41,105,123, 57,111, 76,138,162,181,214,165, 33,194, 46, 23, 26, 41, 49,152, 90, 40,225, 78, 63, 38,166,204, 61,237, +246,205,251, 82,224,240, 79,182,174,108,238,209, 85,161,203,226,135,116, 40,142,253, 82,227, 78, 37,255, 0,226,146,206,156,167, +161,191,184, 53, 54, 18, 8, 53,247,252, 41,108, 80, 99, 56, 82, 61,229,165,212,159, 75,177,161, 8,147,185, 93,236,136,246, 94, +213,106,214,149,199,198,255, 0, 17,212,217,179,238, 10,173,173,115,221, 27, 61, 64,185, 22,228,217,136, 85, 70,147, 62,106,247, + 98,229, 19,146,183,100,220, 18,214,234,221,164,120,203, 82,154,110, 66,170,174, 5,201,122, 11,177,110, 14, 3,225,236,179,135, +178,212,241, 23,140, 33,215, 71, 11,133,202,168,154,193,235,170,175,228,151, 73,191,212,196,192,178,146, 8, 37, 76,132, 21, 68, + 89,105, 31, 17,120,151, 54,226,108,214, 79, 12, 56, 34,126, 93,116,209,151,206, 43,214,229, 40, 41, 45,231,132, 50,145,245,242, +169, 10,202, 8, 32, 50,196, 8,105, 29,161,210,223,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199,236,141,116, 43,233, + 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,207, 95,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199, +236,141,116, 43,233, 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,106,102,159,250,197,112,231,255, 0, 5, 39, +255, 0,208,175,197, 59,147,255, 0,234,195,197, 95,252,124,127,255, 0,161,150,227,167,222,201,206, 30,246, 78,244,224, 27,134, +234,253,209,181,155,125, 93,172,206,219,232,206,205,170, 85,108,219,118,161, 80,150,239,214, 85, 36,151,101, 76,151, 78, 91,146, + 29,229, 74, 71, 50,212, 78, 0,235,174,142,127, 36,254, 28,127,249, 20,218,239,253, 65,181,127,255, 0, 21,168, 67,236,206,242, +251,107,106, 27, 11,183,118,135, 14,118,230,248,218,123, 35, 96,219, 49,169,246,138,246,239,108,225, 81, 63,132, 20,246, 12,185, + 95, 92,181,113, 85,232,203,170, 93,234,124,188,224,255, 0, 4,146,236, 21, 45,180,166, 60,100, 57,144,172,147,102,189,184,158, +209,254, 22,247, 41, 54,175, 17, 19,170,123,167, 72,160, 84, 35,193,188,246,187,121,108,216, 86,109,253, 75, 99,149,165,201, 68, + 43,134, 21, 2, 5, 86,143, 93, 49, 75,106,105, 85, 86,234, 49,190, 62,117, 68, 87,136, 87,168, 78,113,225, 63, 21,230,217,158, +127, 91,147,241, 53, 5,117, 75, 84,212,207,236, 81, 87, 72,103, 68,121,153,145, 24, 4,229,164,150,101, 82,174,202,138,219,115, + 58, 98,193,200,252,101,224,252,151, 41,225,202, 12,239,133, 51, 44,186,145, 41,105, 96,246,233,178,248,197, 59,201, 28, 17,171, +186,157,124,201, 35,186,179, 6, 68,121, 25, 70,174, 95,164,237,173, 75, 62,218,177,233, 17,168, 22,157, 22,153,111,209, 33, 37, +105,135, 73,163,193,139, 77,167, 68, 67,142,173,231, 17, 26, 20, 54,144,211, 9, 83,206, 56,178, 16,144, 10,156, 82,143, 82, 78, +178, 93, 49, 28, 53,113, 19,183, 28, 85,108,189,139,190,123, 87, 80,118,125,159,125,210, 5, 74, 19,114,219,105,138,157, 46, 99, + 18, 31,167,214, 40, 85,152,204,188,226, 34,214, 96, 85,226, 78,135, 45,180, 56,227,105,126, 18,252, 55, 93,108,161,197, 62,250, +231,250,168,106, 41,170,106, 41,234,227,104,170,224,119, 73, 85,193, 14,178, 43, 21,117,112,119, 12, 24, 16,215,222,247,190, 58, + 70,146,122, 90,170, 74,106,154, 41, 18,106, 58,136,209,225,120,200, 40,209, 58,134,141,144,141,138, 50,144, 84,141,172, 69,176, +180,180,180,180,134, 54, 48,180,180,180,180, 48, 48,180,180,181,192,111,104, 5,251,125, 80, 56,143,220,198, 45,253,213,169, 89, + 9,183, 54,167,110,238, 27,118, 11,123,151,122, 90, 50,220,172,139,138,158,153, 72,178, 45,251,125,102, 37,197,116, 63, 9, 82, + 82,182, 38, 6, 89, 68,111, 26, 95,138, 30,142,216, 47, 57, 30, 78,249,221, 99, 81,164,226, 6, 84, 47,168,169,111,215, 68,181, +129, 7,171,130, 78,246, 0,236, 78,216,215,169,168, 20,209,243, 10,234, 23,181,175,110,196,255, 0, 44,119,231, 75, 81,244,103, +138, 29,229,219,186,190,226, 38,204,169, 55,100, 67,220,238, 34,247, 45,250,213,217,125, 65,164,205,147,104,206,165,216,118, 61, + 94,129,106,212, 95,186,100,197,162, 91,207, 73,151, 86,156,153, 30, 59,169, 82,141, 53,244,196,109,181, 55,135,114,241,198,191, + 22, 21,107, 15,123,247, 58, 21,239,182, 80, 41,252, 61,195,225,246, 85, 90,221,164,217,177,110, 10,125,254,238,232, 42, 29, 18, +168, 34,221, 38,172, 62,174,129,245,162, 36,204, 82,163, 52,225, 82,101,134, 98,190,203,109, 37,110, 59,183, 5,230, 62, 70, 90, +152, 57,114,114,192, 44,206, 14,169, 36, 72,144, 16,168,246,213, 43,132, 6,228, 91,204,218, 84,223, 8, 12,198, 29,193, 70,184, +191, 64, 58, 0, 88,157,200,232,162,231,111,112,185,199,119, 52,181, 31,219,163,138, 13,215,187,247, 63,109,175,153, 87,125, 18, +185,126,217, 23,151, 19, 82,104,252, 60,211, 45,201, 52,233,150, 71,240, 34,193,174,162,217,167,220,143,211,222, 93, 66,233,145, + 84,147, 75,108,134,220, 72,230,113,130,136,203, 97, 74,115,194,187,218, 60,116,241, 71, 94,159,183, 22,253, 63,112, 54,166,175, + 63,117,119, 39,104,237,104,115,229, 80,109,233,245, 11, 49,235,225,117,154,109,106,149, 86,182, 45, 90,232,117,138, 91, 85, 35, + 79, 91,126,254,228,106,167, 37, 61,109,158, 66,226,214,144,220, 23,153, 8,213,214,162, 27,132,212,225,139,174,147,174, 69, 33, + 78,131,172, 1, 25,109,118, 10,194,252,179, 32, 1,136, 25,140, 58,136, 42,221,108, 45, 99,125,129,245,219,115,107,117, 29,237, +142,245,233,107,147,209,223,222, 43, 46,151,189,123,171, 87,168, 91,247, 45,193, 96,238,236,107, 86,163,184, 18,175, 13,204,135, + 26,223, 51,155,219,155,122,229,185,225,109, 4,121,171,160, 11, 66,149, 6,229,173, 86, 75, 18,101,144,211, 81, 94, 47, 30, 86, +130,245,116,153,197,253,205,104,175,125,224,212,119, 98,196,186,104,182, 78,217,238,236,253,159,220, 25, 80,109,250, 84, 61,204, +189,109, 75,111,110,106,180, 88,240, 28,129, 37, 16, 46,122,140, 59,158,240,173,209,164, 71,165, 4,181, 37,202, 9,253, 10, 30, + 67,199, 90, 31,253,157,169,144,255, 0,100,153, 42,109, 96,108, 24, 93,173, 25, 33,108, 27, 96, 37, 66, 3,232,144,141, 71,151, +101, 98, 20,246,180, 31,222, 41, 75,252, 58,110, 5,250,122, 30,151, 3,109,247, 24,234,110,150,185,121,125,113, 27,190,246,141, + 14,226,220,138, 85,122,149, 95,137, 79,221, 29,192,219, 42, 86,219,187,104, 69,247, 57, 66,135,195,181,213,186,212,122,171,149, +122,104, 85, 74, 93, 76, 92,212, 56,173,120, 13,169,182, 94,140,242,153, 95,134,178, 36,161,188,127,125,171, 86,214,225,238, 11, + 22,199, 16, 84,107,178,163,121, 39,108,124, 29,207, 68,141,169,183,108, 72,233,163,237,245,233, 92,170,211,106, 53,186,204, 89, + 52,202, 39, 35,139,138,182, 99, 49, 2,101, 90, 83, 81,212,194,240,184,239, 73, 25,143,134,171, 36, 66,194,104,254,198,161,110, + 97, 23, 14,138,202,199, 64, 11,164, 54,162,119, 6,214, 93, 86, 98,161,171, 35, 6,218, 79, 91,118,238, 9, 4, 11,239,126,158, +238,246,218,253,134,210,215, 23,168,252, 66,238,173,122,152,237,253, 54,243, 85,110,231,171, 76,225,138,243,161,236,203, 18,102, +193,102,123,213,219, 34,129, 34,173, 62,218,133, 2,172,137,173,218,242, 46,180,203,140,244, 86, 80,236, 39,101,213,208,220,211, + 33,228,132,186,236, 80,248,135,221,139,146,237,218,187, 18,214,222,123,102,243,129,185, 51,246,200,220,219,133,110,217,182,220, +151, 54,246,175,118, 89, 27,207,114,220, 59,126,196, 88,238, 61, 5,154,162,127,128,148, 71,161,179, 83, 67,181, 56, 13,161,255, + 0,172, 27,152,151,144, 18,105,120, 98,178, 37,118, 51,199,104,151, 83,147,204, 1,108,138,237,184, 67,125, 33,173,125,181, 16, + 66,106,107,129,133,173,141,136, 1, 79,155,167, 77,247, 32,119,239,248,119,182, 58,147,171, 69,118,187, 74,182,233,114,107, 21, +153,105,135, 2, 47,132,149,185,225,188,251,206,189, 33,212, 71,139, 18, 28, 72,205,173,217,211,223,148,235, 45, 49, 29,148, 45, +231,222,121, 13, 52,133,184,180,164,182, 60, 63, 94, 23, 13,249,180,118,173,203,117,202,141, 58,225,125,219,146,149, 84,168, 68, +134,221, 57,154,140,139,106,235,174,219, 34,165,238, 12,168,183, 13,217, 13, 81,219,121,198,219,253, 26, 28,125, 73,108, 37, 1, + 41, 13, 62,232,111,214,218, 88, 87, 53,221, 90,189,235,241,103, 84, 54,214, 35,223,192,237,191,166,243,212, 43,146,234,168,162, +210,230,214,174, 85,210,219,108, 4, 84, 20,139,146, 5, 54, 10,228, 56,219,108, 55,239, 43,109,212,137,238, 41, 44, 50,192,240, +207, 45, 59, 88,201, 19,178, 27,116,186,146, 13,137,182,215, 29, 72, 27,117,198,210,176,101, 86, 29, 24, 3,251,247,199,221,233, +222,106,181,159, 75,167, 84,174,234, 93, 66,210,177,231, 69,184,235,115,168,180, 74,161,155,188,183, 37,187,104, 81,151, 91,175, + 70,163, 80, 40,200, 81,166, 32, 83, 84,169, 82,149, 18, 91,178,216,139, 78, 83, 11,126,159, 42,107, 42,103,136,187,179,237, 34, +226,147,119,235, 63,197,223, 8,251,124,189,158,219,184, 97, 16, 40,176,233,212,196, 92,251,157, 84,166,150,212,167,102,185, 76, +180, 34, 77,106,221,117,114, 22, 2, 25,135, 45, 15, 52,181, 45,110,204,125, 71,175,108,182, 23,109,174,187,130,169, 84,222,157, +223,125,186,149,249,123, 65,247,101,210, 60,100,212,104, 54, 69,155, 36, 7,224,237,133,176,149, 2,203,148,166,146,166,158,173, +205,109, 3,235,170,160, 43, 86, 98, 69,134,211, 59, 51,104,216,150, 77,129, 77,110,141, 99, 90, 54,213,159, 74,109, 41, 66,105, +246,205, 18,155, 68,137,132,126,169, 91, 20,232,205,165,197,117, 57, 82,129, 81, 36,146, 73, 39, 78,217,109, 94, 95,150, 60,146, + 85, 80,254,145,169, 22,208, 11, 40,141, 58,223, 82,180,114, 93,186, 91, 96, 71, 98,164, 27,234,212,195, 81, 80, 21, 35,159,217, +227,223, 81, 0,150, 61, 45, 98, 25,108, 58,223,168,247, 17,136,175,109,165,111,136, 46, 22,110, 90,253,251,188, 55,190,238, 65, +226, 39,118,227, 73, 22,188, 43,214,173, 93, 15,170,216,230,151, 29, 53, 11,198, 13, 89,199, 26,118,108,119, 24,169, 38,135, 69, + 37,232,207,174, 19,213,119,127,239, 68, 64,213, 43,151,138,189,231,148,233, 93,203,191,247,220,103, 10,148,232,142,246,226, 85, +105, 32, 96,149, 21, 51, 79,141, 84,100, 37, 35,175, 68, 55,129,142,128,107,190, 92, 81,109,158,214,113, 35, 67,184,108,237,202, +102, 60, 43, 2,198,163,212, 42,247, 21,248,211, 49,155,173, 80, 37,183,202,252,118,173,218,155,209,221, 83, 79,170,117, 53,160, +227, 77, 36,169,228, 67,121, 32,178,242,233,207, 57,194,234, 71, 15,220, 39, 90, 75,109,193, 77,191,119, 2,124, 94, 96,220,151, +161,219,182,108,103,243,144, 18,185, 21,119,174, 89,106,100,163, 0,129,224,171,201, 60,131, 83,252,135, 54,165,204,160,150,105, + 50,197,106,184,152, 41, 60,176,194,223,170, 17,180, 5, 22, 29, 67, 58,155,146,119,189,240,193, 93, 73, 45, 59,170, 45, 73,228, +176,184, 26,172,111,176, 36,139,220,223,181,129,216, 91,107, 91, 29, 21,246,100,113, 47,186, 91,235,125,110, 4, 59,162, 92, 75, +222,214,164, 89,244,136,116,189,196,146,195,109, 87,221, 69, 6,164,227, 77, 68,157, 83,101,164,170,228,142,252,250,245, 93,166, + 94,150, 12,132,127, 7, 30, 90, 93,113,183, 73, 87,102,245,197, 62, 8,247, 59,106,118,179,113, 23,103, 90,182, 36, 75, 2, 30, +235, 85,168,116, 25, 13,199,172,212,107, 14, 87, 43,209,216,152,205,189, 33,239,126, 9,109,170,147,105,114, 75, 75, 16,216,138, +219,177, 93, 46, 62,219,134, 27, 74, 71,107, 53, 4,226,104,132,121,180,197, 40,197, 20,114, 5,101, 80, 0, 13,113,230,112, 20, +149, 23,107,139, 2,109,109,247,185, 47,153,107, 22,165, 75,205,206,101,184, 39,115,107,116, 27,128,122, 88,239,235,233,133,165, +165,165,168,254, 55,240,180, 29, 66,161, 2,147, 6, 93, 78,169, 50, 45, 58,157, 2, 59,178,166,206,154,251,113,162, 68,140,194, + 11,143, 72,147, 33,229, 4,178,202, 80,149, 21, 41, 68, 0, 6, 73,209,154,212,158, 53,182,250,255, 0,220,189,141,169,219,187, +118,235,139,169,181, 89,166,213,106,148,134,158, 12, 59,113, 81, 32, 51, 52,201,162,180,181, 16,149, 58,102, 59, 6, 74, 80,165, + 0,225,167, 6,243,149, 0, 88,184,159, 52,173,201, 56,123, 58,205,242,220,170, 76,242,191, 45,166,150,104,105, 34,254,242,162, + 68, 66,203, 18,216, 19,118, 35,162,171, 57, 23, 8,172,214, 82,253,194,249, 85, 14,121,196, 89, 38, 79,153,230,209,228, 89,126, +101, 83, 12, 51, 86, 75,253,221, 60,114, 56, 87,149,174, 85,108,160,245,102, 84, 6,197,221, 86,236, 52,131,138, 95,104, 4,186, +199,214, 54, 22,197, 77,122, 13, 40,151,161,213,183, 5, 41, 91, 51,234, 13,245,109,214,109,116, 44, 5, 64,138,174,191,225,138, + 1,245,164,254,133, 45,116,112,232,102,217,108,157,245,187,134,183, 88,166,198,146,138, 37, 30, 21, 78,171, 88,184,102, 54,243, +205,188,244, 72,207, 77,118, 44,101, 40,243, 79,168,186,180, 97, 88, 36, 32,185,206,226,129, 32, 43,100, 54, 19,129,203,238,248, +173,181, 55,114, 41,115,173, 91,118, 27,233,241,105,111,225,154,189, 85, 72, 80,230,100,242, 40,251,132, 63, 37, 44,159, 21, 64, +225,180,167, 62, 34,123,107,102,109,165,171,100,219,108, 91, 52,106, 68, 40,116,214, 97, 24, 34, 35, 12, 33,184,233,142,182,203, +107,104, 54, 7, 80,164,169, 92,196,228,168,168,149, 18, 73, 58,227, 46, 26,240,155,196, 15, 27,243,131,198,254, 48,212, 79,148, +100,169,175,216,178,205, 50, 64,197, 79,217, 84,129,142,186, 74, 91,129,173,223,251, 93, 72, 91,234, 0,172,216,237, 78, 38,241, +115,195,223, 3, 50, 97,192,254, 13, 83, 65,156,103,114, 20, 53,217,166,164,168, 64, 71,218,103,168, 81,162,174,168,169,109, 8, +159,217, 41, 75, 17,164,144,208,226, 44, 52,185, 13,195,169,211,165,188,142,118, 98,207,137, 33,212, 30,203,109,137, 13,184,226, + 8,249,165, 36,125,250,127,189,191, 59, 1,126,241, 15,193, 94,202,238,238,208,211,167, 93,244,109,151,184,170,119,101,215, 68, +161,176,236,233,235,179,175, 10, 4, 24,142, 93, 76, 66,140, 20,185, 76,211, 95,167, 69, 50, 66, 18,165,179, 30,166,244,130, 3, + 76, 60,164,211,226,127,101, 42, 59, 29,186,181,187,117,109, 62,187,118,168,251,213,155, 78,162,182,200,106, 93, 34, 91,202, 95, +186,135, 57, 66, 85, 38, 43,203, 84,119, 64,193,253, 26, 87,128,151, 18, 75,183,195, 79, 26, 53,221,151,166,139, 34,240,164,187, +122,109,226,148,224,141, 17, 46,182,154,189, 13,183,212,165, 72,102, 2,165, 31, 10,109, 61, 74, 90,213,238,238,148, 4, 41,106, + 40,113, 41, 37, 5,151,232,189,226,236,127, 70,191, 20,115,188,175,140,233,189,135,151, 83, 26, 73, 43,163, 50, 69, 61, 47, 62, + 45, 50,104, 12,254,207, 83, 5, 76,154, 39,141, 95, 65, 49, 74, 20,198,204,234,241,244,170,240,114, 79,164,247,132,249, 46, 99, +193,117, 94,220, 37,165,149,227,137, 29, 21,229,130,168,211,204, 26, 46, 97, 84,246,154, 89,233,163,215, 79, 35, 71,204, 2, 88, +139, 9, 21, 81,160, 87,169,110,253, 27, 78, 31,247, 14,201, 78,246,241, 53,120, 64,159,107,237,173,207,108, 82,237,139, 90, 69, + 85,167,160,179,114, 68,163, 76,149, 92,175,220,241,144,248, 79,137, 70,138, 26,139, 29,153, 56, 45,188,228,137, 73,109, 71,193, + 94,122, 95, 89,143,236,147,185,110, 37,110, 61,103,134,205,190,118,245,118, 71,214, 47,186,246,201, 80, 28,168, 63, 81,230,241, + 76,135,214,152, 94,233, 38,103,139,215,198,113, 69,124,221,121,181,134,239,223, 25, 43,190,109,119, 54,195,105,109,159,226,243, +110, 28, 97, 16,106, 24, 17,153,172,214,169,236, 0,134,169,158, 5, 63,244, 20,106, 55, 34, 82, 21, 29,165, 56,167, 82, 2, 22, +180,183,204,210,189, 25,241,187,233,237,225,100,220, 3,152, 80,112,253, 92, 57,166, 99,153, 70,182,130, 10,152,234,164,119, 86, + 89, 18, 33,201, 5, 97, 70,145, 87,153, 52,237, 25, 88,195,132,133,228, 42, 7,154, 94, 3,127,179,211,197,122, 79, 17,114,220, +207,136,233,166,203, 50,220,174, 70,250,249,233,164,165,141, 17,213,163,121,155,158,193,230,117,141,219,151, 5, 58,200, 30, 82, +133,230, 72,149,201,211,219,222,171, 18,185,121,221,181,168, 8, 8,131, 86,185,107,149, 40,105, 74,121, 64,139, 58,167, 42, 76, +127,132,143,135,244, 78, 35,167,207, 77, 71,183,193, 83,207, 4, 92, 7,166,161,226,120,232,185,171,137, 62, 46,121,194, 5,131, + 73,240, 82,160,174,160,134, 66, 7,221,173,145,216,173,173,169,238,230,227,208,109,120,108, 60,170,120,148,204,234,252,180, 33, + 69,184,116,136,238,161, 82, 57,156, 72,194, 30,120,132,178,214,123,173,224,113,202,149, 17,210, 31,105, 23,179, 6, 31,180, 15, +107, 54,119,111,211,186, 82,118,157, 59, 83,112, 85,238, 6, 95,131,103, 71,187, 17, 86, 21,122, 52,122, 72,130, 99,187,113, 83, +133, 57, 44,166, 58, 86,149,165, 78,133, 5, 20, 20, 12, 5,107,144,127,217,239, 11,228,156,117,155,248,159,196, 50, 53, 6, 69, + 81, 49,167, 14, 35,118, 89, 36,209, 81, 36,238,145,198, 25,217, 98,121, 98,141, 74,171, 13, 82, 58,223,200,246,236,191,246,140, +186,241, 7,135,185, 87,133,124, 53, 18,230, 60, 67, 79, 0,168, 49,153, 35, 86,142, 62,101, 52,112, 70,242, 72,200,138,210,199, + 20,210,176,118, 83,166, 56,218,223, 88,151,102,125,130,112,118, 42,169,192, 62,220,155, 3,248, 58,253,211, 14, 69,121,189,216, +141, 20,197,250,250, 61,248,229,122,168, 93,114,229,109, 39,197, 75,206, 82, 17, 78, 84, 37, 57,240,170, 2, 88, 75, 71, 8, 80, + 17,173,246,250, 13,156, 87,180, 78,224,103,100, 28,162, 63, 88,110,202,179, 25,220,245,218, 78, 69,118, 49,221,175,121,170, 25, +141,184,237, 53, 69,181,220, 41,161, 42,215, 76,222, 83,227, 38, 98, 92, 68,140, 74, 75,192,117, 38,227,250, 54,119,189,161, 79, +164, 73,216, 46, 46,110,123, 78,180,253, 25,154,101,232,154,149, 18,165, 73,135, 95,154,143, 16, 72,168,192,114,215,185, 18,237, + 62, 19,168, 82, 1,129, 35,223, 2, 20,149, 45, 50,202, 86, 27, 67,243,193,111,209,227,219,173,146,220,107,127,118,119,231,112, +164,239, 85,205,109, 84,218,174, 81,173,207,169, 81, 69,178, 35, 87, 35, 60,153, 16,234,149,118, 37,204,149, 42,232,125,153, 9, + 75,205, 33,229,199,142, 93, 0,191, 29,240,156, 31, 80, 50,110, 36,240,255, 0,133,248,167,136,120,250,159,140,167,206,102,204, +197, 81,139, 47, 20,147,199, 51, 60,242, 9, 52, 75, 52,159, 86,209,161, 80, 35, 44, 16, 5,210,199,204,186, 91,202,188,243,133, +252, 73,226,222, 17,225,159, 14,106,120, 26,159, 34,131, 42, 52,130,108,204,214,211, 75, 2,165, 60, 92,190,100, 48, 71,245,171, + 35,134, 38, 64,165,201,109,106, 60,175,173,120,101,186,226,227, 30,216,222, 31,145,113,169,212,222, 13,238, 7, 6,204,215,213, + 43,196, 18, 19,114,181,106,109,123, 85, 19, 47,197,202,132,164,212,146,231,141,205,215,196, 74,201,235,211, 90,121,178,118,150, +251, 86,248,244,118,209,176, 55, 14,149,181, 28, 67, 63,187,123,137, 77,165, 94, 87,124,150,160,183, 79,191, 68,251,137,138,172, + 71,101, 79,167,202, 75, 85,121,111,253, 99, 25,144,182,148,167, 95,150,150,144,124, 71, 18, 12,191, 55,139,216,145, 27,114,184, +246,164,241,181, 23,126,103,210, 85, 77,220,141,186,220, 36,237,202,118,242, 36,168,229, 86, 2,232,107, 69, 32, 92,230,240,109, + 65,169, 66,136,128, 94,247, 2,166,125,229, 68, 33,194,145,159,188,127,251, 8,246,135,139,155,230, 86,246,237,181,237, 81,216, +221,230,170,248, 18,174,153,244,186, 83, 85,171, 78,238,170, 68,109,180, 49, 90,169, 81, 81, 50, 35,244,171,136,165,166,146,236, +232,146,128,119,194, 75,143, 69,117,254,103, 75,214, 91,226,215, 8, 67, 22, 85,150,205, 86, 35,138,175, 35,134,138,121,205, 36, +147, 69, 73, 85, 26,176,229,203, 3,162,251, 69, 57,230, 48, 97, 30,180,109, 10,167,202,197,149,139, 52,240,103,141,106, 37,205, +243, 72,104,140,147, 80,241, 4,245,244,244,226,182, 40, 37,173,163,149,163, 60,200,170, 35,145,189,154,161,121, 42, 80,203,203, +117,214,204, 6,181, 8,220,174,226, 71,130,207,107,101, 91,105,167,218,220, 83,113,207,179,208,246,122,238,169,208,173,233,177, +183, 54,243,164,208,173,170,181,102,101, 69,135,109,234, 98,103,201,178, 88, 45,207, 85, 69,134,150,209, 67,168, 82, 61,221, 78, +173, 73,109,181,173, 58,117,197, 87, 1,155,253,192,167,179,178,235,160,238,229,199,101,215,173,141,200,226,147,102,174,107, 61, + 22, 93, 90,117, 86, 35,117, 8, 59,103,187,240,170,243,222, 92,168, 76,160, 38, 69, 61,202, 40,109,109,115,248,137,137,146,174, + 80,141,116,161,143,163,193,196, 46,228,213,168, 20,254, 34,120,219,187,111,155, 38,221,113,180,211,233, 77,199,185,174, 25,241, + 97,167, 8,114, 37, 29,203,202,228,122, 53,190,165, 48, 57, 82,234, 35,200, 8, 29, 60, 21,142,154,234,183, 19,126,200,187, 31, +124, 56, 36,218,238, 11,108,125,198,175,109,125,165,181, 87,181, 22,242,163, 87, 39,211,158,220,106,188,245,210,168,215, 85, 46, + 68, 42,129,170,215,224,171,196,147, 34,233,147, 37,110,182,234, 91,105, 81,195, 44, 70,109,146,148, 54,214,158, 34,228,185, 53, + 87, 15, 81, 71,196,212, 85,249,107, 87, 71, 81, 94,180, 57, 43, 81, 65, 18, 68, 85,227,149, 89,109, 43, 77,170, 53, 86, 9, 12, +154,144,144, 89, 2,128,238,210,120, 95,158,231,148,156, 75,152, 73,194,149,249,118,106,153,124,148,217,123,102, 25,242,215, 84, + 77, 36,193,146, 72,157, 90,240,164, 26,100,118, 66,243, 71,165,192, 96,175,172,152,216,127,163,207,182, 54, 85, 63,129, 26, 5, +213, 18,131, 1,186,245,225,121, 94,117, 27,146,168, 35, 51,239,213,105, 84,250,195,212,170,127,190, 73, 8, 11,121,152,244,248, +205, 54,202, 20, 74, 90, 10, 95, 32, 5,107, 39,133, 62,218,203,122,129,108,123, 96,109,245,210, 41,177,105,109,213,209,195,221, +118,176, 97,180,134, 12,218,147,149, 56,208,159,168, 62, 91, 3,158, 81,133, 78,134,130,179,241, 17, 25, 57, 61, 53, 47, 47,103, +175, 7, 75,224,115,135,139,127, 97,141,234,237,254,138, 5, 74,189, 81, 77,202,253, 13,187,113,201,102,185, 84,122,164,166,141, + 41,170,164,208,194, 90, 47,114, 3,239, 11, 42, 8,230, 56,206, 53,160, 92,119,251, 21,218,227, 43,139,138, 79, 20,201,223,169, +214, 59,244,232, 27,125, 4,217,141,109,212,106,251, 11, 22, 36,247, 38,120,191, 94,185,121,196, 82, 76,164, 44, 39,151,221, 15, +128, 83,205,151,129,228, 17,110, 24,227,108,134,131,196,238, 46,226, 60,195, 51,120,242,140,217, 51, 4,134,110, 92,238, 92, 77, + 42, 52, 0,198,177,153, 20,104, 81, 96,232, 2, 5, 0,233,176, 24,151,241,111, 0,241, 22, 99,225, 63, 5,112,190, 91,148,164, +153,214, 76,249,107,207, 8,150,157, 4,109, 4, 46,181, 12, 36,105, 22, 38, 58,216,234, 40,236, 92,177, 35, 85,201,196, 94,166, +255, 0, 4,227,251,102,171,138,226,141, 80,145,106,127, 43,106,227,151,155,183,111,130, 40, 41,134,253,197, 45,203,106, 77,100, +206, 72,103,248, 45,250, 74, 26,201, 88, 17,189,203,148,159,208,106,118,219,255, 0, 77,225,202, 23, 11,155,155, 59,120,151,101, +141,146,115,108, 43,142,220,242,235, 79, 83, 77, 2, 85,186,237, 13,231, 25, 76, 37,173, 94, 28,153, 78, 35,192,250,189, 49,242, +243,146, 21, 28, 67, 5,242,214,185,225,237, 10,246, 37,236,223, 28, 51,160,110, 93, 50,230,159,180,155,231, 14,139, 6,141, 84, +188,169, 20,168,245,170, 53,231, 14,149, 20, 69,166, 34,238,183, 93,151, 24,202,168, 48,195,108,176,204,230, 36,178,250, 35, 54, +134, 94, 76,166,217,142,134,185,163, 99,253, 27,221,214,159, 80,165, 91,187,205,197,181,110,187,181,116,121, 33,246,109, 11, 90, +155, 92, 73,125,180,171, 33,152,105,184, 43,142,194,160,169, 67,169,117,184,146, 84,156, 20,165, 25, 60,195,123, 59,206,248, 23, +142, 41, 56, 79, 52,204, 56,182,110, 23,174,225,202,104,160,154,140, 82, 79, 49, 38, 34,167, 93, 35,197,104,209,156,173,149,152, +146, 20, 70, 93, 84,165,153,191, 32,200, 60, 65,240,254,183,140,178,156,183,130,224,226,234, 14, 40,171,154,162, 10,227, 91, 4, + 0, 9,129, 81, 29,108,114,131, 35,162, 6,187,162,128, 11, 25, 66, 51,137, 46,188, 20,224,130, 37,122,161,107,241,207, 22,205, + 68,229,213,151,193,189,253, 34, 59,113,121,149, 53, 84, 40, 55,206,223, 79,185,147,150,134, 72, 22,172,106,177,123, 29, 60, 36, + 57,159,135, 58,112,125,151, 27,107,197,206,231,238,109,253, 66,224,219,124,109,173,154,220,132, 90,144,164, 85,209, 87,159, 18, + 13, 86,231,182,219,170,182,183,153,164,123,205, 6,114,159,102, 44,244,195,114, 64,108, 32,164, 58,218,149,148,246,148,183, 0, + 30,195,186,103, 4, 59,219, 95,221, 41, 91,210,238,236, 81,174, 43, 18,191, 97, 78,179,235, 27,115, 6,133, 5,234,101,126, 92, + 7,229, 25,178,149,117,212, 19, 61,159,118,131,224,173,133,199, 8,117, 50, 23,206,113,240,235, 95,184,128,250, 57, 52, 5,238, + 92,237,211,224,251,126,238,109,132,155, 34,168,253, 90,157,107, 61, 18,125, 66, 21,175, 38, 90,150,227,236,218, 87, 93, 26,179, + 18,165, 71,166,165, 75, 33,152,239, 9,107,109, 10, 40, 18,121, 2, 82, 39,213,158, 45,112, 93,125,119, 19,229,145,230,113,193, + 73,155,199, 76,244,245,181, 20, 18,212,211,115,163, 69, 71,134,162,150, 72,214, 70, 81,203, 66,172, 80,165,217,219, 82,178,174, +170,226,135,193,142, 59,203,114,254, 18,205,101,202,100,158,183, 36,150,174, 58,154, 26, 92,198, 42, 74,174, 68,178, 51,199, 61, + 45, 92, 82, 52,106,228, 72,225,215,152, 30,200,138, 85,149,155, 79, 63,120,152,246,113,123, 73,247,246,235,219,109,167,226,139, +140,141,138,188,175,178,213,122,187,181,118, 29,241,126, 64,166,221,115, 99, 73, 93, 54,159,112, 78,182, 41,145,237, 56,210,106, + 13, 56,228,106,115,110, 33, 60,254, 41,132, 84,218, 23,238,207, 41,173, 31,246,169,108, 70,229,240,207, 70,224,147, 98,119,114, +163, 71,170,222,187,125,195,213,118,150,252,234, 12,137, 18,233, 70,139, 43,118,239, 89,244, 56,177,164,203, 97,167, 29, 12, 68, +146, 91, 60,200, 72, 79, 32, 74, 71, 40, 26,238, 94,204,253, 30, 26,228,253,212,164,238,167, 22,156, 77, 94,219,207, 82,164, 79, +131, 56,192,167, 63, 93,167, 79,170,174,154,224,118, 27, 85, 91,234,181, 93,149, 83, 76, 20,173, 8, 10,106, 34, 99, 59,203,144, +220,182,137,206,183, 63,218, 81,236,103,137,199,254,225,237,141,254,141,242,159,182, 63,197,206,219,177,183,108, 80,227,216, 76, + 93,200,157, 30, 61,114,165, 89,102,162,106, 82,110,248, 10,142,176,154,138,153, 45, 22,157,230, 12, 37,207, 23, 42, 41,211, 54, + 91,226,118, 67,149,113, 15, 14, 82, 84,113, 37, 61,110, 65,151, 37, 76,179, 61, 46, 80,244,112, 67, 83, 36, 82,198,139, 2, 70, + 26, 87, 71,230,182,191,169, 81,168, 7, 46,218,138,163,238,105,225, 55, 17,103, 28, 53,197, 21,180,220, 43, 85, 67,196,121,172, +148,176,195, 29,102,117, 29,117, 68,244,145,205, 12,142,213, 15, 41, 72, 99,120,249, 43,203,250,242,218, 47, 24,141,116,134,125, +234,246,125,236,206,223,237,103, 9,155, 11, 64,179,173,250,125, 38, 3, 59, 97,100,212, 92, 17,163, 54,202,230, 85,234,214,237, + 54,167, 88,172, 76, 82, 19,151,234, 82,234, 82,100, 72,125,213,100,173,199,207,100,132,164,111, 48, 24, 24, 29,135, 65,166,203, +102,236, 37,237,126,216, 88,187,122,185,202,169,155, 50,212,183,173,113, 82, 83, 9,138,169,233,160, 82, 33,210,147, 53, 81,146, +234,196,117, 58,152,129,101,176,181,132, 21,242,133, 40, 12,150, 11,143, 78, 49,236,142, 6, 56,109,189,119,206,237,247,106,133, + 98, 35, 63, 80,109,189,164,235,165,183,175,125,198,171, 71,147,252, 28,183,209,200,180,173, 16, 18,168,242, 38, 84, 93, 65,230, +143, 77,165,203,121,176,183, 80,219, 78,115,121,134,183, 63,207, 30, 26, 53,122,250,236,222,165,132, 99,114,242,188,210, 27, 18, + 91,123,146,215, 98,214,176,185,107, 0,113,212, 98,122, 30, 27,225,232,231,174,100,203,178,252,150,145, 76,135, 96,145, 71, 12, + 64, 48, 1,118,178,133,178,170,222,230,193, 65, 36, 12,113, 23,233, 10,251, 69,127,139,219, 56,240, 51,180,149,207, 14,246,220, + 58, 76, 90,158,253,213,105,238,225,251,107,110,170, 45,166, 69, 35,111,195,236,175,154, 61, 90,224, 64, 68,138,131,100,165, 72, +161,165,182, 28,109,216,245,192,166,197,250, 63, 62,207,199, 44, 27, 45,238, 46,247, 46,142,166,111, 45,207,164, 38, 30,218,192, +168, 71, 90, 31,183,118,209,231,218,148, 43,105,105,228, 15, 10,125,126, 68,104,146, 26, 88, 10, 34,147, 18, 26,217,112, 38,161, + 37,189,113, 27,217,255, 0,195, 62,227,251, 81,184,218,174,223,155,197, 50,161,115,219, 13, 92,234,221, 61,253,186, 37, 37,214, +218,174, 63, 83,168,185, 34,149, 99, 68, 49,148,129, 0, 85, 37, 71,114, 43, 76, 50,166,145, 6,141, 74,151,238,188,134, 52,102, +151,250, 18,218,182,237, 58,213,161,211,168,148,168,145,160,194,167,196,143, 18, 60, 88,140,183, 30, 52,118, 35,180,150,153,143, + 29,134, 82, 16,203, 8,109, 41, 74, 16,144, 18,148,164, 37, 32, 0, 53,117,113,253,101, 39, 0,112,165, 23,134, 89, 44,193,243, + 42,197, 90,140,226,116,234,236,225, 88, 67,126,160, 61,151,202,108, 86,153, 34, 86,213,206,123,208,254, 27, 80,214,248,145,198, + 53,254, 44,103,208, 52,121, 85, 11, 61, 54, 73, 76,251,132, 68, 44,166,123,116, 38, 59,183,152, 92, 53, 84,146,178,149,228, 32, + 25, 10, 82, 18,144,148,140, 4,128, 0,244, 3,160,215, 62, 61,164, 30,208, 29,190,246,125,108, 68,221,193,174,166, 21,195,185, +183, 74,103,208,246,111,110, 92,144, 91,126,238,186,153,142,218,156,168, 84,144,203,169,118, 61,155, 75, 18,162, 72,171, 73, 65, + 65, 8,121,152,108,172, 76,155, 21, 42,223,186,157, 78,157, 69,167, 84, 43, 21,138,132, 42, 77, 34,147, 10, 85, 74,169, 84,169, + 74, 98, 13, 58,155, 78,130,195,146,166,207,159, 54, 83,137,106, 28, 38, 99, 52,235,142,186,226,146,134,208,218,150,181, 4,130, + 71, 9,184,174,225,239,128,223,109, 5,235,103,196,178,120,186,133, 90,187,118, 26,145,116,193, 93,191,180, 87, 53,159, 80,147, + 34,153,115,212,232,158,253, 88,147, 10,183, 72,146,245, 74,148,212,218, 52, 38,155,157, 7,154, 22,102, 37, 42,117, 74,117,156, +212,252, 35, 69,149,207,156, 82,213,241, 20, 21, 13,195, 52, 45,174,178, 72, 34,146, 64,163, 75, 24,163,145,145, 78,133,154, 64, +177,177,184,109, 37,180,144, 64, 34,228,227, 92,195, 55,166,201, 42,232,248, 98,122,101,226,188,193,116, 80,199, 81, 52, 81, 22, + 98,202, 37,146, 53,145,135, 49,160,137,154, 69, 91, 50,235, 85, 12, 10,155, 24,223,112, 43, 69,217,158, 45,184,165,187,120,165, +246,138,241, 35,182,116,170,123, 23, 91,119, 61, 74,223,220,203,198,221,164,212,247, 82,240, 90,154,145, 18, 4,155,122, 83,169, + 76, 13,179,165,195,106, 27, 94,232,150, 88,134,243,109, 69,164,194,109, 80,163,204,105,153,125,220, 94,209,127,103,156, 61,184, +186,232, 52, 94, 47, 56,125,117,247,237, 26,244, 24,113, 99,110, 45,186, 93,145, 37,234, 60,166, 35,176,203,104,151,241, 45, 78, + 41, 9, 74, 64,234, 84, 0,215, 43,127,189,146,225,251,255, 0,151,141,236,252,108, 47,255, 0,212,117, 98,186, 62,141, 70,193, + 80,109,171,134,184,206,250,111, 75,206,209,168,117,106,171, 77, 58,108, 79, 9,215, 41,240, 31,150,134,220,228,180,193,240,212, +166, 64, 56, 32,224,156, 28,234,227,226,156,231,194,238, 48,205, 41, 42,234,248,179, 49,165,167,161, 88,226,165,164,134,136, 37, + 61, 52,107,164,104,141, 76,102,218,138,130,204,119, 54, 10, 44,136,138, 40,222, 15,200,252, 93,224,124,162,178,142,139,131, 50, +202,202,154,247,146,106,202,201,235,245,213, 85, 72,218,137,121, 92, 72, 47,160, 51, 4, 81,176,187, 49,187,187,179,241,151,216, +125,188,123, 87,177,188,108,155,223,120,111,251, 87,109,173, 15,226,150,243,164,127, 8,239, 10,196, 74, 37, 35,235, 57,181,155, + 69,248,144, 61,246,107,137, 71,189, 56,212, 57, 74, 66, 51,149, 6, 20, 64,192, 58,156, 37,241,179, 92, 40,241,203,106,237, 46, +225,220,246,214,221,239,165,175,107, 85,218,191,118,150,241,196,122,245, 54, 52,165,184,202, 93,157, 69,169, 68,120, 38,161, 71, +146,245, 54, 31,189, 67,112,189, 2,106,233, 81,140,168,239, 42, 43, 5,184, 0,123, 51,184, 59,180,120,227,226, 73,123, 35,122, + 92,215, 45,167, 72,254, 47,238, 75,185, 21, 91, 80,210,133, 79,223,104,181, 43,126, 19, 17,149,245,197, 62, 75, 62,234,182,234, +239, 21,254,143,159,153,164,114,168, 12,131,250, 11,240,185,177,214,207, 9,155, 29,181,187, 7, 78,186,100,213, 41,118,141, 53, + 54,133,175, 62,230,151, 77, 98,183, 95,122, 59, 21, 90,234,227,165,168,172,176,212,202,144,167,198,170, 72, 83,113,218, 4, 70, +167, 60,241, 64,109,167, 22, 49,227,201,203,105, 56,158,154,191, 47,204,234, 97,226,113, 20, 74,241,160, 40,145,211,114,230, 28, +196,153, 44,218,218,229, 29,117,125,130,110, 45,140,253, 29, 23, 52,173,225, 42,188,187, 50,202,105,103,225, 38,158,102, 73,100, + 43, 36,146, 85,137, 41,207, 41,224,123,174,133, 0, 58, 57, 91,243, 2,216,220, 12, 63,180,219,118,145, 74,138,212, 72,144,152, + 67, 77, 33, 40, 72, 13,164, 97, 41, 24, 0, 0, 58, 12, 1,168,214,125, 36,238, 26, 44,170,175, 15, 59,113,196,205, 42,137, 14, + 22,224,216, 59,137, 73,176,171, 53,136,200, 98, 51,213, 75, 2,242,167, 86,221, 76, 42,145, 5, 42,168, 46, 29,213, 78,163, 42, + 16, 60,230, 50, 42,243,249, 18, 18,251,170, 18,111, 4, 30,160,228,122,141, 71, 19,233, 42,111, 69,183,107,112,145,182,219, 37, +239,241,156,189,119, 91,118,169,119, 3, 20,143, 17,179, 37,155, 43,111,169, 53,105, 85,170,210,208, 57,148,210, 5,199, 87,180, +163, 53,144,128,239,189,200, 40, 89,247,119, 16,170,219,194,167,174, 95, 16,120, 99,216, 11, 9, 94,160, 7,211,125,224, 42,220, +240,214,234,188,157,100,223,109,175,219, 22,175,140, 41,151,191,134,156, 91,250, 68, 41,133, 41,137,143, 85,182,168, 14,158,207, +166,253, 27,157,160, 45,183,222,221,240,212,253, 25, 45,199,171,212,118,115,136, 29,176,151, 33,247,169, 54,142,229, 80,110,122, + 75,110,168, 41,184,138,190, 45,181, 67,159, 26, 49, 42, 42, 67, 62, 61,152,135,139,120, 8, 14, 76, 91,137,202,221,112,234, 82, + 58,139,207,209,155,219, 90,149, 31, 99,247,187,115,230, 71,118, 60, 91,231,115,160,208,105,106,117,183, 80, 38,192,177,109,214, + 20,185,241,212,165,114,187, 24,213,110,170,156,110,100,164, 31, 22,152,242, 20,163,202, 2,101, 13,163,120,178,105,219,196, 78, + 41, 52,214,229,243,208, 27,116,230, 8, 34, 19,125,252,208,250,189,247,193, 60, 25, 90,149,240,199,132, 5, 93,249,190,206,228, + 95,175, 40,212, 76, 97,251,185, 38, 61, 63,225,181,182,194,210,210,210,213,119,139, 59, 11, 75, 75, 75, 67, 3, 11, 86,231,168, +244,137, 50,219,159, 34,151, 78,126,123, 74,105,109, 77,122, 12,103,101,180,182, 20, 20,202,155,146,182,138,208,164, 40, 2,146, + 20, 10, 72,200,193,213,199, 75, 89, 4,141,193,177,247, 96, 98,222,186, 77, 45,198,165,199,114,155, 79,113,137,239,123,196,230, + 87, 14, 50,154,153, 32, 41, 11, 15,203,109, 77,226, 67,220,237,182,121,150, 10,178,128,115,144, 52,195, 92,219,245,176,182,149, +122,185,103,220,245, 58,117, 38,177, 14,165, 62,137, 88,166,205,183,100,165, 18, 94,180,182,226, 54,233, 43,153,126,224, 91,159, + 5,155, 45,232,238,197, 88, 82,208,167,241, 10, 62,100,128,214,182, 39, 90,175,186,220, 34,237,174,239, 92, 87,189,203,114,202, +174,179, 62,249,180,173,155, 70,114, 96, 73, 97,182,233,177,104, 55, 4, 90,205, 74,117, 39,196, 97, 70, 44,234,189, 58,155, 70, +165,212,213,146,151,233,244,134, 89,229, 24, 36,239,229,230,133,166, 97,152,203, 44,112, 21,216,197, 98,193,245, 40, 4,130, 13, +194,173,216,141,137,210, 0, 32,219, 9, 75,204, 10, 12, 42,165,129,253,111, 75, 29,135,199, 97,247,227,225,226,159,135, 84, 56, +170,163,213, 95,119,172, 38, 13,219, 88,247,105, 22,125, 85,171,145, 66,203,155, 66,162,214, 18,136,138,166,123,195,149, 5, 46, +227,166, 8,173,167, 43,148,194,220,113,158,102,153,112,164,250, 39, 17,220, 62, 92, 21, 58, 93, 58,145, 81,141, 34,185, 94,151, + 97,212,226,211,133,167, 80,106,170,170,149,249,112,215, 45,203,118, 92,198, 28,166,133,197,168, 51, 86,164, 85,125,241,199,121, + 87, 1,181,165,233, 10,109, 15,161, 74,182,220, 60, 32,109,125,201,123,215, 47,185,174, 86, 27,170, 87, 55, 43,109, 55, 45,216, +204, 61, 29, 48, 33,205,219,106, 84,138, 75, 84, 24, 49,212,193, 12, 91,213, 70,167, 84,156,170,176, 58,201,118,122,151,204, 20, +134,139,116,232, 92, 31,109,165,187,120,209,239,138, 92,218,235, 53,202, 30,226,110,142,227, 66,113, 79, 68,117,145, 63,115,169, +177,233,206, 81,214,211,177,136, 85, 10,144,168, 20,183,233, 12,118,138,245, 57, 11,202,185,222, 14, 56,145,195,220,178, 86,106, +161, 46,139,128, 74,144, 27, 78,161, 30,201,246, 67,125, 94,175,251,237,109,176,143,246,189, 67,202,133,111,239,189,175,107,245, +235,111, 53,190,235,247,192,151, 23, 20,214,213,149,120,238,245,161,112, 90,149, 90,123,118, 93,223,110,218,116,155,146, 37, 34, +165, 34,213,175, 92, 87,142,216, 91,119,181, 10, 5,199, 93,102, 0, 98,139, 83,155, 86,172,154, 91, 40,230,144, 74,145, 17, 79, +169,147, 50, 58, 23,100,166,241,143,176,110, 91,118,252,155,150, 60,202,122, 85,111, 48,244,196,211,236,186,197,114,218,166, 92, +206, 88,209,239, 59,138,199,163,207,137, 73, 87,214, 85,120,214,244,153,202, 90, 88,103,194,117, 48,100, 69, 14, 42, 91,110,197, + 77,226,167,194, 53, 62,224,168,214,164, 92,187,177,184,117,202, 93,207, 86,176,238,171,166,132,252, 75, 34, 52, 75,138,247,219, +171, 22,218,178,232, 23,101, 70,124, 75, 81, 19, 90,146,100, 90,180,154,171,241, 99, 73, 98, 19,149, 8,201,195, 8,139,207, 29, +204, 89,174, 3, 54,230, 28, 89, 84,218, 93,213,112, 83,169, 85, 8, 13,183, 62, 50,109,173,179,153, 84,126,170,109,166, 45,137, +213, 38,111, 9,246, 59,149,202,124, 73, 44,199, 68,199, 96,199,169,183, 24, 77, 91,133, 9, 76, 55, 93,134,181,227, 28, 52, 99, + 65, 52,210, 44,161, 35,212, 99, 50, 88,176,141, 85,236, 90, 50, 67, 23,214,214,210, 86,214,179,139,144, 10, 77,101,201, 85, 4, + 92,245,183, 75,220,116, 61,133,133,239,123,246, 56,201,110, 78, 45, 54,210,143, 71,187, 69, 26,206,190,106, 23,221,159, 10,239, +174, 77,176,164,109,229,114,157, 93,162,200,181,109, 26, 5,194,253,122,230, 66,160, 17,111,208,220,164,222, 86,170, 68,245, 41, + 75, 91, 85,192,134, 91,117,109,188,218, 1,107,139,222, 30, 41,208,160, 38,182,212,154, 96, 81, 98, 34,164, 83,236,138,173, 86, +132,229,233, 73,143, 2, 77, 86,210,160,202,167, 82,150,229,102,224,167, 57, 85,155,240,177, 28,130,105,117, 4, 48,181,191, 26, + 67, 73,200,239, 78, 20,232,247, 93,227,184,151,181, 59,113,239,187, 58,175,186, 16,107, 20, 59,177, 20, 6,109, 25, 81, 38, 91, + 85,235, 26,194,177,234,148, 36, 49,113, 91, 83, 67, 13,174, 54,221, 80,228,162, 75,124,147, 24,118, 76,180,176,251,104,120,114, + 97, 71,129, 29,185,102, 75,134,157,116, 87,233,212,215,107,237,221,142,192,102,217,219, 23,234, 46,220,107,153, 26,125, 70, 66, +175, 41, 86, 50,235,200,165, 73,156,220,169, 11,130,138,162, 26, 67,243,150, 16, 68, 68,166, 32,196, 67,134,204, 81,243,102,154, + 55, 96, 25,172, 90,225,180,141, 75,126, 89, 22, 86,190,141,141,197,203, 50,155, 12, 6,246,205, 70,202,164, 3,177,176,251,143, +218,190,227,175,167, 96,112,231, 92,188, 65,108,253,156,237, 21, 85,234, 37,205, 77,117, 54,204, 75,162,127,188,109,197,114, 52, +173,190,178,220,185,255, 0,131,148,235,130,242,141, 38,152,219,246,149, 21,117,198, 37, 41,160,227, 97,192,213, 50, 76,191, 5, + 44,199,113,212,227,232,226,211,100, 21, 21,169,244,186, 61,249, 82, 97,202,109,126,252,241,169,187, 81,118,165, 40,183,173,245, + 24,119, 77,250, 28,149, 70,101, 47, 81,162,201,144, 35, 61, 61,165, 56, 94,122, 73,102, 57,144,174,112,155,149,235,194,253, 54, +254,147, 62, 77,127,114,247, 1, 75,185,109,201,150, 53,252,136,169,180, 27, 69,243,183,234,190,107,183,181, 30,208,169,151,173, +119, 21, 76,139, 79, 23, 21, 86,150,196,154,122,162,203,114,155, 49,212, 72,121,217, 74, 76,164, 52,251,165,194,237,235, 26,209, +179,173,109,147,172, 76,141, 81,133,182, 87,238,208, 87, 46,106,213,219, 71,163, 71,122,208,188,167,211, 39,166, 53,106,131, 47, +109,107,104,172, 50,153,222,250,242,158,167, 46,147, 80, 97,184,166, 59, 47,172,204, 15, 66, 37, 60, 57, 12,220,152,228,168,144, + 77, 35, 16,197,159, 68,106,161, 88,234,102,104,191,104, 88, 1,114, 84,173,192,114,193,114,237, 84,161,152, 32, 33, 64,176, 2, +228,155,141,128, 13,233,248,131,216, 12,110,107,245,216,236,216,210,174,155,102, 19, 51, 24,254, 12, 74,185,104,144, 74,126,174, +102,127,139, 76,118,175, 5,151, 65,108,123,159,142,181,183,206, 74,121,146, 94, 82,148, 50, 14,180,215,116,165,219,144, 32,213, +182,215,234, 10, 53,122,167, 42,135, 42,149,118,221,213, 70,214,169, 21,107,134,188,202,229, 86,106, 18, 4, 96,219,174,148,212, + 36,135,144,147, 32, 54,202,144, 24,109,164, 55, 29,160,157,199,135,107, 57, 22,193,139,100,166,162,160,236,107, 61,139, 88, 85, +154, 99,195, 80,113,154, 42,105, 34,162,212,101, 58,174, 69,115, 39,197, 74, 10,206, 14, 19,204,123,235,144, 59,209, 19,116,167, + 75,115,110,234, 52,115,107,213, 46,219,210,159, 99,220,151,204, 58,236, 73,212,214, 41,117,135,213, 18,124,250, 47,142,152,243, + 99,207,171, 72, 8,129, 8,201,140,219, 77, 59, 90,111,154, 74,212,166,148,189, 76,174, 26,121,106,106, 29,239, 34, 68, 9, 80, +110, 46, 9,181,201,219,183, 91,237,190,248, 60,236,234,136, 7,148,183, 95,203, 29, 10,217,141,236,135,113,237,133,155, 34,137, +104, 94, 55, 7,131, 64,143, 79,110,109, 18,136,236,138, 4,185, 20, 96,229, 38, 91, 17,174, 7,228, 6, 36,186,204,216, 18, 99, +188,239, 63, 35,146, 34,186,166, 84,235, 74,109,197,229,117,203,231,113,228, 81, 38, 76, 27,115, 80,181,169, 66, 35,130,109, 86, +161, 91,167,203,170,192,109,238,102,132,198,233, 52, 53, 63, 33,184, 44,146,133,204,125, 1, 82, 99, 70,241, 95,139, 22, 83,173, + 37,181,115,182,167,188,183, 37,129, 6,159,182,219, 79, 95,118,221,177,236,232, 45,208,224,166,152,212, 39, 19, 54, 68, 95,130, + 92,184,146,164, 69, 83,145,233,254, 40, 83,113,195,107, 72,113,182, 68,151, 7,140,251,152,109,170, 91,157,184,213,165,133, 85, + 47,171,178,127, 33,230, 75,114,171,213, 23, 35,250,156,199, 84,159, 15,147, 25,200, 41,229,229,200, 61, 52,228,156, 45, 83, 33, + 46,213, 9, 12,109,184,184, 98,214, 61, 46, 54,177,183, 93,246,239,141,118,204, 17,118,208, 89,135, 93,192, 23,247,125,248,187, +241, 61,191, 16,171, 20,120, 91, 43,100, 59, 38, 45, 50,223,155,227,110,163,143,165,182,103,212,183, 14, 41,104,204,160,206,247, + 98, 91,122,157, 79, 90, 99, 41,149, 50,183, 97,190,216,132,184, 46, 57, 2, 52, 39,156,210, 5, 41, 40, 66,220, 89, 66, 27,109, + 42, 90,220, 95,192,219,105, 72,202,150,226,212,112,218, 7, 82, 73, 32, 0, 59,247,214,204, 79,218,105, 60, 77, 67,171,238, 54, +206,186,245, 31,112, 40,173, 83,169, 53,218, 12, 24,116,183,153,221, 11,113,130,220, 51,122, 91, 76, 85, 22,150, 26, 76, 26,164, +146,195, 50, 28, 10, 83,241,203,235,111,199,134,228, 45,102,150, 23,179, 43,113,174,103,163, 78,220,186,172, 10, 83, 3,192,117, +104,185,234,127,195, 25,237, 41, 32,164,174, 53,175, 72, 83, 84,104,143,114, 21,146,164,150,212, 20,190,185,198, 4,179, 46,173, +203, 50,156,190, 58,121,100, 74, 87,131,103, 86, 97,169,159, 98, 92, 0, 11,184,125,138,176, 91,105, 32,109,107, 6,154,136,106, +106,106, 25,213, 76,161,250, 16, 54, 3,176, 36,216, 2, 58, 17,126,183, 62,252, 48, 60, 43,109,125, 79,127,119,214,218,118,158, +185, 44,218, 22,100,195, 85, 21,152, 78,173,176, 24,129, 33,164,215, 46, 72, 51, 89, 87,232,220,113,192,221, 34,148,242, 50,174, +121,115,101, 55,205, 29,104,115, 82, 78,211, 25,177, 59, 3,102,236, 21,187, 50,139,108,185, 46,165, 62,173, 33,153, 53,170,245, + 73, 17,145, 54,114,162,180, 89,135, 17,150,162,180,148, 67,165,176,133, 61,224,176, 57,202, 21, 37,197, 41,197,149,100, 62,122, +131,113, 6,106,185,165, 96,104,175,236,208, 11, 33, 34,197,137,182,166, 35,168,189,128, 0,244, 85, 23,220,156, 61, 80,210,154, +104,136,127,239, 28,220,251,189, 7,243, 39,212,156, 45, 45, 45, 45, 48,227,119, 11, 95, 8, 4, 16, 70, 65,232, 65,215,221, 45, + 12, 12, 83, 67, 45, 53,146,219,104, 65, 61,202, 82, 1, 63,128,213, 77, 45, 45, 12, 12, 51,123,215,177,246, 78,250, 90,142,219, + 55,132, 15, 17, 77,169, 82, 41, 53, 88,229, 45, 85, 40,211,185, 57, 19, 46,159, 36,164,248,107,198, 2,208,160,166,221, 72,229, +113, 10, 24,199, 21, 55, 95,128,189,229,176,101,201,126,218,136,213,251, 65, 75,139, 49,164, 82,249, 99, 86, 27,103, 36,161, 50, +233, 82, 22, 57,221, 9,192,203, 14, 59,205,140,242,163, 60,162, 65,250,242,180, 33,192, 82,180,165, 96,247, 10, 0,143,219,170, +147,196,127, 5, 56, 23,196,226,149, 89,229, 28,148,121,204, 74, 17, 43,169, 25, 98,168,208, 62,202, 73,169, 94, 41,209,127, 84, + 75, 27, 50, 11,136,217, 1, 55,183,188, 54,241,191,143, 60, 47, 87,165,200,171, 99,172,201,165,114,239, 65, 86,173, 45, 54,179, +246,158, 61, 46,146,192,237,250,198, 41, 21, 92,216,200,174, 64,180, 88,213,177,251,198,219,222, 2,182,186,252, 11, 10,228,255, + 0,246, 90,178, 91,207,151,233,189,211,147, 31, 62,108,117,239,167,207,108,248, 36,222, 91,238,100,115, 87,165,127, 3,105, 10, +113, 62, 60,170,176,241,106, 37,172,142,111,119,166, 48,172,135, 49,156,120,203,100, 12,103,174, 48,100, 58,105,148,245, 30, 99, + 13,130,123,231,195, 26, 33,168,236, 50, 48,211, 77,182, 63,217, 72, 31,208, 53, 83,100,223, 67,239, 15,232,107, 82,167, 52,206, +115, 28,238,154, 50, 15,179,179, 69, 4,111, 99,246,100,120, 99, 18,149, 61,249,111, 17,244, 97,139,115, 58,250, 99,248,133, 95, + 67, 37, 46, 85,146,229,217, 29, 76,128,143,104, 85,150,162, 68,184,251, 81,164,210, 24,131, 14,220,200,229, 95,240,156,107,150, +193,112,227,103,236,125, 9,184, 52,136,161,218,131,220,143, 84,106,146,130, 29,168, 84,101, 37, 56, 15, 74,120, 32, 14, 80, 10, +130, 27, 64, 13,182, 9, 8, 72,201, 39,100,244,180,181,212,185, 94, 87,151,100,153,125, 38, 85,148,209, 71,151,101,180, 40, 35, +134, 24,148, 36,113,160,232, 21, 70,221,110, 73,234,204, 75, 49, 36,147,142, 85,205,115, 92,203, 59,204,106,243,108,222,182, 76, +199, 50,175,115, 36,211,204,197,228,145,207, 82,204,119,233, 96, 7, 69, 80, 21, 64, 0, 0,180,180,180,181,191,134,252, 45, 45, + 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12,104, 15, 16,151, 95, 24, 54,239, 17,123, + 83,103,109, 12, 84,212, 54, 75,118, 69,182, 47, 27,216,219,148, 90,131,187, 24,189,180,184,101, 92,219,132, 23, 42, 76, 82, 37, +139,234,202,151, 77,160,210,125,241,138,135,213,181, 58,116,137,140,248, 9, 90, 64,231,117, 43,136,239,106,117,199, 89,185,105, +117, 10, 52,219, 42, 68,189,220,218,235, 50,177, 79,135,177,151,213,106,118,216, 64,186,248,146,182,109, 10,197, 94,196,168,220, + 27, 33, 79,182,247, 3,109, 33,236,132,171,166,163, 88,171, 53,117,221,106,132,229, 62, 29, 72,212, 41,241, 36, 73,106, 28,131, + 84,132, 47, 28,201, 10,199,108,140,227, 84, 76, 88,197, 69, 69,150,202,143,115,203,215,203,250,134,165, 20, 60, 69, 77, 73, 4, +113, 75,195,212, 85,111, 18,196, 57,143, 18,150,102,142, 70, 98,238, 24, 50,182,184,244, 70,234, 2,130, 99, 89, 13,218, 73,249, +209, 44,195,134, 42,235,106, 36,154, 46, 37,175,163,142, 87,148,152,210,102, 8,171, 36,106,161, 35, 42,200,203,203,148, 73, 42, + 49, 44, 87,154,209,139, 36,116,252,158, 18,111, 54,228,113,174,250,120,178,217,207,122,222, 77,206,102,216,218,235, 50,169,182, +183,141, 11, 96,170,118,165,187, 86,174, 81, 46, 93,174,102,187,109,151, 87,181,116,241,125,223,117,200,235,187,229, 59, 34,206, +174, 87,232,109, 83,149, 52, 24,150,188,232,144,226,189,121,221,222, 37,189,160,182,229,237,191,208,108, 59, 58,250,169,203,183, +173,190, 38,157,179,108,216,155, 3, 85,170, 88,180,107, 78,206,216,154,213,197,195,166,226,216,251,164,154, 35,177,247, 99,117, + 46, 45,225,139,109,211,166, 90,113,234, 19,223, 67, 85,233,113, 87,111, 66, 52,228,205,149,220, 51, 22, 58,149,204, 89, 65, 80, + 24, 4,167,168, 30,131,211, 95, 12, 72,196,133, 22, 91, 42, 29, 1,229, 25, 3,211, 75,197,197, 20,136,176,163,240,229, 36,235, + 18,176, 33,145, 44,210, 60, 84,241,180,133, 86, 48,170, 73,131,152, 2, 42,144,206,124,197, 76,130, 93,105,120, 70,177,218,103, +143,138, 43, 96,121, 93, 72, 43, 36,132,172,105, 45, 76,169, 24,102,149,157,128, 21, 28,178,100,103, 82,136, 60,129,132, 70, 29, + 28,224,214,249,226, 54,181, 83,222,219, 55,136, 39, 43, 85,241,100, 94,246,107, 27,119,127, 86,246,245,141,190,145,120, 91, 23, +102,204,109,181,247, 91,109,168,212,184, 17,169,213,150, 40,215,245,201,118,208,253,234, 19, 64,161,116, 5, 67,154,165,207,141, + 37, 70, 41, 62,217,106,175, 29, 60,104,113, 79, 93,164, 80,248, 84,226,128,108,102,199,212,235,214, 38,211,193,135,178, 27,169, + 46,147,113, 46, 44,255, 0,115,185,183, 61, 15,199,182, 20,196,245, 87, 38,211,216, 92, 23,154, 60,130,143, 6,156,148,254,148, +200,113,217,206, 33,150,155, 57, 67,105, 73,237,144, 49,211,211, 67,187, 77,128,242,138,221,136,195,139, 61,212,180, 5, 19,247, +157,111,240,175, 28,175, 11,103,243,113, 12, 25, 5, 53, 85, 91, 66,177, 70,164,152,227,133,180, 34, 75, 44,105, 26,133, 87,155, + 75, 19,164, 5, 65, 35,170, 0,166,216,110,227, 15, 15,159,139,248,110, 14, 25,168,226, 74,186, 58, 36,153,165,149,192, 89,101, +157, 4,143, 36, 48,202,242,146,204,144,234, 80, 53, 18,206, 99,141,156,150, 92,126,116,252, 63,207,246,190,240,179,111, 84, 45, +109,128,218, 78, 44,118,210,133, 86,172, 61, 95,169,195,163,240,195,113, 77,114,125, 93,248,145, 32,174,108,185,213,189,175,149, + 33,245,136,112, 98,182,132,169,210,134,210,214, 16,148,229, 89,216, 95,229,123,244,129, 63,242,126, 52, 63,251,173,204,255, 0, +254, 61,169,231,253, 81, 76,255, 0,200, 99,127,246, 73,254,173, 47,170, 41,159,249, 12,111,254,201, 63,213,169,173, 79,140,244, +149,147,203, 85, 89,225,206, 77, 85, 85, 49,212,242, 73, 10,188,142,118,221,157,162, 44,199,110,164,147,211,211, 16, 58, 95, 2, +107,104,105,226,164,162,241, 71, 60,163,164,128,105, 72,162,157,227,141, 23,246, 81, 18, 80,170, 58,236, 0, 27,226, 37,155,115, +253,212,126, 49,125,153,188,113,237,174,247,198,222,153, 59,193, 46,175, 96, 72,219,250, 22,228,109,202,182,202,225,187,172,138, + 21, 82,137,114,222,246,157,180,203,246,205, 29, 85, 20,205,129, 74,154,216, 8, 67,198, 83,220,180,197, 40, 34, 90,211,174,108, +123, 29, 56, 93,226,149, 28,122,109, 85,237, 78,219,189,198,219,219,123,106,234,245,201,187,145,114,220,214,181,114,217,129, 10, +149, 34,223,173, 81,102, 90, 18, 69,110, 36,113, 58,173, 81,126, 98, 97,251,154, 2,223,101, 46, 57, 49, 77,165, 17, 22,226, 63, + 64, 22, 96,195,143,159, 6, 51, 45,115, 12, 43,145, 0,100,124,245, 69,170, 85, 61,151,140,134,162, 50,135,137, 36,184,148, 36, + 40,147,243,198,154,161,241,114,174,151, 42,226,204,162,135,135, 40,168,169, 56,157,157,130, 68,186, 35,166,230,211, 71, 75, 40, + 72,213, 66, 72,165, 35, 14,129,130,132,145,152,182,181, 58,112,239, 63,130,212, 85,153,191, 6,103, 85,252, 79, 95, 95, 91,194, + 43, 26,151,149,181,201, 87,201,170,146,174, 18,242,179, 23,141,131,202, 81,202,150, 47, 18,162,175, 45,134,178, 91, 28,254, 11, + 94, 39,235,248,104,231,255, 0,249,185, 70,127,110,177,109,192,143, 34, 93,135,122,196,136,195,210,165, 74,180,238, 40,241,163, + 71,105,111, 72,145, 33,234, 68,198,217, 97,134, 91, 73, 83,175, 45,197, 37, 41, 74, 65, 82,148,160, 0, 36,235, 46,210, 35, 32, +131,216,244, 58,169, 35,115, 27,163,129,114,132, 31,220,111,139,166, 68, 18, 35,161, 54, 14, 8,253,226,216,132, 15,176,167,134, +142, 35,182,159,142,131,114,110,159, 15,251,217,182,150,232,218, 43,214,152,107,251,129,181, 87,213,153, 69,250,202, 85,110,207, +118, 45, 59,235, 91,142,131, 25,143,127,113,168,178, 84,219, 62, 39,136,180,199,112,165, 36, 33, 68,117, 47,219,205,195, 55, 28, +251,238, 54, 30,243,225,142, 29, 70,225,177,182, 89, 85,139,166,109,187, 96,220, 82, 40,155,167, 77,220,121,146, 24,110, 13,239, + 72,138,151, 99, 46,172,220, 26, 44, 70, 24,129,245,108,167, 42,145,159,169,206, 83,113, 11, 78,151, 83, 34,132,192,132,135, 60, +100,198,101, 46,147,146,224, 64, 11,207,219,162, 84,132,172, 20,173, 41, 82, 79,112,160, 8, 63,113,213,149,152,120,159,153, 87, +113,173, 39, 27,140,170,149, 43,105, 34, 16,136, 36, 15, 44, 37,116, 73, 27, 19,114,172, 24,164,140, 1, 7,202,108,119,232,106, +156,179,194, 76,171, 47,224, 42,222, 1,108,226,174, 74, 26,217,140,230,162, 50,144,206,175,174, 41, 20, 11, 43,161, 85,120,148, +144, 65,212, 46, 54,216,136, 25,208, 61,170, 30,218,237,168,164, 39,110,107,112,119, 42,161, 86,167,180,154,124, 73,123,145,195, +123,147,175,152, 73, 79, 52,102, 82,236,185, 86,131, 14,213,229, 7, 80,172, 61, 80,106, 99,238,173, 39,196,113,206,163, 77,149, +151,192,119,180,211,218, 97,189, 44,110, 46,255, 0, 64,220,170, 74,107, 38, 36, 90,246,237,239,133, 26, 85,175, 26,139,111, 48, +234,221,106,157,101, 88, 47,198,128,235,144, 71,143, 49,200,112, 41, 20,248,116,144,252,135, 28,117,248,190, 58,222, 95,232, 6, +237, 2,142,250,185,220,129, 29, 74,245,240,211,253, 90, 50, 61, 62, 20, 79,251,222, 43, 45, 99,205, 8, 0,254, 56,212,132,120, +202,153,122,212, 79,195, 92, 13,149,240,246,109, 84,165, 90,170, 40,213,156,106,234, 81, 86, 56,128,223,205,165,153,208,176, 5, +209,237, 99, 26, 62, 5,190,100,244,176,113, 87,136, 57,191, 19,100,212,110,174,148,114,202,202,135, 79, 64,238,210,202, 78,215, + 82,200,169, 32, 82, 66, 58, 94,248,215,190, 20,248,114,178,184, 89,217, 43, 15,102, 44, 56, 70, 37,191,100,208,163,210,163, 45, +222, 85, 76,168, 74, 82,220,153, 87,173, 84,156, 72, 1,218,172,250,188,153,211, 37, 41, 41, 74, 21, 34,123,133,180, 33, 28,168, + 78,200,105,105,106,151,168,168,158,174,121,234,170,101,105,234, 42, 93,164,145,216,221,157,220,150,102, 98,119, 44,204, 73, 39, +185, 56,189,233,169,169,232,233,169,232,233, 97, 90,122, 90, 84, 88,227,141, 5,149, 35, 69, 10,136,160,108, 21, 84, 0, 7, 96, + 48,180,180,180,180,142, 23,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194, +210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,214, 53,117,217,246,213,239, 67,171,219,183, 69, 34, 21, + 94,149, 91,165, 79,163, 84, 24,146,195,107,113,112, 42,113, 93,135, 45,182, 95, 41,231,142,178,203,206,114,173, 5, 42, 66,136, + 82, 72, 80, 7, 89, 46,150,178, 24,169, 5, 77,136,238, 48, 8, 7, 98, 46, 49,196,171,235,133,221,241,219,202,252,170, 5, 5, +186,133,255, 0,110, 54,227,142, 91,183, 24,180, 43, 87, 5, 89,218, 66,156, 34, 28, 91,130,109, 22,174,210, 93,171,176,128, 27, +113,199, 24,105,215,249, 3,170, 47, 40,169,247, 49, 56,124, 52,111,189,235, 81,137, 67,173, 91, 85,184,244, 57,175, 52,212,250, +127,240, 58,177,105,211,231, 52,181, 0, 89,174,220, 21,122,163,202, 77, 11,186,164,199, 97, 13, 46, 66, 17,224,173,197,178,183, + 24,123,188, 58, 90,146,167, 20, 85,172, 74,141, 2, 59,168,182,162, 91,115,107, 92,168, 54,223,184,232,119,216, 13,176,222,114, +248,203, 92, 57, 11,126,155,126, 7,249,225,157,217,141,156,160,236,245,178,138, 85, 60, 53, 50,183, 53, 12, 57, 94,173,134, 82, +202,230,190,210, 57, 90,139, 21,176, 63,193,105, 44, 36,169, 17,217, 29, 0, 37,106,202,214,163,167,139, 75, 75, 81,233,166,150, +162, 87,154,103, 50, 73, 33,185, 39,231, 96, 58, 0, 54, 3, 97,182, 55,149, 85, 20, 42,139, 42,244,194,210,210,210,210, 88, 54, + 22,150,150,150,134, 6, 32,111,253,251,111,253, 25,127,246,206,255, 0,117, 13, 84, 31, 77,167, 61,189,153,157,251,127,142,111, +251,168,234, 6,201, 25, 61, 71, 79,216,116, 66, 7, 92,227,160,237,253, 29,191, 61,180,202,213,149, 2,195, 94,231,220,191,150, + 52,249,178,126,215,224, 63, 44, 79, 25, 63, 77,151, 39,255, 0, 6,119,218,127,150,103,111,251, 41,107,223,247,236, 95,244,103, +255, 0,219, 47,253,212,245, 4, 4, 2, 7, 95, 63, 47,223,170,169, 25, 61,186,122,250, 31, 81,243,210,126,219, 83,255, 0, 19, +240, 95,203, 24,230,201,127,181,183,192, 98,119,163,233,176,103, 24,246,104, 30,163,167,248,229,121,231, 24,255, 0, 53, 62,250, +168, 62,154,225, 35,175,179, 71, 31, 47,229,149,254,234,154,130, 42, 65,207, 67,215,212,255, 0, 96,209, 9,238, 1, 57,207, 66, +113,249,198,136,213,245, 67, 97, 37,143,253, 43,249, 99, 60,217, 45,187,126, 3,242,196,238, 7,211, 87,201,199,247, 52,251,255, + 0,207, 39,240,255, 0,146,174,190,171,233,171,114,130,127,185,167,159,151,242,200,255, 0,117, 93, 65, 69, 9,235,159,151, 79, +207,231,190,171, 4,115, 15,151,207,215,229,233,211, 26, 76,230, 21,118, 63, 93,254, 85,254,156, 37,237, 18,245,215,248, 15,203, + 19,165, 79,211, 89, 73, 4,159,102,170, 83,233,158, 50,135,207,254,106,191, 45, 18,215,211, 80,241, 19,205,253,205, 94, 80,123, +127,142, 62,115,255, 0,101,109, 65, 56, 67,100,168, 18,128,163,223,185,239,242, 25,237,223, 87, 54,211,203,202, 0, 0,118, 29, + 49,229,158,131,238,210,103, 49,173, 22,250,254,191,225, 79,233,198, 13, 68,189,155,240, 31,150, 39, 74,159,166,146, 79,127,102, +191, 47,111,249, 99,122,255, 0,213, 99, 85, 71,211, 69,207,250, 54, 71, 94,199,249, 98,244,199,175,249,172,106, 11,137, 0,145, +159, 63, 79,199,240,209, 41, 7,203, 0,118, 57,237,143, 77, 96,230, 85,191,241,191,202,159,211,140,123, 76,223,183,248, 15,203, + 19,158,254,253, 11,254,141,175,251, 98,127,186,206,189,143,166,127,144, 15,247, 54,241,159,249,225,255, 0,186,214,160,208,144, + 8,234,123,244,199,237,253,218, 36, 39, 29,124,250,119, 29,189,116,145,205, 43,199,251,255, 0,242, 39,187,252, 56,199,180,205, +109,218,196,123,135,229,137,201,143,166,116, 79,250, 55, 15,111,252,240,187,127,217,107, 94,199,211, 56, 39,191,179,119, 29, 51, +254,120, 95,111,127,241, 91,233,219, 80,111, 66,135,111, 60,254, 7, 24,209, 8,238,125, 72,239,223, 31,119,231,182,138,115, 90, +253,254,190,214,255, 0, 10,127, 78, 11,237, 51,116, 50, 88,250,233, 31,150, 39, 26, 62,153,166,112, 71,179,131, 57,237,142, 48, + 63,221,115, 94,135,211, 49, 57, 0,251, 55,241,156,227,252,112, 51,219,254,171,154,131,194, 82, 70, 48, 64,232, 51,143, 33,242, +252, 52, 66, 49,158,191, 96,244,255, 0,142,136,115,108,195,114, 42, 46, 7,248, 19,250, 48, 95,107,159,246,255, 0, 5,252,177, + 56, 65,244,203, 15,159,179,135, 31,245,191,207,255, 0,149,221,122,254,252,175,166,127,185,197,246,143,229,127,219,211,254, 75, +218,132, 10,112, 10,114,160, 9, 29, 7,168, 61,127,167, 94,243,144, 72,238,122,100,244,207,207, 69,253, 47,152,255, 0,204,127, +146, 63,233,198, 13, 93, 64,255, 0,121,248, 47,229,137,189,127,126, 89,255, 0, 71, 16,255, 0,239,127,229,235,254,107,186, 95, +223,150,127,209,197,255, 0,107,255, 0,247, 93,212, 32,130, 70, 78, 83,156,121,142,227,167, 97,235,175,129, 39, 36, 96,158,227, +228, 15,174,116, 63, 75,230, 63,243, 31,228, 79,233,198, 61,174,163,175, 50,254,235, 47,229,137,191,255, 0,126, 86,112, 79,247, + 56,187, 99, 63,227,127,235,216,255, 0,154,238,144,250,101,100,228, 15,103, 9,200, 56,255, 0, 59,241,143,159, 95,228,189,168, + 65, 28, 19,201,158,160, 12,125,189, 71, 93,124,228, 56, 61, 58,142,199,215,215, 67,244,190, 96,127,246,143,242, 39,244,227, 34, +170,163,188,157, 61,195,242,196,224, 26,250,101, 42,117,105, 66,125,155,238,173, 74, 90, 16,134,216,226,229,114, 31,117,110, 45, + 45,180,204,120,237,112,184, 87, 34, 67,142,173, 8,109,180, 2,183, 28,113, 40, 64, 42, 80, 26,145,125,139,237, 28,187,106,123, +107, 97, 92,219,161,195,163, 59, 99,184,215, 61,173, 2,228,186,182,189,141,220, 55,106,172, 25, 85, 68,137, 81,173,154,141,204, +118,206,154,106, 53,248,244,231,225,154,131,105,167, 50,136,178,214,252, 70,220,146, 35,151,215,249,251,123, 18,120, 79,167,111, +111, 18,114,247,186,251,163, 49, 85,218,222, 24,163,210,111, 53,194,156,128,245, 62,228,222, 74,163,175, 29,169,183,157, 96,172, + 9,108, 83,222,131, 80,184,101, 52,174,132,209, 41,225, 89, 75,196, 25,105, 85,110, 39,101, 73,126,161, 41,197,174, 75,239,169, +114,139,171,241, 63,239,176,162,251,170, 86,121,157, 65, 89,113, 67, 7, 35,169, 4, 18,115, 82,113,247,137,217,238, 79, 87, 22, + 91,147,230, 34, 26,136,198,185,156, 69, 79, 33, 23,221, 80, 44,145, 56, 6,222, 98,116,157,153,122,110, 71, 99,125, 27, 60, 13, +161,241, 3, 47,175,226,174, 50,162,122,236,146, 71, 48, 81, 64, 36,150, 14,107, 70,214,150,114,244,239, 20,133,117,222, 36, 93, + 65,110,172, 77,203, 45,186,186,215,180, 61,151,139, 72, 78,210, 40, 56,230, 50,147,125, 47,149, 37, 77,151, 65,231,254, 5, 97, + 72, 9,229,201,242,231, 29, 51,240,235, 38,139,199, 80,146,160,145,181,193, 5,104, 75,168,255, 0,223,202, 78, 90, 39,195, 82, +214, 13,164, 11,120,116,164, 96,142,161, 65, 94,120,215, 37, 97,212,227,199,149, 78, 9,151, 17,105,146, 42, 43,109,228,184,158, + 66,150,152, 96,162, 49, 81, 60,133,229, 15, 16,124, 93, 73, 25,192,198,117,127,135,119,198,133, 85,181,154, 92,152,232, 50, 28, +186,224, 45, 77,133,168,134,145, 77,106,160,134,156, 25,228,241,210,136, 43, 91,107, 60,205,168,199, 90, 80, 50,188, 26,248,120, +191,199, 91,223, 62,222,224, 91,217,168,122, 27,111,255, 0,163,123,205,183,183,173,183,183, 70,215,125, 26,252, 47,211,253,139, +131,216, 17, 28,143,189,110,104,215, 17,164,174,118, 53,123,111, 17, 95, 80, 78,224,219, 29,102,143,198,144,125,124,131,109, 74, + 72, 74, 85,145,120,165,105,198, 84,135, 7, 50,109,142,133, 46,164,167, 31,102,112, 78, 53,145,195,226,200, 74,117, 13, 42,195, + 67, 36,164, 41,197, 27,185, 11, 13, 21, 41, 73,194,147,252, 30, 10, 94, 8, 28,197, 41, 32, 5,103, 39,166,121,115, 2,240,167, + 70, 20, 80,180,187,134,229,185, 73,145, 29,134,150,242,101, 73,157, 30, 64, 97,134,152, 42,230,117,245, 61, 19,152,140,164, 39, + 42, 42, 1, 32,105,211,165, 85, 16,235,177,228, 37,200,205, 55, 48,170, 47,130,211,169,144,168,175,186,194,157, 76, 57, 13,129, +240,203, 11,104,243,140, 39,147,168, 74, 84, 64,202,195,197,222, 56, 99,182,126, 45,113,183,178,209,131, 98, 7, 66,105,253,247, +233,115,110,128, 3,138,247, 55,240, 35,129, 40,195, 21,225,118,129, 72,107, 19, 85, 94,119, 82,194,219,213, 27,146,171,175, 96, + 71,152,124, 11,113,237, 58,246,213,110,191,179,158,220,176, 55, 74, 7, 3, 3,126,182, 34,238,121,155,106,229,220,202, 87, 17, + 78, 89, 19,118,199,113,165,190,239,212,246,205,239,105,183,176,245,193, 6,220,171, 67, 74, 62,167,174,138,129,141, 46,106, 28, +166,201,143, 6, 89,138,153,124,121, 63, 76,188,131,211,217,192, 8,233,212,113,129,228,124,255, 0,205,115,211, 93,240,187,108, + 11, 23,121, 44, 27,215,104,183, 62,212,167,238, 22,218,110, 61,183, 91,177,239,203, 66,160,208, 85, 46,224,160, 85, 98, 2,253, + 61,213,161,121,131, 48, 56,162,244, 73, 72, 34, 68, 57,212,248,242,227, 45,183,153,109, 73,252,231,120,230,246,106,239,183, 6, + 60, 82, 94,220, 62, 83,108,205,193,221, 91, 81,182, 13,241,179, 87,213,187,104,220, 55, 36,155,231,104,106,242,164, 10, 21, 78, +166,154, 13, 41,239, 10,232,165,186,219,212,154,235,124,169,228,168,210, 87, 32, 1, 30,100,114,171, 79,131, 60, 72,204,115,136, + 37,165,205, 43, 2, 87, 83,141, 66, 67, 28, 72,146,161, 61,172,129, 53,165,192,178,216, 50, 16, 84, 54,151,115,201,126, 41,240, + 67,240,133, 90, 87,229,108, 70, 77, 84,193, 66, 19,169,160,115,246, 86,238, 90, 66,143,111, 41,114, 72,109,181, 29, 64, 44,156, +255, 0,191, 47,234, 71,247, 56, 71, 65,159,243,192,245,237,255, 0, 37,221,124,254,252,192,255, 0,251,184, 58,127,233,129,251, +191,146,230,161, 89, 94,176, 47,187, 81,114, 17,117,216,247,149,174, 99,171,195,147,252, 35,181,171,244, 20,198,115,152,128,219, +235,171,211, 88, 13, 56, 84, 8, 9, 81, 4,144, 64, 7, 88,123, 74, 75,159, 19, 69, 14,164, 21, 0,180, 45, 46, 36, 20,146, 20, + 9,109, 68, 2, 15,124,246,212,249, 51,218,185, 55,142,181, 92,123,132,103,248, 46, 42, 15,110,150,246, 51, 0,111,208,133,191, +238,181,241, 56, 81,244,203,137,239,236,225,192, 29,201,226,255, 0,215,254,171,186,248,126,153,120, 29, 15,179,135,175,203,139, +254,159,143,242, 93,212, 32, 71,158, 48, 9,235,223,204,253,191,118,188,167, 39,161,193,199, 83,242, 36,159,221,165,127, 75,230, + 63,243, 31,228, 79,233,193,189,170,162,223,222,111,255, 0, 72,252,177, 56, 1,244,203,201, 56, 30,206, 14,191,250, 95,255, 0, +186,238,190, 43,233,152, 4,128,127,185,195,159, 80, 56,191,234, 62,223,241, 93,212, 32,142,124,128,239,248,116,243,251,245,224, + 2, 84,115,211, 3,186,122,117, 63,111,200,157, 15,210,249,143,252,199,249, 19,250,113,159,106,159,254, 39,224, 63, 44, 78, 11, +251,242,241,128,127,185,197,247,127, 43,254,191,183,133,221, 47,239,203,198, 79,253,206, 35,129,231,252,175,186,125,255, 0,226, +187,211, 80,130, 66, 58,149, 12,115,116, 4,159, 63,159,111,206, 53,240,167,226,206, 58,142,135, 29,189, 58,232,126,151,204,127, +230, 63,200,159,211,129,237,117, 31,183,248, 47,229,137,190, 15,166, 96, 9, 35,251,156, 36, 99,204,241,125,223,236,255, 0, 21, +237,123, 31, 76,184, 28,127,220,226,239,156,127,141,247,167,127,249, 47,106, 16, 24,207,151,108,247,244,199, 92,126,124,181,244, +117,192,232, 61, 63,183,166,135,233,124,199,254, 99,252,145,255, 0, 78, 49,237, 85, 23, 31, 89,248, 47,229,137,191,143,166, 88, + 79,250, 56,122,245,233,252,175,255, 0,163,252, 87,122,235,233,250,101,100,119,246,112,227, 63,243,191,235,248,127, 37,221, 66, + 19, 3,190, 50, 71, 94,159,213,159,150,190,247, 32,249,119,193, 25,253,190, 93,244, 63, 75,230, 63,243, 31,228,143,250,112, 61, +170,163,254, 39,224,191,150, 38,238,126,153,113, 31,232,224, 56,245,254, 87,248,253,159,201,119,166,169, 43,233,153, 17,254,141, +252,140,227, 63,203, 3, 30, 93,255, 0,205,115, 80,137, 32,156,156, 0, 51,142,224,117,245, 61,123,245,213, 5, 32, 17,128, 51, +158,253,127, 63,145,172,254,151,204, 44,127,180,111,255, 0, 68,127,211,140,251, 84,255, 0,183,248, 15,203, 19,121, 63, 76,212, +130,113,236,221, 39, 7, 31,231,129,248,255, 0,201,111, 95, 15,211, 55, 35,183,179,120, 30,153,255, 0, 60, 47,217,254,107,125, +245, 7,245,128, 51,129,133,119,198, 14, 62,255, 0, 77, 10,172,140,244, 29,122,244,245, 31,111,111,237,209,151, 54,175,239, 83, +123,255, 0,129, 63,167, 25,246,169,251,191,224, 63, 44, 78, 33, 95, 76,228,167,253, 27,185, 30,191,203, 11,253,214,245, 72,253, + 51,220, 28,127,115,115, 63,245,194,255, 0,117,175, 77, 65,216,247,233,128,113,149, 30,227, 30,127,111,150,188, 16,112,114, 0, +207, 92, 14,248,249,244,232, 59,232,227, 53,175, 32, 30,127, 95,240,167,244,224,235, 81, 49, 23, 50,126, 3,242,196,226, 85,244, +208, 57,127,209,181,145,235,252,176,255, 0,221,103, 84,207,211, 67, 35,253, 27, 63,135, 24,191,238,177,168, 57, 45, 35, 56,193, +193, 29,252,191, 31, 95,234,208,235, 73, 57,230, 30,125,255, 0,163, 74, 46,103, 90,127,223,127,149, 63,167, 0,212,205,183,155, +175,184,126, 88,156,137,250,105, 24,200,254,230,199,108, 99,252,113,123,255, 0,217, 99, 84,213,244,210,249,127,209,175,159,250, +227,126,239,228,175,168, 52, 41, 61, 72, 62, 89,255, 0,142,168, 41, 56, 62,164,103, 31,126, 58,232,227, 50,173,255, 0,141,127, +251, 83,250,113,145, 81, 41,232,255, 0,128,252,177, 57,179,244,211,113,219,217,173,147,233,252,177,255, 0,221, 95, 94, 15,211, + 80,198,127,238,106,246,242,254, 88,253,127,254,213,181, 6, 5,142,164,147,229,220,116,200,251, 71, 97,211, 84,150, 6, 51,159, +179,211,246,104,227, 48,172,218,243, 94,253,244,175,244,227, 62,209, 55,237,254, 3,242,196,231,207,211, 85, 32,103,251,154,121, +199,252,242,113,255, 0,229, 87, 84,149,244,214, 72,255, 0, 70,150, 71,254,153, 61,191,236,169,168, 45,169, 56,237,219,247,143, + 95,191, 67, 44,117, 35, 3,175, 92,104,195, 48,171,190,242,237,255, 0, 74,254, 88, 56,158, 75,253,187,253,195,221,238,196,233, +215,244,215,249, 15,254, 13, 12,143, 95,229,149,251,191,146,159,174,168, 31,166,202, 57,185, 71,179, 56,159, 60,255, 0, 44,190, +159,179,133, 62,250,130,147,205,243,116, 35,207,203,167,159, 76,103,203,250,244, 42,153, 60,221,200, 3,183,150, 62,206,158,154, + 88, 86,212,216,125,109,255, 0,237, 95,203, 6,231, 73,183,159,240, 24,157,183,247,236,196,140,143,102,104,199,110,188,102,224, +231,211, 31,201, 71, 94, 15,211,105,229,239,236,204,199,253,115,191,221, 71, 80, 71, 82, 0,206, 51,208,227,167, 94,222,154, 25, +105, 72, 7, 35,174,124,242,122,252,243,246,104,235, 89, 57, 27,203,191,192,126, 88,199, 58, 77,183,189,253,195, 19,188,254,253, +183,254,140,191,251,103,127,186,134,150,160,120, 80, 60,142, 63,111,239,210,209,253,170,163,254, 39,224,191,150, 13,205,147,246, +191, 1,249, 99,234, 65, 0, 3,249,235,162,146, 15, 64,123,244, 31,156,106,138, 70, 79,203,207,243,246,232,132, 12,159,179,175, +223,157,105, 22,185,191, 75,116,194,120,174, 1, 61,189,113,249,249,106,176, 0, 96,121,121,254,253, 83, 70,122,244,200, 36, 12, +231,183,231, 58,174,144, 14,115,158,131, 61, 52, 76, 12,123, 74, 74, 73,234, 49,249,252, 52, 66, 7, 76,250,254,204,106,130, 50, + 71, 92,224,158,153,235,223,231,231,253,154, 41,180,246, 7,203,169,252,253,186, 65,141,205,241,131,176,191,166, 43,163, 29,135, +197,143, 79,159,217,162,144,140,142,131, 3,207,237,253,231, 84, 17,208,244, 3,175,125, 20,140,253,223,191, 68, 98, 69,192,194, + 36, 91,248,227,210, 7, 98, 79, 83,230,122,244,253,253,180, 72,193, 3,207,211,167,159,110,218,164,145,147,246,117,209, 9,237, +140,128, 1,200,251, 71,223,219, 73, 49,185,233,108, 99, 21, 18, 0,193,193,235,223, 61,241,233,162, 83,140, 14,157, 60,134,124, +191,118,168,164,115, 31,219,247,116,237,162, 80,158,163,167, 65,235,162,147, 97,115,219, 4,244, 23,177,255, 0,199,207,250, 98, +170, 64,242, 3,229,162, 82, 9,192,249,119,249,252,245,118,183, 45,171,130,238,172, 83,173,203, 86,135, 85,184,238, 26,180,164, +196,164, 80,104, 52,233,117,122,213, 90, 99,129,106, 68, 58,109, 46,158,203,143,206,146,164,161,100, 33,180, 40,242,182,165, 16, + 2, 73,213,222,187, 99, 94,182,156,151, 98, 93, 54,117,215,108, 74, 96,148, 63, 30,227,182,235,180, 39, 90, 90, 78, 20, 28, 77, + 82,158,215, 41,230, 7, 90,109, 60, 43, 32,137,165, 81, 43, 11,133, 36,106,181,237,123,117,183,107,224,250, 36,229,180,162, 54, + 49, 41,179, 56, 83,164, 27, 94,197,173,164, 27, 88,218,247,182,248,198, 80,144,123,128, 8,207, 65,220,156,249,122,157, 86, 70, + 62, 33,143,179,215,239,252, 63,110,188, 32, 18, 50,217, 14, 1,220,161, 73,115,211,185, 65, 56,237,162, 27, 73, 86, 58,128,125, + 7,127, 95, 61,101,136,223,126,191,127,195, 26,250,131, 11,131,127,120,239,138,168, 73, 56,233,212, 12, 30,190, 64,234,179,125, + 79,108,128, 65, 3,191,221,251, 53,245, 40,236, 58,103,190,122,253,191,187, 85,144,140, 43,169, 3,207,228,114, 15, 95,217,164, +240, 49, 84, 39, 42,193,232, 59,129,129,148,140,118,207,225,175, 74,108,245, 4,242,143, 47, 81,233,175,160,149,103, 24, 10,245, + 30, 99,243,231,175, 67,174, 2,178, 51,230, 48,123,121,159,195,246,235, 24,199,195,174, 40,165, 56,206, 85,212,156,142,157,254, +204,246,215,148,164, 2, 50,163,223,238,235,242,243, 58,172,224,201, 29,122,122,142,157, 51,140,159,151, 93, 92,168,148, 58,189, +195, 84,167, 81, 40,116,202,141,102,177, 88,152,213, 58,145, 73,165, 65,153, 85,171, 85,170, 18, 20, 16,196, 10, 77, 42, 3, 46, + 72,169,206, 90,136, 8,101,134,214,226,179,209, 58,195, 50,162,150,118, 10,171,185, 39, 96, 48, 91,133, 2,231, 97,181,254, 54, +183,239,197,153, 93,240, 57, 64, 30,106, 3,174, 51,128, 61, 53,233, 88, 67, 69,215, 84, 27,101, 56,241, 29, 89, 8,105, 40,238, +165, 21,172,129,140,103, 82, 39,224,247,232,242,113, 5,186, 44,209,175,126, 45,110,120,252, 41,109,245, 65, 45, 76, 98,212,168, +192,137,115,111,205,126, 34,210,167, 80,219, 22, 95,189, 38, 13,132,167, 80,143,133, 85,151,221,152, 18,178, 69, 47,152, 99, 82, + 25,217,126, 4,125,158,220, 32, 70,111,248,177,225,226,214,187,174,202, 84,112,204,221,208,222,132,198,220,171,212,205,121,104, + 12, 72,241,238, 54,151, 77,163,211,164, 45, 56,103,220,169,241,154,109, 74,229, 79, 82, 64,134,103, 28,115,148,101,101,145, 24, +213,204,187, 89, 14,215,247,144, 9,248, 27, 91,212,226,216,224,191, 5,184,251,142, 12,111,150,229, 38,134,142, 80, 8,158,164, + 20, 4, 18, 0,100,140,217,216, 94,195,204, 99,185,176, 23, 36, 3,170,254,203, 46, 26, 46, 77,165,224, 39,102,233,180,203, 98, +123, 55, 94,240,135,247,210,247,144,229, 50, 82, 28,149, 42,249, 17,191,130, 80, 39,169,184,229, 79,197,133, 96,194,183,154,100, +100, 99,197,117, 73, 37, 43, 81, 86,234, 87,236,203,238,132,204, 33, 46,221,170, 32,138,139, 45, 45,243, 6, 98, 99, 20,165,137, +143,123,195,179, 60, 34, 27, 65,240,249, 15, 57, 79, 42,214, 17,130, 72, 35, 99,155,223, 42,234,221,136,202,101,194,143, 66,171, +184,105,112,211, 76, 5,132,211,101,181, 28,123,180,100, 71, 82, 83,238,168, 82, 80,227, 9, 67, 73, 8, 14, 54,132, 97,180, 20, +130, 37, 39,125, 42,234,171,170,153, 34,124,151,131,206,170, 19, 32, 54, 57,101,207,141,200,137,172, 48, 57,190, 37, 8,222, 27, +165, 60,170, 39, 42, 9, 10,109, 42, 35,158,243, 89,104,243,106,250,186,249, 38,156,203, 86,236,231,104,202,139,157,149, 87, 85, +236, 1, 10,190,110,130,198,230,248,244,231,129,168,248,183,129,184,107, 38,225,202, 14, 30,163,155, 47,200,105, 99, 77, 38, 89, +121,146,114,215, 68,146, 59, 8,236,178, 22, 87,121, 1, 82, 69,181, 95, 73, 7, 26, 81, 90,169, 61, 79,168,208,167,204, 91, 44, +184,170,148,168, 83, 66, 11,141, 70,124, 78,167, 84, 35, 51, 29,198, 66,130, 11, 8,121,168,165, 36,146,181, 41, 14, 44, 21, 40, +224, 88,100, 92,178, 84,252, 41, 12, 58,134,169,236,223, 20, 56, 17, 31, 91,158, 31,213,209,106, 45, 85,162,212, 38, 53,239, 67, +159,220,194,222,100,171, 9, 37, 41,111, 45,133, 37,120,214,238,238, 21,145,110,110,237, 53,104,141, 18,147, 65,187,160,213,226, + 84,226, 75, 44, 52,154, 77, 70,163,111,200,247,152,240,235,208,227,114,167,192,113, 14, 20, 25, 44,164, 59, 28,191,226, 56,135, +145,206,141,115, 74,240, 69, 70,139, 58,226, 93, 94,157, 42,151, 38,217,171,209,163,191, 18, 75, 72, 91,241,167,211,107,148, 86, +235, 13,120,141,225, 15,143,117,147,200,218,176,158,118,242,164,158, 78,241, 42,202,121,105,230, 69, 46, 37,138, 83,229, 96, 54, + 39, 96, 53, 11, 27, 48,191,217, 61,150,247, 32, 99,163,184, 11, 53,202,248,178,154, 72,228,131,244,126,105, 66,170,147,211, 72, +202,218, 17,229, 26, 94, 18, 8, 15, 27, 23,116, 14,187, 34, 6, 89, 17, 67,170, 54,206, 82,238,185,177,160,198, 76,229,153, 13, +208,110, 74, 4,198,235, 44, 56,149,128, 69,106, 35, 41,155, 33, 8,201, 46, 37,233,173,153, 1,226, 91, 60,203, 41, 39,176,223, +221,171,219,215,238, 40,178, 42,213,233, 10,163,209,233,181, 8,142, 38,114, 84,251,110,185, 54, 35,209, 31, 13,197, 91,138, 79, +143,206,150,212, 57,242,124, 38,229, 16, 84, 73,240,213,204, 75, 50,143, 87,173, 84,164, 89, 20,181,168, 46,225,151, 26,159, 71, +109, 65, 14,184,229,111,223,226,166, 53, 41,224,179,148, 64,114, 79,132, 90,113, 73,200,104,184,146,174,118,146, 79,101,175,201, +205,219,204,155,102,128,180, 26,125, 18, 28,150, 98,195,105, 10, 14, 85, 92,139, 49, 44, 74,113, 69,160, 66,149, 34, 98, 36, 58, + 20, 83,202,178,235,104, 56, 3, 26,125,225,170,120,167,231,215, 85,141,112,211,105, 68, 66,108, 25,200, 98, 1, 35,204, 2,129, +118, 32,139,221, 73,211,171, 88,164, 60,112,168,124,170,167, 38,200,178,103, 72, 51, 44,237,231,149,166, 81,253,213, 50, 10, 79, +172, 10, 67, 42,201, 44,175, 42,128,126,168, 90, 67,176, 82, 27, 44,157,124, 91, 86,163,172,210, 40,209, 33, 66,112,182,149, 48, +228,143, 4,186,243,202,144,134,136, 71, 50, 71, 59,195,196, 43,253, 81,128,121,143, 54, 9,213, 9,123,191, 49,153,245, 55, 35, +206,109,168,116,233,113, 41,236,173,165,115,203,126,108,150, 24,126, 66, 34,165,149,164, 32, 41,215,163,182,233, 78, 22,166,155, + 90,143, 48,108,145,165, 85, 75,154, 37, 70,161, 46,164,219,243,155,165,183, 95,162, 83, 41,204,184,183, 31,120, 38, 3,190, 45, +101,232,203,231, 40, 76,115, 83, 50,127, 74, 20,164,143,112, 40,242, 9, 31, 98, 92, 79, 79,129, 78,140,203, 11,121,138,245, 72, +215,101,185, 49,196, 39,158, 19, 18, 21, 36,165,158, 84,115,163,196,105,234,116,116, 44,252, 60,143,172,114,249,234,105,237,243, +234, 88,226,151,149, 96, 84, 34, 93, 22,215, 29,128, 4, 3,181,141,183,216,168,177,185,166,163,240,166,136, 67, 12,245,145, 53, + 84,238, 0,153,166,177, 96,204, 18, 87, 55,144,155,186, 70,146, 43, 45,216,107,212, 1, 59, 91,122,169, 91,167, 70,186,227,184, +197,203, 10,131, 87,163,189, 10, 69, 85,214,171,148, 90, 69,113,166, 35, 70, 56,136,137, 81,234,204,184,151,100,173,214,164,200, +104, 6,254, 24,254, 26,193, 30, 33,214,177,238,127, 2, 62,206, 30, 34,208,151,119,167,131, 14, 31,170, 51,171, 76, 70,150,170, +189, 2,208,133,100, 93, 16,152,156,135, 92, 15,166,232,176, 13, 54, 74,101,165,135, 57,220, 33, 69, 97,249, 39,169,192, 0, 26, + 93,210, 95,153, 46,142,195, 48,212,207,240,138, 76,170,188,247,144, 86,212,166, 41,209, 88, 17,109,147,200,217,240, 91,113,230, + 10, 86,128,162,166, 98,165, 96, 97,201, 9, 78,178,250, 69, 65,249,177,152,150,228,245, 53, 78,141,239,234,159, 40,211,220,125, +234,189,102,123,128,204,166,210,121, 79, 70,152, 89, 40,114, 90,121,185, 11, 65,166,199,232,221,121,189,200,179, 42,152, 93, 92, + 75,230,181,135,235, 18,204, 69,152,107,221, 75, 2, 72,234, 69,174, 46, 14, 32, 60, 65,225, 38, 67, 80,102,246,156,185, 96,142, + 64,186, 65, 26,216, 43, 6, 40, 6,149,221,157,212, 46,150, 93, 69, 68,110,116,131, 41,199, 40, 55,231,232,175,112, 39,186, 52, +233,149,158, 27,247,143,120, 56,116,174,173,153, 18, 34,210,174, 57,144,247,130,194,102, 74,185,149, 26, 52,200, 23, 10,162, 86, + 96,176, 86,182,130,146,213, 93,197,161,183, 1, 8, 39,149, 38, 53, 60,110,123, 1,189,162, 92, 20, 64,171,222, 82,246,226, 47, + 16,123, 65, 75, 15, 72,127,116,120,126, 77, 82,239, 20,202,115, 40, 46,174,117,219,183,111, 65, 69,126,215, 97, 8,232,243,169, +139, 58, 27, 74, 74,185,166,114,142, 99,250, 18,209, 46,181,183,224, 68,113,102, 52,106,107,177, 37,200, 76, 89,105,113,113,218, + 56,118, 12, 55,101, 50, 10,230, 23, 86, 85, 37,215,208, 22,167,192, 67, 77,169, 69,206,125,108,205,177,123,137, 81,132,228, 77, +240,230, 79,154,105,244,170, 68,172, 70,170, 45, 44,243, 23,229,205,128,165,133,198, 42, 67,110, 60,176,176,144,220, 86,155, 75, +156,175,184, 82, 37,249,111, 22, 85, 64,218, 42, 36, 46,150,235,171, 86,247,176,186,185, 5,172, 47,228,140,198, 46, 44, 72,234, +121,147,139, 60, 39, 92,176,153,168,117, 68,140,198,218, 71,144, 3, 98,138, 64,212,159,103, 84,140,214, 0, 32, 12, 28,131,124, +126, 50,105,198, 21,146, 20, 2,150,143,132,228, 7, 26, 81,109,214,212, 65,248, 92, 74,194,146,164,156, 20,169, 37, 42, 0,131, +165,219,161,234, 58, 18, 58,228,124,254, 71, 95,166,111,180,163,216, 17,194, 7, 31,240,238, 45,193,218,248,212,110, 26,248,173, +144,137, 82,206,229, 89, 52, 54, 25,176,183, 2,186,219, 40,113, 49,183,135,111,169, 74,106, 53, 73,215,223,228, 75,245,122,111, +187,214,152, 50, 20,235,206, 84, 2, 61,217,127,158,255, 0, 24,156, 20,241, 33,192,134,239,206,217, 30, 38, 54,238,125,139,118, +182,211,245, 43,118,166,211,159, 90,217,123,137,109, 53, 37,113,155,187,182,234,235,101,180,177,115, 80,148,226, 64,116, 0,220, +200, 46,171,221,234, 49, 34, 72, 30, 25,177,178,252,214,159, 48,137, 36,141,135,159,161, 6,234, 78,231, 77,251, 48, 0,221, 90, +199,202,197,117, 32,214,105,170,234, 26,172,186, 65, 29, 84,101, 65, 54, 87,177, 10,215, 32, 13,141,138,150,236, 14,199,245, 75, +111,141, 87,232, 7, 78,223, 46,186,240,164,147,156, 28, 3,215, 4,145,249,235,175, 68,129,142,189, 7, 76, 99,191,151,125, 32, + 65, 39, 61, 71, 76, 36,140,103,167,252,116,233,141, 78,248,166, 18, 9,199, 92,122,143, 95,234,239,175,161, 36,250,244,200, 30, + 93,115,158,191,142,170,121,127,171,248,116,215,196,144, 1,202,147,156,231,167, 92,228,232, 96,111,143,129, 56, 33, 89,201, 25, +230,243,242,215,164,117, 4,143,135, 25, 61,115,251, 63, 29,125,233,140,254,206,216,252,245,215,209,215,246, 12, 1,220,121,253, +253, 52, 48, 58,123,176,136,207, 68,245,233,231,142,164,103,246,106,130,219,198, 9,242, 61, 70,124,244, 78, 14, 58,140,121, 2, + 70, 49,246,252,191,175, 84,207,110,131, 39,246,103, 63,212,127,167, 88, 6,255, 0, 17,140,224, 37,160,224,249,103,215,184,207, +168,252,247,208,170, 64, 0,231, 36, 18,123,250,252,190, 90,184, 57,205,158,184, 61, 58,231,190,125, 58,121,245,208,238, 32,242, +231, 4,117,232, 58,231,175,203,236,214, 65,232,122, 99, 32,158,221, 78, 45,197, 1, 39, 32,245, 29, 49,158,152,199,174,188, 20, +231, 36, 28,121, 28,159,179,207,240,209, 42, 73,234, 20, 7, 79,245,123,146,126,126, 67,174,168,242, 12, 40,100, 99,166, 0,243, +235,158,231, 75,169,184,235,131,168, 34,219,109,243,243,111,195, 3, 40, 3,212,147,129,248,125,186,160, 70, 70, 63, 35, 70, 41, + 35, 56, 30,153, 63, 44, 13, 12,180,144, 73, 3,167,246,126,206,186, 81, 79,108, 24,216,116, 23,254, 71, 0,184, 0, 32,116,206, +122,159,217,215, 31,158,154,162,160, 78, 58,100,103,175,175,221,163, 20,147,230, 7,221,216,158,250, 25, 89,201,230, 56, 39,183, +207,211, 31,119,244,105, 92, 1,208, 95,113,129, 22,128,114, 64,199,200,249,250,140,104,117, 35,166, 6, 1,239,246,103,200,244, +209,138,206, 65, 56,207,160,242,208,199,169,200,207, 95, 92, 14,221, 63,118,149, 7,160, 39,167,207, 95,158,248, 54, 5, 87, 76, +228,103, 25,253,159,187, 66,172,116,206, 15, 78,216,253,164,244,237,211, 70,172,100,142,152,235,220, 30,253,124,255, 0, 62,122, + 25,196,228,156,100, 1,208,227,182, 79,228,104,248, 50,250, 91,127, 92, 91,215,128,112, 14, 73, 39,167,161, 29,123,232,115,223, +168,235,158,191,184,104,199, 19,144, 83,211, 62,126,189, 61, 63, 13, 12, 80, 70, 78,114,125, 15,225,223, 58, 89,122, 97, 81,107, + 3,210,216, 29,105,243, 25,206,133, 90, 72, 39,183,153,251, 62,223,150,116,105, 25,251,186,250,103,228,126, 90, 25,105,206, 73, +200, 62,126,125, 59,253,250, 85, 79, 91,157,176, 69,216,144,119,183,250, 96, 34, 48,113,165,175,107, 73, 39, 35,175,224, 52,180, +174, 15,113,220,216,227,234, 49,143,233,209, 40, 24, 3,231,215,243,247,106,128,198, 6, 1, 31, 35,223, 85,211,204, 59,128, 49, +233,223, 61, 58,233, 18,118, 3,231,221,140,226,178, 60,250,253,223,191, 85,209,220,253,157,189,127, 63,191, 84, 81,143, 33,215, +204,234,178, 6,122,231,177,237,249,242,254,173, 16,157,137,190, 6, 8, 78,112,112, 70, 7,124,143,196,244,243,233,162, 27,234, +126,239,234,213, 4,125,189,188,191,126,189, 18, 64, 86, 14, 8, 30,125, 1,207,244,255, 0,102,181,216,133,193, 78,224,142,199, + 7, 54,115,211, 61, 62,206,158,126, 99, 69,164, 14,128, 16,123, 15,151,236,213,189,146,233, 74, 78, 19,142,153,251,112, 63,171, + 71, 55,223,162,122,140, 28,224,246,249,233, 34,215,194, 71,174, 43,165, 61, 65, 57,232,123, 99,191,167,237,209, 9, 0,142,169, +249,103, 39,175,175,217,170, 64, 18, 71,145,233,231,230,123,231,229,170,232,200, 36,116, 29,135,203,168,243, 62,103,182,176, 73, + 61,123, 96,167, 21,209,156, 1,208, 14,195,241,243,249,104,148, 3,216,156,228,224,103,250,117, 65,160, 72, 29, 58, 3,231,163, + 16, 58,231,175,203,211,211, 73,191,175,207,108, 99,107,145,181,206, 58,159,236,114,180, 36,215,120,223,178,238,166, 92,121,134, + 54,178,207,191,175,249, 50,154, 42, 65,101,248,212, 39,104, 52,196,151, 17,213,181, 46,101, 96,132,144, 65,248, 62,103, 82,170, +147,119, 79,171, 52, 99,214, 12, 27,130, 56,200, 92, 43,154,147, 73,175,197,113, 32,149, 96,181, 85,136,238, 83,215,166,114, 61, +117, 30,111, 98, 93, 13, 12,206,226,110,249, 80, 74, 93,129,102,217,118,147, 11, 61, 22,147, 89,172,205,170, 73, 66, 84, 58,128, +180, 66,104, 17,242,215,110, 85, 89, 62, 34, 74, 78, 18,162, 18,178, 78, 2, 72, 24,243,252, 53,207,158, 33,214, 52,188, 67, 60, + 91,218,146, 56,163, 6,254,160, 73,191,190,242, 16, 55,233,143, 67,190,140,252, 57, 24,240,222, 10,185, 97, 89, 6,113, 87, 87, + 57, 12, 1, 4, 44,130,152, 2, 8,181,138,211,143,223,140, 91,113,184, 80,224,223,122, 90,127,248,197,225,195,111,141, 78, 74, + 74, 28,185,236, 6,100,109,189,210,202,149,255, 0,194, 25,155,109, 45,182, 30,116, 14,184,114, 58,193, 35, 36, 29,114,235,126, + 61,136,232,153, 30,101,195,194, 78,234, 11,142, 74, 18,167, 81,180, 59,192,184, 84, 27,145,224,126, 38,225,219, 27,129, 13, 41, +129, 85,124,254,171,109, 79,106, 42,220, 56, 5,240, 78, 79, 93,141,126, 51,110,161,151, 93, 72, 82,213,250, 21,147,128,162,159, +242,172,156,116, 75,192, 96,143,245,128,214,109,101, 34,179,125, 87, 98,219,150,188, 73,117, 58,171,235, 8, 75,113, 88,113,228, +190,130,160,148, 6,130, 7,194,176,163,212,158,137, 41,207,108,226, 37, 67,197, 89,254, 85, 44,107, 65, 92,242,128,109,202,127, +172,140,251,130, 53,244,131,234,154, 77,174, 21,133,241,105,113, 79,128,254, 26,113,109, 13, 76,249,182, 65, 22, 83, 80, 16,177, +174,164, 11, 73, 52,123,127,120,210, 70,162, 57,108,123, 78,146,165,250,169,223, 16,133,191,246,226,251,218,171,186,173, 97,110, + 77,165,112,216,183,165, 5,229, 49, 86,182,110,106,115,212,202,172, 69, 5, 40, 7, 80,219,163,150,100, 37,129,150,164, 48,167, + 88,117, 63, 19,110, 40, 29, 97,233,193,243, 24, 29,250,143,184,116,215,232,143,190, 62,204, 45,147,226, 95,110, 34,219, 28, 90, + 85,225, 64,173,211, 34, 4,217, 87, 45, 7,192,123,116,108, 57, 14, 35,197, 13,193,172,182,131,239, 52,194,172,248,180,249,101, +232,171,201,194, 80,172, 40,106, 85,157,236, 48,246, 94, 89, 49, 96, 11,150,111, 16, 59,185, 80, 43, 83, 18, 93,168,222, 84,251, + 54,159, 41,214,155,241, 92, 81,129, 64,166,133,196, 36,117, 74, 67,170,207,108,116,206,173,202, 63, 17, 40,214,142, 55,205,233, + 13, 21,112,217,227, 87,141,135,185,128, 46, 29, 67,117,210,202, 74,244,212,246,213,142, 20,207,126,143,124, 95, 14,119, 61, 31, + 6,200, 56,195, 36, 55,104,107, 68,114, 83, 2, 59,199, 46,168,204, 70, 69,177,250,200,100,120,157,124,223, 84, 73,137, 96,225, +130, 70,121, 22, 8,237,202,133, 96,250, 28,227, 72,168, 32, 0, 58,146,113,140, 31, 63,151,222, 53, 61,230,125,146,190,201, 76, + 62,208,225,254,252, 87,128,217,112,248,251,193,118,173,197, 4, 39,152,242,173, 11, 29,115,211, 32,117,193,211, 69,186, 94,193, +159,103, 5,247, 75, 55, 6,222,220,187,247,177,170,142,168,178, 84,212, 27,150,141,124,210, 39, 70, 74,144,228,182,226,199,187, +233,222, 60, 23, 11, 1,196, 7, 82,242,195,107,113, 42,240,151,142, 83,177, 77,226, 46, 75, 83, 47, 41, 81,193,177, 55,242,216, + 0, 46, 73,185, 22,183,223,238,190, 25,235,190,143,254, 42,229,177,123, 69, 87, 14,170,171, 21, 80, 22,161, 11, 51, 57, 1, 84, + 2,160, 93,137, 3,114, 63,142, 35, 1,192, 79,179,155,127,248,252,190,165,208,246,210,151, 26,220,219,219, 90, 68, 49,185,187, +209,119,179, 45,157,189,219,184,210,112,227,112,228, 57, 29, 33,219,162,244,145, 27,153, 80, 40, 80, 57,165, 61,128,236,151, 33, +196, 10,146, 38,173,194, 71, 5, 92, 32,251, 61,109,198,127,137, 11, 71,248,111,187,134, 47,186, 92,156, 68, 95,208,233,213, 77, +203,169,188,166,210,220,230, 45,176,210, 20,198,221, 91, 60,222, 42,147, 78,163,161, 14,132, 16,169, 50,102, 40, 41,100,251, 2, + 70,221,108,222,222,208,118, 35,135,219, 98,141,182,187, 99,183, 80,221, 22,253,169, 5,240, 28,175,120,202,109,117, 43,158,224, +172,168, 42, 69,193,113,212,166, 35,154,109, 86, 73,117,239,122, 88, 75,220,172, 22,219, 70, 15, 39,112, 35,202,153, 34,108, 9, + 83, 16,228,242,167, 30,167,205, 67,209,101, 60,247, 40, 75,203,132,133,184, 16,103,115, 6,213,204,193,117,183,249,130, 73, 35, + 5, 53, 87, 20,120,131, 91,154, 84, 73, 73, 68,198,158,137, 73, 10, 65,221,198,214,239,181,250,134,185,234, 8, 61,113,217, 30, + 12,253, 20, 41, 50,184,169,243,158, 45,133,115, 76,244, 44,114,114,236, 90, 10,109,118,101, 69, 7,109, 69,110, 68,166,247, 32, +244, 91, 5,122, 46, 93,207,151,112,185, 82, 84,201,237, 85,196,152,174,184, 88,241, 23,239,197, 8,146,129,239,112,210,195,217, +143, 82, 97,220,134,151,240, 7,148,160,230, 82, 64, 42,108, 46, 11,170, 52,200,142, 42,108,229, 75,154, 25, 10,128,251,176,220, + 69, 62,231,164,248,160, 73,129, 34, 43, 32,148, 79,109,191, 21,101,149, 97,198,164, 54, 36, 52,149, 5,184, 19, 97,136,251,117, +212, 9,207, 47,222, 75, 83,204, 70,166,198,109, 84,203,178,149, 49, 96, 25, 28,237,178,132,166, 28, 66,181,167, 45,188,144, 84, +217, 47, 45,181,163,161,199,231,178,168,238, 61, 67,174,165, 50, 30, 68,210,138,101, 69, 41, 66,226,214, 24,154,175, 18, 68, 23, + 25,200, 16, 43,237, 53,206, 89, 40, 41,101,229, 18,227, 11, 67,153,107, 85,228,149, 94,103,214, 88,177,181,218,251, 49,190,198, +219, 19,126,194,199,107,117, 59, 14,220,202, 56,115, 41,161,100,166,134, 46, 65,164,220,199, 24, 80,202, 6,149, 99, 29,208, 93, + 86,200,179, 38,148,109, 12,205,160, 36,107, 36, 87,151,170,161,165, 46,223,113,167,151, 78,170, 42, 43,148,218,139,143,133, 60, +212,244, 50,100,136,203,150,242,135,136,250, 60, 22,164,198,112,144,183, 19, 29, 76, 58,165, 45, 0,185,112,131, 94,118, 83,239, + 68, 41,110,145, 84,110, 85, 61, 77, 75,109,178, 94,166,215,169,104, 8, 67,209,226,188, 8,118, 28,136,175, 69,146,129,147,227, +180,167,144,130,160, 73, 24,237, 74,148, 41,180,184,241,225,200,118,224,181,231, 71,136, 98, 84,161,159, 30,183,110, 75,101,207, +122,101,135, 67,139, 34,171, 78, 67,173,161, 72,116, 98, 92, 85,128,204,132, 60,193,241, 18, 44,199,101, 84, 85,252, 43,112,177, + 42, 84, 4, 52, 95, 52,245, 4,179, 84,167,160, 46, 60,163,202, 84, 82,137,173,158,119, 35, 43, 36, 50,180, 41,160, 2, 22, 0, + 48,114,196,178,177, 80, 55,211,178,238, 64,223,114,118,234, 70,226,196,234,190,160,112,250, 40,232,234, 98, 13, 29,180, 72, 74, +135, 58,129, 51,142, 88, 77,113,191,149, 76,133, 66, 76,142, 54, 49,137, 46,240,201,115,180,187,121,113,159,112,167, 74,168,126, +134,164, 39, 75, 21,246,192, 76,150, 24,152,101, 59, 6,160, 22,251,164, 23, 22, 86, 34,169, 37, 64, 41, 77,186,215,114,156,150, + 43,139, 43, 97,169, 85,218,101,105,162, 25, 69,219,106, 92, 52,234,159, 51,106,114, 59,213,187, 98, 11,114, 96,186,162,129,133, + 58,105, 47, 71, 91,228,165, 74,112,210, 83,241, 18,146, 11,135,106,214, 98, 78,172, 73,102, 43,177,164, 67,184,105,116,249, 76, +184,164, 4, 42, 59,240, 23,245, 98,155,113,151,208, 49, 37,216,174, 66, 88, 82,250, 45,200,200,202,137, 72, 26,161,196, 82,249, + 44,237,191,114,123, 77,202,228,191, 13, 50,108,176,183, 27, 75,109,213, 41, 83,161, 73, 7, 42, 42, 37,230,219,111,224, 71, 41, + 82,129, 72, 56, 26, 82,178,211, 80,176, 96,117, 33, 87, 27,130, 65, 15,123,139,250, 43, 17,247,133,176, 59,154,251, 35,230,229, + 30, 34,101,181, 84,209,154,121,115, 5,168,137,162, 38,222, 89,169,228,145, 35,177, 23,211, 13, 74, 42,128,222, 98,209, 33, 93, +247, 45,207, 13,114,155,103,122, 54,250,161, 33,214, 94,250,215,234,202,139,111,115, 54,235, 9,117,115, 33, 84, 25,247,117,161, + 36,186, 75,171,142,226, 92, 32,132,169, 8,234, 2,250,244,178,232,151, 46, 85, 85, 97, 46,180,218,152,141, 41,185, 10, 82,146, +133, 56, 87, 49,135, 28, 75,206, 54,128, 82,149,182,149,114,148,252, 73, 40, 42, 25, 63,173,202,173,165,149,245, 27, 59,105, 37, +133,198,106, 75, 46,199, 11,153,201,226, 56,179, 68,204,101, 51,206,133, 4,148,184,138,122, 64,229,229,233,145,221, 56, 61, 81, +185, 75, 51, 27,159, 80,109, 41,125,186,148, 24,239, 53, 37,180,135, 92,106, 52,136,171,113, 78,165, 68,140, 37, 16,223, 89, 4, +156,167,195, 25, 30,171,240,236,165,105,234,169,128, 26,161,150,226,251, 18, 25,116,220,216,131,250,167,125,192, 39,222,113, 12, +241,161, 4,252, 89,144,102,166, 63, 45, 69, 19,211,173,192, 32, 52, 53, 5, 73,183,217, 0,172,167, 96,196,253, 93,251,227, 89, +170,116,137,115, 41,150,180, 88,239, 52,228,155,128,190,219,171,105, 45,132, 20, 84,125,242,101,110, 97,109,192, 60, 15, 6, 4, +169, 41, 7,205,101, 42, 4, 30,100,235, 48, 98,100,183,170,109, 55, 77,129, 26, 53, 90, 77, 38,159, 64,165, 69,109,165, 59, 30, + 52,118, 31, 90,205,199, 80, 1,144, 68, 88,139, 74, 3, 44,182, 0,117, 80,218,100,243, 23, 20, 81,245,170, 20,128,229,191, 57, +231, 18,227,180,170, 21, 94, 83,170,231,105, 13,211, 41, 41,129, 19,194, 45,180, 74, 72,152,162,162,165,171, 24, 90,155, 91,121, + 64, 1, 10,190, 89,208,106, 49,147, 38,123,140,190, 42,215, 59,205, 63, 4, 41, 77, 7,232,116,248, 77, 39,221, 90,229, 3, 45, + 60,220, 25, 11,121, 77,164,169,180,203,154, 2,178,180,171, 50, 56, 55,242,106, 47,163,123,251,137,182,215, 39,127,128, 23, 32, +147,183, 70, 90,252,198, 22,163,102,103,142,115, 15, 52,168, 39, 72, 47, 37, 68,133,131, 88,139,196,145, 68,178, 49, 42, 54, 4, + 38,158,106, 17,126,147, 14,157, 74,146,213, 34,214,106,160, 3,145, 23, 72, 93, 65,214,154,147, 60, 45,214,208,171,150,181,227, + 40,145, 58,176,135, 20, 0, 88, 40, 71,191, 85, 50,133, 16,199, 40,204,233,149,217, 16, 81, 74,106,213,167,196, 41,166, 68, 93, + 61,218,202,202,222,163, 83, 36,180,202,163, 63,224, 83, 73, 82,235, 51,209, 30, 63, 41, 12,169, 45,248,223, 4,213,169, 74, 90, + 53,128,211,101, 42, 82,164, 55,109,135, 89,147, 41, 74,163,196,152,181, 2,229, 14,132,196,169,105,114, 84,194,235, 37, 15,213, +165,203, 74,222,142,144, 8, 75,184,116,146, 25,235,123, 77,126, 53, 26,159, 50,222,163, 82, 34, 87,170,209, 34,199,165,211, 98, +196,145, 42, 52, 27, 97,182,148, 76,169,143,206,119,244, 45, 5, 21,254,145, 74, 46, 58,167, 16,167, 2, 71, 51,139,214,220,104, + 21,172, 65, 37,238, 69,201, 58,119, 82, 55, 23, 34,254, 81,127, 40,177, 82, 54, 23, 48,154,250, 57, 42, 21,105,164,129,171,170, + 20,141, 98, 87, 0,144,254, 73, 38,170, 44,234,129, 19, 88,176,146, 78, 89, 34,103,179,171,162, 77,157, 81,164,143,123,163, 8, + 73,114, 60, 56, 14, 56, 25,153, 92, 82, 27, 64,113,230,129,159,116,212,234,141,165, 30, 35,232,150,149, 34, 26,138, 67, 35,195, +229,195, 64,160,161,215,163,214,229, 61,114,193,118, 3, 18,169,144,234,116,244, 83,105,213, 73,128, 42,170,162,244,180, 53, 84, +173, 73,139, 52,114,195,114, 72, 17,209, 13, 46,130, 91, 66,252, 80,144,164,132,233,150,102,139, 89,170,162, 58, 42, 11,109, 2, +156,194, 86,221, 33,181,251,181, 38, 42,218, 67, 77,174, 97,127,153, 78,214, 92, 14, 2,191, 29,239, 13,182, 62, 55, 80,210, 57, +121,206,113, 74,153, 54,127,189, 8,203, 67,140,225,184,143, 85,220,123,222,211, 87,121,197,162, 59, 80,232,138, 96,225,196, 37, +231, 93,231,158,158,124,173,226,166, 18,183, 1,113, 59,104,206, 7,217,212,166,214, 54, 39,125,193,177,184,189,190,201, 2,219, +129,115,109, 36, 64,115,202, 58,106,133,145,131,199, 51,172,111, 27,220,150, 84, 18, 57, 32,181,236, 38,119,102,187, 2,172,173, +245,138,161,227,115, 42,109, 53,183, 89,113,151,211, 75,165,167, 49, 32,171,220, 30, 90, 20,243,205, 83,164, 33,100, 75, 87,189, +190,190,121, 21, 18,250, 71, 48, 94, 91,105, 75, 43,121, 74,230,229, 45,103, 23,124, 32,112,213,237, 11,217, 74,166,193,241, 37, +103,179,117, 80, 93,247,138,133,163,115, 83, 94, 17,183, 11,108, 46,100,165,216,113, 47, 43, 30,236, 12, 41,116, 27,141,183,211, +202, 18,144,184,181, 22,208, 98,204,139, 46, 18,220,104,135, 30,225, 76, 56, 81,105,212,133, 48, 41,180,229, 70,162,206,126, 38, + 92, 98,148,206, 66,164,193,166,164, 45,105,171,200, 68,140,120,203, 37, 97, 47, 60,174,114,244,144, 80, 29,171, 42,165, 30,155, + 49, 51, 37,181, 81, 79,132, 15,185,196,151,151,234,114, 30, 44,248, 41,113,104, 4,248,238,184,148,190,180,184, 74,188, 52,182, + 16,234,154, 81, 58,124,203,115, 9,169, 39, 2, 57, 12,104,246, 82,172, 26,204,163, 72, 34,253, 44, 52, 92, 91,236,149, 12,133, +109,183, 62,241,103, 9, 69, 81, 77, 83, 52,208,150, 44, 27, 66,145,121, 36, 63,181, 37,206,204,250,129, 61,116,169,212, 89,131, + 43,201,249,104,123, 74,253,155,155,225,236,203,226, 10,102,204,110,202, 63,132, 86,125,198,138,149,127,100,183,134,155, 1,112, +237,173,219,177,225,202, 67, 75,152,211, 60,203, 77, 6,247,167,123,204, 54,107,180, 85,184,167, 33, 62,251,114, 35,170, 69, 54, + 84, 73, 46,115,200, 36,167, 25,234, 60,137, 61, 71,217,242,198,191, 92,191,104, 95, 2, 27, 99,237, 47,225, 82,247,225,235,116, +208,197, 6,191, 47, 55, 54,209,110, 43, 17, 27,149, 84,218, 45,211,165,197,120, 90,215,101, 56,171, 11,149, 13, 70, 66,225,214, + 96,115,165, 21, 26, 85, 74, 92, 66,166,214,227, 79, 55,249, 64,239, 46,206,238, 55, 15,155,187,185,155, 17,187,212, 5, 91, 27, +163,180, 55,157,106,194,190,104,165,101,216,241,171,116, 57, 30, 18,166,211, 37, 16, 5, 70,131, 54, 18,226, 79,167, 74, 70, 81, + 42, 5, 78, 52,132, 18, 28, 26,183,178,186,229,171,129, 84, 73,169,212,119, 35, 85,129, 0,134,181,188,202, 72, 5,128,210,110, +164,121,139, 34,115,126, 99,150,201,150, 78,208,177,215, 21,236,173,125, 91,218,250, 75,126,181,187, 55,113,190,246, 44, 91, 95, +135,148,129,156,147,147,205,212, 31,144,244, 3, 58,243,202,158,132, 96,121,118,234, 51,223,167,152,213, 84,132,144, 83,212,144, +122,231,250, 71, 93,121,229, 7,168,206, 61, 58,103,231,212,233,216,126,242, 48,223,133,202,123,243, 12,118,207,203,183,111, 61, + 32, 14,126, 17,140, 14,161, 90,245,202, 0,199,235, 2,114, 60,191,110,190, 5, 15,139, 57,201, 32,114,253,216,239,161,239,192, +233,108,123, 39,162,135, 78,189, 62,195,246,249,106,136, 10, 78,112, 73, 80, 61,113,230, 62, 64,254,122,234,166, 18, 83,202,122, +103,184,207, 81,130, 49,223,236,215,174, 80, 6, 9,201,199, 47,111, 46,189, 71,203, 89,192, 63, 27, 96, 53, 1,149, 31, 49,140, +143,183,211, 84, 10,122,103,152,159, 49,204,115,211,229,233,253,186, 57,109,140, 0, 0, 42, 35,161, 61,188,137,207,221,161, 86, + 58,145,216,118,198, 58,231, 30, 93,116, 48, 63,158, 1,112, 96,228,246, 63,119,203, 84, 21,220, 28,101, 35,160,235,242,245, 31, +102,138, 90, 22,121, 72,232, 51,231,247,231,247,104,117, 39, 61, 58, 2, 59, 96,249,104,234, 64,191,160,198, 65, 55,247,255, 0, + 60, 14,160, 50, 60,137, 24,206, 58,103,203, 61, 58,234,146,135,124,156,121, 99,160, 31, 51,219,236,252,116, 73,206, 49,128, 51, +231,231,251,123,106,130,209,216,142,152, 32,159, 63,195, 75, 14,184, 84, 94,215, 29, 79,250, 96, 55, 19,215, 9, 7,190, 79,166, +113,212,157, 10,180,231,174, 51,219, 30,163,230, 61,124,245,112, 94, 8, 35, 56,199,150, 58,254, 63, 97,208,174, 36,246, 79, 78, +132,250,231,203,175,160,237,165,148,155, 11,141,240, 1, 23,176,233,128,148,158,253,122,158,192,247,206,126,126, 93,116, 42,219, + 61,126, 33,142,248, 29,128,238, 64,251,180, 98,130, 72,235,144,115,140, 99, 39,215, 61,190, 90, 29,105, 56, 32,252,142,124,190, +223,195, 58, 58,223,238,254, 95, 39, 6,192,106, 72, 24,199,207,169,245, 30, 90,160,176, 6, 79, 92,227,183,145,249,118,249,104, +165,167, 61,148, 78, 62, 93,254,239, 93, 12,179,220, 30,157, 60,198,115,242,249,127,110,150,193,148,246,192, 42, 80,207, 64,115, +230, 7, 95,188,250,119,213, 21, 12,100, 99, 63,179,231,162,150,129,220, 12,103, 57, 35,191,246,104,101, 2, 7, 81,158,249, 35, +174,127,183, 74, 39,124, 40,187,129,129,212, 62, 68,122,250,125,199, 84, 23,140,143, 92,117,213,117, 19,215,184, 4,231,175, 66, + 79,245,106,130,251,142,158, 93,255, 0,118,149, 29,122, 95, 24, 34,198,227,107,126,239,159,158,216, 20,140, 18, 59,227, 75, 95, + 85,250,199, 75, 75, 13,192, 56, 53,129,222,221,113,224, 31, 34, 70,125, 6,170,115,117, 4, 36,146,112,146, 71,252, 62, 67, 84, + 57, 57,156, 74,190, 46,131,167,126,189, 72,198, 14,138, 73, 72, 0,249,103,174,123,247,243,198,181,201, 39,189,191, 44, 27,238, +190, 43,164,129,129,211, 63,236,245,233,243, 58, 32, 97, 35, 36,140, 31, 65,231,246,249,232,100,242,133, 16, 14, 78, 58,158,157, + 7,144, 58, 37, 4, 36, 28,167,155, 7,168,239,223,182,147, 44,119, 29,113,140, 86, 9, 88, 80, 33, 67,148,142,189, 58,147,229, +223,183,125, 16, 27, 14, 36, 37, 73,206, 14, 71,113,233,215, 84,146,114, 59, 96,121,126,113,162,219, 33, 61, 20,122,227,203, 61, +135,228,105, 51,107,111,211, 4, 38,221, 6,253,190,126, 24,172,132,132,167, 25,192, 31, 46,167,238,209,141,168,114,132,252,186, + 31, 95,234, 58, 17, 41, 24, 32,168,146,115,128, 59,159,179,174,138,108, 18,115,203,216, 12,131,215, 0,103,174,144,194, 71,174, + 42,227,160,207, 92,117,206, 62,223, 33,242,209, 40,194,176, 79, 64,124,186,245, 61,190,239,236,213, 16, 1, 81, 29, 64,242,237, +249,245,209, 45,130, 6, 1,237,228,113,147,251, 59,104, 99, 7,241,193, 13,224,100, 14,158,159,183, 68, 33,125,121,112,122,103, + 36,117, 25,207,111,219,170, 8,237,156, 12,250,116,207,217,159, 61,101, 86,165,169,113,222,213,218, 85,175,104,208,234,151, 29, +199, 92,154,205, 58,143, 67,162, 64,145, 83,170,213,103, 62,174, 86,162,193,129, 17,181, 57, 37,226, 79, 92, 12, 36, 30,101, 16, +144, 78,144,150, 68,141, 93,157,130, 34,110, 73, 54, 0, 1,212,158,192, 96, 14,194,219,159, 78,228,237, 97,234, 73,216,119, 56, +239, 95,177,184, 52,198,205,241, 34,250, 82,145, 37,219,203,111,154,116,243, 97, 74,140,138, 52,229,161, 36,121, 36, 56,165, 99, + 62,127,102,186,125, 58,178,168,165,224,240,108,180,227,106, 45,243,168,133, 3,219,224, 41,253, 99,156, 28,124,181,130,123, 43, + 61,153,123,231,176,246, 46,230, 76,226, 66, 69, 19,109, 99,238,172,123,102, 85,189,105, 61, 82,102,161,115, 83, 77, 53, 47, 41, +114,110, 56,241, 22, 91,166,201, 83, 79, 37, 41, 96, 41, 78, 35, 7,156,131,211, 91,183,187, 60, 21, 87,216,164,202,171,216, 55, + 44, 43,172,211, 80,185, 34,157, 13,254, 73,133,108,167,153, 73,110, 58,212,124, 76,167,200,119,206,185,175,140,211,219,115,250, +250,186,121,150,106, 87, 41,102, 86, 4,217, 99, 69, 62, 95,180, 64, 96, 69,237, 98, 6,161,177, 7, 30,160,125, 30, 51, 92,167, + 42,240,231,133, 50, 92,240,205,148,102, 10, 42, 3,172,240, 74,138,188,202,201,222, 50,206,202, 2,106, 70, 70,243, 90,193,183, +223, 26, 33, 89,187, 38, 56,211,173, 73, 82, 68,134, 29,100, 33,180, 43,195,241,146,165,129, 30,115, 42, 79, 82,234, 84, 82, 20, + 61, 53,220,158, 22,104,113,246,115, 98,169, 87, 66,163,180,230,226,223, 48,159,157,245,162,217,109,215,233, 84,130, 15,134,212, + 53,167, 42, 99,197, 78, 84,181,167,226,199, 98, 53, 30, 10,163,245, 54,234,111,196,144,202,209, 82,166, 75, 80,109,137, 72, 83, + 78, 49, 38, 59,153,147, 79,146,210,250,165,126, 35,100, 96,227, 24,215,127,118,138,242,164,110, 62,192,109,157,106,149, 47, 30, +229, 76, 54,197, 89, 17,150, 68,186,101, 86, 23, 51,106, 97,104, 7, 45,130, 23,217, 88,202,117, 28,118, 20, 81, 23,136,105,153, +198,204, 58,139,149,189,143,111, 45,236, 65,254, 3, 29, 5,199,185,104,158, 14, 29,203,164, 80,217,101, 77, 86,170,133, 93,209, +180,199,170, 20, 96, 14,241,187, 6, 37,127, 93,148, 45,136,181,242,106,229,223, 42,176, 31,122, 91,235, 11,114, 43,173, 63, 43, +152,169,199,159,143,135,153, 45,243, 30,101,243,182,162,159,187,215, 88,194,171,109, 42, 52, 22,155,105,229, 73,168, 62, 22,203, +206, 5, 45,198,219, 49,203, 37, 62, 31, 54,124, 70,223, 9,248,135, 92, 47,174,172,242, 97, 74,133, 54,150,235,136, 92,152,237, + 58,252, 89, 13, 45, 92,139, 46, 50,219,136, 74, 20, 9,248, 28, 41, 32,143, 62,190,122,188, 83, 18,164, 54,242,101, 71, 65,114, + 44, 22,132, 53, 40,114,187, 30, 75,239, 23, 82, 65, 72,234,224, 65, 70,125,121,117, 30, 87, 45,172,129,168,158,155,237,126,135, +115,211,189,187,236, 62, 56,127,142,130,130,138,154, 49, 79, 24,120,134,234,170,193,123,180, 96, 91,169, 10, 66, 18, 15,151, 77, +128, 4,226,231, 71,140,106,110,203,144, 95, 44, 50,131, 42, 92,249, 46, 56,161,202,196, 32,136,201,141, 24, 96, 36,190,183,201, +194, 51,149, 21, 28,117,214,187,111,102,251,181, 33,243,106, 81,228, 61, 14, 37, 33, 97,130,251, 50, 21, 30, 63, 51,105,194,152, + 98,106,148, 82, 95, 81,200, 60,195,245,138,142, 20, 14, 19,125,222, 75,250, 78,218,216,238,219,180,169,142, 42,187, 85,231,169, +204, 91,107,109, 14,183, 50,106, 86,182, 24,105,167,112,133,173,168,202, 43, 80,230, 79,199, 45, 56, 33, 67, 58,228,228,187,229, +250,132,217, 47, 75, 67,178, 96, 58,242, 83, 61,164, 56,226,208,226,208,181,175,198,125, 46,167,157, 35,226,117, 68, 43,152, 40, + 32, 32, 40,140,101,246, 58, 73, 18,147,146,135, 76,211,128,242,145,107,170,177,186,198, 9,237,250,205,184,185,216,218,219,233, +112,238, 72, 56,183, 63,169,204,229, 28,252,143,135,165, 49, 82, 40, 35,235,170, 18,203, 36,204,173, 96,202,132, 24, 98, 13,183, +146, 66,118, 56,218,122,181,245, 81,114,145, 37,110, 60,103,198, 97,207,125,165, 84, 31, 79,131, 90,163,190,219, 97, 10,108, 48, + 26, 9,169, 66, 90, 80,227, 47,128, 80,181, 33,204,169, 42, 79, 34,145,144, 27,238, 36,202, 77, 46, 61, 71,146,158, 91, 77, 34, + 80,129, 80,121,196,192,149, 37,107, 67,234,250,134,230,105, 96,211,223,104,169, 92,205,169, 77, 58,128, 83,145,140, 41, 90,141, + 75,174,173, 77,251,204, 9, 44,170,156,220,176,219,244,224,164,200,165, 79,117,183, 20,184,138, 75,160,173,218,100,118, 89, 33, + 75, 40,230, 73, 95, 94, 82, 7, 38,179,218,117,105, 35,154,151, 61,164,211, 34, 50,180, 74,121,186,147,237,205,163, 21, 60,162, + 29,110, 35,204,164, 37,216,238, 48,180,134,146,248, 5,180,189,243,232,211, 62, 92,169,112,162,228, 27,221,109,123,121,123, 16, +109,110,225, 46, 44,215,186, 62,199,161,242,220,190,156, 36,113,114, 47,203,109,107,162,234,192,145,231, 26, 47,177,110,190, 75, + 27, 13, 65,145,137, 24,220,138, 82,100, 86,167, 67, 85, 85, 5,217, 21, 54, 83, 26,153, 91,143, 41, 84,218,173, 77,175, 19,157, + 16,100, 78,167,184,142,105,169, 96,169, 46,243, 41,104,121,178, 22,223, 34,202,155, 23,250,140,137, 20,138,148,138,125, 82, 20, +234,253, 56, 69,122, 35,244,247, 86,135, 43,244,199,152,112, 33,197, 60,228, 96,159,173,226,132, 50, 84,121,113, 53,165,176,135, + 82,167, 71,194, 53,242, 20, 11,121, 84,166, 35,198,155, 38, 4, 37,169, 19, 41,142,209, 42, 19,225,165,233, 62, 34, 25,142,226, + 80, 30,113, 17,157, 66,149,252,196,164, 18,216, 82, 84,115,167, 38,148,205,126,152,227, 49, 97,220, 38,171, 81, 86, 91, 68, 26, +187, 13,248, 14, 69, 97, 62, 35,143,138,156,112, 22,101, 41, 15, 18, 22,226, 10,194,136,230,230,233,134,127, 42, 6, 37,206,199, +117,101, 43,181,186,143,180, 75, 2,110, 73, 96, 5,128,176, 42, 44,157, 77, 28, 1,181, 71, 86,166, 56,195,160,133,227,150, 34, + 10, 48, 60,200,165, 70,147,146,168,163,204, 71, 45, 85,148, 2,193, 25,163,195,167,111,214, 86,203,172,196,137, 45,186,155,174, +161, 10,167, 73,203, 62,227, 94,136,211,232, 33,202,160, 82,127,192,238, 54, 24, 88, 10,120, 37, 1,208,149, 43,151,151,153,182, +170,166, 34,105,117, 25,181, 40,161, 79,194,159, 53, 78,221,148, 2,130,244,202, 62, 11,173,203,168,196,140,210,177,239,188,139, + 79,188, 52,148,143, 25, 25,113,159,210,140,171, 8,167, 26, 85, 94, 65,131, 35,235, 11,102,226,130, 87, 49,132, 48,166, 27,155, + 34,167, 24, 20, 49, 81,133, 37, 81,151, 26,170, 90,112, 31, 21,124,188,252,170, 13,201, 72, 73,201,204,105,149, 74,157, 57,200, +147,110, 38,154,139, 18, 67,205,195,153,115, 70,104, 51, 79,155, 83, 70, 23, 21, 85, 85, 0,161, 70,146,242,249, 2, 78, 76,126, +101,128,219,173,128,148,235, 34, 80,196, 0,231, 83, 92, 1,220, 90,204, 10,145,112, 0,185, 42, 1, 2,236,108, 45, 99,136,197, +109, 57,134, 90,147, 78, 60,243,173,165,136,149, 15, 48,189,215,148, 86,241,202,190, 93, 81,152,134,165,148, 13, 11,202,242, 35, +169,110,248,110,177, 16, 67, 42,158,104,128,170, 20,215, 22,194,141,110,142,176,131, 25,131,225, 54, 11,133, 84,196,180, 99,164, + 18, 82,252, 36, 58, 2, 73, 90,181,243,137,137,169, 94,219, 91, 8,140,165,159, 30,241,143, 84, 66,139,156,202,240, 96,192, 62, + 18,156, 82,206,124, 78, 89,140,129,203,241, 21, 30, 76, 19,163,109,106, 99,148,203,129,215,161, 22,149, 70,170, 36, 45,108,171, + 31,224, 53, 5,243, 58,217,101,215, 79,193, 25, 79,185, 33, 32, 39, 1,165,190, 66, 50,135, 15, 45,187,123,227, 46,167, 87,178, + 45,198, 26,115,194,143, 66,171,214,144, 26, 91,156,200,171, 26,148,118, 84,145, 31,151, 10, 8,167,198, 11, 4, 31,135,197,207, +235, 37, 39, 74,201, 56, 20,179, 48,220, 2,160, 89,137, 27, 48,218,251, 92,218,224, 27,108,182,181,237,189, 90,213,112,199,197, +185, 37, 66, 63, 50, 26, 82,245, 33,186, 21, 2, 41, 29,149,214,224, 41, 89,127, 85, 64, 0,155,129,164,168,195,121,106,210,157, + 49, 16,180, 67,123,221,105, 23,132,151, 98,143, 8,133,181, 9,233, 2,160,114,132,149, 41,152,202, 77, 80, 0,122, 20,224,133, +140, 19,174,145,216, 85, 22,174,139, 58,117, 20,167,255, 0,116, 45,215,218,183, 92,253, 48,116, 59, 66,168, 71,135, 84,162,201, + 91,137, 33, 46,115, 83,165, 76,101, 96,101, 41, 92, 44,103,200,106,117,145,110,169,112,231, 15, 1,196,123,195, 84,153, 12,178, + 20,148, 41, 94, 28, 38,226,200,119,157,100,120, 95,165,138, 1,112,228,146,114,114,161,173,186,219, 8, 70,145, 86,150,137, 9, + 45, 70,158,138, 76, 55,148,216, 65,109, 45,150, 86,152,239,128, 57, 65, 12, 75,229,234,122,225,213,148,244,209,114,119,104,171, + 4,128,125, 92,254, 87,191, 96,110,192,158,223,104, 2,109,189,142,214,189,197,123,226,102,115, 14,101,151,130,175,170,167, 41, +126,116, 54, 59,220, 24,181, 41, 23,243, 93, 94, 65, 97,177,125, 39,160, 56,182, 92, 20, 69, 77,185,225,210,208,218, 12,121,177, +214,245,101,132,175,147, 20,200,207,169, 77, 67, 12,161, 64,187,239, 14, 55, 24, 58, 82,112,164,176,232,229, 32,231, 94, 29, 77, + 69,138,133, 70, 29, 29,163, 30,174,236, 24, 12, 74,171,176,182, 29, 93, 18,157, 80, 46,135, 10, 99,172, 22,209, 86,126, 34, 28, +247, 86, 74,249, 90, 42, 50,212,149, 37,164,133, 61,149, 74, 50, 96,174,108,231,227,148, 73,104, 70, 98, 34, 90,232,251,142, 52, +174, 65, 30, 63, 46, 28,230,126, 90,201,119, 25, 60,138,113, 64,225,189, 82,183,173,152,148,155,102,178,203,203, 68,215,166, 72, +114,183, 95,156,227,173,149, 84,171, 51, 30, 74, 27, 67, 12,173, 36, 52,203, 81,219,102, 60, 68,130,144,203,109,165, 36,133,120, +138,212,193, 31, 77,212,144, 72, 34,198,251, 27,245, 44, 15,154,214, 6,230,224,239,182,149, 3, 21, 18,113, 76, 43, 65, 3, 50, +137,214, 49, 12, 40,135,117,121, 29,209,158, 71,223, 75, 42, 46,136,204,108, 8,145,132, 74,193,144, 72, 75, 74,213, 54, 21, 45, + 76, 91,246,218, 94,139, 17,193, 28, 86, 29, 14, 46,115,208,212,249, 67, 77, 64,167, 72,144, 20,185,149,135,226,180,158,101,145, +202,195, 40, 83,141,144,227,200, 2,245, 21,216, 52, 92,248, 96, 70,161, 83,252,103, 98,197,145, 15,156,115, 78,109, 49, 66,157, +109, 1,110,205,152,167, 16,175,119, 65,203,206,130,172,229, 69, 42, 23, 85,184,213, 38,116,122, 77, 49, 30,243,112, 48,191,122, +156,175, 0,120, 52,218,131,205, 97, 18,106, 83,146,149, 4,194, 76, 0,146, 91, 88,241,164,101, 41,109,188,184, 10,126, 34,216, + 84, 0,137,213,234,155,149, 73,236,160, 76, 76,164,176,212,104,116,198,150,183, 7,131, 18, 42, 93,229,167,198,253, 69, 23,214, + 76,149,151, 57, 71,195,200,157,109, 69, 33, 82,243, 60,133,180,234,176,248,250,244,211,107, 91,226, 72,211,167,112,188,181,209, + 76,160,213,204,197,106, 0, 96, 24,179, 79, 82,204, 72, 51,121,144,128, 10,249, 98,149,218,225, 28,149, 89, 27,152,205, 94,144, +220,249, 80,209, 79,171, 70, 91, 20,181,184,135, 92,141, 50, 72, 14, 84, 76,118, 19, 36, 34,177, 25,151, 21,138,119,187,114, 19, + 21, 68, 12,117,150,149,132,150,213,150, 54, 98,220,136, 16,188,119,163, 67,101, 5,113,196,105, 72,165,185, 82,119,197, 5,126, +248,228,114,219,144,233,141, 70, 67,104,106, 56, 82,124, 82, 79,136,218, 88, 9,105, 88,156,247,222,169, 82,227,191, 45,232,212, +218, 11, 78, 71, 98, 59,143,161,113, 39, 84, 75, 46,153, 13, 76,172, 45,229,243, 37,135, 29,104,251,180, 52,101,110, 6,210,236, +148,169, 74, 12,138,140, 74,153, 50, 51,206, 33,177, 76,164,162, 59, 73,171, 73, 72,104, 78,168,197,125,231,124, 63, 6, 48,109, +102,142,200, 60,234, 28,229, 82, 93, 7,244,104,105, 39, 91,241,105,141, 99, 37,254,169,195, 11, 90,214,220,144, 53, 30,151,233, +216, 2, 62,226,207, 81, 79, 37, 64, 53, 1,150,150,100,144,129,164,144,145, 57, 33,117, 0, 73,102,157,197,144,162,146,201,229, +185, 91, 7,133,199,163,200,101, 79,198,131, 70,106, 76,183, 83, 33, 17, 40,212,166, 60, 24,241,189,234, 27,101,247,106, 85,121, + 13, 51,138, 77, 9,190, 85, 34, 58,146,217, 82,185,213,225,182,227,202,108, 33,244,163, 51, 30,132, 13,122,179, 61, 46,206,167, +178,218,106, 21, 83, 17,198,105,113, 16,255, 0,130,203, 84,152, 48,121,220,112, 58, 60, 70,144,219, 72, 14,202,154,226, 91, 75, +137,117,229,164, 37,133,166, 84,233, 54,205, 18,152, 42, 78, 72, 74,100, 38,109, 70,157, 75,167,176,101,215,110,185, 45,168,183, + 26, 21, 45,132, 58, 22,233, 81, 25, 47, 73, 45, 70,101, 9, 42,121,228, 37, 28,165,217,183, 32,206,171, 85,105,149,250,165, 82, +149, 14, 75, 94, 12,218, 69,174,167, 26, 93, 42,136,182,199, 51,171,157, 33,213,135,234, 53, 63, 17,100,187, 57, 41,104, 33, 40, + 8,142,218, 24, 74,121,221,169, 86, 22, 72,193,212,205, 96,202, 46, 67, 48,184, 22, 31,101,130,133,184, 4, 88, 49, 35, 72,181, +216, 86, 28, 81, 1,116,150, 73, 25,169,242,225,205, 66,229, 73,146,164,163,105,104,209,130,181,131, 0, 76,135, 75, 68,143,118, +149,228,145, 98,129, 95,138, 36,233,202,152,138,141, 93,169,141, 69, 80, 30,227, 5,244, 43,222, 82,165, 36,243, 74,171,176,208, + 41,106,160,226,222, 82, 83, 28,169, 98, 40, 10, 73, 90,220,201, 68, 52,254,150,111, 2,144,225,187,179,158,209,187, 10,132,211, + 79,213,165, 82,118, 15,137, 25, 20,246,210,148, 75, 91,140,190,246,200, 95,117, 36, 32,115, 57, 41, 10,102,175,109,202,146,122, + 41, 18,232,108, 40,225,134,134,166, 17, 71,172, 75,173,183,254, 28,202,224,136, 19,125,223,220,189,237,247, 37, 21,179, 37,214, + 81, 80,121,191, 1, 45, 16,166,130, 31,105, 33,106, 75, 76,149, 56,163,206,177,200,205,113,141,195,133, 51,141, 78, 12,248,147, +225,150,176,148, 59, 23,119,182,166,230,182,237, 57, 15, 97,150,105,151,140, 70, 87, 85,176,107,200, 50, 27,253, 3,177,111, 58, + 93,191, 49,181, 28, 41, 2, 57, 60,193, 74,200,158,100,149,102, 22,210,191, 88,166,198,203,123,107, 2,250, 84, 17,179, 17,170, + 37, 36, 88, 6, 45,176, 1,135, 60,241, 94, 80,210,197, 55, 50, 52,167,146, 27, 38,149,177,141,119,250,189, 44, 46, 13,254,219, + 16,222,117, 4,220,220,223,242, 16, 41, 10, 0,121,103, 35, 29, 63, 35,174,144, 0,146,129,231,232,122,252,251,246,242,213,103, +105,213, 58, 52,201,244, 90,252, 69,192,174,208,170, 53, 26, 21,114, 3,128,135, 96, 86,232,211, 30,166, 85,233,238,115, 96,133, +177, 82,139, 41,165,103,205,147,175, 33, 3, 57, 79,194, 14, 78,124,199,203,236,212,253, 72, 96, 25, 78,160, 70,198,251, 27,216, +220, 31, 76, 83,251,247, 22, 56,241,142, 65,215,160,207, 76,143, 35,229,243,210, 78, 79,144, 72, 39,250,186,145,142,218,250, 74, +136, 25,198,115,208,129,220,124,245,247, 36,146,124,191,217,244,236,126,205,103,127,191, 3, 30, 72,200,230,229,206, 58,121, 15, +199,215,251,117,236, 5, 31,245, 72,242, 7,190, 62,223, 76,233,114,133,144,114,164,245,198, 7, 65,219,215,238,215,190, 92,127, + 56,224,103, 31, 47,191,211, 67,221,233,129,138, 43, 71,124,156, 15,196, 14,221,186,244,208,171, 3, 3,191,166, 64,201,249,119, +249,234,232,212, 41,147, 22,132, 71,105, 74, 46,186,134, 91, 32, 16, 29,125,194, 18,211, 12,249,188,250,213,209, 40, 72, 43, 89, + 56, 72, 39,166,186, 71,195,191,178, 43,142,110, 36, 99,196,171,219, 27, 61, 83,178,237, 25, 97,151, 26,188,247, 98, 90, 54,206, +131, 38, 59,229, 63,225, 52,182,171,241,205, 66,178,148, 52,175, 16,166, 60, 5,115, 36, 97, 43,202,147,157,121,171, 41,169,236, + 37,148, 43, 55, 69,234,199,224,162,228,159,112,198,205, 37, 29, 93,124,188,138, 26, 89, 43, 38, 29, 86, 36,103, 32,122,182,144, +116,143,123, 88,123,241,204, 5,140,156, 36,231, 29,252,135,224,124,251,232,117, 0, 14, 70, 1, 7, 7,183,159,203,207,166,117, +177,124, 80,240,223,126,112,157,189,183,214,195,110,107, 49,211,119,216, 53, 54, 96,207,155, 77, 84,151,104,213,200,115,224,199, +169,209,174, 75,118, 76,184,204,185, 50,223,157, 79,148,219,177,157,113,166,212, 74, 28, 66,144, 20,218,181,174,203,234, 48, 7, +159, 79, 94,255, 0,111, 83,141,108, 83,203, 28,200,146,198,218,163,144, 2, 58,142,190,160,216,223,220, 69,240,155,199, 36, 18, +203, 12,200, 98,158, 22,100,116, 59, 50,178,157, 44,164, 14,132, 16, 65,247,140, 12,160, 58, 18,122, 12,253,253, 63,179, 67,171, +168,200, 61, 58,140,249,227,207,167,231,182,138, 63,173,208, 17,223,167,203, 25,201,252, 53, 69, 64, 1,142,253,115,246, 15, 67, +173,144,108, 65,244,198, 70,227,125,199,254, 48, 26,129,245, 28,189,186,140,125,224,250,245,208,171,192,201, 25, 7,255, 0,104, +122,103, 69,184, 70, 72, 57, 0, 30,195, 29,124,186,126, 31,179, 66, 47, 62,163, 30,158,121,249,116,210,202, 73, 23, 56, 0,108, + 61, 54,192,202,193,193,193, 4,247,206,116, 58,199,159,175, 67,233,162, 87,235,229,140,122, 96,250,252,244, 58,129,201,200,200, +251,113,131,219, 56,209,199,198,216, 54, 6, 88, 0,100, 39,175,203,167,231,251, 52, 43,131, 39, 36, 2, 64,236, 58,254, 63, 61, + 22,231, 76,100,244,201,251, 60,134,132, 80, 30,188,221,127,104,193,245,251, 52,170,155,223,107, 91, 25, 22,223, 2, 44, 12, 18, + 70, 49,219,212,117,237,161, 87,243,234, 15,111, 44, 31, 92,249,249,232,197,140,103,249,222,127,105,251, 6,133,115, 24,236,123, +246,244,239,223,229,165,147, 10,139, 27,123,190,126,126,252, 12,188,246,199, 76,103, 62,152,254,142,154, 13,206,249,201, 78, 51, +156,140,231,211, 31, 46,250, 49,194, 2,122,244,243,207,151, 79, 93, 90,212,167,148,162, 20, 50,159, 34,158,248, 35,184,244,210, +152, 2,247, 55,232, 48, 59,171, 82, 85,220,156,231,177,199, 79,179, 75, 84,137, 89, 82,129, 64,192, 61, 9,238,125,123,157, 45, + 11,159, 92,102,195,211, 7, 1,145,228, 49,230,115,215,175,153,251,245, 85, 41,199, 65,212,158,255, 0,159, 77, 82, 78,114, 7, +145,207, 79, 35,223,203,237, 26, 37, 0,231, 61, 49,231,219,242, 53,130, 1,198,113, 85,164, 37, 39, 24, 29, 70, 51,230,123,121, +232,129,156,245, 31, 8, 29,193,235,233,231,223,190,169,163, 29,176, 58,117, 7, 26,244,121,242, 2, 82, 20, 60,250,224,142,189, +251,246,210, 76, 0,248,223, 3, 5, 39, 29, 51,146, 59,252,240,123,103,174,138, 64,206, 8, 35, 31,183,240,208,109, 54, 70, 78, + 78, 73,235,147,144, 6, 78, 6, 51,215, 70,163, 57,233,142,157,199,203,229,162, 27,218,255, 0,203,124, 17,187,155,224,134,240, +161,156,231,174, 64,235,211, 29, 63,164,104,132,168,143, 60, 14,199, 24,243,245,249,127, 86,168,160, 96,103,207,203,243,246,141, + 16,132,224,228,245, 7,174, 63,160,231,215, 73, 16, 5,253,223, 39, 9, 28, 86, 71,127, 62,223,143,231, 58, 44, 1,220,122, 99, +160,192,252, 52, 58, 82, 7,219,143,207,238,213, 86,242,162, 60,134,112, 57,142, 0,243, 42, 62,128, 12,232,167, 5, 97,182,231, +108,101, 54,149,175, 93,188,238, 42, 37,171,108, 82,103,215,174, 43,142,169, 10,139, 68,162,210,216, 92,170,133, 82,169, 80,121, + 49,225, 64,134,195, 96,151, 31,113,229,164,118,194, 70, 84, 72, 0,157, 78, 55,217,195,236,235,180, 56, 5,219,136,183,189,229, + 6,143,114,241,101,120,210,144,245,197,112,186,195, 83, 99,109,101, 38,115, 41,113, 22, 77,152,167, 82, 66, 42, 9, 66,147,245, +132,212, 0,227,174,130,132,144,210, 64, 58, 65,236, 48,224, 78,145,183,150, 91, 28,115,238,229, 25, 47, 93, 23, 10,101,211,120, +127,163, 84,163,165, 73,163,211, 57, 87, 30,165,184, 46, 48,226, 73, 76,201, 4, 45,184,107, 35, 40,101, 37,105, 33, 78,103, 93, +206,171,207,168, 77,158,242,214,234,165,120,206, 45,240,239, 57, 83,188,203, 36,252, 62,157, 9,239,170, 51,196, 46, 48,105, 37, +147, 42,160,151, 76, 16,146, 37, 96,109,169,129, 27, 92,118, 83,208,119, 32,181,143,145,135,112,125, 25,188, 13,143, 54, 16,113, +223, 19, 82,137, 17,172,244, 16, 72, 60,170,157,125,165,213,191, 93,246, 49,126,194, 16,247,212,254, 92,102,175, 95,155, 82, 46, +162,100,151,208,236,151, 84, 86,135,157, 83,143, 45, 96,146, 94,142,181, 28,149, 31,231, 39, 61,245, 66,141,115,205,137, 57,175, + 1,247, 75, 76, 35,195, 76,148, 41, 72,125, 46, 37, 67,149, 50, 80, 63, 89,178,122,100,246, 29,245,245,218, 59,147,164, 45, 78, + 62,215, 50,202,148,134,101,254,133,244, 62,145,140,180,188,124, 11, 56,232, 71, 67,171, 83,148,233, 49,170, 13,190,247,248, 44, +245,182, 90,104, 56,144,150, 39, 33, 63, 10,154,125, 67,225,241, 20,158,202,245,193,243,213, 56,106, 88,146,193,203,105,235,239, + 59, 19,191,201,199,127,158, 23,202,218,157,233,146, 24,236, 81,136, 80, 46, 1, 43,107,143, 46,174,130,197,183, 3,169,212, 47, +102, 23,138, 45,142,166,222, 16, 42, 27,183,108,211, 81, 10,232,163, 70,247,155,186,155, 13,174, 83, 92,132, 0, 8,170,165,134, +192, 6,115, 39, 5,106, 72,203,136, 86, 73,233,166,207,131,205,208,115,108,174, 89,118,133,206,234,163,216, 59,146,166, 20,169, + 42, 82,136,161, 93, 77,252, 49, 42, 33, 4,225,182,215,204,148,185,216, 20,171, 61,198,186, 27,110,114,132,166, 53, 69,148, 59, + 30, 90, 23, 25,101,236,171,154, 43,201,240,223,133, 36, 17,241, 35,145, 74,229, 39,161,215, 63,238,253,167,145,106,238,109,193, +110,177, 27,154,158,103,166,165, 71,109,208, 75, 65,135,207,188, 66,117,149,227,252,159, 41,228,233,219, 3, 75,181, 66,188,109, + 27,157, 72,221, 61,223,199, 99,123,219,220, 65,219,108, 51,192, 88,210, 85,228, 53,174, 76,116,104, 30,157,201,185,229, 35, 0, + 2, 19,125,224,147, 75, 37,239,101, 33, 13,213, 69,250,103,114, 80, 10,102,173, 46, 58,164,199,113,180,212,163,184,159,141, 18, + 38,180,144, 27,150,219,136,255, 0, 40,194,218,193,244,234, 52, 13, 53,152, 76, 85,228, 75,126, 75,175, 83,218,112,212,170, 11, +111, 28,170,135, 77,132,169, 78,242,115, 15,209,175, 45,242,143,153,236,117,227, 97,231, 85,171,148, 38,109,155,155,154, 91, 20, +248,232,126,139, 84, 87,199, 38, 34, 85,134,223,163, 74, 82,186,185, 28, 40,126,141, 95,205, 7, 30, 67, 69,110,125, 33,219, 19, +109,119, 58,172, 90, 66, 93,116, 66,166,211,214,225, 63,160,250,214, 82, 3,169, 64,233,241,150, 27,112, 39,168, 3,155, 62, 88, + 58,244,144,243,106,233,148, 11,197, 35,128,123,129,109,205,246,238, 6,199,184,235,108, 71, 42,184,155,216,242,188,198,154,162, + 95,237,180,208,232,140, 11, 90, 66,236,136,172,189,245, 3,160,145,212, 16,122,249, 73,227,159, 17,187,137, 50,231,190,101, 63, + 18,112,228,140,252,162,176, 30, 62, 10,228, 73, 82,164, 22, 95, 72, 63, 2, 91, 10, 66, 22,112, 8, 82, 66,185,126, 28, 29, 79, +145, 81, 80,168, 42, 68,213, 63, 12, 37,188, 63, 45,130,209,128,132,156,150, 26, 75,203, 73, 74,254, 39, 10,138, 92, 67,124,164, +229, 42, 25, 25,186,221,245, 35, 87,185, 43, 18,155, 90,227, 77,126,164,251,143, 7,129,118, 51,188,178, 11,120,144,148,242,135, + 91,232, 71, 50, 10, 92, 36, 36, 39,211, 88,139,213,131, 77,117,196,212, 27, 16,219, 83,220,225,196,169, 47,211,101,161, 71,194, + 11, 92,133, 4,174, 9, 66,203,105,113,183,145,240,248,193,124,202,108,130, 38, 34, 59,179, 29,137,125,253,230,246, 63,127,165, +250, 13,186, 11,218,248,225,108,186, 60,159, 36,202,104, 33, 80,239, 79, 18, 6,232, 36, 44,108,206, 88,216,171,134,102, 58,137, +189,193,232,183,182, 51,138,107,197,167, 35,145, 32,194, 75,137, 45,162,170,204,129, 26, 59,172, 0, 57, 16,250, 88, 42, 67,173, +168, 44,132, 33, 97,105, 81, 89,194,193,192, 15, 21,183, 34, 93,189, 17,133,173,196,213, 88,150,133,188,239, 51, 44,199,149, 29, + 45,142, 86,210, 82,135, 2, 38, 68,112,144,144,148,168, 41, 39, 32,133, 0, 2, 89,200, 80,154,117,109,186,212,100,199,139, 80, +101, 13, 33,216, 78,199,114, 51,238, 37, 74, 91, 78,189, 27,148,178,231, 80,164,172,130, 9, 41,201,238, 14,179,250, 11, 83,227, +182,194,154,145, 2,161, 25,212,187, 44,196, 66,213, 18,124,111, 5,107,100,166, 20,148,169,198,211, 12,115,175,153, 42, 74, 80, + 70, 78, 78, 51,166,186,192,172,178, 6,109,136,220,117,189,189,227,117,177, 30,160, 27,119,233,139, 14,158,162, 39,142, 0,101, + 66, 93,128, 10,247, 70,216,130,108,214,176, 96,108, 65,243, 95,175,187, 27, 7,111,210, 27,168,182,211,116,199,151, 78, 75,232, +110, 83,209,169,177, 26,125, 10,125, 72, 91,143,187, 34, 34,142, 34,172, 0,129,128,132, 45, 73, 72, 9, 43, 56, 80,206,163,202, +184,216,125,223, 26,158,154,225, 56, 80,114,142,180, 69,150,162,178,150,227, 46, 61, 62,106,200, 76,129,146, 74, 91,146, 28, 87, + 54, 67,121, 73,211, 37, 69,159, 9, 83, 19, 42,175, 34,171, 13,106, 74,227,154,156, 84,200, 79,185,120,108,229,135, 25,169, 81, +213,250, 96,176,134,208,128, 65, 64,248,130,145,141, 58,116, 74,219,236,148,159,175, 97, 86, 33,180,182, 20, 87, 17,108,199,169, +180,216, 91,106, 47, 79,130,128, 61,245,230,208,113,204,207, 34,215,156,148,247,212, 94,170, 25,163,109,148, 76,140, 5,245, 41, +218,254,142, 8,213,107,116, 44, 47, 97,229, 55,198,205, 75, 85, 29, 71,255, 0, 73, 68, 85, 96,178,164,159,111, 98,202,179, 71, +229, 98, 69,134,130,202, 77,238, 0, 83, 96,239, 82,107, 84,106,164,152,205,214, 16,245, 17, 75,247,101, 22, 43, 1,232, 83,105, +203,136,165, 50,229, 98, 34,151,202, 17,226, 61,202,145,202,178, 48,162,146,142,250,216,251,105,128,186, 36,170,100,211, 22, 67, + 77,176,209,122, 60,214,153,145, 30,167, 10, 65,240,214,164,164,158, 79, 13, 73, 45,115, 37,224,181, 33,120, 81,230, 79, 42,131, + 59, 69, 16,106,201,139, 50, 64,129, 87,142,243,161,150,146, 80,211,168, 90, 71,134,148, 54,236, 25, 3,150, 43,129, 5,101,229, + 41, 92,199,162, 51,130,112,245,208,236,136, 14, 52, 88,165, 63, 50,139, 34, 51,197,246, 98, 51,239, 14, 83,216, 91,139,113,121, + 76, 73,110,172, 58,223, 48, 72, 13,160,134,135,112,144, 6,154,194, 70, 23,117,229,143,129,216,236, 71, 80, 47, 96,118,184, 4, +222,231,114, 6, 41,222, 44,205,105, 4, 73, 28,205, 45, 7, 45,193,177,250,212,141,149,187, 31, 44,137,107,144,124,172,109,102, +184,117, 1,243, 59, 82,158,154, 90, 88,167,200,142,181,210,164,169,181, 70, 81, 89,144,237, 61,164, 97, 8,142, 95, 89, 89,114, +156,227,128, 6,143, 58,148,202,185,146,172,161, 73, 41, 58,230,163,187, 82,190,163,190,164, 15,240, 15,170, 97, 12,245, 79, 47, +184,169, 46, 41,174,193, 14,169,111,140,231,161, 40,198,122,227, 89, 5, 18, 3,176,154,143, 6,166,202, 9, 1, 73,143, 61,174, +116,199,117, 99, 11,126, 47,134, 18, 84,193,229, 10, 37, 10, 37,180,225, 64, 40, 28, 13,100,168,166,120,245,217, 15,133,120,168, +146,220, 87,219, 46, 28,171, 6, 52,112,158,128,225, 60,175, 70, 87,197,205,140, 40, 16,112, 64,214, 42,193, 90,101, 10,126,211, +169,184,233,123, 31,188,110, 72,220, 3,125,207, 67,138, 55, 49,206,155,219,234, 42,132,129,216,197, 32, 46, 15,145,195, 50, 2, +235,191, 86, 80, 85,250, 18, 70,227, 86,166, 57,149,157,109,178,148,183,224, 71, 1,183, 35,200,142,217, 40, 25, 72,109,212,201, + 82,185, 20,122,144,165,158,100,158,128,171, 25,198, 50,253,209, 40,136, 75,137, 56, 90, 16,244,102,139,216, 60,229, 92,174, 20, +160, 14,224, 59,241,225, 62,105,200,244,214, 51,107,195,108,165,151, 16,146, 22, 20,133, 20, 2, 74, 64,121, 60,138, 65, 87, 76, + 96,117,207,114, 8,243, 3, 79, 5, 53,182,146, 64, 57,193,111,145, 35,178, 84, 80,226, 28,232,165,126,162,177,219, 31,234, 19, +220,105,223, 44,132,121, 88,223, 77,198,253,250,119, 62,253,247,252,113, 75,113, 30,119, 60,175, 32, 4,249,186,239,191, 91,252, + 54,176,222,214,184,191,174, 50, 89, 20,195, 81,143, 72,144,180,173, 79,134, 84,226,176, 3,206, 10,131, 10, 49,156,120,149, 12, +182, 3, 33,100, 31, 37,188, 73,238, 14,172, 46, 81, 36,215,106, 78,136, 82, 13, 46,159, 29,244,173,218,140, 98, 3,147, 86,130, +148, 42,159, 79,101,212,148,184, 90, 82, 9,117,242, 64, 39,157,182, 86, 64, 39, 89,163,142, 4,210, 26,113,106,112, 18,169,104, +109, 13,148, 32,151, 20,219, 9, 95, 85,156,163, 43, 88, 5, 64, 16, 3,157, 50, 73,215,199, 43, 45, 65, 83,113, 91, 14,161,136, +145, 25, 84,196,198, 1,231, 22, 91, 74, 20,150,219,107, 33, 42,116,156, 18,165, 16, 57, 84, 58,142,131, 82, 86,141,140,129, 80, + 14, 99, 42, 29,250, 93,128, 39, 98, 55,238, 64,233, 99,214,219, 98,176,130,186,186, 61, 66,153, 3,200, 12,138,151, 0,172,107, +174,228,216,130, 24,139,170,168, 32,128, 73,218,246, 35, 9,159, 71,167,209,161,120, 20,248,236,194,134,100,203, 91,178, 29, 95, +186,251,203,202, 90, 28,149, 81,118, 76,215,143,188, 39,196, 74,202,151, 33, 97, 35,155,151,196, 40, 72,195, 37, 84,174, 73,169, + 84,154,106,129, 77, 18,105, 49, 10,229, 68,157, 80,241,218,102,167, 32,224, 55, 84, 90, 25,111,222,102,198, 15, 5,251,154, 64, +109, 11,229, 46,180,231, 39, 33, 15,133, 74, 59,117,246,189,234,168,242, 95,136,212,199, 36,199,182,218,105,167,105,241,249, 74, +146,211,181,151, 92, 73, 53, 87, 2,149,206,150, 9, 76, 54,221, 64, 80,109,197, 32, 43, 88,189, 94,149, 6, 43,205,191, 86,230, +247,217,135,221,162,211,216,142,170,140,185,124,205,173, 45, 70,131, 10, 58,124,106,140,226, 75,124,160, 0,202, 50, 8, 82, 18, + 57,198,220, 72,224,134,210, 45,176,191, 96,122, 95,208, 6,189,206,219,216, 29,247,196,207, 33,174,134,153,155,219, 85,171,171, +156, 48,220,187, 89,207, 83, 96, 67, 75, 32, 91,221,193, 17, 45,216,175, 48, 50,178,224, 84, 74, 44,154,236,184,109, 72,113,234, +237,116,165,197,177, 54, 82,143,185,194,138,164,184,249, 16,105,241,143, 44,103,208,121, 50,164,146,226,240,182,220,119, 4,235, + 37,164, 65,153, 92, 80,137,106, 70,139, 82,125,151,164,197,155, 93,168,123,196,123, 46,150,251, 8,240,252, 17,238, 40, 42,185, +170,222, 34,155, 80,141, 16,150, 88,230, 75,114,101, 51,130,141,103,113,118,222, 84,228,199,126,232, 95,240,106,136, 16,215,189, +218, 86,235,201, 53,185, 52,220,146, 81,114, 92,236, 97, 49, 90,112,128, 36,194,166, 1,146,181, 52,236,199,138, 84, 53,147, 85, +149, 73,182, 92,129, 6,223,109, 81,169,207,198,147, 79,163, 83, 41,232, 5, 82, 81, 29,145,152,108,180,165, 54, 91,134,211,156, +200,113,210, 18,218, 3,193,103,153, 99, 39,101,145,165, 85,144, 39, 49,211,208,128,187,218,251,146, 58, 53,134,171, 94,215, 4, + 88,173,147,175,226,120,170,103,246,122, 6, 21,149, 44, 27, 66,168,189, 44, 37, 67, 23, 6, 68, 33, 36, 54, 58,210, 58,127,236, +202,171,173,165,149, 12,145, 11, 77, 10,223,167, 90, 47,203,153, 93,154, 39,203,117,178,229, 86,225,153, 22, 43, 10, 90,217, 97, +108,173,148, 73,109,194,197, 34,138,149,128, 98,176,158, 86, 18,160,180, 32,169,197, 18,171,243, 12, 71,188, 39, 42,174,205, 61, + 18, 45, 72,169, 45, 52,144,181, 82, 30,158,238, 86,184,179,219,134,160,218,163, 82,146,160,225,109, 14, 58,219,178, 20, 76,135, +249, 18, 91,109, 56,227,176, 25,153, 75,137, 81,185,166,184,212, 78, 68,193,165, 81, 33, 56, 20,195, 85, 39, 10, 11, 82,165, 48, +193, 47, 87,234,137,240,209,202,128,158, 72,168, 70, 91, 66, 74,214,240,187,209,162, 25,147, 29,241, 80,243, 20, 40, 45,185, 21, +234,107,146, 57,170,243,146,235,172,178,227, 19,125,225,132, 36,196, 91,197, 42, 68,112,151, 28, 82, 94, 80,113,210, 62, 13, 58, +210,106, 66,183, 75, 35, 17,168,117, 97,109,198,228, 16,111,212,237,190,224, 90,197,113, 23,172,103,117,158,190, 74,182,147, 48, + 80, 99,105, 64,211, 10, 1,101,209, 78,168, 99, 38,107,105,141, 52, 17, 20, 68,221,110,162, 55, 14,212, 81, 18,171, 73, 69, 54, +151, 80,170,193,183,229,135,231, 85, 42,149, 41, 47, 79,143, 80,247, 20, 52,203, 16, 98,229,240,126,168,115,170, 31,125, 39,149, +208,202, 26, 10, 40,231,230,113,232, 15, 68,139, 87,166, 53, 26, 60,198, 94,122, 51, 68, 71,148,250,148, 25,103, 63,162, 83,229, + 41, 41, 99, 37, 69, 44,160, 37, 60,201,103,152,129,206, 20, 27,135, 43, 8,141, 22,153, 2,220,110, 28,171,174,170,134, 89,142, +153,169, 66, 35,209, 88,108,174, 57,126, 80,125, 99,220, 96,135, 91,113, 92,141,161, 33,199, 27, 75,101, 92,216, 34,241, 2, 53, + 62,152,134,101, 34,161, 49,233,206,169,137,117, 56,178,156, 90,231, 45,245,190, 29,112,130,215,199,159, 17, 9,113, 10, 64, 72, +240,130, 80, 82, 83,212, 76,105, 31,217,222, 25, 64,230,104, 8,110,162,224, 1,102,223, 85,193, 99,246,172,183, 96, 73,103, 47, +101, 81, 84,230, 84,205, 52, 18,164,134, 72,163,156,202, 35,140,221,164,118, 98, 85,165,150,214,109, 39, 74,162, 72,246, 71,229, + 5, 65, 26,139,159,203,207,219, 83,176,204,240,223,237, 79,227, 35,111, 41,204, 69,139, 67,175,238, 80,222, 59, 98, 36, 38,195, +113,161,208,183,162,149, 7,112,132, 52,182,144, 3,101,170,213,102,182,215, 40,232,148,176,158,221,135, 48, 73, 36,100, 96, 99, +184, 61,250,246,212,159, 62,150, 45,137, 6,222,246,135,108,254,224, 66, 67,137,123,117, 56, 94,183,220,168,135, 22,209, 74,230, + 88, 87,181,215, 66,109,109,161,180, 2,209, 52,250,172, 0,176,165, 45, 68,165, 61, 64, 1, 34, 48, 64,228, 21, 18, 15,251, 56, +236,115,211, 86, 37, 3,171, 82, 68, 23,236, 70, 90, 53,182,195, 76,108,209,131,111, 66, 22,227,189,136,190,247,199, 60,230, 49, +152,171,170, 80,253,162,193,143,184,200,162, 66, 62,237, 86,255, 0, 76,120, 41,206, 48,160,113,145,142,217,207,150, 15,125,123, + 0,227,148, 14, 92,116, 63,209,247,244,215,220, 39, 25, 35,191, 83,230, 71,159,125, 87,109,178,242,146,134, 70, 92, 87, 96,172, + 36, 4,128, 84,165, 45, 71,162, 80, 0, 36,146,112, 0,201,233,173,195,210,228,218,223,187, 26, 93,174,118,199,134, 90,117,213, + 33,166,208,167, 28, 90,185, 80,132, 2,165, 40,158,192, 1,174,165,240, 33,236,163,226, 11,141,133,195,187,161,181, 31,108, 54, + 57,185,170,102,161,188,215,148, 9, 46,210, 42,138,140,234, 81, 54,157,182,214,243, 78, 53, 39,113, 42,232,234,133, 62,203,140, + 81,226,186,164,251,205, 65, 68, 45,141,111,127,178,155,217, 11, 7,117,232,244, 30, 38,184,174,161,203,107,103,231,248, 21,109, +173,218, 73,190,241, 78,168,239, 51, 13,168,169,155,182,242,228, 90, 36, 81,246,136,186,131,238,144,210, 90,151,113,134,203,171, + 91, 20,149, 36,203,150,181, 2, 36, 72,241, 41,180,202,125, 62, 5, 42,149, 74,131, 14,149, 68,162, 82,162, 70,166,209,168,180, +168,109, 37,152, 52,202, 93, 50, 19, 72, 98,155, 79, 98, 58, 66, 90, 97,150,208,219,105, 24, 66, 83,166, 25,243, 9, 42, 36, 48, +211, 63, 42, 59,216,200, 44, 75, 90,215, 17,131,112, 7, 91,187, 2, 54,178,171, 92,178, 89,124, 43,192, 18,102, 49, 69,153,103, + 74,240,208,200, 3, 69, 2,157, 18, 76,166,196, 60,141,179, 69, 19, 15,178, 22,210, 56, 58,131, 70,186, 89,244,203,132,143,102, + 23, 8,220, 37,199,165,207,176,182,222, 37,237,184,240,218, 71,188,239, 38,234, 68,167,221, 55,203,178, 8, 5,199,104, 48,157, +143,245,101,141, 16,184, 57,155,143, 75,138,210,217, 36,230, 83,228,243,158,151, 69,160,187, 49,126, 36,133, 58,235,129, 35, 46, + 60, 86,226,143, 94,131,153, 68,246, 24, 3,200,118,213,202,135, 74,248, 27, 28,132,168,164, 41, 71, 3, 60,167,178,137,239,204, +123, 15, 64, 52,232,211,232,248, 74, 64, 64, 35, 29, 71,146, 73,235,146,113,212, 96,254,205,107, 90, 40, 75,114,198,159, 86, 38, +236,109,251, 76, 73, 38,219,253,162,109,208, 91, 22,226, 81, 83,208,192,148,180,116,233, 71, 78,189, 18, 53, 84, 94,219,144,182, +187, 30,236,110,205,212,155,226, 36,191, 73,131,133,184, 14,237,254,198,241,107, 70,166, 37,170,205, 10,172,246,199,238, 12,230, + 90, 72, 51,232,213, 6,101, 92, 59,127, 50,122,210, 50,227,241,167, 51, 87,134,218,213,158, 86,166, 6,193, 0, 1,168,116,169, + 41, 33, 39,204,245,237,215, 39,203,251,117,250, 82,251,111,182,226,159,122,123, 47,248,158, 68,212,183,205,103,209,237,109,192, +166, 56,164,149,248, 53, 59, 98,234,166, 45,165,183,223,145, 74, 98,100,132,103,253, 85,145,219, 95,154,217, 61, 0, 4, 2, 74, +134, 8, 61, 7, 49,198, 52,227,147, 73,255, 0,165, 66, 15,216,112,195,220, 36, 0,159,222,225,201,223,169,197, 33,199,180,137, + 77,196, 45, 34, 0, 5,116, 17, 74, 69,250,190,167,136,155,109, 98,194, 32,222,246, 36,247,192,206,116, 56, 35,174, 1,207,238, +253,186, 25, 65, 61,243,212,246,243, 7, 26, 53,192, 0,199, 55, 83,220,158,189,254, 95,142,132, 88, 87, 83,128, 65,237,142,152, +192,193, 56,199,174,159,241, 15,192, 46, 18, 50, 66,124,241,246,227,185,249,232, 98, 58,147,216,252,251, 39,236, 30, 90, 53,207, + 47,191, 65, 58, 65,207,175,110,189,250, 16, 14, 52,178,244, 30,252, 20,218,254,159,207,182, 5,112,227, 39,190, 51,142,131, 31, +120,199, 78,154, 17, 68,242,243, 31,159, 40,251,126,126,154, 37, 72, 61,249,137,198,122,121,118,238,122,245,213, 5,161, 68,100, + 16,191, 34,124,135,231,247,232,227,183,207,254, 48,111,134, 5, 42, 36, 16, 71,124,114,231,182, 61,126,122, 29, 68,103, 25,234, + 1,232, 6, 0,235,229,162, 84,147,145,215,246,116, 0,106,130,240, 62,121,237,229,142,217,251,124,180,162,141,133,183, 31, 63, + 61,177,144, 1, 62,151,192,138, 73, 25,229, 57,201, 57,255, 0,103,240,208,221,251,232,197, 2, 50, 70, 0,235,156, 30,227, 61, + 50, 61,116, 50,192, 29,129,245, 39,203,236,252,116,170,117,249,219, 10, 40, 4,116,183,200,197,185,230,249,199, 41, 42,198, 70, + 82, 58,103, 25,238, 71,150,116, 51,141,184, 1,235,202, 2,112,144, 0, 36,143,159,167,158,174, 42, 0, 30,132,158,249,207,174, +132,121,178,164,158, 85,169, 7, 39, 24,254,119,219,234, 51,165,176,110,158,235,226,222, 82,148,255, 0,148, 36,147,212, 99,211, +208,244,239,165,175, 69,181,182, 0, 82,148,225, 61, 73,192,233,242,239,165,161, 99,233,140,227,210, 7, 92,249, 15,233,252,157, + 20,130, 49,129,223,185,251,245, 65, 32,224, 12,117,234, 63, 19,255, 0, 13, 86, 64,238,124,199, 76,122,104, 96, 96,148,167, 3, +175, 66,127, 28,126,227,253, 90,168,210, 0,200, 56, 61,207, 79,158, 58,231,243,223, 84,210, 73,233,142,131,166,126,239,219,162, + 91, 73, 57,233,223,215,207,166,147,112, 55, 61,255, 0,241,129,143, 96,121,224,159,199,161,251,180, 91, 63, 23,113,203,215, 25, +238,123, 13, 83,109, 35,160,235,215,175,223,141, 18,148,131,208,116,233,158,223,102,147,193, 77,141,238,118,193, 72, 79,216,122, +118,249,250,227,203,207, 85,146, 1, 56, 61, 61, 49,251, 7,109, 14,216,230,198,125, 50,122, 99, 68,160, 2, 64,198,125, 63,225, +164, 90,192,144, 62,122, 97, 28, 86, 29, 14, 58,140,121,159, 62,158,186,218,174, 11,120,121,159,197, 23, 18,123, 87,179,145,130, +147, 79,185,110, 40,206,220,178, 66, 73, 76, 27, 74,150,164,207,184,229,172,143,213, 6,158,202,219, 7,253,105, 35, 90,172, 1, +206,113,144, 59,143,159,245,234, 71,254,193,173,178, 98,146,141,245,226, 34,165, 22, 63,188, 82,169,144,118,234,211,150,250, 66, +158, 98, 93, 83, 19,235,142, 70,200,253, 26,253,223,221, 91, 42, 24, 61,198,152, 56,151, 50, 57, 86, 77, 91, 84,173,166, 80,186, + 80,142,161,155,107,143,122,130, 91,254,220, 76, 56, 7,134, 79, 24,113,142, 65,195,218, 75, 67, 95, 58,243,173,255, 0, 2, 48, +101,152, 92,116,213, 26, 20, 7,179, 48,196,149,103,214, 45,203,102,139, 77,179,109,136,172, 83,237,139, 54,149, 2,215,182,224, + 65, 9,106, 37, 62,145, 72,142,136, 76,165, 49,147,211, 5, 45,100,145,212,231, 39, 86,118,235, 42,143,200,227, 47, 37,210,234, + 18, 24, 83,124,167, 5,120, 37, 7, 39,169, 39, 31,142,154, 22,235,241,228,173,213, 7, 98,188,149,229,164,178,233,228, 89, 82, +186, 30,101,122, 21,107, 39,167, 33,181,182,204, 85, 70,113,109, 7, 2,195,161,204,169,167, 50, 20, 18,130, 15,196, 61, 53,201, + 85,114,187,206,236,205,119,148,147,111,221,239,252,122, 91,240,246,231,132, 50, 26, 12,191, 43,166,165,142, 30, 84, 80,168, 93, + 32, 13, 58, 85, 84,105,177,176, 1,109,176, 91, 3,211, 99,135,136,196,145, 38, 52,105,210, 76,121, 79,186, 10, 76,117,169, 45, +200, 65, 31,170,160, 65,233,140,104,132,199, 66,144,161, 62, 50,221,107,148,150,150,164,248,168,109, 67, 33, 74, 86, 6, 71,200, +131,160, 41,209,224, 56, 99,202,116, 72, 15, 50,217, 66,222,125, 75, 64,192, 24, 0,163,205, 35,215,229,172,162, 35,108, 56,218, +125,222,104, 97,121,193, 42, 81,113, 50, 18,162, 73, 1,181,118, 3, 58, 69,199,148,148, 66,227,107,244,216,237,190,219,127, 28, + 18,170, 83, 9, 43,230,178, 30,161, 74, 4,185, 54, 11,164,181,128, 27, 95, 77,200, 59,139, 97, 81,169,202,247,134,228, 67, 90, + 39, 71, 36, 55, 34, 19,199, 15, 6,193, 24, 91, 89,234,160, 7,109, 86,220,221,191, 69, 90, 85,181,115, 68, 96, 46, 68, 6,140, + 7,138,147,149,150, 82,160,166,208,188,140,168, 39, 39, 25,242,233,167, 58,137, 71,166,201,142,194,201,142,212,216,196, 6,229, + 50,121, 11,153, 61, 65, 3,161,199,207, 78,207,240,125,201,244,162,195,141,165,106, 65, 67,236,188,216,248, 92, 90, 48, 74, 84, + 7, 98, 83,144,126,221,106,152,228,100,145, 44, 64,101, 22,223,184,183, 79,141,173,235, 98,111,138,187,136,120,137, 99,171,130, +101, 58, 30, 38,100,109, 86, 82,202,195, 78,228, 88, 56, 32,141,236,172, 58, 16,109,124, 91,182, 90,193,101,183,152, 82, 35,165, + 30,248,200,113, 65, 41, 9, 79,140, 82, 57,198, 49,211,152,245,251, 78,155,223,104, 77, 33,251, 91,135,122,140,200,202, 44, 42, + 69,199, 77,109, 75, 9, 39,197,247,120, 85, 7, 27,105,208, 6, 86,128,176,147,145,219,151, 56, 58,220,141,174,167, 53, 29,232, +216, 70, 58, 14,152,232,133,143,214, 72, 31,205, 26, 97,253,170,148,143, 23,133, 86,229, 70, 46,101,187,202, 15, 56,105, 57, 89, + 75,148,154,162, 84, 79, 78,191,171,143, 92,159, 93, 75, 50, 90,104,205, 42,203,166,242, 70,111,241,189,135,243,239,235,142,124, +204,184,154,105,248,255, 0, 33,161,119,211, 75, 85, 83, 4,100,118,176,147, 86,254,237,133,254, 24,136, 5, 65,227, 38, 82,145, +202,226, 39, 41,110,184,151,185,156,241, 27, 46, 17,149,180,210, 23,200,250, 75,169,109, 32, 45, 42, 64,235,207,202,174,244,225, + 84,213, 6, 69, 67,223,225,189, 84,158,167,131,113,207,129, 29,150,216,138, 80,148,182,153,212,240,151, 19, 0,248,133,126,240, +180,243,120,152, 79,110,128, 7, 61,166, 95, 74, 93, 83,147, 93,247,105, 92,175, 73,101,190, 69, 71,105, 74,202,153, 10,108,130, +212,142,100,163, 40, 88,230, 36,130,160, 83,202, 52, 77, 26, 68,232,229, 30, 27, 79,123,184, 37, 79,205,166,196,101, 85,116,182, + 73, 71, 35,108, 72, 90, 68,166,220, 46, 4, 56,180, 23, 84,209, 5, 97, 7, 3,149,225,214,234,123,129,216,253,221,239,113,176, + 23, 3,174,219, 95,167,161,116,245, 3,200,177,221,159,162,132,176, 97,182,229, 73, 27,128, 53, 11,223,179, 1,176, 39, 14, 61, +179,110, 49, 87, 92,138,164, 73,146,233,178,165,150, 16,227, 84, 69, 42, 50, 94,109, 10, 71, 71, 96,168, 22, 37,159,133,105, 75, +193, 9, 83,132,168, 41, 95, 14,158, 74, 45, 26,235,147, 34, 76,184,244,134,171, 40,104,204, 83,146, 41,175, 68,162, 76,140, 26, +117, 76,161, 51,233,207, 31, 0,115,161,149,165, 62, 10,135, 57, 87,234, 12,157, 54,148,138,123, 5, 81,133,159, 38,108, 39, 22, +195,242,231, 68, 66,152,157, 2, 68,128,208, 83,174, 57, 5,247, 3,144, 18,140,142,105, 41, 91,107, 89, 89, 79,134, 84,158,109, +108,157,156,170,253, 2, 24,110, 77, 1, 74, 65,106, 28,151,106, 52, 57, 77,206,132,236,118,255, 0, 72,150,159,167,169, 41,148, +219,202,116, 37,124,170,241, 18,165, 16, 50, 10,136,212,110,190, 89, 0,102, 91, 57, 54, 10,173, 96,125, 45,246,150,247,176,217, + 88,139,245,185,184,195,137,205,164,100, 34,153, 99,169,146, 43, 14, 92,202, 82, 66,118,230,106, 62, 73, 25, 71, 75,134,111, 41, + 23, 70, 4, 1,238,148,138, 91, 79,179, 2,163, 42,161,107, 43,221,217,145, 13, 23, 52, 5,211, 28, 76,196,148,190, 35,243,188, +223,129, 37,188,163,195,105,198, 94, 1,193,212, 37, 68,105,199,141,108,212,103, 60,153,146,233, 80,100,164, 73,113, 42,158,134, +163,128, 66,210,128,223, 59,193,178, 90, 87, 40, 29, 82, 74,185, 79, 84,231,174,179,235, 33,170, 93, 82, 77, 65,154,147, 17, 46, + 76,178,176, 41, 85, 40,140, 45,104,144,248, 64, 74, 13, 62,115,105,115, 41,101, 46,164,185,225,171,144, 31,132,142,153,120,104, +155, 91,103, 58,196,127,118,165, 59,108,201,150,211, 50,140,139, 86,167, 83,165,188,209, 10, 66, 17, 17,112, 22,243,140, 60, 16, + 72, 81,231, 97,105,115,147,153, 93,245, 22,146,172,134,180,138,209, 72, 58,244, 55,189,174, 71,217, 35,212,143, 54,251,139, 30, +173,181,252,117, 14, 86,239, 28,240, 77, 72,225, 81,117, 42, 44,182, 50, 45,220,171, 22,130, 84,251, 42, 72, 28,237, 90, 65, 85, + 58, 66,227, 1,178,236,216, 17,129,148,194,170,116,121,146, 79,188, 38, 93, 38, 95,133, 10, 82,217, 78, 91, 18, 24,229,114, 60, +196,167,194, 87,134, 28,105, 10,115,149, 65, 71, 7, 26,218,107,126,109, 90, 10,162,154,132,152, 21, 33, 32, 55,133, 48,201,165, +212, 26, 80, 33, 63, 20,102,159,113,167,222, 82, 65, 82,130, 11,105, 73, 39,225,199, 46,172,180, 45,177,175,198,113,230,233,151, +117, 62,124, 98,178,148,183, 92,183,144,196,137, 9, 81,248,202,103, 82, 28, 65,109, 73,194,146, 20, 24,229, 74,149,158, 83,170, +151,157, 90, 22,218, 91,117,139,187,113, 17, 73,181,172,155, 85,134,101,215,110,181,213, 99,253, 77, 72, 98, 68,134,161, 70, 15, +171,149, 18, 12,199,165, 63, 30, 59, 44, 48,211,146,228, 58,240, 75, 8,112,149, 16,164, 80,243, 60,247, 50, 62,199,125,199,193, + 73, 23,219, 99,125,143, 82, 0,239, 80,241, 39, 21, 71,196,149,209, 83, 82,212,174,107, 81, 80,226, 56,226, 80,230,162, 70,147, +234,226,138, 33, 50, 71, 80,238,238, 21, 99,138, 13,122,152,170,128,194,195, 15, 28,122,147,162, 40,105,244, 58,132, 37,223, 18, + 3,231,194,234,242, 86, 28,114, 59,165, 43, 30, 26,249,214,164,228,128,219,188,202,202,185,192,213,242, 37, 81,151, 30,143, 37, +197, 57,226, 48, 3, 43, 43, 9, 11, 44,184,174,102,157, 83, 95,206, 90, 22, 66, 70, 64,200, 86,124,137, 13, 21,189,112, 82, 46, + 11,114,151,114, 91,117,216,119, 21,175,113, 83, 33, 86,232,117,120,238,174, 76,106,173, 26, 82, 67,145,101, 66,125,192, 11,141, + 45, 4,130,146,128,164, 41, 37,183, 57, 92, 66,210, 3,147,114,251,147,205, 46, 54, 83,202,178, 2, 20,226, 80,132,161, 96,169, + 73, 10, 36,120,173,129,204,140,147,204, 20, 64,198, 59,150,162, 37,117, 42, 5,134,194,253,108, 65,216,110,125, 71, 75, 11,250, + 92,139, 85, 45, 11, 75, 83, 85, 72,209,180, 51,196,206,140,172, 25, 25, 24, 29, 14,146, 35, 0,209,184, 32,134, 82, 46, 24, 18, + 55, 26, 78,240, 90,213, 31,208,130, 86, 9, 4, 18,130, 72, 73,229, 80, 42,230,108,126,177,199, 46,112, 65, 25,207, 93, 58,209, + 39,130, 16,145,159,214, 81, 60,157, 65,194, 72, 0,114,156,158,128, 96, 14,165, 71, 30,128,234, 46,217,220,212,153,116,202,237, +193,112,215,105,214,197,177,108, 64,126,171, 91,175,213, 37,166, 53, 46,151, 79,136, 18,100, 76,145, 41, 67,244, 76, 39, 45,163, +148, 5, 41,199, 22,134,154, 11, 82,210,147,121,177, 56,210,225,140,221, 20,202, 80,185, 43,180,231, 43, 85, 4,209,236,251,142, +240,181,165,219, 54,109,110,224,123,244, 52,198,233,213,121,111, 56,150,164,191, 39, 34, 8,154,220, 70,223,145,203,133,133,114, + 37, 82, 44,159, 40,174,158,140, 87,178, 8,168, 83,237, 72, 72, 38,202, 69,200, 91,220,219, 97,125,133,250,145,136, 77,103, 11, +113, 14, 98,249,179,100,188, 59, 93,159, 12,160, 94,161,169,105,165,154, 56,137, 78, 96, 87,150, 53,100, 83,203, 28,198, 91,150, + 88,129,148,174,133, 36,110,229,114, 79,128,205, 58,148,133, 31, 26, 20,100, 59, 45, 60,196,132,212, 39, 20,202,122, 50, 84, 70, + 84, 27, 10,142,218,188,129,109, 73,206, 70, 5,137,201, 14, 46, 63, 35,110,172, 30, 98,236,137, 60,136, 43, 66,208, 65, 73, 5, +196,225,111,114,171,166, 73,229, 9, 25,193, 3, 88, 95,215,200,158,183, 30, 67,206, 41, 43,116,248,202,117,107,231, 82,249,143, + 62, 86,165,101, 75, 43, 42,230, 4, 2, 9, 87, 55,198, 14,178, 38, 92, 98, 67, 32, 20,251,201, 8, 88,240, 16,146,164, 41, 67, +178,192, 65,194,147,145,216,231, 10,198,125,116,226,139,237, 51,153,109,101,216, 45,137,176, 85, 0, 40, 38,219,249, 64,243, 91, +246,186, 2, 70, 32,113, 80,251, 44, 81, 44,131, 83,130, 89,141,129,187, 49,212,196,131,181,139, 18, 64, 38,192, 90,228,140, 52, + 23, 71, 18,155, 27,182,247,133, 23,109,175,221,230,219,141,180,184,238, 72,209,228,209,169,247,213,194,220, 10,181, 86, 20,201, + 78, 65,135, 62, 60,103,163,251,172, 38, 37, 75,102, 75, 81,164,214, 36, 66,142,250,153, 91,141,169,214,146, 84,119, 30,147, 66, +165, 80,195,147, 41,232, 38,166,235,108, 25,149,121, 74, 76,250,173, 65, 50, 26, 67,141,184, 37,252, 94, 36, 34,194,208,182,218, +140, 81, 20,180, 82, 89, 10,109, 73, 89,131, 15,180, 99,113, 31,190,120,217,226,105,247, 21, 37, 48,237,189,193,122,201,132,220, +231, 27, 90,216,183,172, 58, 52, 11, 98, 37, 40,182,149, 41, 9,140,210,225,202, 12,167,155,149,105,150,162,177,158,154,222,143, +101, 55,180,158,109,129,120, 91, 92, 38,241, 1,118, 84,165,108,197,201, 83,133, 67,218, 59,194,177, 84,117, 3,105,238, 58,130, +145, 22,145,102,215, 42, 78,168,190, 54,130,167, 53,198, 99,180,128,239,129, 65,155, 33,153, 40, 74, 41,207, 76, 66, 18,163,204, + 18,106,169,105,103,136, 44,113,146,169, 37,205,135,152, 11, 55, 64, 21,137,251, 98,218, 65, 1,129, 26,156,119,103,137,223, 65, + 12,230,155,192,222, 23,241, 67,129,120,142,163, 57,207,166,202,105,115, 92,243, 34,120, 80,201, 36, 83,210, 71, 89, 57,203, 94, + 45, 47, 81, 37, 18,146,173, 69, 62,179, 89,161,231,164,145, 39, 16,209, 79, 40,202,229,206,203, 50, 92,167,210,208,107, 18,249, + 17,239,226, 44,119,234, 17,224,182,163,206,183, 36, 8,104, 87,141, 37, 68, 5, 37,149,169, 33,190,156,196,116, 73, 21, 52,233, + 79,123,195,137,167, 34,158,186,130, 89,101,234,213, 77, 81,234, 87, 35, 64,168, 41,152,136,167, 35, 45,198,233,144,132,186,180, +161,158,159,161, 42, 57,214,118,211,109, 82,144, 99,162, 60,122,107, 81,146,184,210, 98, 6,209, 25, 12,173,165,168, 41,185, 13, +180,145,149,165,224,224, 89, 57, 61,193, 61, 53,141, 63,114, 33,233, 11, 85, 22, 2,170, 6, 42, 84,212,185, 46,120, 80,168,201, +117, 77,148,182, 88,156,160,181, 73,125, 4,163, 41,105, 11, 32, 40,146,226, 20, 64,212,177, 40,249,104,218,136, 93, 29, 1,247, +238, 71,235, 92,237,232, 58, 18, 54,181,252,231,165,168, 98,130, 44,186,134,201, 24, 5,166,121, 54, 99,112, 87, 94,233, 10,130, +202,186, 81,249,136, 78,144,193,201, 44, 84,122, 5, 38, 28, 86,234,113,156,144,169,205,161,212, 57, 82,170,201, 76,201, 45, 60, +163,153,137,113,197,182,159,113,143,202,130, 20,219, 0, 33, 33, 33, 36,173, 0,232, 37,215, 92,148,250,153,181,195,113, 24,204, + 83,252, 40,144,178,220,218,116,212, 96,205, 77,188,203,169,196,146,181,168, 6,221,112, 41,150,139,220,205,165, 69, 32,139, 44, +136,107,113,106,122,179, 49,215,100, 48,241,113, 20,248,234,113,186,107, 6, 70, 20,166,155,136, 28,230,125, 10, 89, 0,151, 66, +148,164,164,149, 30,184, 24,253,199,122, 66,165, 47,234,152,208, 81, 88,170, 60,133,169,134,151, 37, 17, 89,142,182,144,160,195, +138,116, 16,184,175,115,146, 26,228, 35,152, 2,144, 10, 70,182, 97, 64, 14,163,229,113,223,173,246,245,220,141,236, 46,119,233, +208,144,112,239, 75,150, 79, 93, 50,162,150,205,103,109, 68,106,254,230, 52,186,181,201,144,170,200,168, 55, 28,194,177, 0, 89, + 74, 58, 49,195,130,197, 46,151, 71,143, 89,156,136, 50, 16,226,147,239, 45,220,146,230, 75, 91,181, 22,228,134, 85, 46, 53, 65, + 42,116,169,215, 27, 81,116, 21,143,136, 56,176, 83,223, 69,209,101,194,118,104,120,212,188,105, 41,116,182,242, 25, 83,206,149, + 54,218,214,160,181,186,242,194,131,168,108,182, 83,205,250,200,108, 3,147,240,233,134,126, 83,142,181, 21,235,160,213, 20,137, +105,109,136,245, 1, 33,149, 69,131, 86, 73, 74,228,162, 18,225, 47,194, 98, 66,176,143,133,208, 29, 73, 36,133, 44,128, 52,237, + 91, 17,157, 91,145, 84,244,169,143,180,227, 68, 21, 75,109,133,243, 33,111,129, 20, 74,114, 56,241, 39,182, 84,174, 82, 70, 20, +165,173, 69, 57,239,167,120,101, 42,241,198, 6,146, 55,181,138,219,126,164, 14,187, 16, 5,245, 16, 5,201, 45,115,133, 51, 76, +165,169, 40,229,154,170,189,170,102,150,227, 88, 37,145,130, 42,169, 88,221,140,154,183, 83,169, 71, 40, 43,236,138, 6,155,195, +227,233,107,174,155, 39,136,190, 10, 30, 97,107,118,164, 56,127,220, 70,158,146,160, 16,217,132,155,246,143,200,210,154, 35,155, +222, 4,191,120, 37, 71, 9, 82, 86, 10, 64,235,168,152,132,228, 28,164,164, 19,215,231,143, 77, 73,155,233, 79, 95,204, 87,248, +240,217,189,185, 66,217,147, 47,105,120,111,164,154,148,182,157, 83,138,126, 70,226,221,245,186,220, 86,150,133,146, 80,148, 83, +104,144,212,158,249, 18,186,147,129,168,234,237,246,223,222, 27,165,119,219,150, 21,133,110, 86,174,219,186,237,172, 68,160, 91, +118,213,189, 79,122,169, 91,174, 86, 39, 44, 34, 53, 58,153, 1,128, 75,239, 43,226, 82,212, 74, 91,101,180, 45,231,150,219, 72, + 90,211, 98,229, 79,202,203,150, 89, 92, 34,171, 76, 88,147,176, 28,199, 55,185,216, 11,111,185,252, 49,198, 60, 76,139,250,126, +189, 32, 28,197,102,132, 46,145,114,196,195, 16, 0, 0, 1, 44, 73,181,128, 4,182,214, 7,108, 96,193, 42, 89, 72, 66,114, 71, +100,165, 36,149, 99,176, 0,119, 58,237,167,177,211,217,215, 3,138,221,197,169,239, 54,241,210, 85, 43,135, 45,155,171,194, 77, +122,148,248, 83,108,110,166,227, 37, 13, 84,169, 27, 94,149,140, 21,219,145, 99, 42, 44,251,145, 77,156,169,135,162, 82,185,144, +185,207, 4,246, 39,129,175,163,187,181, 22, 69, 46,141,184, 92,116,214,164,223, 87,121,101,186,140,141,132,177,171,110,211,108, + 90, 17, 41, 14, 34,153,125,223, 20,181,162,117,229, 60, 3,201, 42, 45, 53,216, 84,224,161,200,151,229, 4,149, 43,177, 76, 91, + 27,113,181,244, 24,150, 14,210, 88, 54,166,216,237,189,188,185, 31, 81,216,214, 37, 26, 21, 6,221,166, 25,110,243, 75,144,204, + 24,141,132,174,107,238,225,201, 18, 29, 43,126, 67,129, 42,121,215, 23,130, 27,243, 44,205,164,167, 43, 26, 24,161, 39,118, 99, +165,220,118, 10,191,105, 84,157,152,182,150,181,202,117, 86, 19,158, 18,240,238,182,106,218, 90,236,242, 5,138,150, 59, 56,166, + 62,103,145,133,180, 9, 71,217, 84,185, 12,200, 75, 22,182,135, 80, 11, 12,100, 74,154,169,242,176,132, 54,203,109, 54,195, 44, + 71,140,203, 81,226, 70,137, 29,164,179, 10, 4, 72,236,165, 45,195,134,212,102, 91, 75,109,182,148,182,219, 76,161, 8, 74, 80, + 18,144,232, 90,112, 2,249, 93,117, 25, 66,146,209, 71, 66, 22,162,163,134,241,211,245,150,177,159,152, 58,106,104,113, 92, 82, +188, 39, 22, 57,159,117,107,144,172,114,134,208,144, 20,235, 77,249,242, 37, 62, 27, 96,249,156,159,144,217, 59, 62,158, 23, 33, +162,160,146, 26, 67, 60,168,236,129, 33,209,134,130,134, 48, 2, 26, 35, 31, 51,211, 77,180, 46,116, 52,199,224, 54,176, 30,128, + 14,214, 29,134,219,219, 98, 14, 47,113, 78, 21, 72, 3, 87,123,254,238,135,222,126,240, 59, 91, 14,157, 22,158, 26,105,164,172, + 5,168, 4,243,159,213,231,121,125,145,208, 99, 30, 93, 60,129,211,139, 26, 35,109, 54, 49,133, 17,220, 16, 79, 83,232, 60,250, +246, 31,187, 86,138,100, 68,165, 73, 8,229, 81,142, 64, 42, 86,112,183, 22,144, 21,130, 15, 85, 36, 19,242, 28,218,203,218, 78, + 49,240,169, 41, 70, 66, 74,122,165, 68,142,170,207,160, 57, 72,251,254, 88,216, 14, 90,230,251, 15,244,249,254,125, 48,211, 87, +166, 54,210, 5,205,133,251,123,192,239,235,247, 3,211, 99,142, 83,123,105,234,144, 40, 62,204, 78, 45,213, 56,172, 10,158,223, +193,161, 68,109,166,214,234,222,168,213,110,106, 44,120, 49,210,219,105,230, 42, 83,161,103,253,144,131,228, 53,249,148, 74,163, + 86, 33,178, 31,157, 73,168, 68, 97, 73, 37, 15, 75,136,244,102,150,130,114, 10, 29,117,176,149,119,242, 39, 7,166,117,250,228, +239, 21, 54,139,113, 81,162, 91, 21,234, 77, 58,187, 2,167, 53,185, 83, 41, 53,168, 81, 42,144, 36, 71,167, 16,227,102, 68, 9, +141, 45,167,146, 37,173,178,146,164,171, 5, 25,232, 70,154, 39,182,131,105, 43,148,145, 68,173,237, 86,217, 86,168,230, 58,226, +138, 93, 86,195,181,102,211,147, 24,131,204,194, 99,191, 75, 41,109,188, 19,219,175, 94,132, 30,186,205, 29,108,244,181, 21, 13, + 12,113,200,178,104, 7, 83, 48, 55, 91,237,178,176,177,213,114,119, 55,218,198,215,196, 43,137,120, 6,163,136,230,167,205,151, + 49, 90, 53, 72, 22, 32,134, 2,250,180,203, 43,106, 45,205, 75, 41, 46, 64,178,159,179,125,239,183,228,250,227,101, 60,188,224, +140,142,128,244,207,144,199,168,198, 48,126,122, 21,192, 0, 3,155, 35, 57,233,215,215,166,191, 65, 78, 47,125,129,220, 19,241, + 21, 2,167, 90,218,170, 35,252, 48,110, 99,233,144,252, 74,205,131, 29,202,134,222,212,103,172, 18,132, 92, 59,119, 53,242,134, + 99, 45,220,115, 59, 76,122, 43,169, 25, 41,109, 88,229, 48,230,227,131,217,183,196,255, 0, 1,119, 35,112,119,146,205, 19,108, + 74,180,247, 33,217,251,193,104,151,171, 59,105,118,144,165,248, 44, 49, 88, 13, 5,219,245,162,132,229, 84,234,138, 35,202, 73, +200,108, 58,145,204,100,244,217,164, 82,178,199, 50, 26,105, 9, 0, 92,221, 24,250, 43,250,158,193,130,177,236,164, 11,226,164, +206,184, 91, 56,200, 65,146,174, 1, 45, 32,219,159, 17, 47, 24,222,195, 93,194,188,123,216, 93,212, 33, 36, 42,187, 28,115,229, +210,158,163,169, 24, 62, 96,119,253,255, 0,215,160,212, 66,187,167, 24,232, 58,249,116,198, 49,219,174,141,117, 3,152,133,229, + 39, 56, 41,199, 80,122,227, 65,120, 97,165,169, 73,201, 43,238, 14, 79, 41,235,146, 61, 52,244, 14,192, 1,182, 35,160, 31, 92, + 14,231, 32, 73, 74,186,231,203, 24,251,137,244,208,101, 3,148, 32, 40,165, 57,236, 60,201,209,133, 63, 26,186,168,231,201, 71, +225, 29,187,121, 13, 81, 86, 50,122, 16,115,246, 12,124,177,163,142,222,236,103, 3, 40, 3,211, 29,186, 30,189,241,215, 57,208, +203, 24, 36, 15, 67,140,252,199,207,203, 69, 47,208,103,166,115,229,147,129,215, 62,186, 25, 64,244,230, 29,124,143,175,113,215, +212,233, 85,189,129,245,235,243,240,198, 69,172,126,125, 48, 42,129,193, 30,127,147,161, 85,246,156, 17,215,204, 2, 8,199,217, +162,148, 58,146, 20,122,103,207,167,159, 83,161, 92, 42,235,233,230, 71,159, 95,232,210,139,215,173,176,170,143, 95,157,176, 50, +206, 15, 76, 31, 80, 71,224,126,220,104, 85,168,227, 28,189,125, 61,126,206,154, 37,100,103, 3,200,156,244,243,249,232,117,227, + 57,235,233,242,251,180,182, 50,126, 54, 56, 25, 99,175,159, 81,231,229,242,210,215,178,172,119,200,244,198, 14,127, 31, 61, 45, + 40, 47, 97,229,191,200,255, 0, 79,155,224,126, 56,162,144, 64, 30,191,143,158,170,163, 62,125,137,232,115,220,250,106,159,236, +213, 69, 35,156,131,204, 71,166, 63, 63,156,233, 54,219,160,220, 99, 35,227,108, 20,131,208, 14,228,121, 99,231,251,116, 80, 56, + 35,184,249,250,104, 22, 57,146, 8, 81,234, 59, 31, 80, 60,243,247,232,209,216,117,207,207, 68,223, 77,200,244,254, 88, 24, 45, + 24,207, 92,231,203, 69, 35,207,183,239,208,173,124,207, 92,126,127,118,138, 64,232, 79,221,249,252,249,105, 44, 16,142,190,251, + 15,145,130, 80, 58,103,215,250,244, 66, 49,140,129,215,212,247,207,245,106,146, 48, 57, 79,150, 7,252,116, 64,193,232, 49,223, + 31, 97,210, 44, 79, 91,236,127,211,253, 48,153,183, 97,138,128, 40, 5,103,208,224,119,235,169,123,123, 41,104,112,173, 78, 2, +173,121, 73,134,167,220,191,111,139,158,183, 80,116, 97, 14, 1, 26, 65,131, 29, 41,199,146, 91,142, 0, 58,136,106, 65,193, 4, +140,224,156,227,211,175, 77, 75,111,217,163,113,199,172,240, 9,183,233,105,231,146,187, 86,241,187, 45,249,133,131,143, 9,213, + 78,114, 75, 97,196,121, 2,219,168, 32,158,224,244,213,121,226, 65,147,244, 28, 33, 13,148,206,186,191,254, 57, 45,142,131,250, + 49, 71, 12,158, 42,209,137,118,101,162,169, 41,214,225,249,148,226,226,196, 27,233, 45,211,181,251, 99,118,128, 83,114,214,210, +153,146,220,116,144,235,125, 10,212,129,205,144, 20,161,156,249,105,224,180,100,161, 50, 35, 25,130, 74, 80, 57, 85,206, 20,176, + 26,230,198, 22,164, 30,253,198,153, 40,181, 49,238,232, 92,122,195, 47, 73, 82,210,211, 81,100, 39,149,110,184,178, 82,218, 1, + 61,252,180,248,219,242,107, 80,222,162, 71,155, 77, 98,169, 61,192,124,102, 35, 56,130, 91,108,254,170, 94, 72,254,110, 58,245, +215, 54,213, 70,193,217,152,217,148,130,111,182,219,117,233,112,127, 28,123, 9,151,215,172, 84,113,194,236,164,181,215,237,232, +114,116,222,246,144, 11,142,228,222,194,248,216, 58, 84,210,135, 89,145,227, 49, 81,108,184, 26, 12,189,132,132,180,123, 21,146, + 58,249,103, 78, 29, 49,216,145,157, 46,202,141, 0, 50,165, 99,153,162,151, 0, 10,255, 0, 80, 14,216,207, 93, 55, 22,253, 58, +116,249, 14,180,186, 68,194,162,227,110, 41, 40,100, 22,154, 72,236,208, 41,238, 63,167, 78,237, 50,222,105,197, 50,210,160,203, + 5, 43,248,209,238,139, 82, 16,172,254,170, 84, 6, 15, 64,123,246,209, 97,137,100, 58,121,100, 21, 38,219,129,125,253,251,159, +203,124, 66, 51,202,138, 53, 13,169,202,221,119, 10,203,112,189, 71,216, 96, 1, 27,139,233,177,239,124, 60, 54,123, 86,252,196, +161, 45,162, 50,155,229, 7,170, 74, 10,129,238, 6, 71,112,116,252,211,104,240,209, 29, 41,140,174, 68, 20,228, 53,207,204,217, + 24,234, 19,232,174,250,105,109, 74, 83,112,209, 24, 57, 24, 70, 14, 44, 8,200,152, 24,136,167,206,112,124, 36,200, 90, 75,189, + 71,243,115,233,167,174,148,195,204, 73,247,101,182,182, 20,172, 18,219,237, 41, 33, 67,200,161, 67,203,168,237,167,136,114,230, +101,187, 11,252, 13,192,191, 66,125,255, 0,150, 57,147,139,234,195, 84,202, 96,169,114,138, 75, 0,206, 26,224,108, 77,134,219, +119, 54,216,237,113,131,109,233, 2,149, 48,165, 68,165, 30, 38, 65, 7,177,206, 58, 19,172, 11,142,250,104,187,248, 72,189,156, +100,243,201,160,212,173,234,211, 33, 37, 75, 0, 55, 52,196,120,156,116, 8,228,153,212,158,131, 26,214,142, 52, 56,200,162,240, +178,104,182,149, 18,205,170,110, 30,239, 93,144, 68,251,106,214,167,179, 37,200,145,162, 56,240,138,204,250,159,186, 52,167, 29, + 74,229, 97, 13,180,210, 74,150, 65,201, 72, 25,215, 24,110,255, 0,109,214,236, 89,181,169,123, 63,196,206,212,209,225,216,219, +139, 33, 54,133,121,152,140,200,163, 86,236,207,172, 95, 67, 44,213, 92, 50, 29, 90, 28,247, 39,220,142,243,241,228,161, 37,109, + 48,160, 22,133, 16,160,237,150,210, 77, 74, 30, 57, 24, 4,148, 29, 42, 55,123,122,233, 0,155, 3,252,176,190, 77,224,151, 30, +113,173, 21, 7, 27,228,116, 52,241,195,151,149,172,136, 84,213,193, 77, 53, 92, 16, 72,162, 73, 41,163,149,129,100, 44, 12,107, + 36,134, 56,222, 75, 34,185, 39, 28,240,171, 81, 92, 18,235, 15,189, 50, 83, 15,182,251,205,242,193, 1,135, 11,172,188,227,129, +215, 90,116, 41, 15,167,152, 55,128,160,127, 87,190,113,171,197,186,251, 84,199, 27,110,231, 91, 11, 8,109,105,102,164,211,204, +152, 75, 4,120,205, 50,166, 93, 67,142, 51, 33,194, 84,147,146,190, 85, 0, 82,178, 59,103,187,207, 96, 84,168,155,135, 92,164, +148,251,168,139, 80,118, 74,101, 49,206,195,115, 26, 83,165,196,200, 97,164,164,165, 44,172,160, 41, 39, 56, 83,110, 36,144, 0, +213, 45,183,165,251,180,225, 57,214, 41,211,231, 46, 59,134, 32,155, 57,137, 75, 47, 56,165, 48,251,207, 7, 20,216, 97,211,207, + 28, 22,210,121,212,147,204,148,242,228,105,122,137, 21, 98, 46,198,247, 22, 0, 1,112,118, 0, 3,218,222,150,216,220,157,247, +199, 91,101, 89,173, 61, 78, 87, 77, 84, 36, 38, 42,136, 21,215, 65,180,182, 96, 28, 89,154,203,123,157,181, 30,246, 5,126,214, + 30, 11, 94,207,114,229,117,201,237, 69,164,202,120,197,143, 54, 85, 82,157, 37,183,147, 22, 59,235,108, 65,134,165, 70,194,224, + 61,226, 33, 45,144,231, 55, 47,196,226,209,149,116,219,107, 39,110,107,207,161,154, 43, 53, 69,192,105,220, 59, 45, 51,224, 51, + 86, 64,151,226,135,152,104,200, 64, 67,211, 90, 7, 24, 74, 94, 41,111, 9,230, 0,233,156,176,182,201, 77,169, 18,170,137,115, +223, 42,193,152,112, 99, 91,243,158,143, 35,199, 74,144,226, 36, 74,147, 13,192,137,144, 80,224, 4,151, 2,137, 82,194, 64, 37, + 56, 27,217,102, 90,215,133, 41, 49, 27,133, 84, 98,165, 57,224,159,142,189, 5,146, 26,113, 35,153,236,152,138,109, 46,169, 69, + 25, 87,137,133,140,117, 36, 18, 53, 10,175,145,203, 5,138, 80,109,208, 48, 59, 17, 96, 8,190,160,123,246, 0,108, 20, 27, 91, + 12, 57,247, 17, 10,106,116,134,130,190,154, 78, 89, 80,156,196, 87, 1,193, 91, 30, 97, 18,163,152,205,238,197, 65, 6,218, 88, + 22,108, 90,237,237,189,152,234,185, 95,164, 89,245,210,228,149, 56,245, 82,107, 53, 74,100,246, 35, 52,164,165,243, 25, 77,135, +115,204,242, 70,121, 29, 74,177,211,148, 96, 43, 79, 29,187, 98, 95,172, 58,106, 17,164, 80, 67, 45, 56, 12, 74,109, 70,100,217, +240, 85, 24,171,153, 44, 69,113,113, 82,236, 53, 20, 4,149, 21, 41, 69, 5, 39, 41, 86, 6,179,123,118,157, 92,141, 29, 16,156, +183,161,203,117,169, 45, 41, 85, 8,181, 70, 27,109, 47,173,212,248,236, 71,106, 84, 99,132,175, 36, 36,133,242,100,225, 68, 4, +141, 58,241, 37,169, 36,181, 81,162,206,163,163,196, 75,109,173,245,177, 34, 3, 69, 39,152,189,239,177, 10,146,225, 89, 79,232, +208,128, 73,194,129, 72, 61,117,169, 79, 70,103, 39,152, 2,179,118,234, 61,230,215,211,210,196,129, 98, 64, 29,141,241, 79,103, +220,101,153, 30,114, 70,144, 85, 43, 2, 13,228, 73, 14,130, 64, 58, 33,230, 2,133,252,192,233,140, 21,185, 0,130, 72,108,110, +143, 14,191, 8,188, 39,209, 80,234, 30, 65,115,252, 6,171, 17,212, 71, 73, 7,149, 40, 68,198,155,113,192, 74, 65, 61,137, 39, +175,124,235,131,126,216,205,247,152,111,141,190,225,194,146,243,176,233,118,141, 10,155,186,215,228, 17, 33,165,138,133,245,119, + 54,244,107, 38, 20,208,210,212, 86,213, 50,201, 6, 83, 77, 44,254,130, 77,220,242,193, 10, 9, 34, 68, 98,167, 69,113,239,115, + 98,162,209,150,227,169,100,164, 50,250, 30,142,153, 10, 67,104, 47,161,113,185,149,250,217,193,234, 7,124,117, 58,132,167,180, + 11,114,157,191, 56,207,226,110,235, 91,220,193,123,191,119, 82,161,167, 35, 13,210,109, 57,205,218, 52,134, 80,174, 65,250, 54, +233,246,252,102,210, 48, 48,150,250,247, 58,147, 81,229,101, 16,136,212, 49,107,111,110,151,247,223,215,107,145,238, 29,206, 45, + 63,161,246, 88,153,247,139,149,156, 79,155,208, 8,233,184, 47, 46,150,174, 32,203, 38,147, 89, 80,241, 82,211,189,164,119, 95, + 36, 18,213,200,157, 74, 75, 28,114, 11, 50,130, 59,157,236,172,221, 24,215,231, 13, 23, 37,147, 81,118, 25,168,236,189,253, 46, +152,218, 93,144,151,101, 53,102,223,141,191,116, 91,190, 19,107, 28,209, 97, 71,172, 69,186,152, 65,253, 80,165, 4,167, 7, 26, +218,107,158,228,161,191, 61,218,125, 49, 94,245, 40,172, 37,210,202,148, 67, 42, 11,229, 81,117,224, 57, 60,114, 15, 92, 2,160, +149, 14,100,228,234, 49,124, 2,239,229, 79,110, 55,233,155, 77,234,234,233,116, 45,237,130,141,181,173,200,114, 66, 99, 70,106, +181, 46,104,159, 98, 79,117,194,147,225, 52,221,203, 17,152,171,112, 17,134,171,110,142, 96, 9,204,138,108,186, 50,226,248, 65, +230, 94, 18,210,234,138,218,116, 40, 56,144,201,253, 42,228, 2,144, 82,232,125, 39,155,155,185, 24,199,163, 70,113, 75, 61, 53, + 66,211, 24,192,102, 80,250,173,177, 4,158,128,236,109,107, 27,244,244, 55,216,120,245,195,212, 92, 51,226,119, 20,241, 60, 83, + 51,208,241, 68,223,164, 41, 96, 4,170, 44,179, 42,251,111, 53,134,197,189,176, 77, 41,141,108,170,146,160, 98, 5,181, 97, 28, + 75,220,181, 26, 38,200,211,104,247, 69, 74,235,183,182,170,177,190,251, 65, 11,117,110,107, 14,159, 10,179,117, 91,182, 75,207, +220, 78,183, 82,133, 14,168, 4, 79,171,216,186,153,183, 21, 41, 82,210, 98, 36, 41, 9,115, 46,170, 58, 78,196,185,236,244,224, +218,187,107, 59,115,220,156, 71,239,126,228,237,173, 2,138,187,170,107, 84,230, 45, 75, 86, 5,193, 65,109,135,229, 52,252, 91, +142,223,106, 82,213, 70,114, 67,192,198,106, 35, 40,154,243,242, 91,140,151, 91,112,244,112,233,245, 17, 14, 44,120,174, 52,203, +140, 76,104,179, 45,183, 16,135, 25,122, 52,130,142,120,210,155,117, 36, 60,203,137, 64, 5,181,165, 73, 88, 7, 57,232, 53,131, +111, 20,122,181,183,183, 23,101,181,105,248, 52,138, 5, 74, 76, 74,251,148,250,116, 97, 1, 16,222,167, 60,106, 47, 70,165, 53, + 21, 77,181, 6,159, 41,244,182,244,150, 67,100, 56,236,116,184, 10, 10,220, 42, 89, 95, 56,135, 46,142, 10, 39,138, 88, 81,180, +202, 38, 14, 74,164,134,226, 72,138, 50,168,146, 61,200, 73, 86, 72,223,161, 85,177,213, 91,112,255, 0,139,220, 97, 77, 6, 89, +195,156, 53,196, 21, 60, 22,207,152, 77, 60,242,208,138, 52, 21, 75, 82,148,144,150,121, 38,162,154,174,158,178, 4,129,185,117, + 52,245, 41,169, 36, 80, 81, 94, 4,118, 96,232,187,243,188, 52, 58, 53,183, 22,179,113, 84,169, 53,196, 81,160,251,245, 41,201, + 62,244,245, 37, 30, 24, 17,105,181, 9, 10,121,208,245, 77,152, 9,140,153, 37,110, 58,225,146,151,148,235,139,112, 41,106,217, +189,151,227, 46,253,131,118,219,180,250,252,122,125,201, 79,118,165, 17,114,150,164, 24,178,216,166,197,117, 15,212, 36, 41,109, +252, 46,145, 13,149,146, 84,156, 16,146,163,211, 58,229, 18,107,239, 62,242,147, 37,199, 31, 91,206,242,186,241,117,192,165, 58, +115,211, 39,155,149,210,121, 78, 15,117, 43,161,198,175,245,237,208,133,180,123, 77,185, 27,181, 83,195,175,211, 41, 12,109,245, +155, 17,197,165, 15, 85, 55, 47,117, 95, 93,149,109, 82, 48,149,164,169,198,162, 73,174, 84, 86, 89,234,134,109,247, 20,190, 92, +115, 20, 34,161,174,138,166, 35, 73, 52,177, 73, 35, 11, 42,177, 35,177,251, 38,224,129,110,227,176,216, 3,139, 63, 49,225,124, +159, 58,137,168,171, 50,122, 67, 83,155,200,176,199,104,150, 37, 89,170,228, 17, 68, 21,129,214,136, 36,145, 64, 37,137, 84, 80, + 88,147,124,113, 55,116,247, 70, 69,253,187,251,165,124,248,206, 6,183, 3,113, 47,219,205,230,124,103, 29,108, 53,115, 87, 43, + 21, 40,234, 47,172,146,232, 75, 18, 90, 9, 39, 39, 13, 39, 9,232, 14,172, 14,214,153,120, 48,183, 78, 92,152, 57,157, 10, 37, + 43,109,167, 26, 13,184,150,207, 80,131,206,176,172, 30,169, 9, 5, 24, 32,105,155,145, 77,159, 79,177, 55,214,248,122, 99,102, + 14,214,238, 37, 54,195,167, 33,244, 45,181,207,144,221, 5,213,204, 44, 21, 16,151,138, 88,241,164,244, 32,167,198, 64, 82, 64, + 41,200, 53, 27,141, 40,118,147, 76, 15, 45,169, 62, 12, 25,243, 2, 86, 20,234, 16,197, 62, 19, 65,165,164,117,229,247,167,138, + 73, 61, 22,177,202, 7, 66, 69,171, 7, 12,211, 48,141, 68, 97,196, 42, 34,118,176,243,125, 68, 82, 27,237,230, 26,101, 64, 77, +183, 59, 94,221,125, 38,200,188, 76,203,114,202, 54,165,142, 67, 20,116, 65, 22, 8,217,183, 68, 90,250,204,182, 21, 7,236,171, + 60,153,116,228, 2, 70,148, 58,202,134,186, 15,209, 95,217,213,187,149,126, 36, 56, 44,216,253,206,187,174, 26,157,110,227,126, +218,126,193,186,149,240,199, 84,155,163,109, 39,191,101, 84, 39,204,125,144, 23, 80,149, 50,149, 75,163, 76,121,231, 85,202,227, +245, 23,148, 15, 58,213,173,192,169,181, 57,184,233, 69, 62, 75, 17,217,117,148, 54, 25,157, 8, 41, 77,184, 20, 57, 18, 85, 21, +196, 40, 55,148, 36,167, 33,106,235,158,185, 26,226,103,176,146,232,171, 73,224,105,202, 90,107, 52,248, 49, 97,111,182,232,183, + 25,185,145,221,148,239,233,169,118, 36,151, 91, 74,223,144,136,236, 44, 74, 46, 41, 40,108,169, 68,173,101, 73,230, 86,187, 41, + 49,154,218,209,205, 42,173, 52, 52,180,165, 74, 68, 70, 98, 69,116,182, 9, 42, 83, 15,150, 84, 82,172,173, 43,228, 0,100, 3, +231,140,166,170, 86,154, 21,107,179,160, 10, 88,238,110,160,139,147,114, 77,254, 59,238,122,227,195,207, 25,248,114,151,135,188, +100,241, 27, 44,203,158, 10, 60,158,155, 59,204, 26,142,156, 69,166, 56,105,158,169,228,130, 24,163, 88,121, 65, 97,137,146, 53, + 32,147,100, 5,141,201,182, 5, 94, 69,230, 10, 94,145, 46,158,251, 79, 45,104,148,212, 6, 23, 14, 74,219,229, 12, 45,182, 36, + 58,225, 37,149, 97, 25,231, 83,121, 7,151,152,115,103, 88,171,145,168,116,244,134, 97,194,115,222,240,219,142,210,234,106,145, + 26, 99, 65,211,209,246,222,146, 74,159,116, 16, 64, 41,113, 93,130, 80,224, 61, 53,146,220, 18, 42,169, 71,189, 65,175, 23,224, + 43,196,110,100,138,180, 52, 73,141, 20,132,150,219,121,201, 49,146,211,140, 32,184, 66, 20, 84, 8, 65, 74, 73,198,117,138, 87, + 28,148,234,162, 34,187, 74,117,192,134,195,141, 85,221,124,204,165, 74, 66, 64, 8,106, 33,105, 1,113,212,225, 81, 86, 31, 66, + 49,205,221, 67, 11,214,189,142,171, 48,185,237,109,186,218,221,251, 94,219,220,117, 0,118,198,190, 89,205,228, 83,161,104,226, +136,234,212,180,224,194,199, 64, 4, 7,140,136,249,140,128,157,144,137, 21, 72,107,233, 54, 57, 45, 21,111, 50,239,128,212,167, +155,106, 99,237, 53, 50, 5, 82, 58,170,112,130, 22,133,248,114,226,201, 82, 20, 84,194, 84,162, 75, 79,133, 20,150,202,144,180, +144, 70,158,219, 70,151, 29,231,155,118, 60,104,204, 22, 63,193,222,142,151, 20,169, 10,146,203,194, 58,208,195,190, 63,232,220, + 83,255, 0, 26, 27, 64, 12,165, 9, 10,230, 9, 32,105,148,162, 91,141, 33,248, 83, 89,126, 99, 48,230,182, 20,180,198,150,244, +129, 79,113, 60,188,170,101,153,170,115,222, 32,173, 37, 93,149,240, 99,149,124,169, 9, 89,109,184,249,226, 98, 31, 5,220, 21, +239,191, 17, 15,200,136,155,150,213,178,166,210,246,246, 59, 73,141, 4, 86, 55, 54,239,228,181,236, 42, 83, 8, 90,185, 31,124, +220, 21, 40,178,202, 18,149,144,213, 45,220,101, 41, 86,157,232,209,181,169, 10,100,111, 40, 23, 59,177, 54,181,129, 23, 4,146, + 58, 1,212,220, 92, 98, 11,198,117,212,212,212,243, 58,213, 20, 77, 12,210, 54,146, 52,132, 30,109, 96, 29,244,170,155,187, 57, + 42, 0, 96,197, 77,204, 4,253,172,219,203, 47,139, 95,105,175, 18,183,101,176,204,138,245, 61,141,200,141,179, 22, 18, 41, 9, + 93, 86, 93,102,147,182,162, 46,222,210,152,166, 51, 24, 19, 62,108,219,142, 29, 80,176,134,211,151, 87, 57, 0, 2, 78, 76,168, +189,147, 30,205, 59,119,129,141,189,137,185,219,145, 71,167,212,120,177,191,168, 72,110,225,150,239,131, 57,157,155,182, 42,104, +109,241,183, 54,188,132,130,150,171,238,183,225,154,253, 69,162, 22,251,224,192,105, 98, 36,114, 29,230,127,176,159,128, 53, 76, +144,190, 60,247,198,152,229, 94,166,106,149, 39, 54, 34, 21,106, 58, 84, 43, 87,116,135,159, 77,209,188,211,162, 60,140, 58,227, + 18,159,150,197, 29,103, 9, 19, 37, 74,154,140,150,153, 34, 80,232,121,231, 86, 94,194,151,206, 84,165,229, 89, 83,132,156,149, +100,255, 0, 59,169,238,117, 52,214,174,144,192, 15,246,106, 75, 42,129,210, 73, 19,102,115,254, 20, 96,116, 95,171,221,172, 52, +163, 53, 11,192,252, 48,106,170,102,226,204,206, 29, 53, 57,147,188,180,145, 48,254,234, 41, 9,101,148,237, 96,238,166,209,126, +196, 86, 97,188,158, 91,213,199, 90, 49,104, 79,128,238, 30,144,121, 9, 61,192,192,201, 10,245,242,251,181,174, 71,196,148,241, +192, 74,219,247,143, 25,101,101, 88, 83,109,158,100, 32,143,231,159, 20,183,140,231,245,116,231,222,179, 3,236,178,194, 18,160, +158, 67,240,159,214,231, 63, 8,200,245,230, 7,246,107, 16,183,233,171,125,220,148, 41, 94, 26,193, 82, 72, 56, 30, 24, 42, 25, + 7,182, 93, 82,127,254,159,144,211, 69, 97,106,138,152,227, 83,176,254, 38,222,238,150,252, 15, 81,139, 78, 53, 68, 46, 72,176, + 83,107,124, 58,253,247,191,243,198,113,108,211, 19,227,169,194,215, 63,134,203, 99, 5, 93, 27,101,146, 22,246, 14, 62, 37, 45, +242, 7,255, 0, 71, 91, 55,104, 83,196, 88,200, 91,141, 21, 62,226,125,225,196,142,201,144,233, 1,182,178,161,208, 1,200, 7, +158, 18,112, 52,218,218, 20, 34, 11, 72, 82, 48,167, 29, 66, 86,162, 9, 37,168,227,198,115, 36,249,169,100, 15,158,126,122,216, + 74, 93, 56,165,176,160, 48, 80,160,230, 79, 96,234,193,228, 24,207, 80,150,250,245,243, 58,216,145,194,132,133, 59,122,123,247, +233,252, 61, 58,123,176,171,188,113,197,169,205,134,223,126,214, 23,251,250,216,250, 19,223, 23,184, 45, 45, 45,164,250,130,146, + 81,130,165, 58, 79,198,161,205,211,205, 71, 39, 29,135,217,171,242, 82,161,202,146, 14, 66, 64, 79, 92, 18,112, 18,132, 16, 7, + 82, 71,151,110,167,174, 79, 64,225, 49,204, 6, 74,148, 8,194, 60,151,142,203, 80, 0,244,206, 50, 62, 95,110,173, 87,197, 93, + 84, 74, 17, 76,101,242,212,170,171, 93, 62,154, 51,254, 77,126, 25, 50,166, 56,148,245, 8,102, 57, 81, 78, 59,184,180, 13, 2, +252,184,139,157,194,142,158,167,111,226,127,215, 17,237, 18, 87, 87, 69, 75, 8, 13, 45, 67,233, 30,130,251,146,127,194,160, 22, +111, 64, 9,233,134, 94,191, 60,214,174, 57,178,155, 80, 92, 88,138,250,178, 34,146, 73, 75,205,197, 89,247,133,181,215,245, 87, + 40,172, 41, 93,185, 91, 30, 93,117,113,101,178,148, 36, 20,167, 60,185, 33, 32,115,124,125,242,123, 32, 17,235,228, 58,103, 58, + 6,155, 5, 49,217, 1, 3, 41, 72, 72, 43, 80,202,251,124, 13,167, 57,231,230, 87,116,142,188,202,202,181,122,119,157,164,242, +182,128, 48,114, 74,210, 29, 82,148,174,231,149, 4, 14,112,122, 96,156, 36, 12,232, 82,130, 20, 22,181,207, 83,241,235,252,127, +134, 38,117,241,198,136,144, 66, 60,145, 40, 65,126,182, 80, 5,205,187,158,167,191,125,177,107,145,209, 56, 56, 42,192, 31, 7, + 50,136, 81, 39,245,114, 6,113,145,215,212,143, 62,186,109,183, 18,195,178,183, 58,203,185,118,235,114, 45, 74, 13,245, 98, 93, +244,185, 20,123,178,204,185,224,179, 84,161,215, 41,210,208, 90, 83, 50,227,188,143,209,202, 66, 15, 51, 50, 26, 45,202,140,234, + 80,244,119, 91, 90, 65, 46, 20,133,132,149, 18,121, 66, 82,146,158,167,227, 3, 9, 11,231,233,205,133, 28,116,233,240,231,231, +171, 4,167,130,146, 70,115,130, 7, 41,230, 1,190, 97,133,140,168,119,230, 25, 87, 47,167, 66,115,128,228,164, 50,233, 32, 21, + 35,161, 23, 7,226, 15, 81,234, 45,238,196, 78,170, 0,218,129, 93, 72,247, 12, 8, 22, 32,141,193, 7, 98, 10,220, 16,110, 45, +112,118,216,254,127, 62,215,111,101, 5,107,129, 75,173,157,208,218,223,173, 46,126, 22, 47,170,217,166,219, 21, 73,139,114,161, + 95,218,219,154, 98, 29,148,206,220,223, 83, 66, 63,194, 24, 91, 77,191,245, 45, 81, 88, 76,246, 99,150, 29,196,198,148, 28,226, + 11,202,192,207,250,185,206, 65,252, 7,207,183,227,175,213, 99,121,118,187,111,119,183,109,239,125,163,221, 75,114, 53,215,183, + 27,137, 66,147,110, 93,212, 9, 73, 66,132,168, 18, 70, 89,155, 1,197, 28,211,235,208,230, 33,137,116,249, 72, 41, 92,105,113, +154, 90, 84, 7, 50, 85,249,178,113,225,194, 13,235,193, 55, 17,215,238,197, 93,238,191, 80,167, 82,159, 69,111,111,238,242,201, +110, 45,251,182,117,197,186,245,165,117,196,233,203,239, 75,138,218,226,212, 26, 24, 84,122,141, 58, 75, 74, 74, 64, 71, 51,238, + 85, 86,192,138, 57,152,176,223,150,204,110, 72, 29, 81,137,234,203,216,159, 51, 46,237,118, 86, 99, 65,113,143, 12,174, 75, 50, +215, 81, 41, 25,101, 83,105, 43,215,145, 46,237,160, 27,127,116,226,230, 50,126,201, 86, 67, 97,203,213,166, 30, 57, 89, 86, 50, + 57, 63, 91, 35,175,110,154,250,115,156,144,122,249,254,255, 0,158,190,132, 99,161, 63, 14, 7, 46, 51,204,122,121,244,234,117, +245, 72,229, 29, 50,113,234,114, 6,127,226, 52,254, 46,118,196, 36, 11, 11,116,192,142, 40,231,160, 24, 29,207,175,231,166,135, + 82,137,238, 64,232,124,241,143,179, 68, 44, 19,211, 24,237,156, 99,160,245, 31,126, 52, 50,128,235,212,121,128, 78, 49,215,207, +246,105, 68, 59, 91,211, 6,181,253,109,251,240, 59,128, 1,240,171,174,122,121,121,246,207,159,246,104,101,244,200,243, 35,246, + 1,147,162, 21,140, 28,140,254,113,161,148,112, 8,235,215, 56,237,248,125,154, 85,112,176,189,136, 39, 3,168, 0, 15,145, 62, + 99,204,143, 35,249,242,208,203,229,235,235,211,242,126,225,162, 87,140,117,249,224,122,159,158,135, 88,233,231,247,118,251,254, +237, 44, 58,142,248,193,237,183, 67,243,247, 96, 69, 12, 31,183,175,217,165,175,171,198,113,140,126,255, 0,187,241,210,210,202, + 77,133,197,207,221,131, 99,202,112, 72, 7,242,117, 92, 15, 35,128, 60,190, 67,250,245, 69, 3, 39,236, 25,209, 40,239,246, 15, +207,219,164,143,175,174, 6, 42,164,124, 64, 14,131,166, 15,207,236,243,242,209, 35,215, 56,198, 62,220,124,191, 62,122,164,143, + 51,208,255, 0, 72,235,253, 31,213,170,160,100,227, 56,233,145,243,252,254,237, 17,175,109,186,223, 3, 4,160,140,231, 62, 93, +207, 79, 77, 22,130, 49,143, 63,233,251, 52, 26, 72, 30, 64,143,179,183,217,162, 1, 74,146, 72, 61, 65,252,115,142,159,159, 93, + 35,140, 48,184,235,108, 20,140, 18, 1,239,158,135,203,239,209,169, 7,166, 14, 79,145,253,186, 1,158,132, 17,149, 14,196, 19, +140,124,243,251,180,122, 72, 79, 76,145,211,160,233,147,164, 9, 36,220,225, 54, 29,199,206,216, 33, 4,224,142,153, 29, 85,219, +183,166,164, 73,236,110,220, 31,173,246,111,125,182,170, 68,175, 13,251,106,189, 68,191,169,177,199,196,183, 33, 84,227, 24, 21, + 2,134,250,229, 41,151, 17, 57, 35, 63,229, 6,117, 29,198,252,179,144,122, 1,230, 79,219,211, 93, 44,246, 85,110,228, 13,175, +226,214,210,164,215,229, 24,246,198,234,192,168,237,157, 95,227,228,108, 75,174, 32, 59,111,188,224, 39, 4, 38,172,195,104, 4, +246,247,157, 70,120,186,135,219,242, 26,232,130,234,146, 37,230, 46,215,221, 14,166,255, 0, 32, 97,247,226,198,240,131,136,227, +225, 95, 18, 56, 87, 54,157,180, 83,123, 64,167,148,237, 97, 29, 72, 48,220,223,107, 43,186, 57,255, 0,166,248,146, 36, 30,101, +188, 76,200, 92,160,148,190,196,228, 14, 82,218,114, 10, 92, 8,242, 87, 93,108,205,136,136, 94, 60,105,208,170, 83, 26,151, 9, +191, 29, 82,222, 74,157, 92,231, 64, 7,195, 90, 79, 64,192,244,244, 26,103, 63,131,149,104,117, 26,148, 68,184,195,109, 83,228, +173,134,209, 44, 2,226,202, 22, 82, 16,178, 79,234,114,242,159,179, 79,213,149, 33,113, 88, 77, 61,112, 27,121,229,248,106,149, + 58, 39, 41,101,148, 19,213, 63, 32, 79, 66, 62,237,115, 51,211,150,121, 6,155,219,175, 91,109,181,133,253,226,219,123,241,235, + 75,241, 11, 79, 76,188,137, 11, 48, 93,149, 89,118, 13,107,151, 89, 1,176, 11,212, 3, 98, 79, 75,219, 27, 67,183,181, 74,244, +214,231, 56,229, 74,158,135, 38, 41, 14, 18,160,166,156, 74, 16,156, 36, 32,118, 65, 62,159,191, 89,190,241,113, 11,110,112,191, +176,215,206,245, 95, 6, 20,202, 61,145, 74, 92,138,101, 45, 18,130,100, 92,247, 68,212,150, 40,116, 70,185,198, 84, 94,156,164, +120,132, 3,202,211,110, 40,118,198,137,219,165, 83,139, 76,133, 80, 28, 90,114,210,212,240,109, 10,241, 74, 15, 76,167,253, 94, +159,126,117,202, 47,164, 21, 92,174, 69,225,135,102, 32,209,169,178,160, 90,181,125,216,152,229,206,180, 71, 8,142,167,224, 81, + 11,148,102, 36,173,177,132,143, 17,201, 42, 66, 85,208,148,156,117, 26,113,203,168, 3, 58,157, 54,103, 33,125,118, 36, 94,196, +237,222,227,213,182,195, 70, 89, 79, 69,197, 92, 91,144,112,245,125, 61,168, 43,234, 1,157,252,177,147, 20, 49, 60,207, 26,149, + 58,245, 75, 28, 77, 18,149, 55, 93, 87, 27,139,227,130,123,191,198,175, 16, 27,247,184, 53, 45,208,191,119, 70,231, 85, 90,163, + 41,199,233,180,154, 61,106,117, 46,133,107,211, 84,247, 52, 26, 77, 22,153, 17,228, 34, 20,118, 27, 40, 72, 87, 47, 57, 41, 37, +106, 42, 36,235,167, 28, 15,251,109,119,107, 98,106,116,123, 7,136,169,179,119,107,102, 31,113,136, 72,172, 74, 90,101,223,214, + 83, 75, 33,180, 78,165,212, 93, 60,213,120,109,143,137,113,159, 82,138,146,217, 13,173, 11,198,163,142,186,235,108,188,164,169, +213,165,121, 56, 0,143,231, 19,148, 16, 58,242,145,159, 46,186, 6,109,204,220, 84,151,229, 73, 75, 76,165, 69, 13,186,181,124, + 13,149,252, 65,167, 20,122, 32, 43,175, 41, 61, 51,208, 28,156, 25, 60, 92, 63, 80, 37, 67, 1, 49, 19,208,129,189,141,182,255, + 0, 21,246,184, 55, 7,184, 56,236,142, 32,151,195,140,255, 0,133,223,133,248,147,134,104, 42, 50, 10, 88,196,113,162,172,112, +123, 24, 69,210,178, 83, 74,129,100,164,145, 7,247,111, 27, 39, 75, 54,164, 44,167,244, 98,220,125,244,218,109,207,181, 44, 93, +211,218,219,134,218,187, 42, 87, 53, 36, 51, 69,220, 10, 51, 17,100, 76, 69,191, 35,149,215, 40, 82,159,113, 5,234, 52,228, 57, +209,198, 86, 27,121,151, 16,161,243, 44, 38,219,240, 59,195,109,247,187, 50,119,219,118,236,200,251,153,118, 75,170, 65,173, 67, +182,174,118,154,153,103,210,171, 16,188, 32,197, 90, 69, 61,192, 77,102, 97, 83, 13, 41, 94, 54, 91, 36,117, 74,129, 58,135, 95, + 6,188,107,223,252, 45,110, 43, 52,233, 52,170,149,203, 96,222, 20,101,215, 83,103, 60,250,190,174,187,227,193, 5,199, 38, 91, +143, 44,148,196,174,178,208,123,149, 72,234,165, 37, 41, 87, 50, 84, 70,166, 95,193, 71, 19,251, 57,196,190,221, 82,183, 35,102, +111, 8,119, 37, 13,224,211, 21,170, 59,206,165,155,154,207,170,129,201, 34,143,114, 82,138,185,226,186,219,193, 72, 75,184,240, +221, 9,202, 85,215, 26,134,231,185, 70,123, 75,158, 38,105, 42,145, 71,202, 88,163,146, 50, 90, 29, 18, 16,197, 88, 92,133,119, +146, 38,219,245,140,108,190,102, 70, 11,198, 92, 75,194, 16,120, 95, 13,105,224,204,246,176, 46,111, 21, 85, 20,213, 74,239, 79, + 89,200,142, 74,121, 30,138,165, 99, 8,209,242, 82,106, 70, 89, 32,229,195, 52, 53, 48, 77, 24, 84,168, 68, 26,105,237, 7,217, + 19, 64,220,153,215, 20, 88,210,156,133, 88,145, 38,124, 79,119,101, 69,163, 18,166,128,243,109, 37, 40, 1, 44,161,169, 41,117, +174,100,245, 74, 25, 74, 0, 3, 3, 90, 51, 69,177,226,173,138, 60,234,204,122, 85, 38,221,129, 41, 51,103,211,161,176, 94,110, + 91,208,250,114, 84,204,148,115, 56,210,150,121,194, 65, 70, 22, 18, 73, 35, 82, 72,226, 42,210,160,110,117,160,197,162,168,115, + 29,188,213, 74,168, 86, 45, 9, 77, 65,126, 76, 10,156,120,126, 17,171,208,229, 78,105, 60,176,167,150, 84,151,226,161,194, 60, +101, 71,113,182,200, 89, 26,226, 82, 54,226, 82, 43,245, 56, 55, 19,146,165, 82,168,173,189, 53,234,122,121,219,167,174, 92, 53, + 21,161,215,162,173,172, 60,148, 33, 24, 82, 73, 88,113, 92,185,201,201, 27,117,108,244,241,194, 26, 80, 4,200,175,177, 5,212, +177, 33,144,129,246, 88,144, 74,234,211,113,184,242,225,135,128,248,146,174,159, 42,143, 44,172,115, 72,249,120, 15, 20,146, 35, + 63, 50,152, 72,218, 26, 20, 93,164,179,172,144,173,201, 8,234, 67,105,179, 12, 29,182,244,136,190,236,139,162, 43,211, 44,218, + 8,144,234,232,245, 56, 11, 17,235, 21,134,156,116,152, 20,134, 80,176,164, 56,209, 72, 43,143,200,135, 22,133,101, 74,113, 57, +214,238,237,187,251,130,203, 76, 67,151, 72,167, 84, 98,133,170, 91,213, 42,148,233, 12, 76,138,192, 82,148,219,210, 68,113,202, +170,138,219,193, 89, 73, 67,106, 72, 42, 40,200,248,181,222,133, 7,252, 38, 61, 94,168,236, 48,218, 34,198,106,222,121,215, 12, + 42, 5,177, 73, 72,109,202,131, 44, 54,165, 4,166,172,236,131,241, 5,128, 23,219,155,149, 1, 39,109, 54,169, 47,214,159,141, + 78, 48, 42, 53, 11, 73,106,126, 99,142,173,244,196,145,119,169,196,182,166,100,201, 84,167, 3,137,162,161,194, 72,100, 6,202, +154, 9, 82,143,134, 60, 50,195, 58,115, 25,121,138, 2, 2, 5,250,155,236, 2,134,216,220, 95,168,238, 13,133,186, 73,115,220, +216,213, 80, 74,207, 75, 13, 76, 72,128,234,144,106, 49, 40, 80,161, 99,149, 74, 52,149, 4,141,198,181, 87,112,116,142, 90,187, +151,130,212,169,221, 85,192, 81, 71,162, 69,143, 17,233,177, 66,234,213,121,210, 29,109,249,104, 83,136, 47,211, 99,197,142,149, + 42, 58, 27, 13,132,100,161, 42, 4, 36, 14,234,214,192, 82,168,207, 6,100, 72,146,243,115, 36,115, 37,223,120, 83, 66, 40,134, +150,151,200,182,225, 67,103,224,109,191, 19,152,143,214, 95, 97,205,166,202,221,175,203,122,100, 42,117, 14, 27, 48, 96, 45,217, +109,187, 93,144,132, 73,164,149, 65, 11,113,200,212, 8,170, 80, 21,149,224, 37, 41,120,242, 70, 10, 10, 9, 83,160, 99, 78, 43, +116,232,146, 18,162,237, 86,169, 54, 43, 79, 52,133, 63, 42,172,182,163, 42, 83,190, 32,120,165,166, 16,210, 27, 75, 65, 69,178, + 18,158, 64,162, 82, 50, 81,157,111, 81, 68, 21,129, 8, 22,227,101,189,237,123,109,114, 1,185,236,109,232, 47,107,226,137,226, +141, 77, 41, 30,203, 30, 87, 20,158, 96,168, 26,121,138, 19,111,172,118,118,179, 18,159,221,137, 20, 88,110,150, 85,193, 53, 73, +145,226,170, 46,101,196, 76,164,184, 28,240, 12,134,153, 95, 43, 10, 74,155, 46,181,207,144,121,194, 7, 62, 9, 82,143, 47,108, +234, 4, 62,210, 58, 72,219,158, 58,184,155,183, 37, 40,183, 29,237,225,189,234, 44, 58, 57,127,200,220,181, 35,117,198, 37, 8, + 56,229,118,159, 89, 74,128,242, 87, 67,131,157, 78,142,170,138, 83,209,158, 69, 30, 52, 6,160, 54,228,136,114, 46, 38, 99, 50, +181,206,146,133,248, 78, 67,166, 72,113, 37, 82, 16,149,149, 37,199,134, 91, 66,242, 26, 11, 88, 90,147, 16,207,164, 3,178,234, +161,113, 5,183,251,173, 73,167,134,104, 59,189, 97,210,168, 85, 9, 52,211,200,236, 43,223,109,162, 38,218,168,185, 41,231, 21, +137, 21, 23,168, 70,202,152,128, 87,226, 56, 92, 95,235,114,171, 51, 28,157, 98,150,190, 8,100,110, 92, 83,221, 79,199, 69,239, +185,177,177, 27, 15,128,189,142, 45, 63,163,127, 17,212,112,127, 20,113, 29, 53, 38,185,106,243,156,177,196, 81, 58,133,230,212, + 82, 85, 83, 84, 44,108,169,172,160, 52,166,171, 97,169,163, 3, 91,114,200, 24,226, 4,154,196,244,219,106,220, 88, 18, 36,123, +230,213,238,117, 58,151,184,116,120,110,184,212,168,118,117, 66, 76, 20,196,186,144,180, 43,157,136,145,234, 12,197, 91,146, 81, +132, 70,114, 83, 75, 43, 75,110,100, 74,151,217,207,198,213, 39,137, 54,238, 61,133,221, 10,180, 42,127, 21,123, 72,167,219,169, +193,146,168,241, 90,223,139, 2, 44,118,170, 52, 45,207,178, 66, 74, 81, 80,184, 88,183,166,211,141,199, 76,103,157,106, 33, 53, +232,129,216,210,102,162, 20, 59,161,215,121,234, 81, 43, 84, 91,170,177,103,222,204, 45,171, 98,241,138,155,114,161, 89, 69, 74, +148,180, 59, 78,143, 92,122,151, 17,151, 83,112, 82,132, 69,184,196,200,129,133, 59, 38, 25,125,133,176,243,141,180,149,244, 87, +132,222, 13,248,140,184, 47,203, 39,113,120,121,171,199,191,238, 93,185, 98, 53,251,111, 91,251, 99, 85,166,215,175, 87, 41,240, + 42,241,155,165,214,182,154, 47,191, 41, 91,145,104,211,234, 42, 83, 92,148,103, 83, 85,163,199,117, 84,250,197, 33,136,225, 97, +185,206,113,194,121,109,101, 27, 45,125, 80,163,171, 2, 95, 99, 38, 41,121,134,115,162, 78, 66,144,133, 38,141,138,205,202, 84, +102,150,120,231,139,150,134, 90,104,163,158, 75,196,249,142,105,226,180,212, 89,118, 93,165,163,138,170,138, 74,220,202, 74,236, +184,209, 80,208,200,239, 65, 46, 97, 87, 27,213, 71, 85, 72,252,182,203, 23, 53,133,225,134, 42, 12,195, 41,170,210,211, 69,154, +203, 85,150,205,166,227,165, 61, 6, 5, 54, 97, 74,156, 18,227, 69,110, 35,140,180,165,169,249, 82,156, 67, 13, 71,138,218, 85, +241,185,226,184,218, 91, 31, 9, 82,214, 50,122,244, 11,114,111, 27,114,131,182,251,199, 34,255, 0,136,154, 45,247,176,245, 58, + 22,218,111, 22,216,181, 81,143, 85,184, 45,221,195,188, 89,183,161, 89, 20, 42,100,159,117, 96, 92,148,187,141,187,194,223,118, +133, 84,102, 59,113,170, 72,126, 72,105, 41,114, 12,164, 55, 75, 99,119,122,224,174, 51,245, 7, 19,219, 89,112,112,215,186,220, + 60,220,144,175, 61,215, 77,193,108, 87,174,237,159,151,101,211,226, 77,189, 33,110,173,151, 93,162, 70,144,154,221,142, 81, 76, +164, 63, 80,165, 60,241,153, 77, 68,215, 72,114,100, 8,147, 31,135,146,113, 71,183, 59,103, 34, 92, 13,253,110,235,173,110,165, +205,184,176,173,202,147,143,193,221, 91, 86, 92, 45,209,191,156,186,104, 59,129,181, 86,205,199,245, 20,121, 48,102,109,181,175, +123,214, 32, 86,104, 82, 40,181, 28,208,209, 13, 52, 53,191, 38,135, 86,101,109,214, 19, 84,229,188, 53, 74,207,159,161,161,167, +175,150, 56, 86,121,140,113,211, 67,100, 55, 51,107,101,157, 73,146, 72,180,145, 11, 42,168,147,153,162,197,146,162,201, 56,112, +210,113,141, 46, 79,196, 20,245, 18, 53, 58,173, 84, 67, 46, 95,106,106,245, 73, 41,170, 2,208,207, 24, 52,245, 80, 86, 80, 37, + 72,165,150,158,114, 90,122,170, 9,135,212,151, 87,227, 20,104, 45, 87, 24, 85, 86,218,241, 42,148, 71,110, 43,170,211, 76,212, + 52,150,132,106,245,151,114, 85,109, 11,162,129, 84,104,168,251,149,106,157,112,209, 42,113,229, 48,188, 58,218,227,142,108, 33, + 77,169, 90, 21,237, 94,168,222, 22,133,223,195,254,202, 10, 93, 82, 93,177,180, 43,183,183,154,236,164, 81, 20,153,146, 98,238, +125,229, 73,129, 91,163,213,175,116, 52,191, 22, 53, 66, 29,188,253,173, 71,167, 81, 57, 76,150,133,213, 81,149, 33, 81,220,148, +211, 74,150,182,225,218, 92, 50,112,247,195,165,153, 77,165, 90,219,117, 99, 91,150, 60, 43,174,244,174,223, 49,109, 27,134,228, +218,202,205,255, 0,107,212,149, 18,116,251,243,114,104,207,201,168, 51,121, 72,220, 7,211, 38,169, 13,184,115,170,215,251,244, +217,244, 88,238, 70,155, 37,169, 49,121, 20,212, 93,185,118,222,225, 46,203,225,223, 98,183, 23,120,253,160,252,116, 84, 55,118, +117,213,191, 91,223, 72,247, 69,219,219,105,184, 23,221, 98, 20,254, 44,230,237,204, 42,236,138,109, 42, 84,217,212,251,153,118, + 17,144, 93, 52,138,101,143, 85,175,174, 58,252, 58,125, 67, 79,254, 28, 54, 93,153,214,174,113, 79, 20,121,133, 44, 97,185,112, + 9,150,105,100, 73, 41, 86, 94, 92, 38, 35, 21,167, 43, 81, 29, 57,169,144, 44, 20,142, 37,170,101,154, 49, 70,106,111,238, 14, +168,151,137,248,115,244,207, 19,210,215,101,116,144,212,140,186,131, 48,134,146, 36,164,139, 59,164,121,107,219, 53,204, 26,181, +229,163,139, 38,160,162,201,235, 36,205,169, 85,235,234,125,154,190, 36,140, 9,162,154, 90, 72,169,213, 45,253,208,118,151, 97, + 90, 91,181, 38, 13,167,103, 94,215,213,102,231,174, 55, 49,215, 31,172,238, 77,247, 17,216,119, 14,228, 45, 49,233,233, 9, 77, + 46, 21, 66, 69,159, 70, 41,134,135, 99,193,140,211, 84,180,200,231,102, 82,155, 18,155, 83,131,120, 85,111,219,154, 3, 50,105, +148,169, 19,160,193,160,214,170,113,194,103,214, 98,211,229,168,183, 62,159, 72, 66,178, 89,147, 84, 14,152,173,252, 45,248, 13, + 54,178, 84,149,147,169,133,123, 64,189,146, 86,255, 0, 13,187,109,182,187,145, 64,219,248,219,185, 14,215,178,234,116, 13,218, +222, 42,148,217, 2, 53, 42,184,204, 22,226,237,117,131, 14,206,132,240,114,194,225,222,157, 83, 53,138,149,106,161, 29, 14, 73, +171, 86, 42,171,153, 89,124,169,230,121, 34,177,182, 91, 65,116,111, 46,243,196,218,253,171,247,251,206,183,116,213,106,146,228, +110, 45, 77,182, 89,136,139,118, 28,148,197,186,119, 9, 54,243, 47, 6,109,107, 54,152,143, 26, 45, 38, 35,139,255, 0, 5,141, + 9, 78,190, 85, 41,232,140,170,115, 83, 86,212,245, 25,140, 21,212, 63,162,231,161,141, 36,125, 43,202,166, 45, 35,172,211, 73, + 10, 63,152,169, 40,176, 6,149,220,186,195,120,162,104,238, 34,191,184, 15, 62,224,252,219,132,178,206, 51,225,190, 45, 60, 75, +193,102,174,190, 55,168,174,180,249,164,116,185,109, 52,249, 86, 93, 75,153, 84,195, 32,246,103,141,107, 43,115,158, 82,101,249, + 74,150,205,227,150,183, 49,167,173,118,253, 35, 52,143, 98,189, 5, 54,159,179,243,109, 77,101, 98, 4,221,196,190,119, 71,112, + 90,102,181, 21, 8,139, 91,164,212,174, 88,182,196, 10,140, 85, 56, 18,219,240,220,254, 9,200, 41,115, 33, 74,231, 82,146,146, +218,155, 42,234,187,209, 27,163,184,237, 90, 72,168, 42,130,200,240,165, 64,143, 38, 82,158,160,173, 74, 13, 9, 84,182,157,124, + 46, 93, 57, 73, 90, 10,152, 73, 43,100,172, 41,160,180,115, 32, 49, 27, 9, 77,177,109, 93,139,217,139, 99,111,227, 72,143,183, +214,214,217,218,118,173,163, 6,173,153, 19, 88,131,108,210, 99,208,101, 65,174,135, 83,148,212,157,159, 79,150,244,181, 20,148, +123,204,229, 43,177, 57,114,208,124, 17, 57,202, 83, 14,170, 36, 5,137, 85, 10, 36,185, 75, 84, 55, 96,202, 71, 42,132,120,171, +113,106,241,219,116,146,219,173, 15, 11,186, 85,148,168,114,194,132,136,200,173, 31,158, 54, 80, 65, 3,168, 34,224,129,232, 65, +213,184,220,116, 23,199, 0,113,150,101, 55, 20,241,127, 20,113, 19,235,165, 25,245,125, 85, 67,198,196,108,179, 84,182,152,185, +133,129, 73,145, 89, 34, 14,220,203, 72, 8,103,229,150, 86,247, 81,110, 91, 49,167, 78,161,215, 37,212,219,113,213,165,218, 85, + 69,240,244, 26,132, 54,129, 11, 49,228,181, 29, 46, 66,168,140,245, 75,156,193,124,161,183, 27, 28,201, 86,190, 81,155,125,104, +135, 34, 12,114,220,121, 41, 40, 98,157, 53,228,170, 35,114, 20,230, 86,221, 26, 80,200,167, 40,169,103,158, 59,169, 8,202,112, +128,131,144, 60,211,163, 71,152,183,230, 83,229,191, 4,133,169,153, 76,134,179, 60,198, 89,109,232, 14,212,225, 62, 86,221, 65, + 13,185,148,165,196,101, 78, 32,243, 37,209,130, 19,153,208,146,134, 81, 41, 19, 11, 49,214, 86, 24,121,165,178,165, 69,168, 40, + 31,135, 1, 64,169, 46,149, 41, 36, 40,254,144, 5, 36,146,188,100, 38,134, 48, 25,152,141,172, 46, 77,136,220, 27,250,141,253, +222,226,122,130,193, 89, 80, 41,169,164,139, 72,146, 84, 43,112,200, 85,236, 84, 40, 87, 84, 1, 94,219, 21,144, 93,244,155, 22, + 69,101,209,125,183,168,209, 97,190,250,204, 70,152, 5, 64,200,140,166,150,203,176, 87,241,151, 94,136,160,178,134,218, 89,230, + 82,128,202,114,162,164,100, 2, 53, 28,111,107, 60, 59,251,143, 63,104, 23, 11,126,205,170, 3, 53,106, 46,201,109,173, 53, 27, +255, 0,189,117,166,249,216,137, 90,147, 49, 18,105,172,202, 66,146,174, 71, 98, 81, 45,102,106, 49, 24, 42,193, 53,155,189,229, +160, 5,197, 73,215,123, 47,141,211, 98,142,167,173,155, 89,193, 42,229, 25,106, 76,148,165, 47, 71,180, 91,112, 5,120,181, 23, + 14, 83, 34,182, 58,174, 44, 18,162,180, 43,149,249, 92,173,165, 40,113,184,160,218,118,243, 51,158,189,219,161, 64, 93,228,170, + 58,109,137, 55, 99,177,210,229,194,253,186,103, 61, 86, 93, 46, 69, 85,196,248,174,194, 85, 90, 68,169, 42, 65, 86, 20,243,235, + 89,234,113,167, 76,190, 73, 36,154, 36, 66, 2,174,204,196,216,168, 96, 86,235, 97,187,142,171,113,179, 0, 79, 96, 43, 78, 39, +200,167,207,168, 64,172,169, 48,195, 60,176,243, 35, 59,153,169,213,129,145, 9,184, 40,178,128, 35,189,201,120,217,238, 72, 33, +152, 74, 45,191,110,218, 20, 10, 5,159,104, 82,163, 80,109, 43, 50,145, 78,182,173,138, 20, 36, 37,152,116,202, 37, 38, 58, 33, + 65,136,219,104, 24, 24, 97,176,165, 43,186,214,165, 45, 89, 82,137,214, 66,192, 44, 56, 50, 64, 66,255, 0, 84,246, 74, 22,174, +188,167,230, 79,109,121, 92,114, 87,226,132,243, 5, 16,162,145,156, 45, 62, 69, 56,238,161,231,246,106,239, 2, 58, 29,109,109, +140, 45, 4,158,231,170, 65, 29, 58, 31, 49,251,181, 41, 93,150,200, 52, 42,216, 5,236,161, 64, 0, 1,233,167,107, 95,107, 15, +118, 6,132,133, 20,133,242, 45,129, 0, 88, 1,181,128, 29, 5,187, 14,150,219,160,198, 15, 92,140,185,115,138, 64, 42, 71,192, + 48, 51,148,245, 42, 81, 7,237,199,237,198,179, 75, 74,130,162,174,110, 64,124, 66, 48,124,213,215,155,149, 64,142,249, 35,240, +215,148, 83, 60, 73,124,161, 36,156,132,103,190,121, 71, 64,125,124,254,243,173,128,177,237,177,134,150,166,134, 7, 42,186,224, +143, 44, 12,121, 14,154, 67,202,160,201,111, 49,218,255, 0, 63,127,239,196,120,213, 0, 90,237,117,185, 55,251,239,238,249,252, + 47,182,197,185,224,181,226,148, 36, 57,202,148, 5,148,228,167,152, 5, 58, 79, 79, 76, 14,157,180,226, 8,126,236,203,104,229, + 60,234, 39, 41, 0,168,144,160, 20,178, 64, 31,173,203,129,242,206,178,138, 93, 27,145,148, 5, 35,225, 35, 39, 61,212, 7,196, + 78, 60,251, 1,143, 61,123,145, 19,153, 69, 69, 4, 41,106, 8, 66, 83,212,227, 32, 37, 32,103,190, 59,159, 85,124,134,144,177, +221,137,249,239,127,225,134,106,140,228, 77, 49,141, 79,213,198,127,211,243, 54,237,139, 84,118, 89,109, 14, 61, 41,212, 70,139, + 13,135, 37,204,148,176, 18,212,104,172, 36,184,227,206, 40,246,108, 37, 56,249,146, 7,158,181,250,179, 86,126,239,172,200,171, +165,165, 49, 78,105, 40,133, 70,101,239,129, 48, 41,109,171,225, 88, 0,126,146, 83,234,203,139, 61, 57, 66,130,124,177,167, 30, +243,170, 10,151, 53,173, 13,126, 37, 62, 51,173,185, 94,117, 25,228,155, 49,165, 7, 24,164,151, 19,254, 82, 35, 74, 8, 47, 36, +116, 83,129, 32,146, 1, 26,196,209, 13,152,192,120,189, 72, 36,248,109,160, 56, 2,128, 5, 63,163, 79, 92,103, 3, 39,160,236, + 58,233, 61, 70,161,194,166,241, 70,119, 63,180,195,227,217,127, 22,248, 41,196,175,135,160, 90, 56,228,204, 39, 66,107,106,150, +209, 41, 6,241,194,108, 75, 91, 99,174, 91, 3,191,217,140, 1,191, 54, 69,192, 76, 50, 27,111, 13, 54, 73, 64, 9, 75,139, 82, +155, 0, 43,169, 44,128, 9, 62, 93, 64,193, 61,206,129,152, 95, 41, 82,138,208, 22, 65, 72, 12,164, 32,165, 0, 36,148,163,152, +144,217,234,147,145,223, 36,228, 96, 13, 93,159, 83,174,103,149, 32, 40,182,126, 55, 51,206,132,145,201,240,161, 7, 35, 62, 99, + 32,129,158,249,214, 55, 45,212, 37, 96, 41, 41,120,167,152, 0,148, 0,129,149,167, 39,148,225, 32,224,247, 61, 71,166,116,224, +158, 91,109,185, 27,219,231,253,127,117,240,237, 35,179,146, 77,153,143,253,199,183,115,176,223,225,139, 75,238,163,147,144, 21, + 40, 96,142,116,142,164,165, 71,170,222, 82,187, 31,136, 4,140,243, 1,229,215, 88,252,183, 65, 72, 11, 82, 74,126, 16, 8, 28, +184, 82, 72, 9, 66, 86,188, 18, 18,124,176, 62,100,224,157, 92, 39, 56,224, 82,146, 23,204,162,174, 95, 9, 9, 79, 55, 83,240, + 40,169, 64,252, 33, 36,252, 92,160,245,192,214, 45, 49,208,142,112, 21,241,171,170, 65, 78, 85,128, 50, 82, 74,129,229, 60,160, +143,187,169,234, 53,176,135,175,112, 15,243, 31,187,175,201,195, 45, 82, 13,247,235,252, 62,255, 0,187,182,253,175,139, 84,247, + 82,160,163,130, 9, 39, 36,167,159,175,196, 10,138, 66,176, 19,215,191,145, 57, 25,215, 6, 61,188, 92, 35, 69,226, 19,132,201, + 91,199,110, 82,195,187,161,195, 10,102, 93,241, 28,140,192,126,125,115,105,170, 47, 48,214,226,219,142,184,128, 86,242, 33, 44, +195,173,196, 64,207, 34,224, 76,242,116,235,186,178,222, 24, 37, 41, 81,237,144, 82,160, 20, 48, 84, 0, 3,162,199, 82, 58,245, + 31,127, 70,250,191, 79,164,215, 96, 84, 40, 85,216,173, 79,160,215, 96, 84, 40, 53,232, 14,182,151, 35,203,161,214, 98, 61, 73, +173, 66,121,165,116,117,135,105,115,166, 54, 71,126, 85,224, 28,246,216, 14,203,105, 35, 63, 89, 25, 12,191, 17, 98, 47,238, 61, + 15,184,145,176, 59,197,243, 92,186, 44,214,138,175, 46,156,218, 42,180, 41,114, 7,145,137, 5, 36,183,172,110, 22, 65,210,229, +109,238,199,229,128, 82, 2,137,239,143, 49,212, 31,152,199,126,154,248,172,145,219,166, 51,147,251,191, 13, 61,188, 74,237, 67, +251, 7,196, 22,245,108,212,198, 21, 21, 91,103,185, 87,117,161, 21,133,168,173, 72,164, 83, 42,242, 5, 1, 65, 71,170,194,232, + 46, 83, 92, 10,235,144,230,114,115,146,198,169,106, 88, 4, 43,155,166, 71, 76,119,245, 30,186,153,211,202,179,197, 12,202,124, +178,168, 97,235, 98, 1,254,120,230,119,142, 72,157,226,149,116, 75, 17, 42,227,209,212,233,101,251,152, 17,138, 46, 16, 70, 51, +235,156, 28, 99,251,116, 42,177,142,195,148,103, 30,125,187,147,243,213,117,168, 30,224, 12,142,248,206, 79,217,161, 87,208, 31, + 60,156,126,255, 0,221,173,192, 44, 0,244,192, 29,190, 56, 29, 89,193,233,255, 0, 14,253, 52, 34,142,113,223,207,184, 3,240, +209,107,237,223, 29, 71,231,243,233,161,156, 32, 2, 51,147,231,142,191, 62,154, 85, 7,124, 42, 44,119,192,171, 35,203, 63,126, +113,231,228,117, 69,125,179,147,255, 0, 31, 93, 87, 95, 55,158, 49,229,249,245,208,235,199,207, 62, 94,159,126,149, 2,228, 99, + 29, 0, 3,231,255, 0, 24, 21,103,175,216, 49,159, 93, 45, 37,254,183,221,211, 75, 74,139,128, 0, 31,142, 13,143,168,198, 79, +124,227,238,199, 79,219,162,145,140,118,235,230,113,251,254,205, 8,223, 83,147,145,208,244,251,241,215, 69, 35,177,235,231,219, +247,232,141,107, 47,108, 12, 18,142,199,167,223,235,249,253,250,169,158,221,250,124,254,126, 94,154,164,140,245,233,211,215,247, +124,245,237, 36, 40,144, 15, 99,131,223,161,210, 78, 54,248, 96, 99,223,140,142,249, 24, 0,103, 25,202, 78,139,108,149,129,212, + 0,124,241,215,168,233,211,239,253,154, 16,180, 1, 56, 0, 36,228,159, 79, 44,147,243,254,189, 86,109, 65, 36, 14,184,198, 2, +143,203,212,253,218, 64,155,117,192,193,237, 39,151, 3,175, 66,123,119, 63, 63,144,209, 8, 95, 51,137, 73, 78, 57,115,241, 30, +221, 60,178,126,122, 8, 60,140,148,130, 85,216,224,117, 87,159,124,253,167,240,209, 63, 11,137,248,186, 28,252, 35,168,207,219, +248,233, 22,234,113,131,235,243,233,139,187, 64, 43,162,136, 63, 49,147,235,233,247,106,247, 70,169,212,104, 85, 90,117,110,145, + 41,200, 53, 90, 68,248,117, 58, 92,198,148, 80,236, 90,141, 62, 75, 82,225, 74,109, 67,170, 84,137, 44,180,175,184,141, 88,152, + 10,229, 79, 96, 48, 57,177,219, 35,167, 79,219,162,211,156, 40,118, 30, 71,184,249,245,242,233,162,144, 24, 21, 97,112,118, 32, +239,132, 15,196,169, 30,155, 16, 71,112, 71, 67,137,193,240,233,185, 20, 62, 44,120,124,219, 61,240,167, 76, 71,191, 84,105,140, + 81, 55, 14,155, 5, 64, 73,165,223,148, 54,155,135, 89,139, 53, 8, 57,103,197,121,191, 25, 25,253,100, 72, 65, 4,131,173,161, +180,210,245, 40,183, 10, 44, 52,248, 14,171,153,247, 36, 40,150,208,211,100, 16,181,171,201, 93, 7, 79, 83,168,161,123, 40,248, +226,137,194,214,237,191, 97,110, 76,199, 6,196,111, 20,202,117, 42,239,113,106, 82,155,179,174, 82, 83, 18,135,123,178,146,127, + 69, 25, 42,113, 12, 78,199,254, 43,149,211,158, 67,169,140, 46,220,104,182,207,128,184,210,104, 79,178,197, 70,159, 80,128,226, + 36, 70,171, 65,146,132,189, 18, 92,121, 77,168,165,248,174, 52,182,212, 10, 73, 7,155, 84, 39, 16,240,233,203,115, 25, 99, 88, +201,130, 67,170, 35,216,169, 61, 47,220,173,244,155,247,243, 17,102, 24,239,143, 11, 60, 80,110, 39,225,218, 88,107,103, 15,152, +229,170,144,213, 33, 98, 60,234, 0, 89,236, 55, 34,117, 93, 98,219,115, 3,198, 8,209,135, 82,196,175,212,218,113,133,198, 84, +117, 38, 71, 32, 67, 78,101, 4,182,142,157, 7,255, 0, 22,125,124,255, 0, 13,121,226,147, 97,169,220,100,236, 45,251,195,253, +214, 96, 83, 89,184, 96, 55, 58,221,184,156, 71,138, 45,139,210,151,207, 34,220,169,161, 93,196,113, 36,248, 82,113,221,137, 11, +244,198,172,116, 62,102,100,181, 29,160, 61,231,149, 60,142, 99,224,101,164,246, 3, 29,128, 25,233,173,128,164, 74, 18, 99,198, + 73,116,183, 25,181,114, 60,178, 57, 76,151, 16, 50,162,162, 14,124, 60,129,246,235, 82,158, 2,165,118,210,203, 98, 45,216,245, +190,219, 94,253, 7,223,139, 66,108,214,122, 57,232,179, 76,177, 18,150,182,141,214,104,102,243, 49, 73, 35, 33,209,244,220,171, +217,133,180,176,210,230,225,188,151,199,230,211,196, 86,208,238, 55, 15,155,153,121,237, 22,231, 81,100,219,215,221,143, 82,149, + 79,168, 71,125,106,110, 52,230, 88, 90,132,122,157, 46,106,128, 76,202,124,136,220,143, 71,121, 63, 11,141,186,146, 8, 36,141, +107, 90,238,137,210, 99,242, 84,194, 39,208,228,243, 69,156,165,101, 50, 16,209, 35,156,184, 17,212, 56,158,138, 66,198, 72,229, + 26,253, 19,125,160,126,206, 29,169,246,133, 88,112,226,214,219,129,100,111, 5,191, 18, 68, 91, 19,116,219,132, 28,148,220, 38, +208,181, 53, 65,186, 99,180, 66,170,182,233,119, 30, 25, 39,198,138, 86,165, 50,121, 74,144, 97, 29,196,223,179,219,138,238, 14, +171, 85, 42, 30,238,109, 69,202,253,158,137,146, 26,165, 95,150,229, 61,202,229,149, 91,134,219,133, 41,155, 18,173, 13,165, 6, + 91, 82, 48,172, 57,202,180,231, 5, 26,179,178, 42,250, 57,225, 72,106,149, 86,169, 74,233, 44,116,220, 29,175, 27,118,123,216, +133,216,130, 59,142,146,250,158, 42,173,226,215, 74,204,190,189,178,218,167,133,214,182,141,111, 32, 18,142,242, 68,219, 84,208, +202,162, 69,119,250,199, 68, 58, 38, 17,181,158, 86, 98,205, 98,245,184,155,179,246,190,133,117, 81, 43,212, 69,205, 93,107,111, +171,201,247,180,220, 22,125, 75,170,221,143, 77,172, 67, 70, 41, 51,212, 66,147,225, 62,180,195,146,121,152,117, 41, 82,145,153, + 39,123, 14, 56,116,186,118,163,136, 57,119,139, 91,231,181, 82,105,117, 56,211, 85,187, 59, 81, 50,174,154, 46,225, 86, 41,142, +178,236, 71, 96, 81, 44, 39,154, 15, 79,169,138,138,154,146,169,140,169,198,154,240,202,146,121, 8,214,156,123, 19,246,162,147, +184,219,245,181,214,173, 74,157,114, 91,212, 68, 94,177, 46, 9, 87,209,164, 82, 35,166,152,213, 40, 26,147,148,152, 53,249, 12, +182,135,161, 77, 92,118,163,188,212,150,221, 87, 43,171, 72, 10, 95, 41,212,194,248,217,224, 59, 96,239,203,211,110,184,157,163, +220,219,119,195,142,224,236,189, 90, 53,199,112,238,141,180,213, 54,131, 86,184,173, 90, 80,241,158,162,204,105,137, 44, 68,247, +146,216,120, 38, 83,136, 82,185, 95, 91,106, 14, 36,132,105, 42,177, 85, 95, 69,196, 84,180,235, 13, 45, 13, 59, 8,229, 63, 84, +100,153,228, 44,254,209,101,229, 8,180, 29, 45, 34, 57,120,102, 98,238, 84, 54,248,177,115, 46, 32,224,110, 24,171,225,142, 26, +226,122,217,198,119,199, 25, 21, 76,116,245,242, 71, 93, 93, 67,144, 67, 83, 72,217,122,208,154, 38,146,170, 74,254,122,137, 97, +203,171, 80,123,126, 86, 13, 50,114,230,134, 52, 43,104,160,110, 52,106,229, 82,239,218, 10,165,197, 42,143, 92,155,112, 63, 79, +182,109,170,172, 86, 42, 53, 42,212, 72,110,166, 83, 17, 83, 38, 18,137,166,133, 50,164,172, 60, 85,240,145,228,123, 92,248,153, +225, 90,117,139, 14,223,186,217,144,212,184,247, 13, 37,217,245,234, 50, 30, 68,154,188, 47,118, 5,245,153, 13, 36, 5, 84,225, +248, 64, 45,114, 16,133, 4,120, 5,183,210,145,135, 23,170, 17,120,166,246,122,210,239, 8,251,245, 73,221, 42,108,202,125, 54, + 85,110, 12,136,116, 25,110, 42,164,252,181,186,183, 36, 84,100, 71,157,200,243,176,212,251, 97, 40,154,128, 27, 80, 87, 42, 0, + 73,215, 28,248,248,246,138,238,223, 31, 27,209,100, 13,189,190,175, 61,174,217, 13,133,184,168,247,110,220, 46,215,168, 72,182, + 43, 50,175, 26, 23,136,134,174, 58,133, 66, 41, 14,213, 96, 61,144,143,113,148, 85, 17,198,121,155,117,149,165, 68, 30, 78,240, +151, 41,171,203,168,248,214,139,140,242,218,147, 61, 39, 46,146,154,176, 74, 94, 58,115, 70,238,237,110,102,210,194,237, 49, 74, +101,167,176,152,106,242, 71,253,233, 17,120, 7,226,111,137,188, 85,195,180,126, 29,112,252,188, 55,150, 71, 72,245, 89,147,103, +144, 54, 91, 11,230, 13, 18, 65,236,212,236,144, 84, 78,202,220,184,170, 37,144,199, 57,137, 21,156, 76,199,149, 3,245, 94,101, +153, 14, 91, 11,118,106, 60, 38, 42, 50, 98,248, 52,232,255, 0,224, 76,210,169,176,210, 23, 58, 67, 75, 75,170,196,215, 65, 90, + 66,200, 82,134, 70, 57,121,122,190,116, 74, 93, 58,224,113, 52,104,137,117, 22,180, 38, 41,236, 84,166,201,117,250,127,189,196, +138,202,165, 63, 77,135, 61,213, 5, 70,128,166,194, 12,199, 18,144,165,140,160, 16,130,179,166,155,101, 55,170,133,187,214,166, +214,220, 55, 67, 20, 74, 22,231,223,150, 76, 91,182, 85,181, 1,133, 66,160,215,231,197,159, 82,164,204,170, 90, 80,221, 39,244, + 42,118,154,185, 47,211,155, 89,114, 42,164,175,221,144,228, 84, 39,195,216, 74,124, 72,107, 67,204, 60,133,205, 66,221, 76,153, +140,248,200,105, 21,106,162,212,144,195,107,125, 39,244,116,228, 20,254,149, 32,124, 73, 74, 16, 82,160,149, 5, 73,200, 40,225, + 8, 33,133,138,157,182, 82, 3, 95, 73,181,137,216,116,212, 13,238,110, 49, 90,230,167, 55,225,188,207, 50,225,188,237,100,164, +205,114, 10,186,138,102, 10, 67, 66,181, 20,181, 15, 75, 52,145, 56, 33,102, 11, 36, 14,177,206, 9, 14, 84, 59, 29,188,174, 84, + 59,173,112, 93,143, 85,131, 21,160,229,114, 44, 58, 45,153, 66, 12, 7, 27,139, 74, 91,136,101,170,139,205, 35,148, 83,216, 89, +109, 47,175,160, 45,198, 97,150, 17,149, 40,129,153,191, 33,138, 45, 46, 76, 10,157, 73, 53,234,220,249, 45, 83,233,211, 28,109, + 44, 82,226, 34,114,131, 18, 43, 40,129, 31,153, 48, 97, 70, 47, 36,186,181,120,174, 58,242, 82,209, 95, 50,212, 18,208, 73, 83, + 80, 80,204,199,127,194, 85, 21,242, 79,187, 56,168,170,169,212,221,108, 50, 91,138,234,193,240,227,178,130, 24,101, 57,229,108, + 41, 75, 86, 74, 20, 9,139,172, 74,165, 58,245,126,172,220, 89,142, 26,131,177,226,196,130, 86,202, 30,125,154,122,189,198,155, + 17,167, 0, 8,166,198,149,239, 78, 60,238, 79,139,135, 31, 80, 75,139, 70,183,210, 72,208, 37,152, 14,131,107,157,246,216,129, +183, 77,134,221,141,183, 54,195, 12,185,100, 85,145,194,212,139,125, 68,121, 69,150, 73, 36, 70, 28,168,213,141,221, 80, 38,242, +239,121, 25,155,153,118, 55,137,194,174, 84, 41,148, 85,183, 64,162,120, 21, 9, 84,184, 49,145, 29, 46, 45, 79, 64,165, 64,110, + 50,132,154,165, 69,214,148, 82,194,220, 74,138,147, 28,101,231,150,232,192, 66, 9, 86,185, 17,237, 36,216, 24,156, 79,108, 45, + 91,106,157,145, 17,119,146,170, 52,251,163,110,235,115,214,150, 35,192,191,179, 38, 60, 55, 42, 47,160, 19, 2,219,168,211, 29, +118,157, 56,164, 20, 50,202,227,203, 3,158, 10, 73,232,220,233,143,193,167,180,203, 82, 67,210, 37,192,145, 88,170, 20, 52,150, +230, 54,253, 90,120,113, 41,119,149, 69, 38,115,235, 1, 12,182, 7,193, 25, 9, 82,185,130, 82,117,175,119,139, 85,218,217,157, +245,121, 66, 42,143,213, 32,176,154,170,185, 28,143, 69, 75, 2,115,178,106, 74,141,250,175, 22, 25,108,248, 12, 35, 8, 91,142, + 54,181,252, 5,122, 88,213,203, 28,145, 75, 78,229, 37,167, 97, 34,183,236,148, 33,148,223, 96, 69,197,183,176, 63,102,214,216, + 58,240,190, 68,114,250,243,152, 23, 19,199, 8,114,242, 72, 72,231, 22,188,108,205,176,101,137,213,157,138,160, 37,149,131,121, +245, 2, 96,171,183, 20,137,123, 31,191,149, 91, 47,123,232, 85, 27, 62, 93, 6,181, 34,220,190,237,155,214,132,186,220, 88,179, +217,150,220, 71,128,149, 75,125,138,149,169, 90, 75,203, 96,211,110, 42, 91,143,176,165,184,194,229,195,126, 59,201,121, 83,127, +216,175,102,198,192,241,189,192, 78,211, 93,151,173, 66,131, 11,121,110, 27,122,109, 78,202,226,103,134,152,244,170, 29,255, 0, +106, 75, 77, 80,127, 7,147,118,200,183,170, 81,169, 27,137,124, 65,102, 20, 38,171, 53, 4, 24,110,205,241, 18,226,164,123,227, + 13,202,211, 37,186,124, 33,108, 79, 16, 66,211,103,113,182,182,139,118, 84,173, 7,156,166,216,183, 99,192, 67,187, 32,202, 95, + 52,202,236,231,238, 88,201, 46,213,173,214,193, 83,203,133, 49, 50, 99,173,245,243, 52,203, 11,115,159, 93, 2,225, 42,126,233, +240,185,105, 84,108, 74, 45, 95,108, 43, 59, 35, 69, 97,250,141, 10,138,230,217, 90,251, 48,139, 9,233, 47,173, 83,167, 92, 23, +133,177, 85, 69, 46,182,212,244, 48,183, 86,228,216,112,223, 43,138, 95,241, 29,230,228, 19,170, 78, 41,201,115, 12,218,154,183, + 54,203,228, 66,244,207, 79, 57, 83,174, 48,118,211, 36,113,139, 51,236,182,144,200,197,209, 89, 4, 74, 66, 18,100,220, 71,196, + 25,253, 47,135,176,101, 60, 41,197, 99, 32,207,114, 92,228,102, 52,138,194,116,168,154, 25, 34,146, 41,169,214,165, 68,180,176, +199, 36,210, 6,122, 3, 28, 20,213, 45, 28,143, 83, 37, 84,238, 34,143, 74,120, 89,225,111,121,247,111,121,238, 89,155,225,184, +220, 82,237,142,251,112,146,253, 17,207,229,239, 14,200,188, 40,150,199, 16, 91, 53,100,203,106,223,161,219, 59,177,105,238, 28, + 8,141,191,184, 84,122,123,188,237, 86, 66, 93,102,187, 65,135, 61,155,146,157, 54, 68,117, 85,170, 29, 5,246,132,237, 76,171, + 94,215,181, 54,235,103,182,227, 99,237,219, 50,147,100,221,151,117,186,253, 38,155, 38,143,114, 90, 87, 4,106,212, 53,220,242, +118,242,194,180,160,179, 75,166, 81, 39, 84,235,112, 68,217,140, 61,226, 50,212,247, 22, 89,118, 35, 77,235, 83,184,202,246,199, +112,111, 70,219,122,181, 6,171,108, 65,226,231,125,105,213,122,204, 75, 11,108,236, 27,130,252,141,176,118,155, 98, 2, 33,193, +175,238,213,251, 13, 81, 98,223, 52,197,206, 75,206,187, 71,165, 38,170,196,168,241,155,138, 85, 9,111, 46, 98, 52, 47,111,189, +188,183, 37,209,109, 10,103, 17, 22, 2,110,109,194,146,227,138,131,118,219,246,163,116, 11, 98,132,235,103, 52,122, 75,118,253, +157, 38, 77, 80, 90, 17,210,101,178,248,116,206,118, 75, 83,212, 28,101,175, 1,149,162, 45,226,190, 70,185,231, 0,203,149,228, +121,123,231,153,198,105, 91, 28,230, 88, 16, 36,112,211, 70,154,212, 24, 39,149,165, 18, 74,198, 72, 89, 35,105,100, 12, 41,231, +158,112, 57,145,137,231, 10,100, 94, 51,241, 87, 23,112,111, 30,211,112, 52,153, 38, 73,225,242, 10, 90,124,155, 50,146, 42,116, + 99, 45, 52,112,243,178,218,153, 12, 21, 85, 52,171, 42,205, 88,212,181,201, 75,149,209, 37, 91, 81,100,148, 51, 81, 75, 49, 50, + 6,217,173,183,155,188, 84,118,173,158, 32,172,235, 87,118, 54,166,179,183,149,203,134,222,225,242, 30,215, 80,233, 54,151,241, +165,100,213,106,245,122,156,138,221,227, 2,160,150, 46, 42,164,235,130,161, 57, 86,251,132, 51, 77,169, 64,173,174,167, 38, 59, + 85, 4, 56, 26, 3,109,118,123,135, 41,252, 96,110,135, 23,245,109,254,221,189,165,168,219,173, 91,123, 97, 87,216,251,190,175, +183,219, 85, 99,219,212,155,126,209,183,217,137,183, 10,131, 66,169, 76,169,205,176,225, 70,165,194, 83,180,116,125, 88,219,175, +148,178,243,175,199, 75,173, 59, 29, 61,249,246,206,238, 94,228,237, 61,211,181,155,117, 97, 50,205, 62,247,110,151, 14,183,114, + 57, 71,149,102, 55,111,211, 40,145,161,125, 74,213, 25, 54,141,222,227,180,202,188,130,169, 82, 23, 30,151, 57,136, 16,218, 83, +108, 72, 50, 38, 25, 64,114, 67,110, 47,253,229,176,174, 10,205,199,103,238,253,237, 99, 85,238,119,154,122,231,157, 75,174,215, + 74,238, 7, 25, 46,152,207,214,220,157, 58, 73,170, 74,109, 18, 30, 75,110,190, 29,121,180, 44,165, 42, 9,232, 21,240,162,151, + 56,225, 46, 16,143, 36,205,178, 88,214,186,130,176,206,181, 50,212,206, 37,168,141, 97,228, 37, 63, 46, 9,201, 90, 37, 96,103, +142, 25,155, 74,243, 26,157, 97,150, 33,237, 83,203,114,127,162,199,141,220, 86,188, 75, 85,151,241,125, 31, 2,167, 23,193, 83, +150, 54, 91, 79, 78,166,152,101, 85,109, 75, 81, 85, 61, 59, 60, 98,150,158,166,174,122, 58, 72, 42,106,150,136,102, 51,123, 10, + 85,205,152, 73, 43, 44, 16,206,123,218, 61,196,127, 12, 59,235,177, 53, 46, 29,169, 86,189, 55,136,234,109,215, 88,166, 26,197, + 38, 53,233,116,109,198,223, 91,198,222, 80,171,209,234,119, 5,221, 67,164, 25,151, 10, 5, 85,136, 33,154, 93, 49, 37, 18, 15, +233,100,202, 97,150,139,131,132,251, 87,179,251, 79,179,194,224,147,101,216,244,202, 5, 90,229,159, 17,119,149,211, 72,110, 69, + 46,248,110,163, 29,217, 43,129, 66,171, 79,122,116,167, 35, 90, 76, 72,147, 37,216,236, 37,215, 98,203,117,126,245, 45, 50,100, +114,186,222,133,219, 60, 77,113, 16,220,102, 29,123,136, 11,214,170, 86,194,217,230,148,229, 46, 98, 20,211,128,115, 50,125,254, +146,190,100,228,116,200, 4, 30,163, 7,187,151, 72,226,234,249,165, 72,105,119,173, 54,145,119,199, 91,105,138, 42,209,169,240, +173,203,214, 44,100,188,211,178, 16,205,110,152,208,135,112, 48,176,215,197, 10,171, 13,109,124, 69,109,200, 97, 95, 24,214,226, +126, 46,204,248,131, 53,169,253, 34,207, 26, 53,144, 71, 4, 79, 21, 56, 17,133, 22,229,150,231, 57, 26, 1, 47, 34,187, 2, 44, + 52,198,170,139, 50,202,126,130,126, 47,120,111,192,109,194,252, 57,154,229,220, 65,148, 9,205,116,180,137,154,214, 10,186,170, +162, 10,137,109, 91, 69, 71,150,198,235, 25, 10, 22, 25,169,163,100, 69,105,125,166,116, 70,126,237,240,173,188,242,233, 18,100, +237, 93,235, 42, 60,202,109,114, 92,138,190,220,221,209,196,104,148,181, 76, 74, 16,170,157,149, 92,105,110,132,210, 43,242, 74, + 19, 42,158,164,115,198,158,234, 36, 48,143, 6, 66,144,210,247,177, 85,202,124, 85, 41, 50, 23,238,234, 96,171,220, 84,131,201, + 81,167,186,242, 66,220,103,194,112,116,136,167, 49,204,218,135, 38,114,149, 36,142, 82,142, 24,109,205,249,100,111,109,188,154, +141,169, 87,121,132, 69,149, 25,154,133, 12, 70,102, 35,244,170,162,202,228,211,227,215,160,171,156, 70, 90,220,109,197,198,112, + 60, 25,150,134, 86, 98, 60,242,193, 74, 54, 70, 21,203,185,137, 49, 41,209, 55, 38,242,181,228,211, 26, 17,157,129, 46,114, 42, +180,121, 76,135,128,240,207,214,112,156,148,134, 86, 18, 75, 79, 49, 33, 50,163,165,120,248,146, 57, 73,105,106,159,147, 26, 7, + 37, 20,121, 74,249,129, 29,199, 81,176, 38,192,147,176,176, 11,229, 39, 28,113,196, 92, 57, 81,148,103, 21,249,110,121, 69, 46, + 69,155, 81,200,201, 87, 73, 60,114, 67, 44, 19, 46,155,235,139, 65,117, 46,165, 73, 11, 30,131,175, 80,250,185, 64,199, 74,170, +247,117,187,111, 83,215, 94,171,203,137, 65,135, 79, 67,143,174,161,207, 41, 13, 62,140, 15, 16, 83, 24,105,167, 37, 84, 28, 81, + 82,130,227, 69,105,245, 45, 71, 41, 66,191, 91, 76,133, 87,124,171,187,130, 29,167,217, 76,213,237,251,106, 66,189,205,119,162, + 28, 98, 37,199, 86,142, 16,162,185, 54,235, 12, 41,106,181,161,242, 45, 99,199,119,154,162, 48, 80, 81, 16,158,154,182,205, 62, +117, 86,178,221, 66,238,151, 81,166,214,156, 82,227, 66,168, 73,171, 77,171,198,152, 82,188,180,236, 27,145,222, 95,115, 36,148, +242, 70, 81,136,160, 29, 56, 67,138, 29, 54, 42,202,179,153,139, 37,154,143, 44,138, 93, 90,115, 13,179, 42, 84, 55, 84,228, 58, +130,154, 32,177, 34,167, 76,116,248, 83,164,158, 85, 21, 58, 66, 29,194,202, 84,242,134, 53,191, 74, 37,168,148, 34, 92,139,239, +126,187,219,125,133,150,228,146, 47, 98, 55,179, 1,136, 86,103, 62, 91, 69, 8, 36,153,106, 8, 60,182,111, 58, 40,216,157, 54, + 98, 36, 0,234,243,171, 58, 3,101,229,106,179, 43,139,104, 91, 70, 44,120,176,217, 45, 59, 21,146,164, 50,232, 71, 43,133,111, +117, 90,230,100,144,252,149, 40,149, 41,210, 74,150,181, 21, 44,149,171, 39, 97,160,209,196, 74, 98,138,211,204, 1,101, 39, 41, +232,160, 84, 80, 91, 86,122, 5,117,207,217,171, 93,167, 74,230,109,190,118,227,151, 50, 18, 67, 73, 80,101,207,212, 10, 45,182, +190,169, 65, 32, 16, 14, 72, 61, 50,113,157, 59,206,211,128,167,184,215,134, 84,218,139, 67, 9,202,136, 9, 81,207,134, 79,235, + 28, 17,243,252,113,169,165, 53, 56,166, 68,176, 35, 72, 23,245, 29, 5,183,191, 78,155,254, 24,174,234,171, 13, 76,138,146,157, +228,111, 49,216, 94,228,111,219,173,201, 22,181,250,250,130,207, 61, 76, 83, 78,129,201,136,206, 30,102,214, 63,241, 74, 61,219, + 81,242, 79, 81,141, 92, 33, 83, 11, 11, 43, 74, 70, 79,235,128, 48,146,159, 95,183, 89,187, 48, 16,248,113,190, 78,100,130, 82, +160,176, 65, 32, 28, 5, 99,215,168,252, 53, 65,216,162, 34,146,199,235, 39, 31, 2,200,193,233,215,144,231, 79, 81,206,164,117, +233,252,125,253,240,213, 89,206, 82,241,176,243, 14,190,132,117, 7,227,110,189,143, 94,183,197,134,155, 9, 14, 77, 73, 35,160, +115, 31,105,236,123,140,118,214,207,217,208, 91, 67, 45, 2, 19,212, 36, 12, 14,163,212,156,142,135,247,233,135,163, 69, 10,155, +158, 95,135,196,200, 0,103, 57,200,252,115,173,138,183, 84,150, 18,214, 79, 47, 42, 82, 64,200,200,192, 25, 63, 34, 51,173,102, +107,129,181,255, 0,158, 33, 53,234,201, 4,224,108,194,246,251,207,207,175,124, 57,232,109,180, 51,202, 72,248,130,113,142,248, + 78, 0, 31, 35,235,246,233,191,188, 42,206, 66,108,193,167,132,253,103, 41,181, 0, 71,255, 0, 2,140,174,134, 73, 35,245, 92, + 39, 33, 30,121,235,229,171,141, 90,228,106, 11, 32, 52, 80,236,183, 73, 12, 70, 4,229, 74, 7, 30, 43,152, 63, 3, 41, 29, 84, +123, 28,224,100,235, 5, 13,173,197, 57, 46, 67,138,125,249, 46,120,146, 95, 88,253,117,156, 97, 40, 39,245, 91, 0,225, 35,176, + 29,180,142,179, 80,220,168,205,149,126,211, 15,223,164, 16,122,250,158,195,208,145,134,108,155, 45,116,149,107,106,210,241, 41, +186,161,255, 0,120,194,221, 71,236, 47,127,218, 35, 79, 77, 86,176, 66,163, 8,205,225,197, 43, 56, 37,105, 65, 56, 36,252, 75, + 82,212,174,171,112,149, 28,156,245,207, 93, 15, 45,216,241, 57,146, 57, 27, 56,200, 72,192, 89, 78, 15, 85,168,159,128, 99, 39, +226, 63, 33,223, 89, 20,167,114,130, 10,130, 80, 72,248, 26, 31, 30, 65, 0, 16,165, 3,208,231,174, 61, 61, 53,129,212,188, 52, + 7, 20, 82,214, 78, 74,148,226,186,164,228, 18, 84,181,103, 36,244,238,122, 30,157, 53,185, 26, 44,106,170,160, 1,238,236, 54, +253,214,249,247,206,169,100,122,153, 25,234, 36,251, 71,160,233,212,122,216,124,236,119,197,146,116,196, 43,156, 23, 20,234,176, + 66, 83, 24, 44, 50, 18, 79, 66,235,132,167,159, 61, 50, 50, 18, 9,206, 15, 83,172, 58,116,165, 37, 64, 4,182,218, 73,199, 59, +139, 10, 82, 73, 66,186, 33, 13, 30, 94, 96,174,108,228,231,168,198,123,139,140,202,131, 79, 30, 70,148,227,238, 33, 74, 65,102, + 43, 97,196, 54,147,211,226, 81, 41, 74,129, 0,103,226, 56,236, 70, 51,172, 78,114,228,243, 5, 43,193,100,115,243, 36,120,134, + 75,201,194,128, 42, 71, 54, 17,204, 60,206, 74,114,122, 18,116,112,214,210, 59,223,241,219,240,190,226,251,116,251,158,201,176, + 10, 23, 73, 61,143, 95,141,182, 61, 58, 16,167,226,118,197, 23,220, 24, 42, 82,202,147,250, 50,234,130,146,217, 45, 36,168,133, + 45, 94, 71,175,197,215,174, 49,223,174,177,233, 50,208, 66,131,105, 61,214, 66, 64, 78,114, 64, 32,244, 61, 27, 42, 36,100, 30, + 80, 0, 29,250,232,185,104, 66, 49, 33,199, 21,150,220, 43, 66,158, 90,158, 9, 94, 72,229, 74, 84,180,165, 36,173, 63,234,146, +156,146, 6,173,114, 20, 80,180,165, 72, 80,112, 20,145,206,164, 41, 92,139, 1, 96,182,144,172, 56,130, 20, 14, 50, 0, 39, 56, +233,141, 46,141, 98, 54,244,254, 95, 29,247,198,133, 76, 90,206,166, 58,175,233,178,237, 97,238,254, 93,189,215,178,204, 42, 33, + 93, 64, 42,248,136, 81, 57,235,147,209, 95,205, 61, 51,156,117,229,239,140,107, 16,158, 7, 42,147,206, 74,138, 85,241,171,148, + 17,140, 96,145,216, 96, 12,125,253, 6,178,233, 89, 1, 42, 89, 0,224,140, 40, 16,146,179,204,164, 55,201,216, 60,158,153, 29, +114, 59,100,118,197,106, 10,207, 40, 35,170, 73,230, 36,114,149,103,155,161, 9, 87, 86,241,147,231,213, 88,193, 58, 92, 49,218, +223,135,110,159,187,221,238,253,216,103,145, 0, 34,219,123,186,124,143,147,136, 13,251,114,237,134,237,143,105, 46,242, 73, 13, + 22,133,233,109,109,125,248,227,197, 1, 40,126, 69,118,199,166,197,148,182,249, 0,241, 0,122,146,174,101, 31,136,168,158, 98, + 78,117,200,194,180,168,126,137,101, 88,239,233,246,107,183,127, 72, 24,180,175,104, 99,158, 27,161,215, 19,195,254,205, 37,246, +129,255, 0, 34,180,195,184,124, 52,148, 17,150,202,152, 45,175,169,201, 11, 7, 0, 99, 92, 70, 83,105,199, 81,140,246,229,242, +249, 29, 75,178,155,181, 13, 41, 59,217,109,211,176, 36,116,235,219,242,199, 51,241, 50, 44,124, 69,158, 34,159, 47,181,212, 31, +255, 0,116,172,199,247, 18,113, 76,168, 40,116, 72, 29, 62, 47, 63,188,117,208,235, 35, 24,207, 92,244,254,221, 86, 40, 35, 62, +152,207, 95,232,251,116, 51,133, 67,168, 78, 71, 81,243,251,244,236, 6,194,221, 48,206,160, 29,173,211,161,253,216,162,179,229, +143,191,211,175,217,170, 11, 0,227,176,245,245,199,175,207,160, 58,244,188,254,177,201, 82,124,188,177,231,246, 29, 81, 39, 39, + 58, 93, 70,194,221, 63,158, 20, 24,164,230, 60,136,232, 72,244, 39,183,109, 12,178, 9, 61,242, 59,122, 30,223,214,116, 74,241, +130, 73, 3, 7,167,246,245,213,189,240,234,136,240,212,148, 97, 95, 22, 70, 74,128,236, 58,249,233, 68,235,140, 3,126,155,227, +193, 36,156,254,113,165,175, 10, 63,237, 99,238,206,116,180,125, 62,182,191,207,191, 25,199,180,146, 15, 65,159,151,174,171,165, + 93,142, 58,142,227, 61, 70,135, 31,120,254,145,251,117, 92, 96,245, 30,127, 46,250, 37,188,191, 15,195,231,231,124, 12, 86,241, + 19,156,117,235,231,142,159,126,136,111, 10,193, 74,187, 28, 99, 24,201, 62,191,136,252, 53, 65, 9, 0,131,220,244,251, 58,232, +164,225, 61,178, 7, 94,221,254,236,246,210, 76, 24,139,124,252,223, 25,219,239,197, 69,160,168,119,233,221, 93, 78, 6, 49,216, +125,186, 33,164,115, 36, 40,247, 29, 66, 71,160,233,235,170, 64,133, 15,207,113,215, 69, 36,242,224,244,244, 35,208,105, 34, 0, + 39,190, 49,143,104,101, 42,238, 57, 85,215,168,198, 72,251,188,244,123,104, 72, 72, 24,201, 79, 78,191,187,166,132, 65, 39,226, + 72, 25,244, 39,167,152,251,180, 90, 22,144, 1, 87,195,147,231,252,236,250,124,244,153, 23,216,158,159,233,140, 17,124, 28,214, + 58,114,244, 24, 61, 62, 93,191,167, 70, 32, 12,103, 39,230, 60,137,199, 94,154, 13,178, 23,215,168, 29,253, 59, 99,250,245, 93, + 11, 73, 95, 47,114, 62,127,102,127,103,150,147,194, 39,221,190, 13,108,129,145,140,228, 16,160, 70, 82,164,158,133, 36,121,130, + 9,200,212,133,253,149, 30,214, 40,187, 66,197,191,195, 39, 20,245,169, 15,236,235,143,162, 14,220,110,140,213,189, 54,163,181, +211,100,184, 17, 30,135,114, 58,162,165,203,177,148,226,240,211,164,149, 65,206, 21,150, 70, 83, 30,118,242, 14,122,121,126,206, +218, 33, 39, 37, 68,227,168,229, 32,128, 82, 65,232, 65, 7,184, 56,237,231,157, 55,102, 89,109, 54,103, 78,208, 84, 37,251,171, + 11,106, 86,236, 71,240, 32,236, 71, 81,211, 14,249, 22,123,153,112,230, 99, 22,103,149,205,202,158, 63, 43, 43, 92,199, 44,100, +130,209, 74,160,141, 72,214, 29,195, 41, 1,144,171, 0, 71,233,189, 78,163,199,149, 6, 5,118,137, 50,159, 88,161, 86, 97,179, + 50,145,112,209,228,179, 81,164,214, 32,202, 66, 93,106,101, 62,161, 25, 74,109,214,150,210,146, 82, 66,186,115,105,198,165,210, +220, 45, 54,156, 0,210, 18,130, 16,156,144,132,160,130,113,234,163,215, 63,102,191, 63,142, 13, 61,168,188, 90,112, 88, 35, 91, +187,121,119,179,119,109,106,165, 54,185,123, 83,184, 1,218,213,172,195, 74,112, 25, 31,193,231,222,112,191,110, 58,164, 21,224, + 48,176,215, 49, 7,195,198,117, 59, 45,161,226,130,149,124,109,157,131,126, 59,105, 34, 25,190,109, 42, 53,196,184,241, 30, 15, +198,138,237, 78, 35, 82, 31,140,211,167,245,219, 66,220, 41, 7,190, 19,170,167, 56,203,165,200,101,140, 85,149,104,230,213,203, +101,189,155, 78,155,220,117, 82, 3, 46,198,227,123, 43,181,137,199, 98,248,121,226, 4, 60,107, 28,144, 81,211, 52, 25,134, 94, +168,243,195, 33, 13,165, 88,233, 15, 20,151, 2, 68,212, 8, 23, 84,117,184,212,128, 27,157,174,166,211,138,218,110, 68,166,202, + 12,226,136,177,129,232,166,216, 72,248,148, 83,159,213, 41, 3, 58,199,247,101,136,115, 44,202,189,191, 58, 53, 62,165, 75,147, + 13,232,255, 0, 85, 84,225, 70,168,193,124, 22,212, 1, 92, 57,109,173, 42, 25,207, 92,107, 7, 94,247, 82,222, 44,120, 49, 37, + 54,166,153, 62, 27, 97,162,180,183,147,212, 19,228,122,244,251, 53,166, 60, 82,241,139, 69,219,203, 98, 69, 54,140,180, 86,247, + 30,234,150,139, 66,201,183, 25,149, 29,233,234,185, 42,196, 70,134,169,113,219, 89,247, 70,154, 91,161,107, 46,114,242,132,100, +244,206,153,205, 97,168, 2,158, 4, 44,100,219,125,135, 64, 78,228,219,222, 73,244,222,221,174, 76,131, 35,204,179,124,218,130, +135, 45,164, 51, 85,202,227, 76,106, 62,206,255, 0,109,219,126, 90, 70,190,103,145,136, 84, 93, 78, 72, 23,191, 48,247,123,113, + 54,107, 98,106,146,105, 9,180, 41, 21,123,162,141, 80,151, 62,153,110, 91,228, 81,105,212,218,178,156,241, 34, 77,169, 72,130, +226, 75, 2, 57,229, 90, 91, 71, 95, 19, 25, 61, 49,174,102,239,183, 16, 27,245,196,245, 64, 82,110,171,182,181, 46,217, 96, 6, + 35,218,212,137, 51, 32,219,108,198,105, 92,201, 85, 69,199, 30, 6,166,164,128, 10,220,112,144, 72,251, 53,214,202, 31,178,178, +163,118, 58,154,214,227,110,196,250,141,229, 94, 90,234,215, 82,232,240, 89,168, 70,166, 84,170, 4,190,168, 41,121,249, 0, 76, + 90, 29,119,151, 56, 9,248, 73, 25,214,146,202,219, 91, 51,104,184,161,111,104, 55, 2,101, 83,114, 54,198,194,191,169, 77,110, + 68,221,177,164, 63, 85,175,214,237, 88,241,211, 82,147, 76,141, 78,128, 22, 91, 87,142,150, 98,205, 74, 85,132,248,171,248,142, + 53,173,150, 83, 84, 83,203, 81, 44,142,139,160, 27, 2,160,233, 3,114,117, 16, 12,141,127, 70, 80, 9, 35,125,241,233,239,130, + 41,224, 38,103, 13,117, 54, 67,153,205,226, 87, 28,112,190, 95, 45,125, 92,210, 83, 86,187,242,226, 42,178,174, 80,149,113,165, + 44, 65,229,100,134, 4,141,150,122,141, 81, 51, 73,162,237, 30,168,196,225,210,109,131,180,183,158,251, 93,182,173, 90, 77,131, + 96, 89,181, 75,242,173, 86, 98, 49,102, 9,183, 41, 18, 99, 82,213, 61,169,147, 28,108, 26,115,213,233,208, 41,241,139, 73, 89, +155, 50, 88, 98, 57, 82,144,225, 71, 44,173,110, 47,174,107,174,254, 98, 13, 58,249, 85, 6,131, 87,171, 39,220, 44,241,181,244, +153,180,166, 32, 5,149,154,122, 42,162,227, 19, 75,165,128, 71,188, 56,178,174,115,204, 82,145,128, 36, 3,237,235,223,234,222, +215,112, 55,182,219, 31, 86, 98, 61,181,187,220,112, 95,208,183,126,253,180, 97, 54,220, 21,109,191, 13,155, 89, 33,113, 54, 95, +106,218,165, 50, 18, 40,148,150,231,154,107,198, 55, 42, 67,242, 41,179, 93,113, 42,113, 74, 86,162, 97,177, 48,209, 39,113,161, + 58, 64, 13,211,225, 75,148, 51,140, 36,165,190, 84,143,159, 65,171, 75,135,178,168,107,242, 90,172,214,180, 51, 59,234, 16,134, + 17,190,133, 64, 20, 55,158, 54, 2, 70,146,225,136, 0,174,157, 43, 97,185,243, 63,233, 63,244,231,241, 66,159,196,102,225, 15, + 14, 51, 37,224,188,143,132, 9,142,161,114,156,207, 55,165,122,154,211,180,201, 83, 95,148,230, 89,116,181,212,212,192, 8,224, + 5,150, 25,142,186,190, 84,124,245,138, 25,117,109,141,230,157,201,225, 47, 99,174,184,147, 81, 37,251, 42,185,185, 27,109,239, +116,234,109, 66,219,122, 4,155, 82,247,170, 85, 97,120, 77, 63, 82,121,198, 42, 45, 83,110,106, 65,247,182, 36,165, 14,184,226, +150,194, 25, 9,113, 3,110,182,151,139,125,212,183,132,104, 23,139,113, 55, 18,137, 24, 33, 42,171,202,150,138, 77,231, 10, 58, + 80,148, 41,215,106,105,101,113,238, 23, 2, 0,109, 6, 99, 41,127,224, 0,190, 84,115,174, 89,251, 50,110,182,111,109,161,226, + 3,101, 36, 58,211,149,138, 21, 94,218,222,203, 78, 35,202, 81, 46, 82,231,199, 69,129,126,193,167,180, 63, 93,214,103,194,179, +170, 50, 48, 15, 42,103, 21,168, 17,147,174,130,217,182, 49, 51,154, 91,177,188,102,144,164, 58, 35,144,191,242,169, 25, 99,159, +148,124, 72, 7,226,207, 80, 49,207,131,216, 83, 92, 69, 69, 29, 6, 99, 95, 73, 34,235, 8,250,148,236, 9, 14, 17,197,138,133, + 2,215,210,116,217,110,164, 91, 97,105,119,134, 62, 33,208,248,151,225,118, 89,196, 28, 81, 28, 85,249,213, 91,213,189, 89, 99, + 36,143,237,143, 83, 41,169,117,146, 89,165,169, 6,105,139, 75,170, 73,228,145,245,134,150, 73, 9, 44,122, 97,110,111,221,149, +120, 67,165,189, 58,161, 34,214,201,105,134,233, 55,148, 69, 83, 11, 50,221, 90, 92, 68, 40,213, 72,110,200,135, 46, 73, 41,108, +171, 14,167,245, 84,130, 65,200,211,166, 94,171, 84,102, 51, 47,194,143, 89,131, 9, 5,184,240,105, 85, 40,147,218, 74,222, 40, + 89, 97,227, 2, 67,137, 97, 78,252, 5,254,110, 85,114,132, 39, 9, 72, 32,233, 93, 14,201,122, 65,143, 22,156,212, 69, 86,100, + 46, 44,135, 38, 57,135, 33,219,180,231, 22,234, 83, 60,161,192, 10,170,170, 8,144, 33,178, 71,233, 29, 30,242,191,208,181,133, +191,182,125,129, 22,137, 24,184,219, 16,105,244,122,116,229, 24,172,196,140,227, 51,106, 82, 37,172, 0, 92,153,226, 37,249,213, + 57, 83, 22,165, 18,225, 82,222,113, 69, 74, 9, 71,234, 68, 9,208,198,209, 94,219,218,228, 15, 83,112, 65,184, 62,227,110,189, +109,178,169, 62, 83, 5,218,149,249, 37,181, 42,198, 87, 89, 80,199,253,217, 86, 70, 70, 98,204, 20,146, 89,197,201,101, 22,230, + 59,242, 41,215, 69, 77, 73,128,236, 67, 18, 58,167,154,138,231, 60, 4,102,158,150, 80, 82,130,218,157,115, 45,198,101,174, 84, +165, 1, 68,114, 52,130,156, 99, 89, 45, 34,212,134,228, 73, 16,146,227,205,181, 1,201, 78, 77,171, 38, 42,218,143,227,144, 4, +201, 12,201,115, 36, 71, 12, 32,165, 43, 3,226,248,212,144, 10,146, 53,126,180,172,233, 73,154,154,212,168,202, 93,197, 80, 97, +136,104,140,211,242,100,192,162,196,109,194,166, 41,208,221,148,163,201,135, 23,227, 62,232, 78, 95,127, 36, 0,218, 27, 1,238, +160, 90,138,170,136,112, 34,196,122,116, 24,179, 26, 97,224,201, 66,151, 91,158, 22,121, 26, 8,112, 2,184,136,155,133, 28, 30, + 89, 15, 32, 1,204,132,117,220,138, 25,100, 69,141, 33, 42, 95,185,185, 36,108, 64,216, 41, 3,125, 76,119, 96, 54,234,214, 58, + 53,249,220, 11, 78,232,142,144,194,128, 23,101, 1, 6,175,214, 62,103,112,219,249, 82,197, 84,238,108, 17,110, 52,139,118, 47, + 29,184,225,215,110, 42,187,173,184,204,207, 72, 80, 85,167,183,182, 36, 9,173, 70,184,111,106,192, 66,170,116,219,106,146,227, +200, 80,164, 50,235, 10, 77, 66,191, 84,117, 10,106,153, 79,228, 73,241, 36,174, 36,119,184, 21,190, 59,243,185,156, 69, 84,159, +170,238, 77,125,233,212, 64,224,114,153, 96, 80,157,149, 74,219, 91,113,168,200, 9,139, 79,161,218,173,191,225,204,247,118,130, + 18,103,207, 18,106, 18, 92, 10,125,231,194,214, 80,151,139,218, 61,196, 11, 91,199,196,197,237, 22,149, 81, 84,157,189,217,229, +191,180,182, 2, 88, 11, 17,100, 68,160,212, 84,221,239,112,178,210, 9,241,102,214,111,225, 52,151, 48, 84,168,148,168, 76,161, + 74,109,180,160,115,231,137,235,103,118, 56,127,147,104,217, 55,156,251,107,111,175,235,178,220,141,117, 86,109, 75,154,123,113, +238, 29,183,163, 87, 2, 87,106,211,239, 74, 50,150,145, 64,189,234,148,231, 29,158,154, 36,149,174,165, 75,167,166, 52,138,188, + 24,138,159, 21,133,236, 83,112,252,185,180,169, 8,169, 20,176,234, 0, 18, 88, 7,176, 39, 89,211,114,119, 4, 70,189, 44,161, +148, 22,190,159, 75,188, 43,225,207, 12,190,140,158, 22,229, 62, 49,120,177, 11,207,199,124, 79, 74, 43, 96,166,138,138, 92,199, + 54,166,167,120, 99,153, 50,252,166,134, 37,121,162,150, 40, 36,137,243,154,231,228, 65, 75, 44,172,185,141,117, 61, 12, 49,202, + 64,184,109,119,103,132,181, 74,129, 79,134,194,135, 43,190,237, 21,191, 29,100, 96, 37, 40,117, 73, 82, 99, 35, 32,124, 88, 42, + 63,170, 53,226,221,219, 54,154,144,210,159,144,184,110,188,191, 9,111, 50,130,176,158,110, 80, 84,251,171,202,128, 1, 93, 73, +229, 25, 56, 37, 0,140,233,155,215,238,236,178, 81,245, 6,230,196,184, 38, 72,117,114,146,204, 10,157, 18,124,222, 68, 55,238, +229, 13,192, 85, 62, 51,171,139,134,207, 35, 41,140,233,231,202,146,147,144,117, 96,166,239,230,251, 91, 78,170, 52,187,154,100, +238, 69,175,198,143, 95,161, 83,106, 18,154,101, 79,165,231,152,117,164, 67,133, 45,134,212, 82, 91,194,156, 5, 45, 44,164, 2, + 66, 84,155, 34,147,133,243, 36,165, 20,116,217,188, 35,151,238,126, 97, 4,254,177,125, 68,239,211, 82,223,173,172, 0, 24,167, +179, 47,246,170,125, 30,232,243,104, 31,139,124, 24,227,142, 30,161,169,102,142,147, 50,172,203, 50,121, 41,229, 42, 69,218, 3, + 30,118,241,202, 0,243,200, 41, 94,165,129, 22, 42, 88,227,163,116,203, 17, 8,185, 93,183,106,208,252, 38,221, 75,239, 69, 82, +148,212, 98,226, 86,217,118, 44,165,167, 9, 65,101,223, 60,148,144,181, 96,168, 43, 0,252,174, 91,214,181,183, 10,117, 86,179, + 50,153, 73,166, 83,194,214,252,233, 83,209, 26, 43, 44,162, 64,140,219,206, 58,234,210,112,235,191, 11, 64,100, 44,244, 4,168, +145,172,123, 98,119,186,189,184,148,118,141, 70,148,197, 50,191,111,207, 66,201,167,161,249, 52,249,241, 42,212,229, 7,204, 15, +126, 66, 92,110, 3,140,161, 73,118, 19,202, 81, 97,108,148,161,199, 27, 91, 78,107, 86,119,238,216,221, 43,230,252,250,182, 13, + 58,183, 46,147, 70, 13, 38, 4, 56,116,185,179,162, 69, 46,180,223,141, 81,142,184,140, 41,147, 41,114, 84,242, 75,171, 82, 84, +194, 91, 72,230, 64, 90,214,181, 33,200,201,170, 43, 89, 94,208, 24,128, 15,166, 66, 20,216, 3,112,111, 96, 88,110, 78,159,118, +155,220, 99,160, 60, 98,250, 99,112,207,134,255, 0, 71, 46, 29,250, 64,120, 83,195, 50,248,169,148,241,245, 69, 30, 93,144,193, + 67, 79, 83, 28, 82,215, 85,189,122,153,115, 32,105,154,178,134, 26,105,168,101,163,146,156,211,189, 75,102,130, 44,173, 68,114, + 77,207, 71,110, 15, 18, 59, 61, 18,251,183, 45,234,180,107,233,187, 1,250,171, 17,238,235,214,213,164, 83,170,247, 53, 22,146, +247, 59,114, 43, 22,149,141, 85,159, 17,119,100,134, 63, 68,234,163,187, 34, 18,164, 53,206,152,138,117,244,161,183, 58,193, 87, +225, 15,135,235,154,206,165, 93,187, 71,198, 37,215,186, 16,174, 74, 84,106,197,183,252, 7,217, 27,135,115, 66,233,111,133,248, + 82,110, 88, 27,108,185, 18, 44, 98,226,138,217, 76, 74,176, 98,168,211,208, 31, 14, 67,113, 0, 40,199,138, 77, 58,219,219, 50, +244,105,201,133,114, 94, 12, 56,227, 82,225, 41,246,106, 20,107,126, 74, 1, 10, 21,105,145, 29, 83, 87, 29,105,183,135, 90, 99, + 14, 24,108,168,230,161, 33,210,145, 21,121,134,197,241,157,196,167, 13,119,204,187,239,101,247, 94,228,180,103, 85, 93, 74,238, +122, 27,239, 11,130,196,190, 89, 74, 3, 65,139,247,111,234,106, 52,187,152, 37,129,200,203,193,152,211, 98, 54, 3,112,101,197, +108, 4,133,235, 56, 58, 10,228, 87,202, 71,178,152,134,242, 75,119, 19, 27,222,225, 88,150, 31,254, 96, 54, 34,214,141,213,129, + 30, 77, 63,251, 74,190,146, 28, 63,196,245, 21, 94, 41,241, 81, 90,138,137,238,120,103,135,232,114, 90, 51,145,166,250,161,204, + 42,243, 28,191, 56,115, 80,172, 17, 36,201,106, 30,171, 49,165, 99, 58,215,215,101, 85,180,199, 46,155,165, 84,250,206,231,112, +167,186, 84,202,229, 58, 84, 41,147,169,133,248,238,197,175, 91,119, 93, 18,221,187,232,146, 84,224,168,218,183,125,171,122, 80, +169,146, 69, 62, 91, 77,165,197, 50,182,199,186,202, 90, 37,197,125,153, 76,161,221, 73, 67,102,161,181,186, 27, 75, 97,238,133, +149, 75,174, 53,111,223, 86,211, 87,109, 54,213,185, 35, 77,146,237, 17,137, 14,200,167, 84,169, 77, 86, 23, 24,190,212,104, 85, + 56,114,217, 98, 72, 75,241,159,101,166,228, 0, 16,240, 9,226,206,213,123,125,246,154,253,183, 26,179,248,203,225,125,202,139, + 46,178,168,179,235,251,104,229, 22,255, 0,179,166, 52, 82,164, 41,247,246,211,115,158,110,161, 69,150,180,149,143, 14,155, 84, +150,134,210,172, 54,180,249,236,206,213,123, 69, 61,143,214,236,216, 85,123,123,115, 55,238,195,166,195,122, 53,197, 19,108, 46, + 26, 79, 16, 44,236,253, 26,226,128,250,223,131, 85,141,183, 84,234,188,232,106,173,199, 90,212, 89,142,137, 15, 83, 81,144,125, +209,101, 40,228,141, 47, 10,102,180,149, 86,154,156, 24, 92, 29,108,129,135,154,226,204, 2, 44,137,115,111, 54,226,254, 93,182, + 24,147,120,185,244,188,240,119,233, 7,195,249, 54,103, 93, 17,224,159, 17,114, 33,203,106,209, 45, 37, 92,121,173, 8, 71, 34, +150,170, 58,150,200,101,166,150, 41,220, 61, 44,139, 5, 76,112,171,213, 71, 20,136, 39, 4,118, 6, 29,186,134,194, 27,148,195, +193, 62, 44, 68,187, 21,106,102, 84, 30, 70, 85,205,142, 80,158, 87,201, 81, 7,153,192, 0,192, 80, 64,211,149, 66,165,180,203, +136, 67,104,240, 27, 90,130,130, 17,226, 37,166,148,162, 1, 67, 73, 94, 66, 83,252,227,140, 39, 39,160,215, 35, 46,223,110, 95, +179,178,219,105,233,244,219,195,120, 47,233,139, 89,112, 67,182,118,102,191, 77,247,149, 21,115, 41,196,213,175, 41,244,200,241, + 80, 85,142,139,201,194,137, 9,207, 77,115,159,136,255, 0,164,222,229,137, 30,163, 15,134,190, 13,228, 85,153, 9, 87,213, 91, +165,191, 87,204,167, 45, 40,174, 45, 76,182,204,169, 86, 14,216,198,101,228,255, 0,133,202,109,178,212,219,137,132, 41,194,148, +158, 96,180,131, 37,202,248,118,182, 90,133,138, 42,118,185,221,117,133, 75,133, 32, 29,216,168,185,189,236, 14,163,109,129, 0, +219,143,243, 63, 16,184, 90,150, 55,105,115,232, 42,165, 31,169, 77, 42,212,177, 32, 14,130, 18,226,224, 0, 53, 57, 0,216,238, + 55,196,195, 45, 68, 22,211,205,146,176,133, 54,151, 20,132, 15,133,229,231,144, 40,224, 37, 5, 65, 39,151,155,148, 18,158,152, +235,167, 48, 77, 75,205,166, 35, 10,241, 36,158, 64,164, 52, 60, 79, 9, 9,207, 48, 83,160,114,149,103,148, 96,103,182, 73,215, +230, 7, 43,219,203,237, 79,157,190,246,230,253, 61,196,180,212, 75,181, 94,156,213, 51,101,233,182,221, 22,223,225,210, 69, 2, +168,227, 11,169,218,181,125,167,162,176,212,122,212, 25, 8,142,218,126,176,154,244,170,211, 68, 7, 88,168,182,234, 82,177,213, +203,167,233, 12,113,211,199,133,235,182,188, 54,240, 99,176,227,101,238,251,254, 37, 46,135, 81,183,246,214,113,190,247, 95,112, + 47, 39, 98, 37,203,129, 54,157,199, 86,136,195, 22, 53,140,193,106, 91,252,225,149,204, 98, 19, 75,118, 84,180,165, 7, 18,169, +178, 74,170, 69, 51, 56, 73,209, 23, 81,210,224, 42,219,115,204, 50, 5,109, 34,219,149, 87, 3,115,219, 16, 36,241, 71, 32,204, + 22, 85,167,138,163,219, 12,129, 32,128, 37,228,152,177, 1,116, 88,216, 92,246,107, 17,218,230,195, 19,125,171, 92,246,205, 30, + 90, 32, 84,171,244,168,149, 5, 16, 61,205, 83, 89,247,180,147,216, 56,218, 23,148,121,247,198,178,122,125, 22, 5,114, 40,154, +138,154, 22,210,134, 80, 99,180,183,112, 79,162,136, 1, 95,118,123,235,152,220, 17,123, 63,247, 3,103,237, 26, 77,219,197, 85, +255, 0, 51,114,119,174,160,202, 42, 21, 90, 12, 74,180,170,149,181,104,202,120, 37,197,211,222,171, 73, 81,114,229,171,182,181, + 40, 63, 37, 88,100,184,149,120, 41,228,194,143, 75,153,101, 48,185, 91,107,153,134,155, 1, 8,109,165, 41, 41, 74, 64, 1, 32, + 4,224, 99, 3, 80,103, 78, 51,204,101,157,185,180, 57, 21, 10,146, 34, 81, 20,149, 19,184,236,206, 95,148,177,131,216,104, 15, +110,168,167,108, 60,209,182,123, 57,246,138,169,146,133, 91,117,142, 38,105,152,127,215, 43, 89, 24,145,251, 10, 7,241,197, 84, +154,117, 14, 91, 72, 18,147, 35, 46,114, 97,104, 83,107, 42, 39, 25, 0,249,254,115,167, 66, 11,229, 77,120,141, 0,191,209, 21, + 33, 25,229,241, 84, 82, 74, 83,146, 59,103, 90,221, 94, 77, 82,101,118,154,148,130,244, 86,221,202,228,255, 0, 60, 39,160,229, + 89,254,119,200,247,211,203, 6,164, 88,105,150, 65,236,148,131,147,213, 56, 24,206, 62,221, 45,195,237,153,206, 43,169, 51,119, + 73,100,164,125, 34, 72,211, 64, 97, 96,110, 1,191, 81,243,214,210, 12,210,138, 24, 41, 40,102, 89, 57,178,213, 33,105, 1, 32, +244, 32,111, 96, 45,125,246,219,221,139,140, 97, 48, 58,236,154,131, 46,153, 46,146, 87,204,146, 82,132, 15,242,109, 36,167,167, +132, 6, 59,119,206,190,200,170,100,132,160, 21, 41, 56, 1, 36,134,210,133,100,156,114,158,195,191,225,170,166,170,211,105,248, +149,212,255, 0, 59, 56, 36,156,100, 15, 64,113,246,235, 24,171,213,226, 60, 10,142, 60, 84,244, 75,137,232,164,103,245, 65, 82, + 71, 80, 58,100,117, 7, 79,209, 82,242,147, 69, 59,116,245, 27,159, 93,250,111,240,235,241,195,116, 85,144, 77, 56, 50,195,229, + 27,121,122, 40, 22, 2,202,123, 1,254, 33,247,226,229, 38, 74,212,210,138,159, 75, 96, 2, 2, 89, 3,156,146, 72,192, 46,118, +242,234, 6,176,138,131,208,130,143, 59,105,144,180,243, 97,114, 84,183, 74, 71,117, 30, 85,124, 41, 72, 32,103,160,201,234, 15, + 82, 53,100,169,214,165, 52,218,131, 78,182, 91, 7, 5,229,115, 43, 41, 62,101, 9,253, 85, 99, 29,115,128,122, 16, 53,132, 78, +168,190,250,242,169,137, 87, 33, 4, 48, 26, 80,111, 0, 28,172,132,175,226, 56, 4,128,162, 71,159, 77, 32,237, 34, 54,153, 1, + 86, 59,239,247,110, 15,243,248,219,221, 40,164,162, 89, 84,201, 21, 66,136,191,195,112,122,116, 32, 11,143,131, 90,221, 78,196, + 28, 93,170, 53, 86,220, 45,182,214,121,193, 56, 75, 24,202, 63,156,175,242,120, 8, 79,194, 49,147,208,172,140,107, 28,144,185, + 14,165,196,243, 54,128,227,107, 95, 40, 1,247,148, 10, 82,160,148, 36,114,161,156, 18,146,126, 53, 99, 7,225,193, 26, 21,201, +165,223,209,170, 87, 43, 69,196,145,224,199,109, 32, 21,142, 84, 37, 68,147,135, 50, 73, 61, 7,235, 99, 61,180, 42,150, 9, 83, +110, 45,199,193, 66,138, 91, 83,156,173,178, 57, 84,149, 20,132, 36, 4, 47, 4,158,234, 33, 74, 7,212,107, 34, 85, 36, 91,174, +195,111,187, 14, 2, 4,136, 88, 88, 50,239,114, 9,216,252, 64,239,107,131,210,253,111, 96,106,135, 9,241, 91, 90,152,154,224, + 81, 10,117,183, 66,150,132,132, 32,132,199, 90, 18, 18,211, 62, 25,202,136,229, 86, 80, 71, 55, 78,180, 86,211,138, 90,218,109, +210,132,173, 42, 40,195, 97,226,160,188,146,149, 61,202, 17, 24,252, 7, 4,147,128,148,146,114,179,143,162, 72, 66, 20, 93, 82, + 91, 32,243,151, 0, 13,184,226,121, 87,250, 54,210,216, 3, 57, 40,248,112, 84, 48,188,119,233,112,142, 86,234, 29, 75,124,173, +161,158,235,112,133, 50, 75,156,174, 56,246, 66,135, 48, 3, 10, 10, 0,128, 64, 10, 4, 29,108, 70,250,118,191,227,252,183,237, +110,134,223,125,175,163, 80,140,221,139, 15, 94,194,214,251,186,251,205,239,140,110,108, 82,150,189,228, 33,212, 54,225, 10,142, + 29,108, 40,168, 1,209, 40, 65, 63, 3, 28,169, 5, 42,200,193, 95, 80, 71,124, 14,168, 18,210, 86, 21,203,202, 82,160, 8, 0, +169, 41, 24, 9, 81, 60,184, 87,196,165,224, 12, 28, 28,231,190,156,202,203, 43,100, 60,180,187, 46, 83,142,128, 90, 68,167, 20, + 70, 74,148,144,167, 1,235,149, 35,157, 71,249,216, 72, 0, 37, 61,155,106,154, 76,153, 41,136,149, 4,169,231,163,196, 66,202, +129, 9,117,245, 33,158, 98,160,112, 71,136,224, 32,158,132,126, 26, 84, 48, 2,250,134,223,233,191,126,157,125,253,112,216,241, + 18,202,161, 65, 55, 29, 0,222,246,181,135,238, 29,126,252, 64, 99,219,127,112,181,112,123, 74,183,173,166, 28, 82,255, 0,130, +214,206,212, 89,178, 82,176, 66, 90,159, 67,176,105, 47, 75, 67, 68,147,204,215,137, 82, 24, 35,204, 30,154,228,170,206, 51,216, +231,166, 58, 99,237,251, 53,183, 60,121,238, 60, 93,220,227, 99,138,189,200,132,233,122,157,114,111,133,244,154,114,249,150,180, +154,125, 6,168,171, 94, 25,104,172,228, 50, 89,161,161, 72, 29,130, 92, 0,116, 26,212,101,246, 56, 61, 59, 96,227, 63,241,212, +247, 43,140,165, 5, 18,176,179, 8,144,144,122,130, 84, 18, 62, 32,155, 28,114,150,121, 50, 85,103,185,197, 66, 29, 81,207, 87, + 80,202,123, 21, 51, 57, 82, 15,189,108,126,252, 8,178, 15, 79, 76,232,117,245, 36,142,192,224,252,191,179, 85,214,174,254,137, +207,231,246,104,101,224, 28,231,161,235,248,233,200,126,252,104, 1,220,109,129,221,230,199, 97,142,189,189, 51,215, 63,159, 61, + 14, 64, 0, 96,247, 29,126, 71, 68,169, 89, 62,120,252,245,208,202,238, 79,204,253,154, 92,108, 5,240, 48, 58,192,202,135, 67, +215,243,231,249,198,133, 81, 3, 57,249,224,119,237,229,162, 28, 39,169,249,249,126,125, 52, 26,200,251,199,127,179, 74, 45,198, +227,126,216,200,253,248,160,178, 50, 58, 3,211,207, 63,184,253,186, 90,240,163,147,159,195,236,210,210,184, 24,175,170,168, 61, + 49,215,167,225,161, 16,112,122,156,116,213, 97,248,103,161,251, 51,164,216, 90,227,174,173,255, 0, 60,100,245, 38,214,190, 14, + 73, 56, 0,142,152,239,145,247,116,213, 66,176, 7, 82,172,142,216,249,246,207,222, 52, 58, 84, 83,211, 29, 7,111,236, 58,242, + 80,162,174,101, 47, 8, 61,128,206, 71,222, 7,174,116,131,222,222,236,101, 69,254,127,150, 46,141,168, 96, 0, 57,137,206, 73, +254,145,243,192,215,213, 44,173, 73, 8, 39, 9, 56, 87,124,103,247,245,254,141, 80,105,188,242,146,174, 81,158,128,117, 61, 49, +215, 25,244,209,205,167, 57,192,206,127,164,117,237,249,237,164,172, 79,207,166, 48,109,219, 21, 90, 56, 35, 35, 32,143, 46,221, + 61,125, 15,125, 28, 57, 72, 79,160, 62,127,205,251, 62,125,244, 50,121,112, 0,252,253,190,154, 37,176, 85,142,192,124,135,244, +231,207,166,177, 97,123,227, 24,184,178, 15, 76,159, 82, 63,163,247,234,184, 24, 57, 24,201, 57, 7, 31,135,219,161, 16,175, 35, +231,219,250, 49,162,146,113,220,245,232, 65,198, 59,246,199,175,246,233, 22, 22, 36, 97, 50,187,220,155,223,231,255, 0, 56, 37, + 43, 8,199, 58,186,159, 32, 59,244,249,104,146,238, 70,113,140,249,250,227,183,159, 77, 4,113,144,190,153, 63, 44,227,184,200, +252, 53, 81, 36,116, 32,231, 29,201,251,125, 7,150,146, 98, 58,223,225,130,219,221,123,117,193, 41,119, 24,248,249, 64, 32,224, +227,175, 94,160,122,244,206,167, 39,236,166,220,118,247,115,129,157,165,148,252,148, 73,171, 88, 74,169,237,245, 93, 33, 73, 46, + 54,186, 44,133, 38, 1,113, 61, 74, 65,132,228,126, 92,227, 35,168,212, 42,118,215,108,110,189,211,185, 98,219, 86,181, 49, 83, +231, 73, 5,229,186,227,137,139, 78,167,194, 66,128,145, 85,173, 84, 93, 79,135, 74,164,183,252,247,156,234,162, 66, 26, 67,174, +148,160,203, 23,217, 2,214,215,112,241,106,238,110,209,215,119,102,143, 34,181, 87,151, 2,239,168, 76,172, 75,110,139,108, 53, + 53,136,201,133, 34, 21,179,239,238, 5,184,218, 82,218, 11,139,119,149,215, 15,196, 91, 66,126, 17, 4,227, 9,104,167,142,154, +137,228, 6,169, 95, 86,155, 95, 74, 21, 96, 75,158,136, 11, 5, 3, 81, 26,142,194,230,246,184, 60, 26,124,214,135,136,167,204, + 41,105,100,124,178, 88, 36,167,158, 80, 44,129,137, 73, 35, 0,159,180,193,212, 2, 20, 18,129,238,218, 65, 23,235,214,231, 75, +174,219, 59, 83,184, 21,235, 93,151, 30,184,224, 91,147, 13, 27,193,104,188,236,105,178, 18, 35, 38,162,134, 82, 50,234,163, 33, +213,188, 0,207, 86, 70,181,171,102,120, 8,183,217,222,155,115,124, 46, 59,138, 53,229,105,208,108, 90,123, 86, 21, 10, 66,223, +155, 42,179,121,215, 33,166, 69,211,124,221,210, 95,234,244,211, 45,231, 83, 25,177,128,216,198,122,164,107,107,162,239,150,195, + 32,148, 57,188,187,110,233,193, 75,141, 34,227,167, 60,130,146, 48,180, 45, 33,226, 20, 8, 39, 35,207, 26, 14,226,227, 7,134, + 29,183,182,107,183, 12,173,200,163,213,169,246,180, 23, 39,205,163, 89,141,125,115, 86, 84,102,186,172, 83,169,144,129, 84,133, +127,178,128,126,237, 65,225,142,150,158, 82,226,162, 33,169,116, 0, 89,111,114, 69,200, 23, 59,157,133,183, 61,135, 91, 99,179, +242,190, 62,226, 28,135, 33,205,114,204,161,165,203, 70,109,205,246,202,132, 82, 30, 74, 87,138, 56,249, 76,250,117, 70,177, 5, +155, 76,136,234,116, 85, 84, 45,129,101, 97,144,207,224,179,103,238,181, 56,183, 81,123,208,158,152,250,158,156,245,169,125,220, + 20,116, 60,235,202, 42,121,197, 48,137, 42, 66,150, 73, 60,184, 78, 0, 56,244,208, 91,129,114,240,113,236,166,216,187,155,114, +235, 20,202,117,183, 21,229,201,153, 69,162,189, 37,138,222,236,111, 13,232,227, 74, 84, 26, 29, 62,109, 77, 74,149, 44, 56,247, + 39,140,233, 40,139, 17,165, 41,231,112, 0,207, 27,248,128,250, 66,114,226, 82,170, 52,190, 16,184,115,190, 43, 19, 3, 14, 52, +141,201,220,155,106,174, 41, 84,247,112, 66,100,195,183, 41,209, 86,185, 78,160, 14, 96, 30,113, 8, 56,248,186,103, 81,143,226, + 11,136,157,247,226,127,114,100,238, 30,253,238, 45,126,244,188,158,105,214,162,199,173, 62,168,205, 81,169,238, 40,172,211,168, + 86,223,192,221, 6,154, 50, 7, 43, 76,160,168, 1,206,181,158,186,127,203, 56,124,207, 46,161, 18,211, 34,253,166, 54, 14, 6, +215,180,103,204, 24,247, 50, 42,129,179, 89,197,215, 20,239, 27,253, 36,248,135,244, 13, 71, 12, 80,113, 94, 97,196, 20,179,105, + 38, 7,168,168,108,188, 50,127,118,243,135, 96,181, 38, 34,111, 20, 96, 58,169,220, 60,100, 95, 24, 39,180,115,137,253,201,226, +247,127,170,251,223,186, 82, 27,254, 16, 94, 74,118,124, 26, 44, 87, 92,118,155,105, 91, 81,121,162, 91, 54,141, 31,196, 63, 13, + 58, 13, 59, 9,230,192, 47, 62,243,210, 23,241,186,117,175, 92, 57,196, 97,202,237,211, 57,208,178,252, 42, 34,147, 24, 1,211, + 46,149, 5, 18, 60,253, 6,173,251,228,231, 53,219, 29,128, 65,247, 42, 12, 6, 79, 41,200, 5, 73, 4,129,215,191,174,178, 14, + 26,216,118, 93,122,230,134,202,121,164,204,167, 68,139, 29, 9,238,183,223,119,194,101, 41,207,153,113,104, 31,126,172,212,141, + 41,120,124,197, 24,209, 26, 34,128, 46,118, 28,192,119, 59,147,183, 82, 73, 39,169, 36,239,142, 53, 53,117, 21,115,214, 86, 85, + 74,211,213, 84,180,178, 72,231,118,103, 42,204, 73,176,238,123, 0, 0,232, 0, 27, 98,109, 63, 71,223,128,234,125,203,195, 15, + 16,156, 74,220,244,174,123,199,114, 99,200,218,237,155,145, 45,177,136,116,123, 98, 92, 90,221,217, 83,134,149,167,225, 85, 82, +187, 18, 29, 56,186, 15,197, 30,152,164, 14,138, 57,216,168,246, 17,161,213, 31,142,228,117, 50, 90,146,235, 97, 10,230, 75,225, + 8, 56,228,115,185, 67,169,229, 41,229,239,204,112, 8, 58,236,151, 0,219, 99, 15, 98,184, 76,225,239,107,105,113, 83, 17,187, + 99,109,109,231,167,180,148,132, 41, 85,138,164, 38,234,181,105, 14,116, 28,206,174,124,199,201, 39,174,123,233,168,226, 23,134, +171,150, 93,110,226,220, 91, 38, 61, 58,161, 65,144,255, 0,214,146,168, 44, 62,182, 43,237,206,148,240,247,152, 52,168, 9,103, +146,167,207, 53,197, 58,202, 3,136, 63,166, 80, 94, 2, 65, 52,151, 19,209, 54, 99, 28, 89,138, 38,170,131,118,127, 82,142,117, + 40, 61, 55,137, 74,160,247, 13,239,215, 29,145,225,180,210,240,102, 89, 6, 69, 36,194, 24, 42,163, 73,100,212,214, 95,105,101, + 94,110,228,237,169,174, 22,254,128,108, 0, 3, 82,108,234, 84,116, 52,134,210,201, 41,147, 33, 50, 29, 8,240,203,143,186, 2, + 0, 83,220,201,207, 58, 67, 40, 7, 36, 0, 19,132,156,107, 99,104, 52, 8,210, 93, 98,116,150,210, 36,193,113, 47, 65, 13,129, +225,199,203,101,135,198, 79,235, 74,113,133, 41, 10, 89, 5, 32, 16,148,242,167, 36,170, 87, 15, 59,203, 71, 82, 20,230,223, 76, +148,128,134,151,205, 74,153, 75,168, 33,105,194, 64, 39, 19,144,162, 0, 37, 71, 41, 4, 99, 28,189,244,241,218,123, 83,186, 79, + 41,180, 35,109,238,133, 20,114,133, 45,113,162, 37, 61, 14, 28, 74,221,114,104, 72, 79, 81,147,216,245,198,162, 81,100,213, 74, + 64,146,146, 66, 91,182,134,244, 22,232, 13,237,215,211,210,214, 24,178, 78,125, 70,186,229,108,198, 24,237,177,102,158, 32, 0, + 54, 4, 18, 91, 96, 64, 3,222, 5,177,113,161,208, 12,134, 16,211, 10, 90, 34,143,242,202,115,224,151, 49,158,230, 50, 29, 74, +147,238,236, 18,160, 10,191, 89, 64,114, 35, 1, 74, 86,178,171,163,112,237,237,158, 85,185, 95,170,208,239,234,203,242, 38,132, + 82,227,109,214,216,222,251,153, 34, 51,212,224,196,176,253,106,153, 99,209,229, 46,149, 79, 64,228, 45, 41,208,217,144,176, 88, +142,149,168, 40, 7,150,209,216, 45,211,158,164, 57, 54,149, 73,183,217, 80,229, 46,213,234, 77, 72,113, 41, 0,142,127,114,166, +182,234,138,136, 63, 8,231, 66,124,250,119,214,136,251,111,106,123,151,194, 15,179, 87,116,183, 91,103,247, 82,225,178,183, 81, + 55, 54,223, 91, 16,111, 43,121,168,212,249,212,202,101,201,112,177, 6,177, 22,136,227,168,117,112,106, 47,198, 43, 67,115,185, +253,229,144, 74,152, 83, 75,194,132,166,147,135,179, 55,167,146,177,104,218, 8,163, 49,131, 44,171,101, 82,242, 36,105,101, 37, + 93,174,238, 0,210, 13,137,213,184,190, 34, 25,199,137,124, 27,150, 48, 25,157, 89,207,105, 98, 73,154, 90, 74, 25,209,101,153, + 68, 78,197, 69, 87, 38,162, 8,201, 42, 11,115, 17,137, 23, 64, 22,225,150, 51,124,116,238, 62,206,240, 93,121,221, 53,125,139, + 98,254,183,183,166,236,173,213, 46,123, 18,139,190, 78, 91,107,223,205,183,143,115, 74,157, 85, 27,132,254,217,209, 34,200,137, +176,244,148, 57, 59,154,223,149,118,189, 34,254,168, 6,195,212,202, 37, 1,178,229,101, 17,220,184, 46,123,134,236,174, 85,110, +107,134,183, 87,184,110, 58,228,233,117, 42,229,201, 93,156,253, 74,191, 90,168,206,125,114, 39, 77,169, 84,100,184, 86,235,239, + 72, 90,214,224, 4, 37, 74, 86, 72, 39, 36,218, 42,181, 73,149,138,165, 74,181, 92,157, 58,167, 88,172,212,165, 86, 43, 53,106, +148,217, 85, 42,173, 98,179, 80,115,198,159, 87,171,212,230,186,183,234,149, 55,158, 37, 78,200,125,199, 29,112,245, 90,142, 6, +128,109,101,110, 97, 36, 6,179,241,128, 71, 49, 62,185,242, 26,176,114, 30, 31,163,201, 33,178, 14,117, 76,191,106, 66, 5,197, +194,141, 9,251, 40, 52,128, 22,229,136, 85,214,206, 85, 72,164,252,120,250, 73,120,157,244,128,204,169, 36,227, 28,238, 99,195, +217, 60,113, 67, 69,150,137,165,120, 17, 41,193, 88,102,171,119, 98,213,213,195, 83,191,180, 77,245,112, 73, 61, 64,160,130,138, + 25,228,133,136, 90,148,234, 57, 93, 9,121, 9, 80, 90, 91,144,148,188,144,176,114,149,165, 14, 2, 18,224, 80, 4, 40, 96,130, + 50, 8, 58,204,169,155,143,113,209,211, 21,169,110,192,185,160, 68, 11, 17,232,183,173, 53,187,170,154,198, 82, 82, 61,205,249, +174, 9,212,229, 15,255, 0,131, 48, 54, 63,248,163,211, 24, 96,228, 10, 88,201, 41, 7,162,137,244,238, 63, 57,213, 53,164, 43, + 36, 14,185,200,252,159,150,159, 39,166,130,161, 52, 77, 10,202,163,166,160, 13,137,238, 13,174,167,222, 44, 71, 99,138,111,135, +120,167,136,248, 74,170,106,190, 27,206,170, 50,105, 42,192, 74,133,134, 66,176,213, 68, 13,249, 53,148,230,244,245,180,228,253, +170,106,184,166,129,255, 0, 94, 54, 24,116,231,239,189,238,150, 89,133, 64,254, 15,237,252, 36,248,206,123,141,131, 77, 48, 29, +151, 33,230,210,209,151, 80,170, 84,195,206,184,250, 26, 64,229, 8, 74, 50,160,149, 45,107, 8,109, 8,177,171,117,119, 10,108, + 7,169,170,189,110,207,170,159, 74,208,253, 57, 21,201,173, 71,113, 46,161, 40,144,133, 73, 74,196,165, 54,232, 78, 92,111,222, + 60, 37,149,168,148,124, 74,206, 0,166,219,230, 33,120, 36,117,206,124,251,143,219,175,170, 91, 74, 90, 19,207,241, 32, 19,200, +147,240,156,250,254,205, 37, 29, 21, 36, 32,133,167, 64, 24,223,236,130,111,182,228,145,114, 71, 98, 73, 54,218,248,156,102,190, + 58,120,209,157,242, 99,172,241, 87, 62,130,146,154,148, 80,197, 71, 69,153,213,101,153,108, 20, 34, 40,225, 52, 84,185, 86, 89, + 37, 30, 91, 75, 70,241, 68,139, 37, 45, 45, 36, 84,242,232, 13, 44,108,196,177,172,227,188,193, 37, 92,169, 75,105, 8,109,150, +208, 16,219,109,131,209, 13,161, 0, 37,180,228,147,128, 7, 82, 79,114,117, 72,146,163,205,129,140, 14, 81,216,140,129,158,184, +237,223, 94, 84,177,158,216, 4,224, 31, 32, 73,237,246,107,233, 9, 80, 79, 50,129,198, 79,194, 64, 35,215, 61,126,205,109, 95, +111, 47,109,189,216,170, 85, 2,233, 91,105, 10, 6,221, 0, 3,160, 30,158,131,165,177,229,212,133,160,131,128,125,112, 51,211, +236,243,208,105, 11,230, 60,201, 8,109,191,139,226,248, 78, 71,159,207,251,116,122, 20, 20, 50, 7,145,200, 61,199,151, 95,191, + 67,169, 36, 55,151, 49,215,161,201, 4,252,137, 0,246,233,161,179,111,219, 6,177, 6,221,251,126,255, 0,227,138,110,123,186, +192, 82,130,150, 8,200,194, 73, 3,182, 73, 31, 61, 75,227,232,215,112,195, 99,223,219, 35,198, 38,227,110,133,131,105,238, 13, +175,184,202,183,248,125, 93,173,121, 80, 32, 92, 54,253,118,207, 69, 45,203,170,246,167, 78,131, 84, 97,109,174, 60,137,213,122, + 35, 78,132,242,171, 48, 16,160,164,173,180, 40, 68, 24,149,143, 8, 54,158,138, 74,147,205,144,144,181, 99, 24, 3, 29, 15,109, + 77,123,217,103,184,103,103,189,143,246,187,116, 6,164, 81,171,123,149,186,219,227, 85,173,205, 79, 52,105,170,164, 82,174,168, +214,139, 78,199,144,180,167,195,143, 48, 82, 93, 67, 79,160,169, 10,102, 26,210,135, 57,138,185, 98,156, 99,155,193,146,101, 73, + 89, 80, 12,138, 37, 10,177,139, 6,150, 66,173,201,141, 9,232, 76,161, 9, 36, 16,136, 25,200, 33, 72,197,129,225,126, 86,115, +110, 47,162,164, 72,185,210,136,228,101, 7,117,187, 20,132,234,244, 26,101,111,190,214,223, 28,193,223, 63, 97, 79, 4,115,184, +194,185,209,179, 27,239,185, 54,175, 14,116,135,150, 47, 93,165,163, 83,105,149,186,237,191,122,205, 66,164,162,196,218,237,215, +185, 31,144,220,155, 36, 48,243, 62, 60,137,208, 39,207,167, 56,164, 69,140,229, 65, 78,120,204,111, 6,212,251, 26,125,155,123, +125, 58,216,185,109,203, 55,136,138,110,227, 80, 37,198,122,216,220, 26, 55, 21,119,221,175,121,219,245,200,177,194,145,114, 81, +170, 86,149, 42, 2,105, 21,166,212, 60, 80,227, 40, 75, 45,172,132,134,150,223,194,108, 27, 71,113,203,157, 91,184, 42,197, 34, + 81,147,122, 93, 21, 71, 34,115, 36, 46, 82,152,170, 10,100, 82,181,243,128,150,154, 17, 84,177,200, 6, 11,105, 81, 80, 1, 58, +222,155, 74,229,118,163, 38,164,121, 90,136,212, 8,204, 83, 34,180,202,131,110,158, 98, 36, 84,159, 83, 97, 28,172, 45, 43, 91, +109, 37, 72,230, 95, 43, 74, 4,164,144, 53, 71,103,220, 99,198,175, 58,200,217,245, 68, 48,132, 0,197, 3,242, 22,221, 8, 44, +154,100,147,169, 93, 83,188,174, 86,218,156,144,111,212,220, 79,225, 79, 9,228, 78,100,161,201,225, 89, 2,172,143, 33, 82, 89, +164,178,130,234, 9,180,107,204, 58,149, 35, 85, 80,157, 55, 14,113,212,219, 99,136,234,228,106,101, 18,155, 87, 66, 43,171,106, + 35, 20,230,230,213, 86,165, 86,106, 81,233,145,219,143,245,157, 94,162,202, 82, 39,213,158, 8, 74,228, 72,240,144, 31,125,213, +185,225,160,171,151, 78,181,189,187, 22,141,226,232,140,220,143,169,234, 75,115,193,110, 28,247, 27, 75, 82, 94,236, 27,137, 40, + 30, 71, 22, 72,232,147,202,162,122, 0, 78,185, 81, 30,244,240, 36, 85, 11, 97, 75,143, 66,134,205, 38, 36,144,114,151,170,110, +182,100, 75, 96, 4,171,162,144,234,163,165, 65, 32,245, 74,178, 8, 26, 10, 61,219, 41,136, 17,203,239, 31,124,142,204,154,156, +175, 13,210,158, 95,136, 52,201,108,142,169, 62, 50,148,126, 69,191,150,148,202,184,199, 54,167,208, 37,169, 53,106, 7,153,101, +243, 27, 0,162,250,143,152, 27,234, 59,146, 0,182,199, 21,248,142,186,130, 68, 16, 73,204, 22, 91,197, 37,200, 58,148,200, 0, + 63,105,108,186, 23, 99,179, 29,212,244, 27,233,106,113,119,182,151,183, 20,183,231, 10, 22, 90, 95,184,110,205,174,179, 85,117, +110, 45,213, 17,214, 92,183,173,234,168,126, 51, 38,204, 66,193,230,145, 91,105, 50,153,247,130, 7, 35, 78, 18,214, 74,210,172, +108,130,235,136, 99,157,106, 88,230, 57, 24,206,126, 30,184, 29,122, 99, 35,174,184,239,193,253,153,180, 27, 99,196,214,228,110, +244, 17, 42,218,187,248,132,179, 97,219,181,104, 40,144,201,180,230,222, 73,172,174,167, 38,226,195,235, 46,192,175,213,208,195, +104,125, 33, 94,236,228,180, 23,194, 91,114, 74,129,232,125,205,113, 42, 50,221, 64,113, 73, 41, 74,147,200, 62, 21,165,105, 39, + 60,201, 61,142, 2,178, 62, 90,181,184,106,180,102,212,111, 59, 48, 18, 60,132, 50, 0, 46,130,202, 66,144, 55,247,134, 61, 71, +223,105,215, 25, 75,194, 85,210,100,173,193,144,212,211,209, 46, 91, 68,149,130,172,222, 99,154, 8,239, 94,118,188, 98, 35, 41, + 2, 1, 17,229,242, 66,157,152,184, 14,149, 74,248,109,178, 71,136, 2,123,168,115, 2, 14, 14, 57,186,118, 32,228, 31, 62,191, + 45, 97, 51, 47, 98, 23,151, 29, 87,134,165, 30, 85, 12,144, 73, 56, 9, 36, 28,115,140,128, 50, 48,190,217,242,214,190, 84,238, +181,120,174, 53,206, 10,138, 20,251,121, 81,248,208, 14, 28,111, 62,153, 35,167,145, 94,177,148, 93,188,217,104,175,152, 41, 36, +165, 46, 12,115, 32, 15,137, 25, 36, 18,180, 96,127,181,202,144,175, 93, 74, 99,129, 80,108,110,126, 63, 15,221,249,252,113, 22, +167,164, 88,198,195, 87, 75,254, 23,239,215,227,252,142, 54,149,187,161, 46,158,100,184, 10, 85,203,158,101, 4,148,156,144,121, +194,199,192,114, 21,229,141, 90, 42,114,158, 91,107,145, 76, 8,113,208, 10,213, 17, 74, 45,161,212,100,229, 76, 41, 32,144,224, +234,174, 78,161, 92,159, 14, 20,113,166, 18, 37,213,201,202, 92,120, 40, 0, 57, 92, 36, 41, 65, 39, 56, 67,160,145,146, 15, 76, +158,152, 57, 32, 19,157,102,144,110, 4,175,225, 82,207, 50, 70, 72, 4,148,117, 57,200,207, 83,144, 6, 64,237,203,243,234,149, + 69, 58, 78,154, 36, 23,244, 61,193,236,111,235,211,249,140,110, 67, 81, 45, 20,162,104, 13,237,177, 83,114,174, 63,101,198,215, + 30,253,136,189,193, 83,190, 47,109,215,101,185,200,130,228,102,194, 92, 90, 75,164, 58,231, 42,146, 73,229, 80,113, 35, 60,189, +138,136,248, 74,128, 86, 58,234,234,212,199,221, 1, 78,200, 88, 33, 68, 16,142,102, 27, 82, 21,132,242, 40, 55,146, 82,112, 59, + 17,133, 39, 33, 64,231, 88, 13,198,183, 11, 6,169, 79, 9, 91,204, 2,185,108,130,176,149,181,132,149,201, 71,135,250,206,161, +180,146,226,123,173, 0,158,139, 29,113,232,181,233,174, 28,169, 77,128,142, 71, 27, 45,169,120, 83, 43, 79, 55, 50,121,143,249, + 64, 84,147,211,161, 24,193,202,134, 98,211, 43, 81,204, 98,153,246,107,216,216, 88,131,109,238, 59,250,223,241, 6,248,157, 80, +188,121,165, 42,212, 83, 34, 68,192,217,212,145,169, 24,117,235,185,235,117, 35,175,186,197, 67,227, 22, 64, 10, 60,141,168,243, +128, 10,146, 74,212, 91, 65, 32, 37, 74, 41, 42, 91, 32,227,252,152,234, 9,207, 49, 35, 87,149, 84, 92,140,217, 90, 25, 74, 60, +117, 4, 33, 47,165,213,199,195,201, 42,109,160,129,149,198,144,226,142, 19,206, 49,147,240,163,148,243,105,158,139, 82, 82,138, + 1,113, 92,142, 19,203, 33,183,156,229, 70, 87,204,203,109,242,184,163, 29,174,101,225, 33, 28,203, 82,148,148,148,231, 35, 87, +196, 84,214,134,138,188, 73, 40,112,151,217, 83,209,203,109,180,180,164,252, 94, 34, 22,162,183,100,103, 28,223,168, 83,130,148, +143,136,157, 47, 28,195,190,192, 88, 95,247,119,235,183,190,247,177,191, 77,244, 42,224,209,114, 95, 93,183,232,119,183,196,245, + 29, 59, 16, 63, 12,178,167, 82,117,101,214,158,116,143, 5, 24, 90, 23,206,135,176,149, 30,171, 28,152, 67,133,148, 37, 68,130, + 72, 82,136,233,216,106,111, 20,187,199, 75,216, 78, 31,183,187,123,107, 14, 3, 11,107, 54,178,243,187,194, 90, 57,118, 69, 74, + 29, 37,232,118,227, 17, 80,181, 15, 26, 67,151, 45, 70,140,218, 83,159,252, 98,186,121,105,253,153, 86, 47, 7, 9,115, 32, 43, + 45, 41,124,222, 48,200, 88, 62, 39, 83,200,159,140,117, 57, 42,192,233,231,168,229,253, 33,126, 36,209,101,112,247,183,156, 51, + 81,166, 20,220,123,253,118,139,190,234,105, 14,114,189, 19,107, 54,170,107, 47, 14,101, 54,172, 24,245, 77,192,149, 76,140,166, + 92,229,230,106,223,125, 65, 36, 5, 99,118,157, 26,170,122,122, 52, 39, 85, 75, 0,125, 66,117,118, 29, 62,202, 6, 59,122,116, +190,198, 41,159, 87,166, 83,147,230, 89,163, 16,134,138, 38,100,189,183,152,128,144,169, 29,124,210,178, 41,223, 96, 73,219, 16, +244, 92,153, 82,150,236,202,131,161,234,140,247,159,157, 80,125, 32, 97,234,132,215,151, 38,107,224, 96,116, 92,167, 94, 87,207, +155, 66,172,131,211,207, 61,115,246,127,110,136,115,169, 29,135,115,161, 87,230,174,152,245,239,216,121,254,124,181,105,160, 0, + 11,108, 63, 45,182,199, 34, 42,236, 13,205,207,174,253, 14, 6, 86, 50,113,249, 63, 47,150,135, 81, 10,242,192,235,159,159,204, +250,104,133,250,130, 20, 72,252,244, 26, 21, 71,161, 62,125, 79,223,165, 20, 18, 70, 21,192,234, 32,117,249,224,103,231,246,124, +180, 51,131, 57,234, 1, 4,245,209, 90, 17,194, 14,122,247, 57,199,203,231,165,199, 81,129,129, 85,211,167, 82, 79,115,242,244, +199,166,116, 42,200,207,108,117,199,219,215,207, 68,185,242,238, 7,159,111, 95,223,160,150, 79,126,152, 61,193,243, 61,127, 63, +118,148, 65, 97,210,247,249,255, 0, 92, 12, 82, 36, 2,122,129,247,254,255, 0, 61, 45, 81, 95,235,119,242,252, 62, 95,159, 93, + 45, 31, 3,108, 86, 29,251,103,229,162, 52, 42, 87,219, 61, 15,145,199, 76,131,229,170,129, 68,158, 94,108,116,207,111,159, 94, +190,189,244, 71, 2,221,108, 70, 14,195,173,190, 63,195, 7, 54,123, 21,125,223, 63, 67,162, 7, 95, 35,246,121,232, 38,240, 58, +100,147,243,252,247,254,173, 22,149,245,244, 62, 94,126, 95,102,146,193, 58,116, 56, 41,161,203,212,156, 99,200,252,243,216,104, +214,200,243, 0,253,248, 39, 64,165, 89, 29,191, 17,231,231,131,157, 86,108, 20, 44,168,172, 16,172, 1,159, 47,179,238,210,109, +233,109,135,242,198,113,112, 10,193, 1, 67, 4,249,129,223,237, 35,243,215, 68,167, 3,168,200, 39,161, 29,191,102,122,118,208, +169, 81, 32, 12, 12,140,119,237,140, 1,140,143, 60,232,128,172,100,156,100, 96,228, 96,147,246, 99,229,253, 58, 79, 24,193,141, +168,119, 61,113,211,239,233,131,248,104,132, 28,224,245, 56,235,243,233,235,143, 45, 0,133,103, 3,168, 4,250, 14,255, 0,105, +213,126,108, 17,133, 41, 57,207,234,250,255, 0,195, 72, 55, 94,183,198, 45,251,240, 96,194,212, 65,206, 15, 99,156, 99,167, 83, +223,166,178,107, 86,133, 46,228,174, 83,168, 84,230,131,242,231,203,102, 43, 41, 89,195, 69,215, 20,122,190,224,255, 0, 37, 29, + 13,165,110, 56,175,230,182,210,136,235,140,226,141,149,172,148, 40,242,164,140,243, 0,115,229,231,167, 83,107,106,201,163,215, + 27,102, 59,168,106,161, 80, 68,168, 17,165,168, 14,120,254,244,202,121,148,223, 55,119,212,203,110,165, 63, 53,159, 44,231, 74, +177,164,138,154,105, 34, 0,200,138, 72,248,250,159,147,183, 77,240,231,146,208,195,153,231, 25, 94, 91, 81, 57,166,167,174,158, + 24,157,199, 85, 87,117, 86, 43,125,181, 16,108,183,219, 81, 23,218,248,222,138,101,205,111,109, 53,188,139, 14,206, 6, 92,185, +106, 97,219,158,165, 20, 33,169,181,218,147,105,229, 75,211,229, 39,172,106,107, 74, 42, 76, 88,249,229,105,177,148,165, 78,169, +197,168,202, 52, 58,189,201, 45,107,152,251,134, 43,136,241, 26,136,133, 56,212, 96, 73,206, 22, 82,160,183,187,255, 0, 56,129, +159,230,233,172,181,109,231,101, 77,113,174, 96, 84,151, 11,234, 90,143, 58,214,238,114,165,184,181, 28,173,106, 39,185,234,115, +211,167, 77,109, 61,163, 22, 44, 22, 27, 91,137, 83,171, 74,128, 82, 1,207,234,158,188,201, 56, 29,255, 0, 15,232,173, 43,102, +142,152, 57, 86,230,207, 39,153,152,245, 98,109,185,219,238, 30,131, 97,176,176,238, 92,135,135, 96,160,165,130,158,154,139,217, +233,169,194,164, 80, 40,217, 20, 91,173,247,102, 39,119, 98,117, 51, 18,204, 75, 18,113,157, 88, 27, 77, 6,162,243, 10, 91, 45, +173,210, 17,204,134,249,192, 79, 80, 63,214,237,246,249, 13,116,123, 98,182, 58, 4, 74,205, 30,167, 79,136,195, 21, 8,242, 27, +109,110,132, 5, 41, 73, 87,235,167, 43, 4, 56,130,140,228, 96,131,208, 99, 90,225,182, 40, 67,142, 48, 16,148,176,211,139,108, +165, 13,164, 41,196,146, 1, 0, 28, 0,122,103,200,227, 93, 65,218,186,205,175,107,194, 23, 45,203, 58, 29, 22,218,182, 96, 72, +174,220,149,170,131,237,177, 22,155, 74,165,199, 84,185,211,101,200,116,132,182,210, 35, 52,242,142, 78,112,156, 0, 78, 6,171, + 12,238,173,234,222, 88,228,156,164,106, 9, 35,215,160, 2,195,177, 61,189, 58, 92,224,103,185,230,105,150, 32,167,167,102, 26, +193, 82, 7,165,183, 6,219, 90,219, 1,190, 56,205,197,103,181,207,127,173, 13,203,184,118,215,133,170,141, 31,104,108,203, 18, +227,169,219,114,110, 38,173, 59,114,175,120,222, 85,138, 12,199, 41,181,154,156,153, 53,154,123,241,232,148,133, 84,163, 74,110, + 60, 86, 88, 82,220,105,176,227,238,146,190, 68,232,182,233,123, 64,184,141,223,154, 60,154, 6,249, 57,181,123,167, 78,146, 84, +227, 18,107,187, 67, 98, 81,110, 42,116,165, 0,145, 34,159,117,218,148,120,114, 99,114,227,163,101, 42, 70, 84,115,229,173, 86, +221,155,170, 61,231,185, 27,133,121, 69, 66, 4, 43,174,251,188, 46,104, 37,150,148,210, 87, 78,184, 46,106,173, 86,152,226, 26, + 95, 86,138,160, 76,140, 84,147,241, 37, 74, 32,128, 65, 26,194,202,138, 27, 72, 66, 66,146,164,249,147,216,250,231,207, 87, 69, + 31, 7,240,224,142,134,170,163, 33,165,108,202, 5, 70, 19,180, 17,154,132,144, 1,186,205,167,154,132, 27,219, 75, 46,158,139, +101,216,113, 46,113,196, 25,150,101,152,213,213, 75, 88,211,164,146,185, 69, 33, 74, 4,212,116, 0, 45,109,150,194,253, 77,174, +196,146, 78, 25, 29,226, 14, 57,121,205,113,232,130, 3,142,211,225,184, 35,161,210,251, 60,158, 24,194,153,113, 74, 39,194,232, + 48, 51,240,246,211,245,236,251,162,194,185,248,143,179, 45,121, 83, 19, 21,250,213,203,107,181, 9,165, 71,118, 87,191,186,213, +102, 27,130, 3, 81,152, 66,148,243,239, 41, 41,105, 3, 24, 5,238,101,124, 41, 58,101,247,161,159, 22,181, 69,168, 39, 42,110, +109, 13,166,193,234, 48,228,124, 36,164,245,239,145,174,129,251, 9,174,186, 5,165,237, 66,225,233,203,134,153, 75,169,179, 93, +122,232,183,105,102,171, 29,185, 77,211,107,245, 27,114,161,245, 77, 90, 19,110,130,148, 84,153,121,149, 6, 86, 70, 82, 94, 37, + 63, 16, 4, 76,106,145,166,225,202,216,163,115, 19,154,118, 0,141,244, 17,182,175, 48,111,179,107,216,131,211,124, 55,240,245, + 50,102,121,237, 29, 36,238, 33, 74,218,128,140, 64, 27,115, 13,172,189, 64, 38,246, 91,130, 3, 17,112, 70,216,253, 60,108,203, +170, 61, 38,218,163, 69,169,210,215, 6,123, 52,168, 12, 42, 18, 30, 74,149, 13, 45,197,109, 30, 2,136,232, 84,156, 96,142,195, + 24,211,173, 99,205,135, 95, 67,163,195, 82,216,105,226,174, 71,124,148,149, 2, 51,235,129,141,105, 44, 90,227,175,203,110, 58, +159, 60,234,145,200,227,139, 86,113,133,225, 74, 81,201,236,156,159,187,231,170, 28, 4,113, 50,246,254,220,188, 78,211, 27,167, +174,157, 67,217,253,200, 98,198,160, 62,226, 84,149,213,154,110, 59,134, 85, 65, 74, 80,193, 38, 67, 46,128,145,156, 36,167, 56, +206,171,117,160,130,138,122, 97,237, 82,206,210, 2,164, 74,193,245,233, 0,234, 42, 2,170,144,127,100, 1,189,173,233,213,116, + 57, 94,103,152,229, 89,246,102,140,213, 17,228,201, 12,179, 73, 36,128, 58, 9,234, 18,153, 52, 40,182,162,210, 72,183, 8, 0, + 85, 5,141,128, 24,234, 84, 22, 97,190,160,211,140,160, 37, 73, 9, 37, 39,151, 35,203, 4,118, 61, 53,114,153, 78,153, 71,107, +235, 40, 14, 61, 50,158,222, 60, 88,104, 36,186,207,108, 43,161,248,155, 29, 63, 29, 97, 20,201,202, 47,103,152,116,235,202, 79, +126,158, 94,167,229,242,211,203,110,200,247,142, 86,186, 45, 43, 28,139, 74,199, 69, 36,140, 40, 28,142,185,211,232,142, 26,149, +210,124,143,250,172, 54, 32,246,233,212,123,143,108, 87, 57,193,168,203, 88, 74,126,186, 30,174,140,110, 24, 27, 95,115,186,183, +163, 11, 88,251,182, 38, 90,149,147, 81,103, 43,113, 42, 36,101, 41, 4, 97, 63,236,131,246,106, 57,159, 74,191,116, 98, 90,254, +207, 59, 39,109,189,229, 13,212,183,107,126, 44,232,173, 70, 10, 79,139, 34,151,103,194,170,220, 21, 37, 33, 4,228,182,151, 83, + 3,152,129,211,196, 79, 81,158,178, 30,102,146,109,219,145, 41, 96, 40, 65,169, 43,197,142,145,209, 8,117, 68, 7, 25, 3,237, + 80, 32,127,181,168, 24,253, 41,190, 42,105,187,177,198, 54,217,240,225,110, 85, 81, 54,139,195,101,145, 34,125,214,152,206, 7, + 99,181,184,187,128,182, 37, 59, 9,124,170,199,189,197,183, 98, 83,146,176,122,161, 83, 8, 58, 74, 58,202,145, 17,201,101, 26, +102,168,170,131, 88,244, 90,105, 22,173,158,223,176,226, 5,136,155, 90,243, 32,234,192, 98, 1,158, 71, 76,139, 85, 95, 79,189, + 36,176, 18,155, 91,205, 48,228,232,235,246,147, 91,189,183, 39,148,198,196, 2,113, 23,105, 12,224,142, 92,114,128, 57,115,230, + 60,193, 31,158,218,166,220,116, 96,148,167, 35,185, 0, 30,135,231,131,219, 70, 58, 91,112,228,147,129,219,200,129,212,245, 26, +163,239, 1,162,164,182, 58, 16, 2,148, 48,123,246,233,248,234, 69,123,110, 78,199,253, 49, 95,238,192, 91,182, 41,184,218,146, +112, 2, 85,145,205,128,115,240,232,117,175,166, 2,185, 84,122,144,123,252,146, 48, 58,249,126, 26,246,165,183,205,207,226,242, + 41, 68, 0,146,160, 57,188,186,141, 8,236,164,182,248, 10, 66, 79, 40,192, 24,234, 78, 51,205,246,235, 5,182,178,131,140,233, + 61,206, 62, 37, 37,100,130, 84,143, 85, 20,247,251, 9,215,196, 52,218, 22, 28,108, 23, 20, 73, 10, 73, 32, 16, 58,117, 3, 29, +117,111, 83,203,146,247, 41,116,161,190, 96,162,140,245, 64, 79,113,246,247,209,173,134,220,112, 58,130,174, 68,156, 21, 96,167, + 56, 29,142,124,186,235, 23, 38,226,214,237,108, 24, 0, 8,223,231,108, 84,202, 80,181, 45, 75, 37, 10,236,140, 14, 84, 19,208, + 21, 19,249,206,145,240, 91, 89, 35, 4,168, 2,181, 39, 36, 1,143, 63,207,219,175, 14,180,248, 91,135,225, 44, 44, 19,203,230, +113,158,202, 35,190,147, 72, 75,188,184, 10, 97,180,167,149, 94,101, 68,116,193,200,235,219, 67,113,176,234, 62,253,255, 0,241, +140, 88, 27,158,199,247, 99,223,138,128,176, 16, 74,202,192,200, 64,234, 51,216,159,151,174,144, 56,112,168,255, 0,226,210, 65, + 39,211,169,193, 30,191,219,161,201, 91, 97,101, 11,229, 33,124,169,112,164, 97, 67, 25, 41,193, 29, 62,221, 18,149, 30, 64, 28, + 41, 83,138,201, 81,233,203,131,211, 7,167, 95,158,178,160,129,238,248, 99, 4, 11,219,211,111,159,187, 23, 91,122,216,174,223, +151, 45,171,103, 91, 30, 48,173, 94, 23, 45, 2,211,161,169,134,124,101,166,185,117,214,160,219,116, 71, 18,206, 63, 72,148,213, +170,176,202,135,110, 84,156,234,116,188, 70, 90, 86,214,200,237,141,191,195,253,145, 22, 45, 26,196,217,203, 30,212,219, 59,118, +140,216, 15, 52,105,182, 85, 52,210,220,144,228,146, 7,188, 57, 58,187, 14,173, 81,121,213,101,199,100, 86,221,117,213, 5,175, + 81, 5,246,122, 41,151,120,231,225, 49,165, 45,167, 25, 70,253,237,171,138,109, 68, 6,138,152,185, 35, 72, 66, 58,164,128, 60, + 86, 81,140,142,248, 24,212,167,184,174,185,213, 80,146,133, 73, 46,189, 42,116,101,176,243,171,116,136,206,165, 92,181, 24,242, + 29, 66,122, 56,175,137,244, 12,128,174,102,202,115,202, 19,170, 83,197, 9,101,168,206,184,107, 46, 36,242, 99,215, 57,177, 27, +176, 33,119, 7,246, 0,242,159,241,145,183,126,148,250, 56,229,176,205,157, 87,230, 36, 3, 52, 82, 67, 18,237,186, 42,142,113, + 96, 78,222,114, 22,253,238,138, 65,198,134,236,221,125, 48,227, 85,230, 51, 33,182, 20, 46,139,193, 78, 71,146, 11,172,173, 49, +107,213, 39, 22,218,176, 65,104, 45,181, 17,240, 28,231, 10, 57,192,214,224, 91, 87, 56, 52,186,124, 87, 37, 60,195, 17, 27,114, +181, 86,168, 52,165, 33,208,211,232, 84,135, 35,180, 82,172, 45,194,149, 57,206, 62, 17,225,181,156,149, 19,174,110, 88, 21,191, +119,114,244,165,183,202, 67, 27,155,118,199, 87, 58,178, 4, 89, 50, 96,212,208,176,140,117, 30, 4,208, 18, 6,122, 47,168, 24, +193,216,148,220,233, 17, 19, 8, 58,234,126,185,152,195,115,214,218,208, 94, 77, 49, 13,178,244,133,248,196, 0,223,193, 29,180, + 33, 36,116, 68,133,242,242,101, 71, 81,250,188,185,106, 15, 67,113, 99,239,183,107,245,232, 9,183,107,219,224, 58,227, 63,165, +142,190,158, 48, 77,158,254, 98, 55,217,118, 36, 14,246, 5,200, 7,112, 64, 22, 35,166,219,210, 47,185, 82,233, 80,131,107,114, + 60,217, 83, 30,159, 55, 1, 97, 10,126, 99,143, 59,200, 93, 39, 36,248, 79, 52,216, 74,146, 85,208,149, 28,227, 87, 58,150,229, + 67,154,202, 4, 96, 35, 72,171, 77,110, 44, 73,100, 36,180,229, 58,157,136,136, 91,136, 10,230,111,157,193, 37,215, 17,208,101, +244,168,228,117,214,181, 64,187,158,122, 93, 82, 99, 15, 54,251, 37,214,153,128, 31,117, 72,105,199, 39,177,225, 23,146,164,156, + 48,194, 20,135,157, 91,128,140, 41,148,243,100, 17,156, 82,117,230,220,185,110, 46,150,234,204, 86,210,213, 38, 18,207, 68,178, +246, 20,194,221,232, 57,159, 45, 69, 67,133, 75, 72, 8, 74,217, 4,243, 28,107, 65,114,134, 28,192, 19, 72,150,215,216,116,216, +247, 29,143,240, 35,215, 20,246,103,146, 44,245, 78,252,176,174,237,171, 80, 54,208, 8, 14, 67, 30,182, 4,169, 0,130, 8,141, +150,215, 27,108,165, 82,240, 65, 91,130, 60,226,182,132,167,101,192,151, 29,238, 83, 25, 20,197,120, 81,158, 74,218, 87,253,240, + 30, 74,156, 5, 56, 40, 82,144, 70, 78, 52,237, 90, 94,211,206, 31,238, 61,215, 87, 13,251,187,120,211,246, 99,125,216,166,219, + 53, 27, 46, 70,225,213,169,180,173,188,223,218, 29,126, 20,116,211,238, 11, 14,254,117,214,224,219,183,114,235, 2,165, 77,157, +110,215,151, 5,255, 0,172, 41,143, 26,124,233,201, 95,132,215, 47,235,155,134,253, 49,169,137,139, 33, 17,217, 13,120,112, 82, + 15, 49,240, 35, 44,163,195,112,169, 32,252,110,120,100, 14,255, 0, 6, 84, 78,117,197,111,105,134,220,238, 93,231, 65,219, 45, +247,167,109,213,197, 90,217,251, 58,155,114,237,149,225,186, 16,105,102,169,111,209,111, 26,133,206,237,223, 6,220,186, 37, 68, + 46, 57, 71, 74,105,117,120,239,199,126, 99, 76,195, 90,234,170,101,153, 10,125, 14,182,139, 3,128,178,227, 14,113,200,102, 49, +197, 94,146, 41, 26,186, 58, 14,100, 76, 1, 54,102, 4, 50,105,239,205,107, 48,109,241, 25,226,106, 58,222, 29,225,154,236,230, +154,152, 85, 54, 88,209,177,136, 41, 60,216,218,101,137,193, 42, 24,198,232,143,175, 85,138,168,137,139, 93, 73, 6,112,183, 37, + 78,163, 2, 75,208,150,135,161,212, 82,216,153, 17,169,141,173,151,176,166,195,172,115, 50,232, 25,142,243, 42,192, 88,248, 20, +135, 67,169, 82,146, 1,214, 30,110,102,229, 6,164, 37,229,248, 15,167,153, 14, 21,167,199,131, 45,149, 41,178,218,193,232,133, + 37,208,234, 20,133, 14,138, 74,146,161,200,172,136, 53,240,131,237,106,226,159,133, 24, 84, 59, 53,218,219, 59,239,178, 52,133, +176, 33,109, 62,233,213, 42,115, 87,110, 83,210, 19,207, 27,108,183, 21,133,187, 86,176, 89, 90, 16,222, 98,161, 83,232,235, 9, +248,233, 74,207, 48,145,223, 13,254,212,238, 15,184,152,159, 78,162,209, 47,183, 54,118,249,175,188,219, 14,237, 94,249, 74,164, +218,245, 37, 92, 79,169, 49, 99, 27, 63,112,216,112, 91,183,164,105,106, 74, 80,226, 84,253, 38,123,107, 83, 14,125, 94,162,183, + 66,108,186,204,183, 48,166,102,149, 71, 62,156, 30,169,168,233, 30,174,159,105, 0, 23, 14,192, 50,168, 43,245,131, 77,196, 95, +135,248,215,135,243,244,142, 40, 42,125,147, 48, 63,251, 60,246, 73, 9, 31,170,141,253,220,164,236, 80, 35,107,102, 86, 28,176, + 93, 65,235,149, 54,227,231, 82,252, 98,143,120,111, 30, 50, 3,153, 10, 74,242,148,190,207, 95,141,149, 1,219,201, 64,160,158, +157, 92, 10, 45,120, 41, 72, 30, 42,210,211,129, 60,138, 36, 39,194, 40, 56, 9,201,199, 34, 15,194, 82,125, 71, 47, 98, 51,173, + 78, 57, 42, 4,150,225, 74, 68,136, 85, 24,204, 38, 66, 27,148,194,153, 91,140, 60,112,210,188, 53,165, 42, 92, 71, 18,144, 65, + 31, 2,199, 43,141, 41, 93, 9,204,232,245,213, 45, 41,192, 82, 28, 24, 15, 5,245, 67,125, 1,240,211,143,214, 37, 36, 97, 93, +148, 8, 56, 7, 58,212, 89, 53, 45,155,126,155,250,244,189,247,220,131,214,195,222, 7, 80, 36, 83, 0,111,109,143, 66, 55,176, +233,219,176,244,244,232,113,182,208,103, 41,109, 2,130, 8, 28,170, 10, 7, 24, 72, 25,194,155, 35,170,130,179,216, 16,115,215, + 3, 58,111, 43, 10,114,143, 57, 62, 8, 83,116,247,138,158,104, 35, 42,247, 7, 50, 75,237, 35, 36,226, 62, 87,206, 17,241, 16, + 21,132,140, 32, 1,125,182,231,180,168, 76, 58, 9, 40, 84,116,130,133, 30, 98,133, 5, 4,164,144,145,213, 29,122,131,213, 61, + 0, 36, 29, 13,118, 6,157,142,165,164,161, 74, 66,131,137, 36, 16, 75,137, 11,198, 66, 58, 1,225,133,117, 7,177,199, 76,105, +179, 52,167, 21, 20,206, 20, 94, 88,188,203,247, 14,159,247, 13,175,219, 99,141,204,138,188,229,245,233,172,222,154,164,132,144, +123,143, 71,223, 96, 84,155,244, 59,106, 94,135,127, 84,218,177, 40, 8,109, 77,171,152, 21,173,176,163,224,169, 71,153, 72,125, + 10, 73,232,160, 71, 80,122,228,147,140,224,235, 37,102,160, 10, 82,164,185,132, 45, 57, 74,215,202,149, 96,228, 37, 5, 93, 73, + 30, 65, 68,115, 96,128, 73,233,134, 98,157, 41, 13, 56, 75, 78,101, 30, 32, 41,200, 60,139,109,106, 31,174,223, 79,137, 36, 30, +189,207, 76,140,117,214, 72,221,101, 45,182,162,165, 36, 32,100,243, 41, 75, 81, 70,115,204, 0,245,193,235,219, 60,157,117, 24, +134, 67,166,254,131,225,214,223,195,240,185, 63, 9,141,122, 6,118, 85, 58,239,247, 92,246,191,191,212,255, 0,166, 51, 26,229, +207, 71,161, 82,171, 21,250,253, 86, 21, 10,222,160,210,170, 53,218,245,110,162,164,183, 78,161,208,104,176,228, 85, 43,117,153, +206, 45, 73, 9,137, 18,151, 18, 91,238,228,225, 72,142,160,158,165, 57,252,241,248,236,226,198,175,198,143, 19,187,139,190,210, +211, 34, 37,167, 54, 67, 54,134,209, 80, 36, 40,149, 91,187, 67,106, 59, 42, 29,153, 29,224, 82, 63,247, 86,123, 78,203,172, 84, + 21,128,163, 54,224,117, 10,232,210,117,219,143,110, 55, 31,168,247, 9,220, 13,237, 45,117,106,153, 60, 65,155,196,245,118,153, + 33, 73,250,186,148,129, 22,167,110,108,123, 50,218, 88,204,249,174, 8,181, 59,157,180,158,102, 99, 49, 2,144,247, 42,222,154, +216,140, 58,201, 42, 87, 55, 92,245, 24,242, 62, 93, 51,208, 99, 86, 23, 10,101,174,168,115, 74,133,179,204,161, 98, 4,110, 35, +184, 38, 79,255, 0, 83,109, 63,224, 1,129, 34, 76,115,135,139, 28, 75, 29, 69, 68,124, 51, 69, 46,168,168, 95, 93, 91, 41,184, +105,192,178, 67,126,252,133, 36,200, 55,250,214,208, 64,120,119,164,226,207, 66, 6, 58, 99, 61,253,127,110,168, 40,146, 14, 79, +145, 3,176,234,117,236,175, 32,140,119,245,254,173, 14,178, 50, 7,166,115,251, 53, 54,197, 56, 6,195,215,223,143, 26, 25,222, +163,190,112,127,103, 95,199,190,136, 80, 4, 28,249,117,233,242,208,171,236, 62,223,191, 74,170,144, 55, 30,252, 27, 3,172, 12, + 19,233,219,241, 26, 21,194,122,100, 96, 15, 50,122, 99,167,203, 68, 45, 88, 7,168,198,127, 12,119,207,207, 39,246,104, 39, 14, + 65,238,122,244,207, 92,117,243,209,240, 49, 73,194,122,158,135,167, 78,221,191,225,160,214, 70, 49,230,127,175, 85,214,124,179, +246,254,237, 12,162,115,131,131,230, 15,203, 74,168,176, 3,231,255, 0, 56, 24,164,161,156,124, 57,251,241,165,175, 42, 81, 4, +128,123,105,104,248, 61,215,161,234, 61,195, 9, 4, 17,131,140,142,223,159,183, 85, 65,193, 7,254, 56,208,233, 56, 57,252,117, + 84, 28,245,242,237,243,207,245,104, 16, 14,221,176,115,176,176,216,246,251,173,130,144,113,212,117, 31,209,147,251, 52, 64, 81, + 7, 3, 57,199, 92, 12,227,237,208,169, 35,151, 56,237,220,122,227,174,171,161, 97, 64, 96, 17,233,247, 31,233,206,144, 35,125, +251,225, 50, 15,218,181,186,127, 44, 28,217, 61,137,207, 79,219,211, 69,160,115, 4,228,115, 96,228, 12,227,183,110,191,142,129, + 66,176,164,143, 53, 1,246,117,209,136, 61,199,167, 81,162,144, 13,182,219, 5,193,232, 56,201, 61,187,103,231,233,170,157, 57, +128,201,237,219,190,122,158,195, 61,244, 58, 14, 70, 85,219,229,220,254, 78,137, 78, 6, 9,248,142, 58, 30,199,229,215, 73,176, + 32,251,176, 49, 85,178, 80, 71, 49, 24, 29,179,128,122,159,234,206,170,161,228,172,227, 5, 63, 51,208,106,130,129, 57, 36, 12, + 43,246, 12,103,250, 53,245, 33, 41, 28,169, 39,168,200, 39,169,243, 62,154,215,113,110,214,192,193, 69, 75, 80, 41, 11, 40, 72, +242, 79,235, 44,117,198, 14,142,138, 84,193, 74,208,181,165,208, 82,164,172, 44,165,214,212,133, 5,182,227,107, 79, 84, 56,149, + 0, 82, 71,108,122,116,213,184, 21,116, 32, 12, 36, 16,175, 92,121, 99,240, 58, 41, 11, 82,192,198, 50,156, 1,158,159,143,207, + 73,144, 8, 32,238, 14, 5,200, 32,131, 98, 8, 32,251,198,227,247, 28,108, 53,141,190,213,107,108,134, 43,180,182,171,204,124, + 41, 19, 35, 60,136, 85, 18,145,128, 11,205,175, 13,186,160, 60,210,164,149, 28,156, 13,108,141,181,197, 54,220, 70, 82,197, 66, +151,116,195,121, 72,202,146,221, 49,185,109,229, 32,244, 75,141, 75, 60,221,199, 95, 93,115,201, 4,164,124, 94,189,207, 82, 7, +168,253,186, 37,176, 66,144, 22, 84,164,142,169, 32,227,161,236, 8,243,244,251,245, 28,174,225,188,174,181,153,164,137,162,103, +235,203,114,160,244,191,151,117, 31,114,140, 91,121, 55,141,220,125,147,211,199, 74,107,169,243, 88,225, 80,170,107, 41,214, 89, + 52,139, 90,242,161,142, 87, 35,177,119,115,110,248,235,133,191,199,206,218,219, 45, 52,170,125,157,118,214,229, 55,146,132,186, +136,148,166,213,201,219,244,179,102,224, 18, 71,250,170, 3, 29,180,196,241, 5,199, 86,232,111,197, 1,251, 8, 50,221,147,182, +143, 56,211,211,237, 58, 60,167,100, 74,185,156,140,226, 94,138,213,215, 87, 83,109,251,229, 61,183,144,219,158,226,195,104,140, +227,141,161,111,151,249, 82,145,162, 3,148,130, 92, 5,192, 20, 20,148,231,148, 55,212,227, 4, 14,186, 61,162, 86,176,146,225, + 80, 56,228,194,113,201,219,161,207,235,116, 56,211,117, 47, 5,112,245, 21, 84,117,201, 69,207,170,132,134, 71,149,218, 77, 12, + 8, 33,149, 73,229,134, 82, 46,173,163, 82,145,169, 72, 32, 28, 53,241, 15,138,188, 97,196,116,243, 82,213, 84,195, 69, 77, 80, + 10,200,180,176, 44, 69,212,245, 83, 35, 25, 38, 10,219,134, 85,145, 85,193, 42,192,169, 32,158,135, 75,235,241, 20,165,243,156, +130,149,228,227,191,234,252,191,175, 69, 53,226, 20,169,146, 9, 42, 80, 87, 50,134, 0, 79, 79,192,118,208,142, 44, 52,130, 84, +175,137, 56,248,146, 49,143, 64,122,117,233,170,145,222, 81, 66, 66, 73,248,178, 73, 87, 82, 79,108, 12,246, 29, 53, 36, 61, 54, + 29, 62, 70, 43, 94,183, 35,123, 91,175,205,241,136,238,148, 54,166, 91, 20,250,139, 88, 47,209,166,170, 59,233, 79,254, 76,255, + 0, 80,172, 99,160,230, 39,240, 58,198,120,103,221, 57,187, 25,196,150,199,238,244, 21,134, 94,176, 55, 62,210,175,186,181, 28, + 15,112,143, 87,142,138,146, 84,113,217, 84,215,101, 39,255, 0,165,167,117,218,108,106,205, 62,177, 68, 90, 2, 93,157, 79,120, +165, 71,245, 68,134, 82, 86,218,243,228,123,254, 61,245,167, 85, 38, 11,109,188,210,135,233,152, 91,140,184,160,122,120,145,212, + 83,145,142,255, 0,171,251,117,187, 66, 18,104,170, 41, 36,251, 18,234, 83,255, 0, 68,162,196,254,253, 93,251,227, 20,149, 82, +101,249,133, 45,100, 91, 73, 4,145,202,189, 62,212,108,174, 63, 16, 49,250,180,211,238,200,245, 37, 67,171,211,156, 15,194,174, + 65,129, 89,167, 45, 4, 20,189, 10,173, 21,153,145,214,133,121,160,178,242,122,249,231,190,180,239,217, 89,188,242,168, 28,101, +113,223,195, 53, 74,165, 21,248,241,110,200, 59,151,105, 48,148, 54,212,150, 99, 85, 66, 25,171, 70, 90,211,133, 72, 8,121,198, +149,215, 37, 35, 61,129,214,138,112,241,237, 18,181,246,247,217, 85,195,199, 23, 55,221,185, 92,188, 87,110,170,222,216,155,158, +135, 70,113,168, 85, 74,133,213, 66,154,237,182,137,209,228,212, 2, 90,247, 81, 18, 12,119,150,178,172, 40, 40,165, 36,172, 99, + 92, 76,225,195,218, 43,112,108,191,180, 68,241,163, 87,137, 53,218, 13,213,121, 85, 13,251,109, 69,117, 79, 59,252, 93,220,210, + 61,214, 85, 57,148,140, 9,179,169,240, 12, 87, 90, 24,253, 35,176,207, 39, 85,140,213, 94,201, 95, 89, 89, 81, 50, 68, 88,229, + 41, 44, 77, 97,114,211,137, 33, 50, 70,130,251,177,141, 24, 11,126,210,130,124,216,234, 92,247,139,178,110, 30,135,135, 86, 26, +240,171,156,212, 69, 53, 68, 96, 18, 70, 89, 60, 14, 18, 89, 46, 45,161,102,104,166, 0, 18,247,167,107, 0, 6,255, 0,166, 5, + 42,103, 57, 65, 82,185, 64, 32,133,247,194,134, 58, 28,253,191,183, 79,189,167, 40,130,133, 15,136,130, 15, 48,207, 92,244,234, + 62,127,191, 90,215,182,213,122, 45,249,108, 90, 55,197,175, 49, 85, 11, 94,248,160,211,110, 91,114,123,145,228,195, 92,170, 77, + 82, 51,114,163, 41,232, 51, 90,109,232,174,134,220, 0,165,196, 37, 67, 29,181,181, 22,173, 32,176,218, 22,172, 0, 58,144, 15, + 48, 35,161,232, 51,211,182,149,165,204, 0,210,250,182, 96, 8, 55,216,131,107, 17,234, 8,177, 7,208,223, 12,252,106,244,209, + 69, 44, 79,229,112, 89, 74,158,160,131,165,148,142,161,131, 2, 8,234, 8, 32,216,139, 99, 84,189,166, 92, 73, 94, 92, 36,240, + 71,190, 60, 72,109,253,170,139,190,243,218,251, 81,202,181, 6,152,247, 63,185,197,151, 53,246,105,136,172, 84, 2, 7, 50,224, + 67, 84,180,200,117, 35, 4,165,140, 2,158,227,242,123,220, 13,193,188,183,102,246,187, 55, 70,255, 0,174,202,185,175,125,193, +184,106,119,117,217, 95,154,225, 92,154,165,106,179, 33, 82,165,200, 61,127, 70,202, 74,130, 26, 64,248, 91,109,180, 33, 32, 37, + 35, 95,176,103, 17, 91, 65, 79,226, 3, 96, 55,155,100,106, 73,104,195,221, 29,180,188, 44,162,167,194, 11, 49,228,215,104,147, + 33, 65,146,176,160, 71, 43, 83, 28, 97,207,145,107, 58,252,126,111,173,183,174,109,101,223,114,237,205,200,243, 14, 87,172,107, +134,183,104, 86, 21, 21,196,191, 31,235, 27,118,163, 34,153, 41,108, 62,142,143, 50,181,199, 42, 74,135,250,248,242,211,205, 11, + 23,205,103,169,168,185,146,170,158, 46, 83,159, 68,102, 90,132, 67,211,202, 69, 43,202,122,183, 50, 37, 98,121,105,106, 87, 55, + 74,198,201,233,231,141, 79,232,234, 57,204, 82, 16, 6,132,158, 85, 50, 83,153, 27,174,169, 99, 74,129, 10, 55,149, 68, 19,180, +118, 47, 41, 56, 67,100,168,171,151,155, 61, 79, 95, 60,122, 15, 61, 35,130,164,243, 43,195,200,232, 85,144,149, 30,190,103,160, +235,163,138, 10, 81,148,161, 61, 1, 57,207,196, 1,237,229,215, 58,179, 73, 73,100, 1, 32,169,109,175, 10,108,133,117, 65, 61, + 64, 35,211,190,164, 33, 71, 78,184,138, 6, 12,221,108,127,211,249, 99,203,205, 18,188,146,148,164, 30,157,114,114, 49,212,122, +121,235,227,237, 45,212, 2, 7, 84,167,184, 57,230,251,255, 0,214,210,105,196,231,225,201, 72, 78,112, 71,161,193,239,249,235, +162,163, 54,227,231, 9,229,102, 56, 25, 86,126, 37, 18, 58,142,158,154, 26, 64,223,165,177,147,211,115,112, 58,252,252,223, 22, +213, 70,117,150,146,176,201, 81, 88,230, 39, 35,152, 1,253, 61,115,159,248,104,168,146,144,231,232,202,255, 0, 85, 56, 40,229, + 0, 30,157, 78,124,245,114, 83, 5, 65, 72, 11,202,122,142,131, 4, 30,196,245,208, 41,136,220, 55, 57,130, 80,160,172,229, 74, + 5, 71, 24, 57,192, 61,188,255, 0, 13,102,195,174, 10, 13,246,245,219,231,231,243,194, 75,106, 66,138,139,202,121, 62, 73, 39, + 41, 64,244,249,235,195,175,165, 29, 16,164,129,215, 3,176, 10,244,237,242, 58, 13,247, 86, 20,162,210,241,205,219, 9,199, 76, +118, 57,252,252,244, 57,121,183, 22, 18,162,114, 8, 46, 36,167,166,122, 30,132,122,147,160, 1, 61,122,224,218,109,176, 59,124, +252,244,193, 73, 62, 42,249,210,160,160, 6, 10, 58, 4,243,117,237,215,174,169,202,116,144,148,163, 9, 35, 41,232,112, 73, 35, + 26,244,226,149,225, 44, 52,218, 83,202, 50, 6,112, 73, 3,166, 20, 60,186,106,200, 38, 56, 22,159, 25, 41, 42, 74,136,229, 35, + 39,237,230, 7, 25, 25,253,154,205,172, 79, 99,140,129,115,240,254,120,124,184,115,189,156,218,173,243,217,253,196,140,226,154, +114,201,221, 29,189,186,157,144, 2, 28, 76,104,148, 91,202,137, 62,170,234,144,226,146, 10, 19, 71,106,164, 78, 72,192,235,229, +214, 89,252, 84, 79,135, 38,165, 91,167, 64,144,125,222, 21, 90, 83,212,194, 9,203,148,103,102,202,149, 75,147, 29,226,231,198, +199,134,165,180, 86,174, 83,250, 48, 82,145,204,117, 12,134, 36, 32, 58, 89,144,219,141, 68,148, 28, 97,215, 25,112,135,124, 41, + 13,150, 30, 13,148,156,182,191, 13,197,224,142,160,224,143, 93, 73,106,193,222, 9,123,221,195,158,213,110, 37, 84, 5,220,177, +173,145, 99,221,170, 9, 90, 82,245,211, 97, 33,139, 66,186,235,106,113, 41, 18, 89,144,221, 38,151, 80,109,206,169,241,170, 79, + 3,133,165, 68,213,126, 32,229,133,243, 12,131, 53, 81,228,136,205, 3,157,175,169,213, 36,139,223,107, 71, 40,244, 5,135, 82, +109,142,146,250, 55,230, 49,199,158,230,217, 92,205,165,166,142, 42,152,199,111,171, 99, 12,173,241,188,212,235,255, 0,117,239, +229,177,215, 10, 45,116,211,119, 43,112,233,170, 37,182,230, 76,183, 43,177, 16, 48, 67,141,212,104,203,167, 84, 84,210, 85,250, +200,247,186, 39, 42,135, 76,169,127, 17,201, 25,126, 41,181,229, 37, 94,246,130,227,139, 83, 98,158,134,210,180,160,134,139,132, +169, 8,228,234, 57,157, 60,196,119, 33,160, 58, 3,173, 54,220,106,162,232,187,147, 64,173, 32,128,221,114,157, 86,182,101,168, + 2,112,236, 98,110, 58, 71, 42, 0,200, 82,156,139, 85,108,168, 12, 37, 47, 14, 99,215, 89,237, 42,241,122, 42, 89,121,149,120, +143, 68,240,228, 71, 67,193, 97, 42,112, 20,248,104, 82,146, 14, 81,149, 36, 43, 61,130,149,202, 79, 77, 54,154, 98,201, 79, 48, + 93,157, 23,215,245, 64,140,254,242,183,247, 3,113,214,216,234,185,107, 85, 90,190,153,200,103,134, 73, 8,185,181,196,141,207, + 0,122,217, 95, 77,199,166, 54, 18,161, 94,151, 79,143,238,201, 90,156, 74, 11,144,195, 67, 45,167,222,100,242,185, 41,107, 79, + 47, 68,161,128,211, 94, 17, 4,143,139,237,214, 33, 94,188,163, 65,166, 48,194, 95, 91,117, 54,202,144,132, 54,165,128,183, 95, +199,188,184,162,159,133, 33, 12,114, 39, 3,184,113, 99, 62, 90,108,110,125,200,155, 57,192,243,237, 54,135, 98, 37, 65,105,104, +184, 83, 38, 67,170, 74,157,117,106, 82, 65,231, 43, 42, 36,158,164, 28,103,182,152, 91,179,113, 22,203, 82, 31,144,227,141,177, + 29,133, 60,243,188,138,117,126, 27,202,229, 79,134,132,140,173,213,186,224, 64,230, 35, 28,249, 82,146,156,168,109, 83, 80,180, +133, 70,155,131,247,250, 91,173,253,215,233,123,143,190, 31,153,230, 40,116,234, 94, 76,155, 11, 13,199,112,250,136, 0, 48,181, +193, 30,164,142,215, 14, 21,209,121,205, 91,172,198,128, 37,214, 37,203,151, 18,147, 71,162, 69, 74,158,159, 91,173, 84, 31, 76, + 74, 61, 38, 10, 82, 57,149, 46, 76,199,210,132, 36,116, 79,141,204,122, 13, 72,111,103,182,153,253,140,217, 59, 59,105,234,166, + 43,245,214, 40,146,102,238, 75,165,136,243,169,213, 75,230,241,120, 86, 47, 54, 36,211,230,178,227, 21, 26, 75, 53, 55, 26,167, + 24,207,180,236,119, 35,210, 16, 22,218,146,117, 21, 91, 99,137, 58,134,192,111, 54,211,110, 76,122, 84, 42,181,197,100,221,246, +174,224,205,167, 84,216, 19,169,212,123, 66, 37, 89, 42,151, 77, 97,181, 39,195,159,114, 79,128,212,245,169,240, 22,212,111,116, +105, 13,225, 69, 58,152,173,218,236, 42,179,108, 87,233, 14,186,253, 46,181, 6,157,112, 82, 30,120, 56,211,238,209,110, 10,124, +106,204, 5, 62,219,128, 41, 18, 61,194,107, 60,193, 64, 44, 45, 4, 30,186,117,106,119,163, 48,188,177,253, 92,232,116, 31,218, +177, 26,182, 29, 0, 5,108,118, 44, 24,145,181,142, 35,114,231,116, 85,239,152,101,148,181,162, 92,195, 43,146, 35, 87, 18,135, +188, 13, 42, 22,128, 23, 42, 35, 98, 66,200, 24, 35, 57,137,208,164,161, 30,202,120, 41,197,183,177,147, 96, 55,194,117, 82,245, +225,250,163, 11,134,125,197,158,169, 14,206,182,216,166, 75,169,236, 93,114,190,156,248,141,189,108,196, 90,166,237,169,121,196, +181,250,106, 40,147, 79, 30, 49,116, 81,219, 78,117, 26, 30, 33,248, 90,223,142, 22,238, 53, 90,251,235,183, 21, 75, 77,169,146, +228, 66,162, 92,232, 13, 87,118,250,239,240, 22,241, 75,150,189,233, 78, 11,167,214, 10,153, 99,198, 17,203,141,204,109,181,161, + 79, 69,104,144, 53, 62, 58,210, 27,142,235,239, 21,135, 25, 12,160, 78,108, 32,130, 2, 20,150,218,156,215,108, 60,148,173, 41, + 88, 7, 42, 65, 24, 28,201, 25,193,174,203,122,131,116,219,213,139,110,241,182,232, 55,173,161,112, 70, 84, 43,170,207,186,169, + 84,234,253,183,113,211,152,109, 97, 46, 84,104,245, 86, 28,142,237, 70, 59, 5,226,196,128,132,200, 66, 22,182,154,125,146, 80, +180,201,178,222, 38,170,167,211, 29, 71,246,200, 86,223,104,218, 69, 29, 1, 87,177,189,186,233, 96,214, 30, 85, 40, 0, 56,170, +184,143,195,156,143, 60, 18, 84, 69, 23,232,156,193,247, 18,194,160, 70,237,183,247,176,221, 84,146, 79,219, 83, 27,110, 29,203, +146,109, 13, 30, 23, 61,163, 28,100,240,219, 38,149,107,237,182,228, 73,189,236,148, 58,150,218,218, 61,216, 67,151,221,136,166, +144,210, 25,240, 41, 6,169, 45, 53, 11, 53, 66, 58, 57, 80,186, 76,248, 97,190, 98,160,218,142,164,109,178,158,214,237,167,175, + 65,161,127, 41,109,181,191,248, 74,174, 85,212,196, 72,247,141,118,159, 86,189,184,118,184, 38, 56,243,200, 67, 20,205,205,163, + 65, 92,187,103,244,108,243,134, 42,113, 37,120, 42,121, 41,114,160, 80, 84,117,167,220, 73,251, 19,182,242,247,150,245,217,194, + 29,220,173,162,186,165, 45,185,180,237,176,187,166,214,235, 27,115, 85,154,242,203,141, 53,105,221,169,247,138,213,131, 33,111, + 58, 60, 24,243, 19, 85,132,218, 80, 19,227,198, 71,195,173, 7,218,190, 57,120,161,246,121,238,117,107,135, 46, 42, 54,246,212, +222,125,182, 66,215, 76,220,221,149,190,133,155,115,191, 81,182,165,170, 84, 41, 82,173,155,198,146,212,216, 50,159,240,155,121, +200,241,235, 44, 76, 97,206, 80,135,152,140,178,151, 90,121,170,146, 44,222, 17, 46, 79, 77, 21,101, 90,144,210, 68,210, 26, 90, +141, 23, 26,157, 24, 36,177, 72,226,224,221,193, 66, 60,166,100, 39,106,230,105,184,247,129,158, 20,172,144,102, 25, 56, 96,130, + 73, 11, 77, 13,172, 72, 85,114, 4,208,176, 63,238,220,198, 0, 12,193, 90,219,205,107,111, 55, 22,222,185,109,106, 77,203,105, + 92,212, 27,170,209,172,183,227,209, 46,123, 90,179, 79,185, 45,186,219, 47,160, 44, 55, 78,175, 80,230, 63, 25,215,130, 20, 20, +227, 72,116,188,206, 64,121,180, 19,141,103,175, 87,204,134,148,133, 47,152,148,124, 42, 90,135, 81,202, 0, 79, 42,142, 57,128, +233,159,246, 64, 39, 57, 58,138, 47, 16, 27, 71,120,112, 95, 98,211, 61,164, 94,203, 13,207,174,217,124, 50,238, 29,187,102,110, + 70,229,240,243,119,189, 42, 85,155, 77,162,222,245, 72, 16, 41,117, 22,108,155,169,231, 90,184,109, 7,235, 46,162,151, 58,152, +243,203,175,208,101,130,245, 6,171, 58,144, 89,145, 18, 68,155, 3,127,214,247,155, 98,118,115,120,231, 91,109, 90,114,247, 99, +108,236,173,194,145,108,177, 83, 77, 90, 45,188,253,219, 67,139, 87,122,147, 14,164,243,190, 44,248, 45,185, 37, 98, 59,143,101, +242,194,155, 18, 15,188, 7, 73,143,214,196, 35,167,138,170, 9,185,212,211, 51, 37,153,116, 75, 28,128, 41, 49, 75, 29,205,152, + 95,170,150, 83,177,218,235,123, 43,134,115,213,207,218, 72,189,141,233,170,169,213, 93,148,221,209,145,142,149,120,220, 40,189, +200,177, 4, 41, 27, 0, 8,185,198,215,109,149, 22, 37,219,112, 75,167, 73,165, 92, 21,191,118,183,110, 26,195, 20,107, 85,228, + 68,174, 84,165, 82,105,206,202, 98, 44, 87, 92,162,212, 48,165, 45,180,169,192,152,142,168,161, 4, 36, 36,229, 99, 64, 56,226, +223, 77,219,218,203, 74,243,176,184,111,131,100,212,184,131,106,210,106,188,182,174,237,198,176,104,236,108,117, 26,191,107,238, + 45,231, 67,159,114, 83,238, 42,188, 53,220, 59,203, 46,201,218,125,206,169,219, 54,146, 99,166,100,164,216,146,234, 18,227,161, + 2,157, 2,167,204, 14, 62, 61,170,123,199,195,134,245,239, 23, 13,187,105,102,194,182,165, 83,246,238,171,105, 84,183, 81, 53, +244,170,245,137, 87,220,107, 45,183,233,117,187, 54, 41,166, 73,133, 64,143, 76,250,217,135,130,156, 67,211,229, 61, 20,165, 50, + 32,160,164,235,150,155,127,199,229, 2,218,166,220, 17, 47,141,155,184,239,201,213, 27, 39,106,105,180,122,212,125,229,250,134, +170,214,227,109, 78,199,111,230,200, 68,190,174,249,149,109,181,172,187,121, 82,106, 16, 56,129,184, 42,147, 41, 97,218,124,229, + 79,183,224, 36,215,213, 28,203,110, 70,206, 69,195,144, 85, 69, 5, 70, 98,154,105,203, 23, 84, 82, 9,145, 88, 2,188,203, 43, + 29, 22,223, 64,107,155,217,130, 11,134,211,227, 63, 18,206, 91, 83, 89,150,100, 83,153,115, 5, 2, 9,166,100,112, 41,101, 77, + 75, 50,195,172,141, 83, 43,150, 83, 39, 47, 66,149,186, 60,183, 82,141,110,225,240, 39,196,221,155, 81,191,231,222,141, 89,213, + 55,237, 88,247,245,205,127,221,171,222,173,181,185, 61,226,240,182,175, 86,237, 91,186,211,159, 89, 98,236,113,202,246,245, 75, +190,106,209,152,110,218,100, 61,112, 84, 36,212, 28, 91, 16, 22,220,105,170,139,127,159,236,242,222,186, 77, 26,239,166, 87,232, +112,233,215,213,183,115, 90,106,118,188, 55, 27,106, 92,217,154, 61,128,237, 3,137,199,119, 10,177,114,223, 77,221,139, 75, 53, +122, 53,223,195, 53,253, 73,112, 71,241, 98,181, 54,200,172, 83,221,113,115,223,163, 51, 57,230,147,199, 5,183,187,182,199, 20, +139,188,118,233,203, 98,159, 84,186,183,115,137, 91, 34, 52, 27,238, 84,170,188, 61,236,220, 94, 32, 44,203,171,108, 40,237, 75, +107,110, 95,141, 88,160, 80,145, 95,186, 77, 97,137,205, 83, 25,174,211,162,188, 99, 84, 40,149, 52, 64,143, 46,157, 75,218, 83, +101, 77,186,105, 19,162,236, 45,249,108,218, 84, 43,254,198,220, 58,109, 34,211,226, 14,155, 2,237, 19,173,203,215,141, 77,199, +186,173,217,247,125, 99, 98,170, 16,170,182,125,110,232,227, 78,236,167,187, 2, 77, 5,212,166,211,181,219,161, 84, 87, 88,151, + 81,153, 91, 22, 42,173, 58,216, 2, 66,109,243,176,249,247,227,159,188,172,197,153,181, 23,220,146, 73, 36,158,189,183, 55,238, +119,191, 83,134, 79,133, 94, 26, 54,163,119, 40, 23,245, 15,114,220,191,142,226,213, 56,139,225,227,133,189,165,172,237,181,249, + 97,155, 30,221,191,119,242,131,196, 96,167, 93,151,172, 39,236,250,202, 55, 62,208,102,241,218,107, 53,128,138, 37,126,130,149, + 83,107, 53, 9,204, 84,230, 17, 17,189, 55,212,190, 3,248,146,172,211,160,212,169,214,189,181, 33,186,142,219,211,247, 54, 44, + 95,227, 14,196,106,162,186,125, 98,181,178,180, 58, 45,166,105,207, 92, 9,120,110,100,217, 28, 70,108,107,177,109,190, 79,173, +221, 99,115, 41,203, 76, 94, 97, 37, 17,242,109,137,226,246,211,217,104,251,163, 81,127,101, 62,187,186,171,187,235,180,188, 70, +108,210,237,235,249, 22, 93,137,180,219,153,179, 84,221,245,137,101, 55, 93,179, 23, 99,212,230,110, 13,155, 14,126,244, 71,153, + 30,155, 22,183,110, 58,135, 44,136,172,191, 58, 84,105, 79,178,151,218, 87,181, 90,244, 52,109,183, 49,108, 26,164,171,191,110, + 45, 11, 30,153, 2,181,115,110, 83,149,219, 97,171,198,196,221, 46, 9,183, 14, 21,126,223,177, 98,217, 80,152,183,109,137, 17, +184, 39,182,216,149, 73,247,169,115, 94,157,126,212, 38,174,188,170,109, 62,145, 66,136,100, 17, 21, 93, 71,204, 47,211,227,220, +219,115,111,195,225,108, 1,107, 11,252,252,239,134,106, 63,179,199,115,133,155,125,215,171,187,135,179,118,237,197,106,110,150, +201,109,205, 10,223,153,185,246, 52,250, 21,249, 15,122,172, 61,215,189,169, 23, 85,173,123,210,110, 87,226, 85,161,161,221,180, + 69, 50, 35, 16,154,153,245,133, 70,101, 86, 39,143, 18,101,191, 50, 43,173, 61,131,193, 94,250,238,142,241,110, 54,200, 89,144, +172,105,247,150,215, 94, 63,197,253,209, 54,126,230, 88,150,253,156,245,230,245,238,157,187,165, 91,118,205,231,112, 87,162,211, +175, 26,213, 74,234, 15,179, 73,139, 75,126, 92,138,179, 48,164, 75,167,183, 38, 43, 46, 58,157,172,107,218, 71,106,187,184,205, + 93,151, 6,202,110, 37,197,110,209,175, 29,134,190,172,246, 39,241, 13, 5,253,203,160, 93, 60, 62,109,135, 18,118,213,139,112, + 73,220, 10,142,200, 73,165, 84,170,177,119, 63,136, 8, 23, 60, 70,218,180,225,210,217,143,182,241, 40,114,169,117, 3, 80,155, + 86, 12, 7, 9,252, 89,216,124, 52,223,247, 21,199, 92,217,203,159,115,109, 71,183, 27,106,119, 94,200,183,218,221,216, 86, 93, +205,110,222, 91, 37,184,134,249,219,247, 46, 91,196,109, 93, 86, 53,227, 71, 49,101, 84,161,213,227,179, 69,164, 59, 61,217, 13, + 76,139, 38,154,150, 85, 17,245,109, 21,212, 94,194,230,253,122,118,237,252, 63,118, 51,229,219,231,249, 97,202,188, 61,155,155, +199,118,239,117,185,183,155, 45,111,219, 48,169,151,253,165,181,247, 29,144,197,255, 0,186, 86, 69,154,185,177,175,167, 54,191, +110,233, 53, 41,149, 43,218,189, 9,184,108,215,247,190,249,155, 69,160, 50,234,210,253, 65,250, 53, 77,200,172, 42,159, 74,151, + 45,166,227,134, 30, 29,118,127,120,246,186,191, 46,244, 59,148,198,229, 93, 91,162,198,209,109, 69, 98,214,187, 45,122, 85,145, +109,220,147, 54,155,112,111,218, 69, 66,255, 0,180,170,251,125, 80,157,121, 82,101,220,150,181, 18,154,240,167,215,104, 46, 83, +162, 85, 36,212, 19,245,147,172, 55, 5,237,158,182,189,170,118,111,241,175,183,251,177,186, 92, 50,213, 47,138,213,133, 67,216, + 27,113, 74,181,183,186, 14,223, 84,174,122, 47, 11,119,174,202,223, 59, 29, 14,226,170,191,178,245,148,204,114,158,230,219,222, + 52, 89,210, 61,212, 74,157,109,221,244, 74,100,119,233,207,218,140,207,171,105,175, 15, 60, 86,219, 59, 19,183, 23, 37,185, 55, +107, 42,215,157,246,197,244,141,202,218,155,189,189,196,135,110,218,246, 85,232,222,219,222,187,117, 26,163,120, 88,142,109,229, + 70, 70,225, 69,136,139,192, 85, 33, 71,143, 94,160, 33, 53, 10, 36,116,205, 53, 8, 43,126, 27,135, 2, 45, 74,111,229,107,222, +224,251,173,219,227,235,252,241,159, 47, 99,243,255, 0,140,109,229,209,192, 61,139, 67,254, 54, 13, 55,134, 30, 56,238,159,226, +247,134,189,165,221,155, 88, 82,239, 26, 58,127,141, 58,134,224, 29,184,254, 17,110,133,181,238,252, 37, 74,228,217,202, 39,240, +190,165,239, 17, 99,253,100,191,208, 49,227,221, 17,185, 92,241,117, 46,135,178,187, 35, 81, 28, 31,213, 31,183,183,186,171, 31, +122,172,157,204, 93,241,102,218,215,157,151, 58,233,188,119, 54,204,184,111, 91, 90,206,160,237,157, 94,102,218, 53, 31,110,232, + 55, 5,201, 73,181, 97, 62,229, 82, 21,212,253, 17,170,156,202,136, 53,143, 5,170,122,233,238,255, 0, 21,182, 21,251, 73,221, + 38,109, 61,163,187,173, 42,230,243,109,206,204,217,215,189, 66,226,221,186, 53,235, 74,102,187,180, 15, 88,202,106,225,181, 40, +212,205,160,161, 61, 71,164,207,141,102,114, 42,155, 50,125, 77,232,203,169,120,130,166,250, 89,240,157,111,237,173,252,177, 83, + 70,217,139, 67,114,246,121,205,192,178,182,194,199,221,235, 38,179, 78,133,124, 51,107,215,171,138,221, 10,189,205, 93,167, 93, + 54,173,114, 93,149, 85,143,101, 93, 20, 42,173,118, 11,240,157,147, 78,174, 70,121,218, 70, 95,139,225,190, 91,109, 66, 82,230, +223, 59,143,119,166, 50, 8,184, 3,231,127,135,166, 49, 78, 42,118,162,139,177,156, 68,238,246,208, 80, 63,132, 77, 83,182,246, +242,168, 91, 74,166, 93,239, 65,153,117,219,117, 40, 41,100, 86,172,219,150,169, 75,166,194,137, 94,175, 81, 43, 42,159, 72,151, + 83,133, 10, 28, 42,156,138, 35,149, 8, 81, 34,197,146,211, 13,173, 88,184,129,221,147,190, 91,193,122,238,130, 40, 10,181,162, + 92,146,233,172,210,109,231,107, 47, 92,147, 40,244, 11,118,135, 75,181,237,216, 53, 75,142, 68, 40,170,184,107, 72,161, 81,105, +222,253, 60, 68,134,137,147, 11,242, 90,133, 13,183, 81, 21,165,172, 21, 55, 58, 70,221,186,116,193,180,169,223,215, 31,255,217, +}; + diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index 5d24b93418b..993cbceae18 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -40,8 +40,8 @@ extern char datatoc_blenderbuttons[]; extern int datatoc_prvicons_size; extern char datatoc_prvicons[]; -extern int datatoc_splash_jpg_size; -extern char datatoc_splash_jpg[]; +extern int datatoc_splash_png_size; +extern char datatoc_splash_png[]; extern int datatoc_Bfont_size; extern char datatoc_Bfont[]; -- cgit v1.2.3 From be613fd9ddf02aca2d619b6aaa615fff5a02661b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 16 Sep 2009 00:59:55 +0000 Subject: OSX should use libsndfile in /lib, not /usr --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7196049f964..c881dec03db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,7 +409,7 @@ IF(APPLE) ENDIF(WITH_JACK) IF(WITH_SNDFILE) - SET(SNDFILE /usr) + SET(SNDFILE ${LIBDIR}/sndfile) SET(SNDFILE_INC ${SNDFILE}/include) SET(SNDFILE_LIB sndfile) SET(SNDFILE_LIBPATH ${SNDFILE}/lib) -- cgit v1.2.3 From 51f1e822900fbae5b239ddfcfd488eccbbbcc31b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Sep 2009 01:15:30 +0000 Subject: Object mode Selection options brought back for view3d.select - 'center', while Ctrl is held select objects from their center location - 'enumerate', while Alt is held, give a list of objects under the mouse - Object selection menu now uses icons with names - operator object.select_name(name, extend=False) - keybindings so combinations of Ctrl/Alt/Shift can be used (like in 2.4x) - logic text input field was using deprecated ID_SCRIPT rather then ID_TXT details - added comments to DNA_ID.h ID types - removed unused ID types Sector and Life - added uiIconFromID() to get an icon from the object. - using name for selection is weak but currently there isnt a really good way to do this. --- source/blender/blenloader/intern/readblenentry.c | 2 - source/blender/editors/include/UI_interface.h | 2 + source/blender/editors/interface/interface_utils.c | 59 +++++++++ source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + source/blender/editors/object/object_select.c | 53 ++++++++ source/blender/editors/space_logic/logic_window.c | 2 +- source/blender/editors/space_view3d/view3d_ops.c | 20 ++- .../blender/editors/space_view3d/view3d_select.c | 140 +++++++++++++-------- source/blender/makesdna/DNA_ID.h | 65 +++++----- 10 files changed, 255 insertions(+), 90 deletions(-) diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 9cd45a268da..3d21bb54e2b 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -99,7 +99,6 @@ static IDType idtypes[]= { { ID_IP, "Ipo", IDTYPE_FLAGS_ISLINKABLE}, { ID_KE, "Key", 0}, { ID_LA, "Lamp", IDTYPE_FLAGS_ISLINKABLE}, - { ID_LF, "Life", 0}, { ID_LI, "Library", 0}, { ID_LT, "Lattice", IDTYPE_FLAGS_ISLINKABLE}, { ID_MA, "Material", IDTYPE_FLAGS_ISLINKABLE}, @@ -110,7 +109,6 @@ static IDType idtypes[]= { { ID_SCE, "Scene", IDTYPE_FLAGS_ISLINKABLE}, { ID_SCR, "Screen", 0}, { ID_SEQ, "Sequence", 0}, - { ID_SE, "Sector", 0}, { ID_SO, "Sound", IDTYPE_FLAGS_ISLINKABLE}, { ID_TE, "Texture", IDTYPE_FLAGS_ISLINKABLE}, { ID_TXT, "Text", IDTYPE_FLAGS_ISLINKABLE}, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 921aa60f9b2..77c4e4d3475 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -420,6 +420,8 @@ uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int short x1, short y1, short x2, short y2, void *idpp, char *tip); int uiDefIDPoinButs(uiBlock *block, struct Main *main, struct ID *parid, struct ID *id, int id_code, short *pin_p, int x, int y, uiIDPoinFunc func, int events); +int uiIconFromID(struct ID *id); + uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip); uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip); uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 63f81c9e46c..539c71cc497 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -33,6 +33,7 @@ #include "DNA_color_types.h" #include "DNA_listBase.h" #include "DNA_material_types.h" +#include "DNA_lamp_types.h"" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_texture_types.h" @@ -509,6 +510,64 @@ int uiDefIDPoinButs(uiBlock *block, Main *bmain, ID *parid, ID *id, int id_code, return x; } +/* currently only object-data types */ +int uiIconFromID(ID *id) +{ + if (id==NULL) + return 0; + + switch(GS(id->name)) { + case ID_OB: + { + Object *ob= (Object *)id; + + switch(ob->type) { + case OB_EMPTY: + return ICON_EMPTY_DATA; + case OB_CURVE: + return ICON_CURVE_DATA; + case OB_SURF: + return ICON_SURFACE_DATA; + case OB_FONT: + return ICON_FONT_DATA; + } + + return uiIconFromID(ob->data); + } + case ID_ME: + return ICON_MESH_DATA; + case ID_AR: + return ICON_ARMATURE_DATA; + case ID_MB: + return ICON_META_DATA; + case ID_CA: + return ICON_CAMERA_DATA; + case ID_LT: + return ICON_LATTICE_DATA; + case ID_CU: + return ICON_CURVE_DATA; + case ID_LA: + { + Lamp *la= (Lamp *)id; + switch(la->type) { + case LA_LOCAL: + return ICON_LAMP_POINT; + case LA_SUN: + return ICON_LAMP_SUN; + case LA_SPOT: + return ICON_LAMP_SPOT; + case LA_HEMI: + return ICON_LAMP_HEMI; + case LA_AREA: + return ICON_LAMP_AREA; + } + return ICON_LAMP_DATA; + } + } + + return 0; +} + /* ****************************** default button callbacks ******************* */ /* ************ LEGACY WARNING, only to get things work with 2.48 code! ****** */ diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 7d52e9c7c56..315b6632051 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -79,6 +79,7 @@ void OBJECT_OT_select_by_layer(struct wmOperatorType *ot); void OBJECT_OT_select_linked(struct wmOperatorType *ot); void OBJECT_OT_select_grouped(struct wmOperatorType *ot); void OBJECT_OT_select_mirror(struct wmOperatorType *ot); +void OBJECT_OT_select_name(struct wmOperatorType *ot); /* object_add.c */ void OBJECT_OT_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 6ee43765475..dce09d47b2c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -102,6 +102,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_select_linked); WM_operatortype_append(OBJECT_OT_select_grouped); WM_operatortype_append(OBJECT_OT_select_mirror); + WM_operatortype_append(OBJECT_OT_select_name); /* XXX - weak, not compat with linked objects */ WM_operatortype_append(GROUP_OT_group_create); WM_operatortype_append(GROUP_OT_objects_remove); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 50ba4ab2934..cfd65ad18ec 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -923,6 +923,59 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); } + +static int object_select_name_exec(bContext *C, wmOperator *op) +{ + char *name= RNA_string_get_alloc(op->ptr, "name", NULL, 0); + short extend= RNA_boolean_get(op->ptr, "extend"); + short changed = 0; + + if(!extend) { + CTX_DATA_BEGIN(C, Base*, base, visible_bases) { + ED_base_object_select(base, BA_DESELECT); + } + CTX_DATA_END; + } + + CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { + if(strcmp(name, base->object->id.name+2)==0) { + ED_base_object_select(base, BA_SELECT); + changed= 1; + } + } + CTX_DATA_END; + + MEM_freeN(name); + + /* undo? */ + if(changed) { + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_select_name(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Select Name"; + ot->description = "Select an object with this name"; + ot->idname= "OBJECT_OT_select_name"; + + /* api callbacks */ + ot->exec= object_select_name_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_string(ot->srna, "name", "", 0, "Name", "Object name to select."); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first."); +} + /**************************** Select Random ****************************/ static int object_select_random_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 3040d73bda9..4afa56582a2 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1534,7 +1534,7 @@ static short draw_controllerbuttons(bController *cont, uiBlock *block, short xco uiBlockBeginAlign(block); uiDefButI(block, MENU, B_REDR, "Execution Method%t|Script%x0|Module%x1", xco+4,yco-23, 66, 19, &pc->mode, 0, 0, 0, 0, "Python script type (textblock or module - faster)"); if(pc->mode==0) - uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "", xco+70,yco-23,width-74, 19, &pc->text, "Blender textblock to run as a script"); + uiDefIDPoinBut(block, test_scriptpoin_but, ID_TXT, 1, "", xco+70,yco-23,width-74, 19, &pc->text, "Blender textblock to run as a script"); else { uiDefBut(block, TEX, 1, "", xco+70,yco-23,(width-70)-25, 19, pc->module, 0, 63, 0, 0, "Module name and function to run e.g. \"someModule.main\". Internal texts and external python files can be used"); uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-23, 19, 19, &pc->flag, 0, 0, 0, 0, "Continuously reload the module from disk for editing external modules without restarting"); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 7da2e591b10..e179809adc9 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -201,7 +201,25 @@ void view3d_keymap(wmWindowManager *wm) /* selection*/ WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE); + RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "center", TRUE); + RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "enumerate", TRUE); + + /* selection key-combinations */ + km = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0); + RNA_boolean_set(km->ptr, "center", TRUE); + RNA_boolean_set(km->ptr, "extend", TRUE); + km = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT, 0); + RNA_boolean_set(km->ptr, "center", TRUE); + RNA_boolean_set(km->ptr, "enumerate", TRUE); + km = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_ALT, 0); + RNA_boolean_set(km->ptr, "extend", TRUE); + RNA_boolean_set(km->ptr, "enumerate", TRUE); + km = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL|KM_ALT, 0); + RNA_boolean_set(km->ptr, "center", TRUE); + RNA_boolean_set(km->ptr, "extend", TRUE); + RNA_boolean_set(km->ptr, "enumerate", TRUE); + WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT|KM_CTRL, 0)->ptr, "deselect", 1); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index a7696d9fe31..c639b445f9e 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -53,6 +53,7 @@ #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_rand.h" +#include "BLI_linklist.h" #include "BKE_action.h" #include "BKE_context.h" @@ -845,56 +846,87 @@ static void deselectall_except(Scene *scene, Base *b) /* deselect all except b } } -static Base *mouse_select_menu(ViewContext *vc, unsigned int *buffer, int hits, short *mval) +static Base *mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, short *mval, short extend) { - Scene *scene= vc->scene; - View3D *v3d= vc->v3d; - Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */ - Base *base; short baseCount = 0; - char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t"; /* max ob name = 22 */ - char str[32]; - - for(base=FIRSTBASE; base; base= base->next) { - if (BASE_SELECTABLE(v3d, base)) { - baseList[baseCount] = NULL; - - /* two selection methods, the CTRL select uses max dist of 15 */ - if(buffer) { - int a; - for(a=0; aselcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base; - } - } - else { - int temp, dist=15; - - project_short(vc->ar, base->object->obmat[3], &base->sx); - - temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]); - if(tempselcol==buffer[ (4 * a) + 3 ]) + ok= TRUE; } + } + else { + int temp, dist=15; + + project_short(vc->ar, base->object->obmat[3], &base->sx); - if(baseList[baseCount]) { - if (baseCount < SEL_MENU_SIZE) { - baseList[baseCount] = base; - sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1); /* max ob name == 22 */ - strcat(menuText, str); - baseCount++; - } - } + temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]); + if(temp < dist) + ok= TRUE; + } + + if(ok) { + baseCount++; + BLI_linklist_prepend(&linklist, base); + + if (baseCount==SEL_MENU_SIZE) + break; } } + CTX_DATA_END; + + if(baseCount) + - if(baseCount<=1) return baseList[0]; + if(baseCount==0) { + return NULL; + } + if(baseCount == 1) { + Base *base= (Base *)linklist->link; + BLI_linklist_free(linklist, NULL); + return base; + } else { - baseCount = -1; // XXX = pupmenu(menuText); - - if (baseCount != -1) { /* If nothing is selected then dont do anything */ - return baseList[baseCount-1]; + /* UI */ + uiPopupMenu *pup= uiPupMenuBegin(C, "Select Object", 0); + uiLayout *layout= uiPupMenuLayout(pup); + uiLayout *split= uiLayoutSplit(layout, 0); + uiLayout *column= uiLayoutColumn(split, 0); + LinkNode *node; + + node= linklist; + while(node) { + Base *base=node->link; + Object *ob= base->object; + char *name= ob->id.name+2; + /* annoying!, since we need to set 2 props cant use this. */ + /* uiItemStringO(column, name, 0, "OBJECT_OT_select_name", "name", name); */ + + { + PointerRNA ptr; + + WM_operator_properties_create(&ptr, "OBJECT_OT_select_name"); + RNA_string_set(&ptr, "name", name); + RNA_boolean_set(&ptr, "extend", extend); + uiItemFullO(column, name, uiIconFromID((ID *)ob), "OBJECT_OT_select_name", ptr.data, WM_OP_EXEC_DEFAULT, 0); + } + + node= node->next; } - else return NULL; + + uiPupMenuEnd(C, pup); + + BLI_linklist_free(linklist, NULL); + return NULL; } } @@ -958,14 +990,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff /* mval is region coords */ -static void mouse_select(bContext *C, short *mval, short extend, short obcenter) +static void mouse_select(bContext *C, short *mval, short extend, short obcenter, short enumerate) { ViewContext vc; ARegion *ar= CTX_wm_region(C); View3D *v3d= CTX_wm_view3d(C); Scene *scene= CTX_data_scene(C); Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL; - unsigned int buffer[4*MAXPICKBUF]; int temp, a, dist=100; short hits; @@ -981,10 +1012,9 @@ static void mouse_select(bContext *C, short *mval, short extend, short obcenter) if(vc.obedit==NULL && obcenter) { /* note; shift+alt goes to group-flush-selecting */ - /* XXX solve */ - if(0) - basact= mouse_select_menu(&vc, NULL, 0, mval); - else { + if(enumerate) { + basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend); + } else { base= startbase; while(base) { if (BASE_SELECTABLE(v3d, base)) { @@ -1006,6 +1036,8 @@ static void mouse_select(bContext *C, short *mval, short extend, short obcenter) } } else { + unsigned int buffer[4*MAXPICKBUF]; + /* if objects have posemode set, the bones are in the same selection buffer */ hits= mixed_bones_object_selectbuffer(&vc, buffer, mval); @@ -1016,9 +1048,9 @@ static void mouse_select(bContext *C, short *mval, short extend, short obcenter) for(a=0; aptr, "extend"); + short center= RNA_boolean_get(op->ptr, "center"); + short enumerate= RNA_boolean_get(op->ptr, "enumerate"); view3d_operator_needs_opengl(C); @@ -1590,7 +1624,7 @@ static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event) else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) PE_mouse_particles(C, event->mval, extend); else - mouse_select(C, event->mval, extend, 0); + mouse_select(C, event->mval, extend, center, enumerate); /* allowing tweaks */ return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED; @@ -1611,7 +1645,9 @@ void VIEW3D_OT_select(wmOperatorType *ot) ot->flag= OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first."); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first."); + RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only)."); + RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)."); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 9e5212e159f..0c38421a3f5 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -155,40 +155,37 @@ typedef struct PreviewImage { #endif /* ID from database */ -#define ID_SCE MAKE_ID2('S', 'C') -#define ID_LI MAKE_ID2('L', 'I') -#define ID_OB MAKE_ID2('O', 'B') -#define ID_ME MAKE_ID2('M', 'E') -#define ID_CU MAKE_ID2('C', 'U') -#define ID_MB MAKE_ID2('M', 'B') -#define ID_MA MAKE_ID2('M', 'A') -#define ID_TE MAKE_ID2('T', 'E') -#define ID_IM MAKE_ID2('I', 'M') -#define ID_IK MAKE_ID2('I', 'K') -#define ID_WV MAKE_ID2('W', 'V') -#define ID_LT MAKE_ID2('L', 'T') -#define ID_SE MAKE_ID2('S', 'E') -#define ID_LF MAKE_ID2('L', 'F') -#define ID_LA MAKE_ID2('L', 'A') -#define ID_CA MAKE_ID2('C', 'A') -#define ID_IP MAKE_ID2('I', 'P') -#define ID_KE MAKE_ID2('K', 'E') -#define ID_WO MAKE_ID2('W', 'O') -#define ID_SCR MAKE_ID2('S', 'R') -#define ID_SCRN MAKE_ID2('S', 'N') -#define ID_VF MAKE_ID2('V', 'F') -#define ID_TXT MAKE_ID2('T', 'X') -#define ID_SO MAKE_ID2('S', 'O') -#define ID_GR MAKE_ID2('G', 'R') -#define ID_ID MAKE_ID2('I', 'D') -#define ID_AR MAKE_ID2('A', 'R') -#define ID_AC MAKE_ID2('A', 'C') -#define ID_SCRIPT MAKE_ID2('P', 'Y') -#define ID_NT MAKE_ID2('N', 'T') -#define ID_BR MAKE_ID2('B', 'R') -#define ID_PA MAKE_ID2('P', 'A') -#define ID_GD MAKE_ID2('G', 'D') -#define ID_WM MAKE_ID2('W', 'M') +#define ID_SCE MAKE_ID2('S', 'C') /* Scene */ +#define ID_LI MAKE_ID2('L', 'I') /* Library */ +#define ID_OB MAKE_ID2('O', 'B') /* Object */ +#define ID_ME MAKE_ID2('M', 'E') /* Mesh */ +#define ID_CU MAKE_ID2('C', 'U') /* Curve */ +#define ID_MB MAKE_ID2('M', 'B') /* MetaBall */ +#define ID_MA MAKE_ID2('M', 'A') /* Material */ +#define ID_TE MAKE_ID2('T', 'E') /* Texture */ +#define ID_IM MAKE_ID2('I', 'M') /* Image */ +#define ID_WV MAKE_ID2('W', 'V') /* Wave (unused) */ +#define ID_LT MAKE_ID2('L', 'T') /* Lattice */ +#define ID_LA MAKE_ID2('L', 'A') /* Lamp */ +#define ID_CA MAKE_ID2('C', 'A') /* Camera */ +#define ID_IP MAKE_ID2('I', 'P') /* Ipo (depreciated, replaced by FCurves) */ +#define ID_KE MAKE_ID2('K', 'E') /* Key (shape key) */ +#define ID_WO MAKE_ID2('W', 'O') /* World */ +#define ID_SCR MAKE_ID2('S', 'R') /* Screen */ +#define ID_SCRN MAKE_ID2('S', 'N') /* (depreciated?) */ +#define ID_VF MAKE_ID2('V', 'F') /* VectorFont */ +#define ID_TXT MAKE_ID2('T', 'X') /* Text */ +#define ID_SO MAKE_ID2('S', 'O') /* Sound */ +#define ID_GR MAKE_ID2('G', 'R') /* Group */ +#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */ +#define ID_AR MAKE_ID2('A', 'R') /* Armature */ +#define ID_AC MAKE_ID2('A', 'C') /* Action */ +#define ID_SCRIPT MAKE_ID2('P', 'Y') /* Script (depreciated) */ +#define ID_NT MAKE_ID2('N', 'T') /* NodeTree */ +#define ID_BR MAKE_ID2('B', 'R') /* Brush */ +#define ID_PA MAKE_ID2('P', 'A') /* ParticleSettings */ +#define ID_GD MAKE_ID2('G', 'D') /* GreasePencil */ +#define ID_WM MAKE_ID2('W', 'M') /* WindowManager */ /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */ #define ID_SEQ MAKE_ID2('S', 'Q') -- cgit v1.2.3 From 8df1bb99f96fe9981a73c131b6637998fca8862f Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 16 Sep 2009 03:10:25 +0000 Subject: * enable high res smoke rendering in voxeldata texture --- source/blender/render/intern/source/voxeldata.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 17858e55e3d..9318d37620c 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -167,12 +167,10 @@ void init_frame_smoke(Render *re, VoxelData *vd, Tex *tex) SmokeModifierData *smd = (SmokeModifierData *)md; if(smd->domain && smd->domain->fluid) { - //int big = (smd->domain->flags & MOD_SMOKE_HIGHRES); - int big=0; - if (big) { - //smoke_turbulence_get_res(smd->domain->wt, vd->resol); - //vd->dataset = smoke_turbulence_get_density(smd->domain->wt); + if (smd->domain->flags & MOD_SMOKE_HIGHRES) { + smoke_turbulence_get_res(smd->domain->wt, vd->resol); + vd->dataset = smoke_turbulence_get_density(smd->domain->wt); } else { VECCOPY(vd->resol, smd->domain->res); vd->dataset = smoke_get_density(smd->domain->fluid); -- cgit v1.2.3 From cc100eadc5386a55965bacfa22afbb23c1541be5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Sep 2009 06:02:56 +0000 Subject: Operator cheat sheet (from the help menu) writes all operators (including PyOperators) and their default values into a textblock. Useful for an overview and checking consistancy. eg. http://www.pasteall.org/7918/python added rna functions text.clear() and text.write(str) --- release/ui/bpy_ops.py | 6 ++- release/ui/space_info.py | 30 +++++++++++++++ source/blender/blenkernel/BKE_text.h | 4 +- source/blender/blenkernel/intern/text.c | 32 ++++++++++++++-- source/blender/makesrna/intern/rna_internal.h | 1 + source/blender/makesrna/intern/rna_text.c | 2 + source/blender/makesrna/intern/rna_text_api.c | 49 ++++++++++++++++++++++++ source/blender/python/intern/bpy_operator.c | 54 +++++++++++++++++++++++++++ 8 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 source/blender/makesrna/intern/rna_text_api.c diff --git a/release/ui/bpy_ops.py b/release/ui/bpy_ops.py index dff8125fca1..83c2e82bf6c 100644 --- a/release/ui/bpy_ops.py +++ b/release/ui/bpy_ops.py @@ -3,6 +3,7 @@ from bpy.__ops__ import add as op_add from bpy.__ops__ import remove as op_remove from bpy.__ops__ import dir as op_dir from bpy.__ops__ import call as op_call +from bpy.__ops__ import as_string as op_as_string from bpy.__ops__ import get_rna as op_get_rna # Keep in sync with WM_types.h @@ -130,7 +131,10 @@ class bpy_ops_submodule_op(object): return op_get_rna(self.idname()) - def __repr__(self): + def __repr__(self): # useful display, repr(op) + return op_as_string(self.idname()) + + def __str__(self): # used for print(...) return "" % (self.module, self.func, id(self)) import bpy diff --git a/release/ui/space_info.py b/release/ui/space_info.py index 9fc35c46f29..6e32cf9b071 100644 --- a/release/ui/space_info.py +++ b/release/ui/space_info.py @@ -188,6 +188,9 @@ class INFO_MT_help(bpy.types.Menu): layout.itemO("help.blender_eshop") layout.itemO("help.developer_community") layout.itemO("help.user_community") + layout.itemS() + layout.itemO("help.operator_cheat_sheet") + bpy.types.register(INFO_HT_header) bpy.types.register(INFO_MT_file) @@ -246,10 +249,37 @@ class HELP_OT_user_community(HelpOperator): __label__ = "User Community" __URL__ = 'http://www.blender.org/community/user-community/' +class HELP_OT_operator_cheat_sheet(bpy.types.Operator): + __idname__ = "help.operator_cheat_sheet" + __label__ = "Operator Cheet Sheet (new textblock)" + def execute(self, context): + op_strings = [] + tot = 0 + for op_module_name in dir(bpy.ops): + op_module = getattr(bpy.ops, op_module_name) + for op_submodule_name in dir(op_module): + op = getattr(op_module, op_submodule_name) + text = repr(op) + if text.startswith('bpy.ops.'): + op_strings.append(text) + tot += 1 + + op_strings.append('') + + bpy.ops.text.new() # XXX - assumes new text is always at the end! + textblock = bpy.data.texts[-1] + textblock.write('# %d Operators\n\n' % tot) + textblock.write('\n'.join(op_strings)) + textblock.name = "OperatorList.txt" + print("See OperatorList.txt textblock") + return ('FINISHED',) + + bpy.ops.add(HELP_OT_manual) bpy.ops.add(HELP_OT_release_logs) bpy.ops.add(HELP_OT_blender_website) bpy.ops.add(HELP_OT_blender_eshop) bpy.ops.add(HELP_OT_developer_community) bpy.ops.add(HELP_OT_user_community) +bpy.ops.add(HELP_OT_operator_cheat_sheet) diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index bd14053d121..07e05756ea3 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -48,6 +48,8 @@ int reopen_text (struct Text *text); struct Text* add_text (char *file, const char *relpath); struct Text* copy_text (struct Text *ta); void unlink_text (struct Main *bmain, struct Text *text); +void clear_text(struct Text *text); +void write_text(struct Text *text, char *str); char* txt_to_buf (struct Text *text); void txt_clean_text (struct Text *text); @@ -74,7 +76,7 @@ void txt_delete_selected (struct Text *text); void txt_sel_all (struct Text *text); void txt_sel_line (struct Text *text); char* txt_sel_to_buf (struct Text *text); -void txt_insert_buf (struct Text *text, char *in_buffer); +void txt_insert_buf (struct Text *text, const char *in_buffer); void txt_print_undo (struct Text *text); void txt_undo_add_toop (struct Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc); void txt_do_undo (struct Text *text); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index dac426de4eb..350b0acba9d 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -130,8 +130,10 @@ undo position static void txt_pop_first(Text *text); static void txt_pop_last(Text *text); static void txt_undo_add_op(Text *text, int op); -static void txt_undo_add_block(Text *text, int op, char *buf); +static void txt_undo_add_block(Text *text, int op, const char *buf); static void txt_delete_line(Text *text, TextLine *line); +static void txt_delete_sel (Text *text); +static void txt_make_dirty (Text *text); /***/ @@ -537,6 +539,30 @@ void unlink_text(Main *bmain, Text *text) text->id.us= 0; } +void clear_text(Text *text) /* called directly from rna */ +{ + int oldstate; + + oldstate = txt_get_undostate( ); + txt_set_undostate( 1 ); + txt_sel_all( text ); + txt_delete_sel(text); + txt_set_undostate( oldstate ); + + txt_make_dirty(text); +} + +void write_text(Text *text, char *str) /* called directly from rna */ +{ + int oldstate; + + oldstate = txt_get_undostate( ); + txt_insert_buf( text, str ); + txt_move_eof( text, 0 ); + txt_set_undostate( oldstate ); + + txt_make_dirty(text); +} /*****************************/ /* Editing utility functions */ @@ -1315,7 +1341,7 @@ char *txt_sel_to_buf (Text *text) return buf; } -void txt_insert_buf(Text *text, char *in_buffer) +void txt_insert_buf(Text *text, const char *in_buffer) { int i=0, l=0, j, u, len; TextLine *add; @@ -1544,7 +1570,7 @@ static void txt_undo_add_op(Text *text, int op) text->undo_buf[text->undo_pos+1]= 0; } -static void txt_undo_add_block(Text *text, int op, char *buf) +static void txt_undo_add_block(Text *text, int op, const char *buf) { int length; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 7de80843f27..4d8ef7082b6 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -205,6 +205,7 @@ void RNA_api_main(struct StructRNA *srna); void RNA_api_mesh(struct StructRNA *srna); void RNA_api_object(struct StructRNA *srna); void RNA_api_scene(struct StructRNA *srna); +void RNA_api_text(struct StructRNA *srna); void RNA_api_ui_layout(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index cd39c317bc5..22cf7e7aeae 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -223,6 +223,8 @@ static void rna_def_text(BlenderRNA *brna) prop= RNA_def_property(srna, "markers", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "TextMarker"); RNA_def_property_ui_text(prop, "Markers", "Text markers highlighting part of the text."); + + RNA_api_text(srna); } void RNA_def_text(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c new file mode 100644 index 00000000000..b048a6b59d0 --- /dev/null +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -0,0 +1,49 @@ +/** + * + * ***** 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. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + + +#include "RNA_define.h" +#include "RNA_types.h" + +#ifdef RNA_RUNTIME + +#else + +void RNA_api_text(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *prop; + + func= RNA_def_function(srna, "clear", "clear_text"); + RNA_def_function_ui_description(func, "clear the text block."); + + func= RNA_def_function(srna, "write", "write_text"); + RNA_def_function_ui_description(func, "write text at the cursor location and advance to the end of the text block."); + prop= RNA_def_string(func, "text", "Text", 0, "", "New text for this datablock."); + RNA_def_property_flag(prop, PROP_REQUIRED); +} + +#endif diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 0c1d974c978..69a7e554452 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -118,6 +118,58 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) Py_RETURN_NONE; } +static PyObject *pyop_as_string( PyObject * self, PyObject * args) +{ + wmOperatorType *ot; + PointerRNA ptr; + + char *opname; + PyObject *kw= NULL; /* optional args */ + int all_args = 1; + int error_val= 0; + + char *buf; + PyObject *pybuf; + + bContext *C = BPy_GetContext(); + + if (!PyArg_ParseTuple(args, "s|O!i:bpy.__ops__.as_string", &opname, &PyDict_Type, &kw, &all_args)) + return NULL; + + ot= WM_operatortype_find(opname, TRUE); + + if (ot == NULL) { + PyErr_Format( PyExc_SystemError, "bpy.__ops__.as_string: operator \"%s\"could not be found", opname); + return NULL; + } + + /* WM_operator_properties_create(&ptr, opname); */ + /* Save another lookup */ + RNA_pointer_create(NULL, ot->srna, NULL, &ptr); + + if(kw && PyDict_Size(kw)) + error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); + + if (error_val==0) + buf= WM_operator_pystring(C, ot, &ptr, all_args); + + WM_operator_properties_free(&ptr); + + if (error_val==-1) { + return NULL; + } + + if(buf) { + pybuf= PyUnicode_FromString(buf); + MEM_freeN(buf); + } + else { + pybuf= PyUnicode_FromString(""); + } + + return pybuf; +} + static PyObject *pyop_dir(PyObject *self) { PyObject *list = PyList_New(0), *name; @@ -162,6 +214,7 @@ static PyObject *pyop_getrna(PyObject *self, PyObject *value) PyObject *BPY_operator_module( void ) { static PyMethodDef pyop_call_meth = {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL}; + static PyMethodDef pyop_as_string_meth ={"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL}; static PyMethodDef pyop_dir_meth = {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL}; static PyMethodDef pyop_getrna_meth = {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL}; static PyMethodDef pyop_add_meth = {"add", (PyCFunction) PYOP_wrap_add, METH_O, NULL}; @@ -171,6 +224,7 @@ PyObject *BPY_operator_module( void ) PyDict_SetItemString(PySys_GetObject("modules"), "bpy.__ops__", submodule); PyModule_AddObject( submodule, "call", PyCFunction_New(&pyop_call_meth, NULL) ); + PyModule_AddObject( submodule, "as_string",PyCFunction_New(&pyop_as_string_meth,NULL) ); PyModule_AddObject( submodule, "dir", PyCFunction_New(&pyop_dir_meth, NULL) ); PyModule_AddObject( submodule, "get_rna", PyCFunction_New(&pyop_getrna_meth, NULL) ); PyModule_AddObject( submodule, "add", PyCFunction_New(&pyop_add_meth, NULL) ); -- cgit v1.2.3 From e03b8b7be7c34450b0e419bbf1d8dfb78a8439b1 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Wed, 16 Sep 2009 09:55:06 +0000 Subject: loopcut tool. hold down ctrl-r, then leftclick. due to current limitations on operator design, there isn't any built-in edge sliding to this tool. --- source/blender/editors/mesh/loopcut.c | 67 +++++++++++++++++++++++++++---- source/blender/editors/mesh/mesh_intern.h | 1 + source/blender/editors/mesh/mesh_ops.c | 17 ++++---- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index c7e10d5809f..dfdb713d345 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -93,6 +93,7 @@ typedef struct tringselOpData { EditEdge *eed; int extend; + int do_cut; } tringselOpData; /* modal loop selection drawing callback */ @@ -258,8 +259,14 @@ static void ringsel_finish(bContext *C, wmOperator *op) { tringselOpData *lcd= op->customdata; - if (lcd->eed); + if (lcd->eed) { edgering_sel(lcd, 0, 1); + if (lcd->do_cut) { + EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data); + esubdivideflag(lcd->ob, em, SELECT, 0.0f, + 0.0f, 0, 1, SUBDIV_SELECT_LOOPCUT); + } + } } /* called when modal loop selection is done... */ @@ -281,7 +288,7 @@ static void ringsel_exit (bContext *C, wmOperator *op) } /* called when modal loop selection gets set up... */ -static int ringsel_init (bContext *C, wmOperator *op) +static int ringsel_init (bContext *C, wmOperator *op, int do_cut) { tringselOpData *lcd; @@ -293,7 +300,8 @@ static int ringsel_init (bContext *C, wmOperator *op) lcd->draw_handle= ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST); lcd->ob = CTX_data_edit_object(C); lcd->em= BKE_mesh_get_editmesh((Mesh *)lcd->ob->data); - lcd->extend = RNA_boolean_get(op->ptr, "extend"); + lcd->extend = do_cut ? 0 : RNA_boolean_get(op->ptr, "extend"); + lcd->do_cut = do_cut; em_setup_viewcontext(C, &lcd->vc); ED_region_tag_redraw(lcd->ar); @@ -317,7 +325,36 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) view3d_operator_needs_opengl(C); - if (!ringsel_init(C, op)) + if (!ringsel_init(C, op, 0)) + return OPERATOR_CANCELLED; + + /* add a modal handler for this operator - handles loop selection */ + WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + + lcd = op->customdata; + lcd->vc.mval[0] = evt->mval[0]; + lcd->vc.mval[1] = evt->mval[1]; + + edge = findnearestedge(&lcd->vc, &dist); + if (edge != lcd->eed) { + lcd->eed = edge; + ringsel_find_edge(lcd, C, lcd->ar); + } + + return OPERATOR_RUNNING_MODAL; +} + + +static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + ScrArea *sa = CTX_wm_area(C); + tringselOpData *lcd; + EditEdge *edge; + int dist = 75; + + view3d_operator_needs_opengl(C); + + if (!ringsel_init(C, op, 1)) return OPERATOR_CANCELLED; /* add a modal handler for this operator - handles loop selection */ @@ -379,13 +416,12 @@ static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -// naming is whatever this should use... void MESH_OT_edgering_select (wmOperatorType *ot) { /* description */ - ot->name= "Loop Cut"; + ot->name= "Edge Ring Select"; ot->idname= "MESH_OT_edgering_select"; - ot->description= "Add a new loop between existing loops."; + ot->description= "Select an edge ring"; /* callbacks */ ot->invoke= ringsel_invoke; @@ -398,3 +434,20 @@ void MESH_OT_edgering_select (wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); } + +void MESH_OT_loopcut (wmOperatorType *ot) +{ + /* description */ + ot->name= "Loop Cut"; + ot->idname= "MESH_OT_loopcut"; + ot->description= "Add a new loop between existing loops."; + + /* callbacks */ + ot->invoke= ringcut_invoke; + ot->modal= ringsel_modal; + ot->cancel= ringsel_cancel; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 887474414b3..11a974f2c49 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -243,6 +243,7 @@ void MESH_OT_sticky_add(struct wmOperatorType *ot); void MESH_OT_sticky_remove(struct wmOperatorType *ot); void MESH_OT_edgering_select(struct wmOperatorType *ot); +void MESH_OT_loopcut(struct wmOperatorType *ot); #endif // MESH_INTERN_H diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 606614cd1f1..6da42f28af4 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -321,8 +321,17 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_specials); WM_operatortype_append(MESH_OT_edgering_select); + WM_operatortype_append(MESH_OT_loopcut); /* macros */ + + /*combining operators with invoke and exec portions doesn't work yet. + + ot= WM_operatortype_append_macro("MESH_OT_loopcut", "Loopcut", OPTYPE_UNDO|OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MESH_OT_edgering_select"); + WM_operatortype_macro_define(ot, "MESH_OT_subdivide"); + */ + ot= WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "MESH_OT_duplicate"); WM_operatortype_macro_define(ot, "TFM_OT_translate"); @@ -335,12 +344,6 @@ void ED_operatortypes_mesh(void) WM_operatortype_macro_define(ot, "MESH_OT_extrude"); WM_operatortype_macro_define(ot, "TFM_OT_translate"); - /*combining operators with invoke and exec portions doesn't work yet. - - ot= WM_operatortype_append_macro("MESH_OT_loopcut", "Loopcut", OPTYPE_UNDO|OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "MESH_OT_edgering_select"); - WM_operatortype_macro_define(ot, "MESH_OT_subdivide"); - */ } /* note mesh keymap also for other space? */ @@ -349,7 +352,7 @@ void ED_keymap_mesh(wmWindowManager *wm) ListBase *keymap= WM_keymap_listbase(wm, "EditMesh", 0, 0); wmKeymapItem *kmi; - //WM_keymap_add_item(keymap, "MESH_OT_loopcut", RKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "MESH_OT_loopcut", ACTIONMOUSE, KM_PRESS, KM_CTRL, RKEY); /* selecting */ /* standard mouse selection goes via space_view3d */ -- cgit v1.2.3 From 103e11359d3838ac944f2a8895a41cc26ab9e74b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Sep 2009 10:09:57 +0000 Subject: - rna/python api object.create_render_mesh(...) support for getting a mesh from metaballs and curves (bevel, surface, text etc). - povray converts curves to meshes on export, (metaballs don't need meshing). - use 'extend' bool rather then 'seltype' enum for object_select operators for consistency. --- release/io/engine_render_pov.py | 2 +- source/blender/editors/object/object_select.c | 61 ++++++++-------- source/blender/editors/space_node/node_select.c | 8 -- .../blender/editors/space_view3d/view3d_select.c | 2 +- source/blender/makesrna/intern/rna_object_api.c | 85 +++++++++++++++++++--- 5 files changed, 105 insertions(+), 53 deletions(-) diff --git a/release/io/engine_render_pov.py b/release/io/engine_render_pov.py index 22cf1a36dbb..c1cd84c8978 100644 --- a/release/io/engine_render_pov.py +++ b/release/io/engine_render_pov.py @@ -275,7 +275,7 @@ def write_pov(filename, scene=None, info_callback = None): for ob in sel: ob_num+= 1 - if ob.type in ('LAMP', 'CAMERA', 'EMPTY'): + if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META'): continue me = ob.data diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index cfd65ad18ec..432aaf2d2cb 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -53,6 +53,7 @@ #include "BKE_property.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_utildefines.h" #include "WM_api.h" #include "WM_types.h" @@ -117,22 +118,16 @@ void ED_base_object_activate(bContext *C, Base *base) /********************** Selection Operators **********************/ -static EnumPropertyItem prop_select_types[] = { - {0, "EXCLUSIVE", 0, "Exclusive", ""}, - {1, "EXTEND", 0, "Extend", ""}, - {0, NULL, 0, NULL, NULL} -}; - /************************ Select by Type *************************/ static int object_select_by_type_exec(bContext *C, wmOperator *op) { - short obtype, seltype; + short obtype, extend; obtype = RNA_enum_get(op->ptr, "type"); - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); - if (seltype == 0) { + if (extend == 0) { CTX_DATA_BEGIN(C, Base*, base, visible_bases) { ED_base_object_select(base, BA_DESELECT); } @@ -166,9 +161,9 @@ void OBJECT_OT_select_by_type(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - RNA_def_enum(ot->srna, "seltype", prop_select_types, 0, "Selection", "Extend selection or clear selection then select"); + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", ""); - } /*********************** Selection by Links *********************/ @@ -192,7 +187,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) Tex *tex=0; int a, b; int nr = RNA_enum_get(op->ptr, "type"); - short changed = 0, seltype; + short changed = 0, extend; /* events (nr): * Object Ipo: 1 * ObData: 2 @@ -202,9 +197,9 @@ static int object_select_linked_exec(bContext *C, wmOperator *op) * PSys: 6 */ - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); - if (seltype == 0) { + if (extend == 0) { CTX_DATA_BEGIN(C, Base*, base, visible_bases) { ED_base_object_select(base, BA_DESELECT); } @@ -327,9 +322,9 @@ void OBJECT_OT_select_linked(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", ""); - RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); - } /*********************** Selected Grouped ********************/ @@ -575,11 +570,11 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *ob; int nr = RNA_enum_get(op->ptr, "type"); - short changed = 0, seltype; + short changed = 0, extend; - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); - if (seltype == 0) { + if (extend == 0) { CTX_DATA_BEGIN(C, Base*, base, visible_bases) { ED_base_object_select(base, BA_DESELECT); } @@ -628,8 +623,8 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", ""); - RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); } /************************* Select by Layer **********************/ @@ -637,12 +632,12 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot) static int object_select_by_layer_exec(bContext *C, wmOperator *op) { unsigned int layernum; - short seltype; + short extend; - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); layernum = RNA_int_get(op->ptr, "layer"); - if (seltype == 0) { + if (extend == 0) { CTX_DATA_BEGIN(C, Base*, base, visible_bases) { ED_base_object_select(base, BA_DESELECT); } @@ -676,8 +671,9 @@ void OBJECT_OT_select_by_layer(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20); - RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); } /************************** Select Inverse *************************/ @@ -878,9 +874,9 @@ void object_flip_name (char *name) static int object_select_mirror_exec(bContext *C, wmOperator *op) { char tmpname[32]; - short seltype; + short extend; - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); CTX_DATA_BEGIN(C, Base*, primbase, selected_bases) { @@ -894,7 +890,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - if (seltype == 0) ED_base_object_select(primbase, BA_DESELECT); + if (extend == 0) ED_base_object_select(primbase, BA_DESELECT); } CTX_DATA_END; @@ -920,7 +916,7 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first."); } @@ -981,11 +977,11 @@ void OBJECT_OT_select_name(wmOperatorType *ot) static int object_select_random_exec(bContext *C, wmOperator *op) { float percent; - short seltype; + short extend; - seltype = RNA_enum_get(op->ptr, "seltype"); + extend= RNA_boolean_get(op->ptr, "extend"); - if (seltype == 0) { + if (extend == 0) { CTX_DATA_BEGIN(C, Base*, base, visible_bases) { ED_base_object_select(base, BA_DESELECT); } @@ -1020,8 +1016,9 @@ void OBJECT_OT_select_random(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first."); RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f); - RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select"); } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 94e17b56a02..94691dd0ed2 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -224,12 +224,6 @@ void NODE_OT_select(wmOperatorType *ot) /* ****** Border Select ****** */ -static EnumPropertyItem prop_select_types[] = { - {NODE_EXCLUSIVE, "EXCLUSIVE", 0, "Exclusive", ""}, /* right mouse */ - {NODE_EXTEND, "EXTEND", 0, "Extend", ""}, /* left mouse */ - {0, NULL, 0, NULL, NULL} -}; - static int node_borderselect_exec(bContext *C, wmOperator *op) { SpaceNode *snode= CTX_wm_space_node(C); @@ -288,8 +282,6 @@ void NODE_OT_select_border(wmOperatorType *ot) RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); - - RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", ""); } /* ****** Select/Deselect All ****** */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index c639b445f9e..b1fec793b09 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1592,7 +1592,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first."); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first."); } /* ****** Mouse Select ****** */ diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 6545898c1ab..cfbd363e358 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -38,30 +38,92 @@ #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_object.h" +#include "BKE_main.h" #include "DNA_mesh_types.h" +#include "DNA_curve_types.h" #include "DNA_scene_types.h" /* copied from init_render_mesh (render code) */ -static Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) +static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, Scene *scene) { CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; + Object *tmpobj = NULL; DerivedMesh *dm; Mesh *me; - /* TODO: other types */ - if(ob->type != OB_MESH) - return NULL; + switch(ob->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + { + int cage = 0; //XXX -todo + Curve *tmpcu = NULL; + + /* copies object and modifiers (but not the data) */ + tmpobj= copy_object( ob ); + tmpcu = (Curve *)tmpobj->data; + tmpcu->id.us--; + + /* if getting the original caged mesh, delete object modifiers */ + if( cage ) + object_free_modifiers(tmpobj); + + /* copies the data */ + tmpobj->data = copy_curve( (Curve *) ob->data ); + +#if 0 + /* copy_curve() sets disp.first null, so currently not need */ + { + Curve *cu; + cu = (Curve *)tmpobj->data; + if( cu->disp.first ) + MEM_freeN( cu->disp.first ); + cu->disp.first = NULL; + } - dm= mesh_create_derived_render(scene, ob, mask); +#endif - if(!dm) - return NULL; + /* get updated display list, and convert to a mesh */ + makeDispListCurveTypes( scene, tmpobj, 0 ); + nurbs_to_mesh( tmpobj ); - me= add_mesh("tmp_render_mesh"); - me->id.us--; /* we don't assign it to anything */ - DM_to_mesh(dm, me); - dm->release(dm); + /* nurbs_to_mesh changes the type tp a mesh, check it worked */ + if (tmpobj->type != OB_MESH) { + free_libblock_us( &(CTX_data_main(C)->object), tmpobj ); + printf("cant convert curve to mesh. Does the curve have any segments?" ); // XXX use report api + } + me = tmpobj->data; + free_libblock_us( &(CTX_data_main(C)->object), tmpobj ); + break; + } + case OB_MBALL: + /* metaballs don't have modifiers, so just convert to mesh */ + ob = find_basis_mball( ob ); + /* todo, re-generatre for render-res */ + // metaball_polygonize(scene, ob) + me = add_mesh("Mesh"); + mball_to_mesh( &ob->disp, me ); + break; + case OB_MESH: + { + dm= mesh_create_derived_render(scene, ob, mask); + // dm= mesh_create_derived_view(scene, ob, mask); + + if(!dm) + return NULL; + + me= add_mesh("tmp_render_mesh"); + me->id.us--; /* we don't assign it to anything */ + DM_to_mesh(dm, me); + dm->release(dm); + break; + } + default: + return NULL; + } { /* update the material */ @@ -94,6 +156,7 @@ void RNA_api_object(StructRNA *srna) func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); 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."); -- cgit v1.2.3 From 42af96ed4277de4e275094229cad83329c33cf62 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 16 Sep 2009 14:02:01 +0000 Subject: use platform.uname instead of os.uname (suggested by Carsten on the ml), it's more portable --- release/io/netrender/slave.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index 1dcb608931e..cec5439fc63 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -1,4 +1,4 @@ -import sys, os +import sys, os, platform import http, http.client, http.server, urllib import subprocess, time @@ -10,10 +10,10 @@ MAX_TIMEOUT = 10 INCREMENT_TIMEOUT = 1 def slave_Info(): - sysname, nodename, release, version, machine = os.uname() + sysname, nodename, release, version, machine, processor = platform.uname() slave = netrender.model.RenderSlave() slave.name = nodename - slave.stats = sysname + " " + release + " " + machine + slave.stats = sysname + " " + release + " " + machine + " " + processor return slave def testCancel(conn, job_id): -- cgit v1.2.3 From 9fea9d065d80b12b3750c8fe777114c0522a105c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 14:45:10 +0000 Subject: 2.5: fix bug in Levels node, giving NULL pointer free warnings. --- source/blender/nodes/intern/CMP_nodes/CMP_levels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_levels.c b/source/blender/nodes/intern/CMP_nodes/CMP_levels.c index 28b769a8a97..6056e9a28f4 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_levels.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_levels.c @@ -329,8 +329,8 @@ bNodeType cmp_node_view_levels= { /* execfunc */ node_composit_exec_view_levels, /* butfunc */ NULL, /* initfunc */ node_composit_init_view_levels, - /* freestoragefunc */ node_free_standard_storage, - /* copystoragefunc */ node_copy_standard_storage, + /* freestoragefunc */ NULL, + /* copystoragefunc */ NULL, /* id */ NULL }; -- cgit v1.2.3 From b5b0a62c9715130ac371356cd2511371e14b9d40 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 16 Sep 2009 15:00:35 +0000 Subject: netrender: default temp path on windows to something more useful --- release/io/netrender/ui.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index df2b6288fb0..2ec0b62de4a 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -213,11 +213,18 @@ NetRenderSettings.BoolProperty( attr="server_broadcast", description="broadcast server address on local network", default = True) -NetRenderSettings.StringProperty( attr="path", - name="Path", - description="Path for temporary files", - maxlen = 128, - default = "/tmp/") +if os.name == 'nt': + NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = "C:/tmp/") +else: + NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = "/tmp/") NetRenderSettings.StringProperty( attr="job_name", name="Job name", -- cgit v1.2.3 From 7c5695c8011d128d7a40b28bf2146fdaab063dbe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Sep 2009 15:55:00 +0000 Subject: - bpy.data.sounds was a collection of ID's rather then Sounds - last commit, missed include for rna_object_api.c & bad args to find_basis_mball - use enum for GHOST tablet type None/Stylus/Eraser, had duplicate definition for these in C. Only tested X11, may need to cast to an int for other OS's. --- intern/ghost/GHOST_Types.h | 8 +++++++- intern/ghost/intern/GHOST_SystemX11.cpp | 6 +++--- intern/ghost/intern/GHOST_WindowCarbon.cpp | 2 +- intern/ghost/intern/GHOST_WindowWin32.cpp | 4 ++-- intern/ghost/intern/GHOST_WindowX11.cpp | 2 +- source/blender/editors/interface/interface_handlers.c | 2 +- source/blender/makesrna/intern/rna_main.c | 4 ++-- source/blender/makesrna/intern/rna_object_api.c | 3 ++- source/blender/windowmanager/WM_types.h | 6 +----- source/blender/windowmanager/intern/wm_event_system.c | 4 ++-- source/blender/windowmanager/wm_event_types.h | 2 +- 11 files changed, 23 insertions(+), 20 deletions(-) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 2441251dc33..73ed0bdd1fa 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -64,8 +64,14 @@ typedef enum * the pen's angle in 3D space vertically downwards on to the XY plane * --Matt */ +typedef enum { + GHOST_kTabletModeNone = 0, + GHOST_kTabletModeStylus, + GHOST_kTabletModeEraser +} GHOST_TTabletMode; + typedef struct GHOST_TabletData { - char Active; /* 0=None, 1=Stylus, 2=Eraser */ + GHOST_TTabletMode Active; /* 0=None, 1=Stylus, 2=Eraser */ float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ float Ytilt; /* as above */ diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 5dba76adb02..9f6f3b4d5b0 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -684,12 +684,12 @@ GHOST_SystemX11::processEvent(XEvent *xe) { XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe; if(data->deviceid == window->GetXTablet().StylusID) - window->GetXTablet().CommonData.Active= 1; + window->GetXTablet().CommonData.Active= GHOST_kTabletModeStylus; else if(data->deviceid == window->GetXTablet().EraserID) - window->GetXTablet().CommonData.Active= 2; + window->GetXTablet().CommonData.Active= GHOST_kTabletModeEraser; } else if(xe->type == window->GetXTablet().ProxOutEvent) - window->GetXTablet().CommonData.Active= 0; + window->GetXTablet().CommonData.Active= GHOST_kTabletModeNone; break; } diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp index 87bb86a37e7..362e949a0a4 100644 --- a/intern/ghost/intern/GHOST_WindowCarbon.cpp +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -183,7 +183,7 @@ GHOST_WindowCarbon::GHOST_WindowCarbon( updateDrawingContext(); activateDrawingContext(); - m_tablet.Active = 0; + m_tablet.Active = GHOST_kTabletModeNone; } } diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 366adb3ab86..7cc75979030 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -244,7 +244,7 @@ GHOST_WindowWin32::GHOST_WindowWin32( m_tablet = fpWTOpen( m_hWnd, &lc, TRUE ); if (m_tablet) { m_tabletData = new GHOST_TabletData(); - m_tabletData->Active = 0; + m_tabletData->Active = GHOST_kTabletModeNone; } } } @@ -704,7 +704,7 @@ void GHOST_WindowWin32::processWin32TabletInitEvent() } } - m_tabletData->Active = 0; + m_tabletData->Active = GHOST_kTabletModeNone; } } } diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 3aff9d64a17..708256f75f5 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -425,7 +425,7 @@ void GHOST_WindowX11::initXInputDevices() XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); m_xtablet.StylusDevice = 0; m_xtablet.EraserDevice = 0; - m_xtablet.CommonData.Active= 0; + m_xtablet.CommonData.Active= GHOST_kTabletModeNone; /* Install our error handler to override Xlib's termination behavior */ old_handler = XSetErrorHandler(ApplicationErrorHandler) ; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 152695c9162..1041418b059 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2116,7 +2116,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton wmTabletData *wmtab= event->customdata; /* de-sensitise based on tablet pressure */ - if (ELEM(wmtab->Active, DEV_STYLUS, DEV_ERASER)) + if (wmtab->Active != EVT_TABLET_NONE) fac *= wmtab->Pressure; } diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 344135acaff..910a15890cb 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -259,9 +259,9 @@ void RNA_def_main(BlenderRNA *brna) {"worlds", "World", "rna_Main_world_begin", "Worlds", "World datablocks.", NULL, NULL}, {"groups", "Group", "rna_Main_group_begin", "Groups", "Group datablocks.", NULL, NULL}, {"keys", "Key", "rna_Main_key_begin", "Keys", "Key datablocks.", NULL, NULL}, - {"scripts", "ID", "rna_Main_script_begin", "Scripts", "Script datablocks.", NULL, NULL}, + {"scripts", "ID", "rna_Main_script_begin", "Scripts", "Script datablocks (DEPRECATED).", NULL, NULL}, {"texts", "Text", "rna_Main_text_begin", "Texts", "Text datablocks.", NULL, NULL}, - {"sounds", "ID", "rna_Main_sound_begin", "Sounds", "Sound datablocks.", NULL, NULL}, + {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound datablocks.", NULL, NULL}, {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature datablocks.", NULL, NULL}, {"actions", "Action", "rna_Main_action_begin", "Actions", "Action datablocks.", NULL, NULL}, {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle datablocks.", NULL, NULL}, diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index cfbd363e358..e51dcbe3c57 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -40,6 +40,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_object.h" +#include "BKE_mball.h" #include "BKE_main.h" #include "DNA_mesh_types.h" @@ -101,7 +102,7 @@ static Mesh *rna_Object_create_render_mesh(Object *ob, bContext *C, Scene *scene } case OB_MBALL: /* metaballs don't have modifiers, so just convert to mesh */ - ob = find_basis_mball( ob ); + ob = find_basis_mball(scene, ob); /* todo, re-generatre for render-res */ // metaball_polygonize(scene, ob) me = add_mesh("Mesh"); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 806f5409b0a..c24cf783063 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -276,12 +276,8 @@ typedef struct wmGesture { } wmGesture; /* ************** custom wmEvent data ************** */ - -#define DEV_STYLUS 1 -#define DEV_ERASER 2 - typedef struct wmTabletData { - int Active; /* 0=None, 1=Stylus, 2=Eraser */ + int Active; /* 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER */ float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ float Ytilt; /* as above */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 306b99dcfcc..9d5bd13ea25 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1498,10 +1498,10 @@ static void update_tablet_data(wmWindow *win, wmEvent *event) const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin); /* if there's tablet data from an active tablet device then add it */ - if ((td != NULL) && td->Active) { + if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet"); - wmtab->Active = td->Active; + wmtab->Active = (int)td->Active; wmtab->Pressure = td->Pressure; wmtab->Xtilt = td->Xtilt; wmtab->Ytilt = td->Ytilt; diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 3da621bda85..b331e036b9e 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -40,7 +40,7 @@ #define EVT_DATA_GESTURE 2 #define EVT_DATA_TIMER 3 -/* tablet active */ +/* tablet active, matches GHOST_TTabletMode */ #define EVT_TABLET_NONE 0 #define EVT_TABLET_STYLUS 1 #define EVT_TABLET_ERASER 2 -- cgit v1.2.3 From 6b5ba700594051b834008020b9371601ee52268c Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 16 Sep 2009 17:13:03 +0000 Subject: 2.5 Ghost Compile Fix for windows. Patch by b333rt. Thanks! --- intern/ghost/intern/GHOST_WindowWin32.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 7cc75979030..e2caf31edee 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -720,15 +720,15 @@ void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) switch (pkt.pkCursor) { case 0: /* first device */ case 3: /* second device */ - m_tabletData->Active = 0; /* puck - not yet supported */ + m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */ break; case 1: case 4: - m_tabletData->Active = 1; /* stylus */ + m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */ break; case 2: case 5: - m_tabletData->Active = 2; /* eraser */ + m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */ break; } if (m_maxPressure > 0) { -- cgit v1.2.3 From feff78170d088bc2c2b5c0824c247895ea0987b1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:04:01 +0000 Subject: RNA * PROP_NEVER_NULL is now a flag instead of a subtype. * It works for function parameters too now, so setting this flag can help avoid NULL checks in the function. * Renamed LocalLamp to PointLamp, making it consistent with the UI name. * Set icons for the different lamp struct types. --- source/blender/makesrna/RNA_access.h | 2 +- source/blender/makesrna/RNA_types.h | 4 +- source/blender/makesrna/intern/makesrna.c | 1 - source/blender/makesrna/intern/rna_access.c | 13 ++- source/blender/makesrna/intern/rna_brush.c | 3 +- source/blender/makesrna/intern/rna_define.c | 4 +- source/blender/makesrna/intern/rna_key.c | 6 +- source/blender/makesrna/intern/rna_lamp.c | 18 ++-- source/blender/makesrna/intern/rna_material.c | 23 +++-- source/blender/makesrna/intern/rna_modifier.c | 21 +++-- source/blender/makesrna/intern/rna_object.c | 3 +- source/blender/makesrna/intern/rna_particle.c | 10 +- source/blender/makesrna/intern/rna_pose.c | 6 +- source/blender/makesrna/intern/rna_rna.c | 1 - source/blender/makesrna/intern/rna_scene.c | 12 ++- source/blender/makesrna/intern/rna_screen.c | 6 +- source/blender/makesrna/intern/rna_smoke.c | 6 +- source/blender/makesrna/intern/rna_space.c | 9 +- source/blender/makesrna/intern/rna_text.c | 6 +- source/blender/makesrna/intern/rna_ui_api.c | 14 +-- source/blender/makesrna/intern/rna_userdef.c | 129 +++++++++++++++++--------- source/blender/makesrna/intern/rna_wm.c | 6 +- source/blender/makesrna/intern/rna_world.c | 9 +- source/blender/python/intern/bpy_rna.c | 9 +- 24 files changed, 208 insertions(+), 113 deletions(-) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index ca3ac62ba00..40f640473db 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -249,7 +249,6 @@ extern StructRNA RNA_LimitDistanceConstraint; extern StructRNA RNA_LimitLocationConstraint; extern StructRNA RNA_LimitRotationConstraint; extern StructRNA RNA_LimitScaleConstraint; -extern StructRNA RNA_LocalLamp; extern StructRNA RNA_LockedTrackConstraint; extern StructRNA RNA_MagicTexture; extern StructRNA RNA_Main; @@ -329,6 +328,7 @@ extern StructRNA RNA_PointCache; extern StructRNA RNA_PointDensity; extern StructRNA RNA_PointDensityTexture; extern StructRNA RNA_PointerProperty; +extern StructRNA RNA_PointLamp; extern StructRNA RNA_Pose; extern StructRNA RNA_PoseChannel; extern StructRNA RNA_Property; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index e7fe86afd03..353c859cf27 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -110,9 +110,6 @@ typedef enum PropertySubType { PROP_XYZ = 28, PROP_RGB = 29, - /* pointers */ - PROP_NEVER_NULL = 30, - /* booleans */ PROP_LAYER = 40, PROP_LAYER_MEMBER = 41 @@ -149,6 +146,7 @@ typedef enum PropertyFlag { /* pointers */ PROP_ID_REFCOUNT = 64, + PROP_NEVER_NULL = 262144, /* internal flags */ PROP_BUILTIN = 128, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index d0c7824dc9d..c734cdfec87 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1419,7 +1419,6 @@ static const char *rna_property_subtypename(PropertyType type) case PROP_ACCELERATION: return "PROP_ACCELERATION"; case PROP_XYZ: return "PROP_XYZ"; case PROP_RGB: return "PROP_RGB"; - case PROP_NEVER_NULL: return "PROP_NEVER_NULL"; case PROP_LAYER: return "PROP_LAYER"; case PROP_LAYER_MEMBER: return "PROP_LAYER_MEMBER"; default: { diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 9472cdb300c..738d52bfbcd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1409,10 +1409,17 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value) { - PointerPropertyRNA *pprop= (PointerPropertyRNA*)prop; + IDProperty *idprop; + + if((idprop=rna_idproperty_check(&prop, ptr))) { + /* not supported */ + } + else { + PointerPropertyRNA *pprop= (PointerPropertyRNA*)prop; - if(pprop->set) - pprop->set(ptr, ptr_value); + if(pprop->set && !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL)) + pprop->set(ptr, ptr_value); + } } void RNA_property_pointer_add(PointerRNA *ptr, PropertyRNA *prop) diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 70daa3690da..eea29381b92 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -219,7 +219,8 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FIXED_TEX); RNA_def_property_ui_text(prop, "Fixed Texture", "Keep texture origin in fixed position.");*/ - prop= RNA_def_property(srna, "curve", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Curve", "Editable falloff curve."); /* texture */ diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 0b54d4a8e14..45517546c16 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -134,7 +134,7 @@ PropertyDefRNA *rna_find_struct_property_def(StructRNA *srna, PropertyRNA *prop) if(!DefRNA.preprocess) { /* we should never get here */ - fprintf(stderr, "rna_find_property_def: only at preprocess time.\n"); + fprintf(stderr, "rna_find_struct_property_def: only at preprocess time.\n"); return NULL; } @@ -155,6 +155,7 @@ PropertyDefRNA *rna_find_struct_property_def(StructRNA *srna, PropertyRNA *prop) return NULL; } +#if 0 static PropertyDefRNA *rna_find_property_def(PropertyRNA *prop) { PropertyDefRNA *dprop; @@ -175,6 +176,7 @@ static PropertyDefRNA *rna_find_property_def(PropertyRNA *prop) return NULL; } +#endif FunctionDefRNA *rna_find_function_def(FunctionRNA *func) { diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index fbe339fe7f3..e66ee683e61 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -414,7 +414,8 @@ static void rna_def_key(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Key", "Shape keys datablock containing different shapes of geometric datablocks."); RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA); - prop= RNA_def_property(srna, "reference_key", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "reference_key", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_pointer_sdna(prop, NULL, "refkey"); RNA_def_property_ui_text(prop, "Reference Key", ""); @@ -426,7 +427,8 @@ static void rna_def_key(BlenderRNA *brna) rna_def_animdata_common(srna); - prop= RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "user", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "from"); RNA_def_property_ui_text(prop, "User", "Datablock using these shape keys."); diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index dc59a75edbc..d00a0d61bf6 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -99,7 +99,7 @@ static StructRNA* rna_Lamp_refine(struct PointerRNA *ptr) switch(la->type) { case LA_LOCAL: - return &RNA_LocalLamp; + return &RNA_PointLamp; case LA_SUN: return &RNA_SunLamp; case LA_SPOT: @@ -477,13 +477,14 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_update(prop, NC_LAMP|ND_LIGHTING, NULL); } -static void rna_def_local_lamp(BlenderRNA *brna) +static void rna_def_point_lamp(BlenderRNA *brna) { StructRNA *srna; - srna= RNA_def_struct(brna, "LocalLamp", "Lamp"); + srna= RNA_def_struct(brna, "PointLamp", "Lamp"); RNA_def_struct_sdna(srna, "Lamp"); - RNA_def_struct_ui_text(srna, "Local Lamp", "Omnidirectional point lamp."); + RNA_def_struct_ui_text(srna, "Point Lamp", "Omnidirectional point lamp."); + RNA_def_struct_ui_icon(srna, ICON_LAMP_POINT); rna_def_lamp_falloff(srna); rna_def_lamp_shadow(srna, 0, 0); @@ -502,6 +503,7 @@ static void rna_def_area_lamp(BlenderRNA *brna) srna= RNA_def_struct(brna, "AreaLamp", "Lamp"); RNA_def_struct_sdna(srna, "Lamp"); RNA_def_struct_ui_text(srna, "Area Lamp", "Directional area lamp."); + RNA_def_struct_ui_icon(srna, ICON_LAMP_AREA); rna_def_lamp_shadow(srna, 0, 1); @@ -571,6 +573,7 @@ static void rna_def_spot_lamp(BlenderRNA *brna) srna= RNA_def_struct(brna, "SpotLamp", "Lamp"); RNA_def_struct_sdna(srna, "Lamp"); RNA_def_struct_ui_text(srna, "Spot Lamp", "Directional cone lamp."); + RNA_def_struct_ui_icon(srna, ICON_LAMP_SPOT); rna_def_lamp_falloff(srna); rna_def_lamp_shadow(srna, 1, 0); @@ -683,11 +686,13 @@ static void rna_def_sun_lamp(BlenderRNA *brna) srna= RNA_def_struct(brna, "SunLamp", "Lamp"); RNA_def_struct_sdna(srna, "Lamp"); RNA_def_struct_ui_text(srna, "Sun Lamp", "Constant direction parallel ray lamp."); + RNA_def_struct_ui_icon(srna, ICON_LAMP_SUN); rna_def_lamp_shadow(srna, 0, 0); /* sky */ - prop= RNA_def_property(srna, "sky", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "sky", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "LampSkySettings"); RNA_def_property_pointer_funcs(prop, "rna_Lamp_sky_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Sky Settings", "Sky related settings for sun lamps."); @@ -702,12 +707,13 @@ static void rna_def_hemi_lamp(BlenderRNA *brna) srna= RNA_def_struct(brna, "HemiLamp", "Lamp"); RNA_def_struct_sdna(srna, "Lamp"); RNA_def_struct_ui_text(srna, "Hemi Lamp", "180 degree constant lamp."); + RNA_def_struct_ui_icon(srna, ICON_LAMP_HEMI); } void RNA_def_lamp(BlenderRNA *brna) { rna_def_lamp(brna); - rna_def_local_lamp(brna); + rna_def_point_lamp(brna); rna_def_area_lamp(brna); rna_def_spot_lamp(brna); rna_def_sun_lamp(brna); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index e23333713c4..18c0dc42e17 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -667,6 +667,7 @@ static void rna_def_material_colors(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "ramp_col"); RNA_def_property_struct_type(prop, "ColorRamp"); RNA_def_property_ui_text(prop, "Diffuse Ramp", "Color ramp used to affect diffuse shading."); + RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL); prop= RNA_def_property(srna, "use_specular_ramp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAMP_SPEC); @@ -678,6 +679,7 @@ static void rna_def_material_colors(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "ramp_spec"); RNA_def_property_struct_type(prop, "ColorRamp"); RNA_def_property_ui_text(prop, "Specular Ramp", "Color ramp used to affect specular shading."); + RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL); prop= RNA_def_property(srna, "diffuse_ramp_blend", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "rampblend_col"); @@ -1615,37 +1617,44 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); /* nested structs */ - prop= RNA_def_property(srna, "raytrace_mirror", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "raytrace_mirror", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialRaytraceMirror"); RNA_def_property_pointer_funcs(prop, "rna_Material_mirror_get", NULL, NULL); RNA_def_property_ui_text(prop, "Raytrace Mirror", "Raytraced reflection settings for the material."); - prop= RNA_def_property(srna, "raytrace_transparency", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "raytrace_transparency", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialRaytraceTransparency"); RNA_def_property_pointer_funcs(prop, "rna_Material_transp_get", NULL, NULL); RNA_def_property_ui_text(prop, "Raytrace Transparency", "Raytraced reflection settings for the material."); - prop= RNA_def_property(srna, "volume", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "volume", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "vol"); RNA_def_property_struct_type(prop, "MaterialVolume"); RNA_def_property_ui_text(prop, "Volume", "Volume settings for the material."); - prop= RNA_def_property(srna, "halo", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "halo", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialHalo"); RNA_def_property_pointer_funcs(prop, "rna_Material_halo_get", NULL, NULL); RNA_def_property_ui_text(prop, "Halo", "Halo settings for the material."); - prop= RNA_def_property(srna, "subsurface_scattering", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "subsurface_scattering", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialSubsurfaceScattering"); RNA_def_property_pointer_funcs(prop, "rna_Material_sss_get", NULL, NULL); RNA_def_property_ui_text(prop, "Subsurface Scattering", "Subsurface scattering settings for the material."); - prop= RNA_def_property(srna, "strand", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "strand", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialStrand"); RNA_def_property_pointer_funcs(prop, "rna_Material_strand_get", NULL, NULL); RNA_def_property_ui_text(prop, "Strand", "Strand settings for the material."); - prop= RNA_def_property(srna, "physics", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "physics", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "MaterialPhysics"); RNA_def_property_pointer_funcs(prop, "rna_Material_physics_get", NULL, NULL); RNA_def_property_ui_text(prop, "Physics", "Game physics settings."); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 32e34559f1f..ffc2d78a6ce 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -930,12 +930,14 @@ static void rna_def_modifier_softbody(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SoftbodyModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_SOFT); - prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "SoftBodySettings"); RNA_def_property_pointer_funcs(prop, "rna_SoftBodyModifier_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Soft Body Settings", ""); - prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_pointer_funcs(prop, "rna_SoftBodyModifier_point_cache_get", NULL, NULL); RNA_def_property_ui_text(prop, "Soft Body Point Cache", ""); @@ -1551,15 +1553,18 @@ static void rna_def_modifier_cloth(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ClothModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_CLOTH); - prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "sim_parms"); RNA_def_property_ui_text(prop, "Cloth Settings", ""); - prop= RNA_def_property(srna, "collision_settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "collision_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "coll_parms"); RNA_def_property_ui_text(prop, "Cloth Collision Settings", ""); - prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Point Cache", ""); } @@ -1609,7 +1614,8 @@ static void rna_def_modifier_collision(BlenderRNA *brna) RNA_def_struct_sdna(srna, "CollisionModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_PHYSICS); - prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "CollisionSettings"); RNA_def_property_pointer_funcs(prop, "rna_CollisionModifier_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Settings", ""); @@ -1780,7 +1786,8 @@ static void rna_def_modifier_fluidsim(BlenderRNA *brna) RNA_def_struct_sdna(srna, "FluidsimModifierData"); RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM); - prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "fss"); RNA_def_property_ui_text(prop, "Settings", "Settings for how this object is used in the fluid simulation."); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3d43dfdfc2c..8e805597e11 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1224,7 +1224,8 @@ static void rna_def_object(BlenderRNA *brna) /* game engine */ - prop= RNA_def_property(srna, "game", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "game", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "GameObjectSettings"); RNA_def_property_pointer_funcs(prop, "rna_Object_game_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Game Settings", "Game engine related settings for the object."); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index bbbb13c6e97..02fa0c25335 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1871,10 +1871,10 @@ static void rna_def_particle_system(BlenderRNA *brna) /* access to particle settings is redirected through functions */ /* to allow proper id-buttons functionality */ - prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); //RNA_def_property_pointer_sdna(prop, NULL, "part"); RNA_def_property_struct_type(prop, "ParticleSettings"); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE|PROP_NEVER_NULL); RNA_def_property_pointer_funcs(prop, "rna_particle_settings_get", "rna_particle_settings_set", NULL); RNA_def_property_ui_text(prop, "Settings", "Particle system settings."); RNA_def_property_update(prop, 0, "rna_Particle_reset"); @@ -1904,9 +1904,10 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hair Dynamics", "Enable hair dynamics using cloth simulation."); RNA_def_property_update(prop, 0, "rna_Particle_hair_dynamics"); - prop= RNA_def_property(srna, "cloth", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "cloth", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "clmd"); RNA_def_property_struct_type(prop, "ClothModifier"); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Cloth", "Cloth dynamics for hair"); @@ -2082,7 +2083,8 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* pointcache */ - prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "pointcache"); RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_ui_text(prop, "Point Cache", ""); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index b568fb38dfb..b5c0716bed1 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -428,7 +428,8 @@ static void rna_def_bone_group(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); // TODO: editing the colors for this should result in changes to the color type... - prop= RNA_def_property(srna, "colors", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "colors", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "ThemeBoneColorSet"); RNA_def_property_pointer_sdna(prop, NULL, "cs"); /* NOTE: the DNA data is not really a pointer, but this code works :) */ RNA_def_property_ui_text(prop, "Colors", "Copy of the colors associated with the group's color set."); @@ -486,7 +487,8 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_POSE|ND_TRANSFORM, "rna_Pose_update"); /* Relationships to other bones */ - prop= RNA_def_property(srna, "bone", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone", "Bone associated with this Pose Channel."); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 196d25ada86..37a1c9fb186 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -853,7 +853,6 @@ static void rna_def_property(BlenderRNA *brna) {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, {PROP_XYZ, "XYZ", 0, "XYZ", ""}, {PROP_RGB, "RGB", 0, "RGB", ""}, - {PROP_NEVER_NULL, "NEVER_NULL", 0, "Never Null", ""}, {PROP_LAYER, "LAYER", 0, "Layer", ""}, {PROP_LAYER_MEMBER, "LAYER_MEMBERSHIP", 0, "Layer Membership", ""}, {0, NULL, 0, NULL, NULL}}; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 15329b126d3..e82f25a11fd 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2032,19 +2032,22 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET, NULL); /* Tool Settings */ - prop= RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "toolsettings"); RNA_def_property_struct_type(prop, "ToolSettings"); RNA_def_property_ui_text(prop, "Tool Settings", ""); /* Unit Settings */ - prop= RNA_def_property(srna, "unit_settings", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "unit_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "unit"); RNA_def_property_struct_type(prop, "UnitSettings"); RNA_def_property_ui_text(prop, "Unit Settings", "Unit editing settings"); /* Render Data */ - prop= RNA_def_property(srna, "render_data", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "render_data", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "r"); RNA_def_property_struct_type(prop, "SceneRenderData"); RNA_def_property_ui_text(prop, "Render Data", ""); @@ -2056,7 +2059,8 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Timeline Markers", "Markers used in all timelines for the current scene."); /* Game Settings */ - prop= RNA_def_property(srna, "game_data", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "game_data", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "gm"); RNA_def_property_struct_type(prop, "SceneGameData"); RNA_def_property_ui_text(prop, "Game Data", ""); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 7a243327bd1..2a72845dd42 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -135,10 +135,10 @@ static void rna_def_screen(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Screen", "Screen datablock, defining the layout of areas in a window."); RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN); - prop= RNA_def_property(srna, "scene", PROP_POINTER, PROP_NEVER_NULL); - RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the screen."); - RNA_def_property_flag(prop, PROP_EDITABLE); + prop= RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE|PROP_NEVER_NULL); RNA_def_property_pointer_funcs(prop, NULL, "rna_Screen_scene_set", NULL); + RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the screen."); RNA_def_property_update(prop, 0, "rna_Screen_scene_update"); prop= RNA_def_property(srna, "areas", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 943129c7169..7bccd685c1d 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -211,11 +211,13 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x "); RNA_def_property_update(prop, 0, NULL); - prop= RNA_def_property(srna, "point_cache_low", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "point_cache_low", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]"); RNA_def_property_ui_text(prop, "Point Cache", ""); - prop= RNA_def_property(srna, "point_cache_high", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "point_cache_high", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "point_cache[1]"); RNA_def_property_ui_text(prop, "Point Cache", ""); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index bb01ab9a9c7..c2f565e4912 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -491,7 +491,8 @@ static void rna_def_background_image(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); - prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); RNA_def_property_ui_text(prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed."); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); @@ -779,7 +780,8 @@ static void rna_def_space_image(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, NULL); - prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); RNA_def_property_ui_text(prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed."); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, NULL); @@ -808,7 +810,8 @@ static void rna_def_space_image(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, NULL); /* uv */ - prop= RNA_def_property(srna, "uv_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "uv_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "SpaceUVEditor"); RNA_def_property_pointer_funcs(prop, "rna_SpaceImageEditor_uvedit_get", NULL, NULL); RNA_def_property_ui_text(prop, "UV Editor", "UV editor settings."); diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index 22cf7e7aeae..8c9b2b58887 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -198,7 +198,8 @@ static void rna_def_text(BlenderRNA *brna) RNA_def_property_struct_type(prop, "TextLine"); RNA_def_property_ui_text(prop, "Lines", "Lines of text."); - prop= RNA_def_property(srna, "current_line", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "current_line", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "curl"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "TextLine"); @@ -209,7 +210,8 @@ static void rna_def_text(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Current Character", "Index of current character in current line, and also start index of character in selection if one exists."); - prop= RNA_def_property(srna, "selection_end_line", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "selection_end_line", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "sell"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "TextLine"); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index e3cae8ab453..16bc988a54b 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -89,7 +89,7 @@ static void api_ui_item_rna_common(FunctionRNA *func) PropertyRNA *parm; parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); RNA_def_property_flag(parm, PROP_REQUIRED); } @@ -146,7 +146,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); - RNA_def_boolean(func, "icon_only", 0, "", "Only show the property's icon, with no text"); + RNA_def_boolean(func, "icon_only", 0, "", "Draw only icons in buttons, no text."); func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); api_ui_item_rna_common(func); @@ -165,7 +165,7 @@ void RNA_api_ui_layout(StructRNA *srna) api_ui_item_common(func); api_ui_item_rna_common(func); parm= RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_string(func, "search_property", "", 0, "", "Identifier of search collection property."); RNA_def_property_flag(parm, PROP_REQUIRED); @@ -254,21 +254,21 @@ void RNA_api_ui_layout(StructRNA *srna) func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); parm= RNA_def_pointer(func, "data", "Modifier", "", "Modifier data."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); RNA_def_function_return(func, parm); func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); parm= RNA_def_pointer(func, "data", "Constraint", "", "Constraint data."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); RNA_def_function_return(func, parm); func= RNA_def_function(srna, "template_preview", "uiTemplatePreview"); parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock."); RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "parent", "ID", "", "ID datablock."); - parm= RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot."); + RNA_def_pointer(func, "parent", "ID", "", "ID datablock."); + RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot."); func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer."); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 1a000525fda..b38475469b0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -197,25 +197,29 @@ static void rna_def_userdef_theme_ui_style(BlenderRNA *brna) RNA_def_property_range(prop, 0.5, 2.0); RNA_def_property_ui_text(prop, "Panel Zoom", "Default zoom level for panel areas."); - prop= RNA_def_property(srna, "paneltitle", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "paneltitle", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "paneltitle"); RNA_def_property_struct_type(prop, "ThemeFontStyle"); RNA_def_property_ui_text(prop, "Panel Font", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "grouplabel", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "grouplabel", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "grouplabel"); RNA_def_property_struct_type(prop, "ThemeFontStyle"); RNA_def_property_ui_text(prop, "Group Label Font", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "widgetlabel", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "widgetlabel", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "widgetlabel"); RNA_def_property_struct_type(prop, "ThemeFontStyle"); RNA_def_property_ui_text(prop, "Widget Label Font", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "widget", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "widget", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "widget"); RNA_def_property_struct_type(prop, "ThemeFontStyle"); RNA_def_property_ui_text(prop, "Widget Font", ""); @@ -334,97 +338,113 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ThemeUI"); RNA_def_struct_ui_text(srna, "Theme User Interface", "Theme settings for user interface elements."); - prop= RNA_def_property(srna, "wcol_regular", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_regular", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_regular"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Regular Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_tool", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_tool", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_tool"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Tool Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_radio", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_radio", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_radio"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Radio Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_text", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_text", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_text"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Text Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_option", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_option", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_option"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Option Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_toggle", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_toggle", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_toggle"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Toggle Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_num", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_num", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_num"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Number Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_numslider", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_numslider", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_numslider"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Slider Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_box", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_box", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_box"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Box Backdrop Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_menu", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_menu", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_menu"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Menu Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_pulldown", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_pulldown", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_pulldown"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Pulldown Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_menu_back", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_menu_back", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_menu_back"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Menu Backdrop Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_menu_item", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_menu_item", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_menu_item"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Menu Item Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_scroll", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_scroll", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_scroll"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "Scroll Widget Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_list_item", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_list_item", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_list_item"); RNA_def_property_struct_type(prop, "ThemeWidgetColors"); RNA_def_property_ui_text(prop, "List Item Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "wcol_state", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "wcol_state", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "wcol_state"); RNA_def_property_struct_type(prop, "ThemeWidgetStateColors"); RNA_def_property_ui_text(prop, "State Colors", ""); @@ -1380,87 +1400,104 @@ static void rna_def_userdef_themes(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", "Name of the theme."); RNA_def_struct_name_property(srna, prop); - prop= RNA_def_property(srna, "user_interface", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "user_interface", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tui"); RNA_def_property_struct_type(prop, "ThemeUserInterface"); RNA_def_property_ui_text(prop, "User Interface", ""); - prop= RNA_def_property(srna, "view_3d", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "view_3d", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tv3d"); RNA_def_property_struct_type(prop, "ThemeView3D"); RNA_def_property_ui_text(prop, "3D View", ""); - prop= RNA_def_property(srna, "graph_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "graph_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tipo"); RNA_def_property_struct_type(prop, "ThemeGraphEditor"); RNA_def_property_ui_text(prop, "Graph Editor", ""); - prop= RNA_def_property(srna, "file_browser", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "file_browser", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tfile"); RNA_def_property_struct_type(prop, "ThemeFileBrowser"); RNA_def_property_ui_text(prop, "File Browser", ""); - prop= RNA_def_property(srna, "nla_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "nla_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tnla"); RNA_def_property_struct_type(prop, "ThemeNLAEditor"); RNA_def_property_ui_text(prop, "NLA Editor", ""); - prop= RNA_def_property(srna, "dopesheet_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "dopesheet_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tact"); RNA_def_property_struct_type(prop, "ThemeDopeSheet"); RNA_def_property_ui_text(prop, "DopeSheet", ""); - prop= RNA_def_property(srna, "image_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "image_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tima"); RNA_def_property_struct_type(prop, "ThemeImageEditor"); RNA_def_property_ui_text(prop, "Image Editor", ""); - prop= RNA_def_property(srna, "sequence_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "sequence_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tseq"); RNA_def_property_struct_type(prop, "ThemeSequenceEditor"); RNA_def_property_ui_text(prop, "Sequence Editor", ""); - prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tbuts"); RNA_def_property_struct_type(prop, "ThemeProperties"); RNA_def_property_ui_text(prop, "Properties", ""); - prop= RNA_def_property(srna, "text_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "text_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "text"); RNA_def_property_struct_type(prop, "ThemeTextEditor"); RNA_def_property_ui_text(prop, "Text Editor", ""); - prop= RNA_def_property(srna, "timeline", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "timeline", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "ttime"); RNA_def_property_struct_type(prop, "ThemeTimeline"); RNA_def_property_ui_text(prop, "Timeline", ""); - prop= RNA_def_property(srna, "node_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "node_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tnode"); RNA_def_property_struct_type(prop, "ThemeNodeEditor"); RNA_def_property_ui_text(prop, "Node Editor", ""); - prop= RNA_def_property(srna, "logic_editor", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "logic_editor", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tlogic"); RNA_def_property_struct_type(prop, "ThemeLogicEditor"); RNA_def_property_ui_text(prop, "Logic Editor", ""); - prop= RNA_def_property(srna, "outliner", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "outliner", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "toops"); RNA_def_property_struct_type(prop, "ThemeOutliner"); RNA_def_property_ui_text(prop, "Outliner", ""); - prop= RNA_def_property(srna, "info", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "info", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tinfo"); RNA_def_property_struct_type(prop, "ThemeInfo"); RNA_def_property_ui_text(prop, "Info", ""); - prop= RNA_def_property(srna, "user_preferences", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "user_preferences", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "tuserpref"); RNA_def_property_struct_type(prop, "ThemeUserPreferences"); RNA_def_property_ui_text(prop, "User Preferences", ""); - prop= RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_collection_sdna(prop, NULL, "tarm", ""); RNA_def_property_struct_type(prop, "ThemeBoneColorSet"); RNA_def_property_ui_text(prop, "Bone Color Sets", ""); @@ -2100,7 +2137,8 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_CUSTOM_RANGE); RNA_def_property_ui_text(prop, "Use Weight Color Range", "Enable color range used for weight visualization in weight painting mode."); - prop= RNA_def_property(srna, "weight_color_range", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "weight_color_range", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "coba_weight"); RNA_def_property_struct_type(prop, "ColorRamp"); RNA_def_property_ui_text(prop, "Weight Color Range", "Color range used for weight visualization in weight painting mode."); @@ -2331,27 +2369,32 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Styles", ""); /* nested structs */ - prop= RNA_def_property(srna, "view", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "view", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesView"); RNA_def_property_pointer_funcs(prop, "rna_UserDef_view_get", NULL, NULL); RNA_def_property_ui_text(prop, "View & Controls", "Preferences related to viewing data."); - prop= RNA_def_property(srna, "edit", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "edit", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesEdit"); RNA_def_property_pointer_funcs(prop, "rna_UserDef_edit_get", NULL, NULL); RNA_def_property_ui_text(prop, "Edit Methods", "Settings for interacting with Blender data."); - prop= RNA_def_property(srna, "language", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "language", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesLanguage"); RNA_def_property_pointer_funcs(prop, "rna_UserDef_language_get", NULL, NULL); RNA_def_property_ui_text(prop, "Language & Font", "User interface translation settings."); - prop= RNA_def_property(srna, "filepaths", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "filepaths", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesFilePaths"); RNA_def_property_pointer_funcs(prop, "rna_UserDef_filepaths_get", NULL, NULL); RNA_def_property_ui_text(prop, "File Paths", "Default paths for external files."); - prop= RNA_def_property(srna, "system", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "system", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesSystem"); RNA_def_property_pointer_funcs(prop, "rna_UserDef_system_get", NULL, NULL); RNA_def_property_ui_text(prop, "System & OpenGL", "Graphics driver and operating system settings."); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 53532e3f383..fff51ad8ade 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -278,7 +278,8 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); - prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "OperatorProperties"); RNA_def_property_ui_text(prop, "Properties", ""); RNA_def_property_pointer_funcs(prop, "rna_Operator_properties_get", NULL, NULL); @@ -404,7 +405,8 @@ static void rna_def_window(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Window", "Open window."); RNA_def_struct_sdna(srna, "wmWindow"); - prop= RNA_def_property(srna, "screen", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "Screen"); RNA_def_property_ui_text(prop, "Screen", "Active screen showing in the window."); RNA_def_property_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index d2eebbc61aa..c6068d0a650 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -461,17 +461,20 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_update(prop, NC_WORLD, NULL); /* nested structs */ - prop= RNA_def_property(srna, "ambient_occlusion", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "ambient_occlusion", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "WorldAmbientOcclusion"); RNA_def_property_pointer_funcs(prop, "rna_World_ambient_occlusion_get", NULL, NULL); RNA_def_property_ui_text(prop, "Ambient Occlusion", "World ambient occlusion settings."); - prop= RNA_def_property(srna, "mist", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "mist", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "WorldMistSettings"); RNA_def_property_pointer_funcs(prop, "rna_World_mist_get", NULL, NULL); RNA_def_property_ui_text(prop, "Mist", "World mist settings."); - prop= RNA_def_property(srna, "stars", PROP_POINTER, PROP_NEVER_NULL); + prop= RNA_def_property(srna, "stars", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "WorldStarsSettings"); RNA_def_property_pointer_funcs(prop, "rna_World_stars_get", NULL, NULL); RNA_def_property_ui_text(prop, "Stars", "World stars settings."); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c2335bea995..65c701c0041 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -628,17 +628,18 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v case PROP_POINTER: { StructRNA *ptype= RNA_property_pointer_type(ptr, prop); + int flag = RNA_property_flag(prop); if(!BPy_StructRNA_Check(value) && value != Py_None) { - PointerRNA tmp; - RNA_pointer_create(NULL, ptype, NULL, &tmp); - PyErr_Format(PyExc_TypeError, "%.200s expected a %.200s type", error_prefix, RNA_struct_identifier(tmp.type)); + PyErr_Format(PyExc_TypeError, "%.200s expected a %.200s type", error_prefix, RNA_struct_identifier(ptype)); + return -1; + } else if((flag & PROP_NEVER_NULL) && value == Py_None) { + PyErr_Format(PyExc_TypeError, "property can't be assigned a None value"); return -1; } else { BPy_StructRNA *param= (BPy_StructRNA*)value; int raise_error= FALSE; if(data) { - int flag = RNA_property_flag(prop); if(flag & PROP_RNAPTR) { if(value == Py_None) -- cgit v1.2.3 From 615624805129f989a735a9edf20c9f562725063b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:05:28 +0000 Subject: UI: fix region edges cursor to show the right direction, was always vertical now. --- source/blender/editors/screen/screen_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 5d938ba36cc..2cc5500c3ef 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1140,7 +1140,7 @@ static void screen_cursor_set(wmWindow *win, wmEvent *event) if(az->type==AZONE_AREA) WM_cursor_set(win, CURSOR_EDIT); else if(az->type==AZONE_REGION) { - if(az->x1==az->x2) + if(az->edge == 'l' || az->edge == 'r') WM_cursor_set(win, CURSOR_X_MOVE); else WM_cursor_set(win, CURSOR_Y_MOVE); -- cgit v1.2.3 From 4596f0ee5ea4139ccf3df787df503940a0f8fef2 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:07:49 +0000 Subject: File Browser * Fix warning for non-existing "relative_paths" property. * Fix problem where the image browser would keep trying to load images it failed opening. --- source/blender/editors/space_file/file_ops.c | 7 ++++--- source/blender/editors/space_file/filelist.c | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 0e0ad88906e..faca6db75bf 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -531,9 +531,10 @@ int file_exec(bContext *C, wmOperator *unused) RNA_string_set(op->ptr, "directory", name); strcat(name, sfile->params->file); - if ( RNA_boolean_get(op->ptr, "relative_paths") ) { - BLI_makestringcode(G.sce, name); - } + if(RNA_struct_find_property(op->ptr, "relative_paths")) + if(RNA_boolean_get(op->ptr, "relative_paths")) + BLI_makestringcode(G.sce, name); + RNA_string_set(op->ptr, "path", name); /* some ops have multiple files to select */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index c0b16e639c0..582a5997ef5 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -592,10 +592,12 @@ void filelist_loadimage_timer(struct FileList* filelist) } if (limg->done) { FileImage *oimg = limg; - BLI_remlink(&filelist->loadimages, oimg); BLI_remove_thread(&filelist->threads, oimg); + /* brecht: keep failed images in the list, otherwise + it keeps trying to load them over and over? + BLI_remlink(&filelist->loadimages, oimg); + MEM_freeN(oimg);*/ limg = oimg->next; - MEM_freeN(oimg); refresh = 1; } else { limg= limg->next; -- cgit v1.2.3 From e0d36b73a1e364f70de315afb915b68d74a8e170 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 16 Sep 2009 18:22:53 +0000 Subject: #19317: Some more missing notifiers for the "2 open properties windows" scenario. Scene Buttons should be fine now. --- source/blender/makesrna/intern/rna_scene.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index e82f25a11fd..68b29919ff4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1302,7 +1302,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "planes"); RNA_def_property_enum_items(prop, color_mode_items); RNA_def_property_ui_text(prop, "Color Mode", "Choose BW for saving greyscale images, RGB for saving red, green and blue channels, AND RGBA for saving red, green, blue + alpha channels"); - + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + prop= RNA_def_property(srna, "resolution_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "xsch"); RNA_def_property_range(prop, 4, 10000); @@ -1319,6 +1320,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "size"); RNA_def_property_ui_range(prop, 1, 100, 10, 1); RNA_def_property_ui_text(prop, "Resolution %", "Percentage scale for render resolution"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "parts_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "xparts"); @@ -1574,6 +1576,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, field_order_items); RNA_def_property_ui_text(prop, "Field Order", "Order of video fields. Select which lines get rendered first, to create smooth motion for TV output"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "fields_still", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_FIELDSTILL); @@ -1643,6 +1646,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, threads_mode_items); RNA_def_property_ui_text(prop, "Threads Mode", "Determine the amount of render threads used"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "motion_blur", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_MBLUR); @@ -1726,6 +1730,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "displaymode"); RNA_def_property_enum_items(prop, display_mode_items); RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "output_path", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "pic"); -- cgit v1.2.3 From 6b5ce9366d176a753348fcf1f2753f76cd164a2f Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 16 Sep 2009 18:32:03 +0000 Subject: Fixed Resolution and Aspect Ratio Notifier for camera mode in 3D View. NC_OBJECT, won't do it alone, added ND_DRAW. --- source/blender/makesrna/intern/rna_scene.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 68b29919ff4..08efa13d8f4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1308,13 +1308,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "xsch"); RNA_def_property_range(prop, 4, 10000); RNA_def_property_ui_text(prop, "Resolution X", "Number of horizontal pixels in the rendered image."); - RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT, NULL); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, NULL); prop= RNA_def_property(srna, "resolution_y", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "ysch"); RNA_def_property_range(prop, 4, 10000); RNA_def_property_ui_text(prop, "Resolution Y", "Number of vertical pixels in the rendered image."); - RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT, NULL); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, NULL); prop= RNA_def_property(srna, "resolution_percentage", PROP_INT, PROP_PERCENTAGE); RNA_def_property_int_sdna(prop, NULL, "size"); @@ -1338,13 +1338,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "xasp"); RNA_def_property_range(prop, 1.0f, 200.0f); RNA_def_property_ui_text(prop, "Pixel Aspect X", "Horizontal aspect ratio - for anamorphic or non-square pixel output"); - RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT, NULL); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, NULL); prop= RNA_def_property(srna, "pixel_aspect_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "yasp"); RNA_def_property_range(prop, 1.0f, 200.0f); RNA_def_property_ui_text(prop, "Pixel Aspect Y", "Vertical aspect ratio - for anamorphic or non-square pixel output"); - RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT, NULL); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, NULL); /* JPEG and AVI JPEG */ -- cgit v1.2.3 From de59f34be0a2da17a90950aef1c87a0bb6c74052 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:32:10 +0000 Subject: UI: action editor header now also uses template for browsing action datablocks, was last place using deprecated uiDefIDPoinButs. --- source/blender/editors/space_action/action_edit.c | 34 +++++++++++ .../blender/editors/space_action/action_header.c | 67 +++------------------- .../blender/editors/space_action/action_intern.h | 2 + source/blender/editors/space_action/action_ops.c | 1 + source/blender/makesrna/intern/rna_space.c | 46 +++++++++++---- 5 files changed, 82 insertions(+), 68 deletions(-) diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 89633d0cdfe..9e05c482ecb 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1331,4 +1331,38 @@ void ACT_OT_mirror (wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); } +/* ******************** New Action Operator *********************** */ + +static int act_new_exec(bContext *C, wmOperator *op) +{ + bAction *action; + + // XXX need to restore behaviour to copy old actions... + action= add_empty_action("Action"); + + /* combined with RNA property, this will assign & increase user, + so decrease here to compensate for that */ + action->id.us--; + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); + + return OPERATOR_FINISHED; +} + +void ACT_OT_new (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "New"; + ot->idname= "ACT_OT_new"; + ot->description= "Create new action."; + + /* api callbacks */ + ot->exec= act_new_exec; + ot->poll= ED_operator_action_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index 8674f481a18..57546d440b0 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -260,61 +260,6 @@ static void do_action_buttons(bContext *C, void *arg, int event) } } -static void saction_idpoin_handle(bContext *C, ID *id, int event) -{ - SpaceAction *saction= CTX_wm_space_action(C); - Object *obact= CTX_data_active_object(C); - - printf("actedit do id: \n"); - - switch (event) { - case UI_ID_BROWSE: - printf("browse \n"); - case UI_ID_DELETE: - printf("browse or delete \n"); - saction->action= (bAction*)id; - - /* we must set this action to be the one used by active object (if not pinned) */ - if (saction->pin == 0) { - AnimData *adt= BKE_id_add_animdata(&obact->id); /* this only adds if non-existant */ - - /* set action */ - printf("\tset action \n"); - adt->action= saction->action; - adt->action->id.us++; - } - - ED_area_tag_redraw(CTX_wm_area(C)); - ED_undo_push(C, "Assign Action"); - break; - case UI_ID_RENAME: - printf("actedit rename \n"); - break; - case UI_ID_ADD_NEW: - printf("actedit addnew \n"); - if (saction->pin == 0) { - AnimData *adt= BKE_id_add_animdata(&obact->id); /* this only adds if non-existant */ - - /* set new action */ - // XXX need to restore behaviour to copy old actions... - printf("\tset new action \n"); - adt->action= saction->action= add_empty_action("Action"); - } - break; - case UI_ID_OPEN: - printf("actedit open \n"); - /* XXX not implemented */ - break; - case UI_ID_ALONE: - printf("actedit alone \n"); - /* XXX not implemented */ - break; - case UI_ID_PIN: - printf("actedit pin \n"); - break; - } -} - void action_header_buttons(const bContext *C, ARegion *ar) { ScrArea *sa= CTX_wm_area(C); @@ -409,9 +354,15 @@ void action_header_buttons(const bContext *C, ARegion *ar) xco += 30; } else if (saction->mode == SACTCONT_ACTION) { - /* NAME ETC */ - xco= uiDefIDPoinButs(block, CTX_data_main(C), NULL, (ID*)saction->action, ID_AC, &saction->pin, xco, yco, - saction_idpoin_handle, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_ADD_NEW|UI_ID_DELETE|UI_ID_FAKE_USER|UI_ID_ALONE|UI_ID_PIN); + uiLayout *layout; + bScreen *sc= CTX_wm_screen(C); + PointerRNA ptr; + + RNA_pointer_create(&sc->id, &RNA_SpaceDopeSheetEditor, saction, &ptr); + + layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, 20+3, 20, 1, U.uistyles.first); + uiTemplateID(layout, (bContext*)C, &ptr, "action", "ACT_OT_new", NULL, NULL); + uiBlockLayoutResolve(C, block, &xco, NULL); xco += 8; } diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index e5f0ab8994e..4326bed62d3 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -99,6 +99,8 @@ void ACT_OT_frame_jump(struct wmOperatorType *ot); void ACT_OT_snap(struct wmOperatorType *ot); void ACT_OT_mirror(struct wmOperatorType *ot); +void ACT_OT_new(struct wmOperatorType *ot); + /* defines for snap keyframes * NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h) */ diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 42b033040b1..cd4a7b30eff 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -83,6 +83,7 @@ void action_operatortypes(void) WM_operatortype_append(ACT_OT_insert_keyframe); WM_operatortype_append(ACT_OT_copy); WM_operatortype_append(ACT_OT_paste); + WM_operatortype_append(ACT_OT_new); WM_operatortype_append(ACT_OT_previewrange_set); WM_operatortype_append(ACT_OT_view_all); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index c2f565e4912..6b6e8b5b98e 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -38,8 +38,7 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "BKE_paint.h" - +#include "WM_api.h" #include "WM_types.h" EnumPropertyItem space_type_items[] = { @@ -80,11 +79,15 @@ static EnumPropertyItem dc_all_items[] = {DC_RGB, DC_RGBA, DC_ALPHA, DC_Z, DC_LC #ifdef RNA_RUNTIME +#include "DNA_anim_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "BKE_animsys.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_context.h" +#include "BKE_paint.h" #include "ED_image.h" #include "ED_screen.h" @@ -227,13 +230,6 @@ static void rna_SpaceTextEditor_text_set(PointerRNA *ptr, PointerRNA value) st->top= 0; } -static void rna_SpaceFileBrowser_params_set(PointerRNA *ptr, PointerRNA value) -{ - SpaceFile *sfile= (SpaceFile*)(ptr->data); - - sfile->params= value.data; -} - /* Space Properties */ static StructRNA *rna_SpaceProperties_pin_id_typef(PointerRNA *ptr) @@ -311,12 +307,36 @@ static void rna_View3D_display_background_image_set(PointerRNA *ptr, int value) } /* Space Time */ + static void rna_SpaceTime_redraw_update(bContext *C, PointerRNA *ptr) { SpaceTime *st= (SpaceTime*)ptr->data; ED_screen_animation_timer_update(C, st->redraws); } +/* Space Dopesheet */ + +static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA value) +{ + SpaceAction *saction= (SpaceAction*)(ptr->data); + saction->action= value.data; +} + +static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr) +{ + SpaceAction *saction= (SpaceAction*)(ptr->data); + Object *obact= CTX_data_active_object(C); + + /* we must set this action to be the one used by active object (if not pinned) */ + if(obact && saction->pin == 0) { + AnimData *adt= BKE_id_add_animdata(&obact->id); /* this only adds if non-existant */ + + /* set action */ + adt->action= saction->action; + id_us_plus(&adt->action->id); + } +} + #else static void rna_def_space(BlenderRNA *brna) @@ -1039,6 +1059,13 @@ static void rna_def_space_dopesheet(BlenderRNA *brna) srna= RNA_def_struct(brna, "SpaceDopeSheetEditor", "Space"); RNA_def_struct_sdna(srna, "SpaceAction"); RNA_def_struct_ui_text(srna, "Space DopeSheet Editor", "DopeSheet space data."); + + /* data */ + prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceDopeSheetEditor_action_set", NULL); + RNA_def_property_ui_text(prop, "Action", "Action displayed and edited in this space."); + RNA_def_property_update(prop, NC_SPACE|ND_SPACE_DOPESHEET, "rna_SpaceDopeSheetEditor_action_update"); /* mode */ prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); @@ -1425,7 +1452,6 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) prop= RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "params"); - RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceFileBrowser_params_set", NULL); RNA_def_property_ui_text(prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser."); } -- cgit v1.2.3 From 3a6bf17b3ef696c572207d5af3381c6327fe6a92 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:47:42 +0000 Subject: UI * Fix problem with curve mapping / color ramps not updating things like previews propertly. Now it uses the RNA update of the pointer from the material/texture/.. so each of those can define their own update, but still share the RNA struct. * Code for these templates is now in interface_templates.c * Fix exception for "axis" property, now it always shows normal widget with the PROP_DIRECTION subtype. * Remove context from uiBlockLayoutResolve, no longer needed. --- release/ui/buttons_data_lamp.py | 2 +- release/ui/buttons_material.py | 6 +- release/ui/buttons_scene.py | 3 +- release/ui/buttons_texture.py | 8 +- release/ui/space_userpref.py | 2 +- release/ui/space_view3d_toolbar.py | 4 +- source/blender/editors/include/UI_interface.h | 8 +- source/blender/editors/interface/interface.c | 24 +- .../blender/editors/interface/interface_handlers.c | 8 +- .../blender/editors/interface/interface_intern.h | 3 + .../blender/editors/interface/interface_layout.c | 48 +- .../blender/editors/interface/interface_regions.c | 2 +- .../editors/interface/interface_templates.c | 505 +++++++++++++++++++-- source/blender/editors/screen/area.c | 6 +- .../blender/editors/space_action/action_header.c | 2 +- source/blender/makesrna/intern/rna_ui_api.c | 8 +- 16 files changed, 546 insertions(+), 93 deletions(-) diff --git a/release/ui/buttons_data_lamp.py b/release/ui/buttons_data_lamp.py index d5aaa5ad679..0dbda46bccf 100644 --- a/release/ui/buttons_data_lamp.py +++ b/release/ui/buttons_data_lamp.py @@ -301,7 +301,7 @@ class DATA_PT_falloff_curve(DataButtonsPanel): def draw(self, context): lamp = context.lamp - self.layout.template_curve_mapping(lamp.falloff_curve) + self.layout.template_curve_mapping(lamp, "falloff_curve") bpy.types.register(DATA_PT_context_lamp) bpy.types.register(DATA_PT_preview) diff --git a/release/ui/buttons_material.py b/release/ui/buttons_material.py index dc11731d7a9..9f1c216c36b 100644 --- a/release/ui/buttons_material.py +++ b/release/ui/buttons_material.py @@ -28,7 +28,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel): # this manages materials for all engine types engine = context.scene.render_data.engine - return (context.object) and (engine in self.COMPAT_ENGINES) + return (context.material or context.object) and (engine in self.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -282,7 +282,7 @@ class MATERIAL_PT_diffuse(MaterialButtonsPanel): if mat.use_diffuse_ramp: layout.itemS() - layout.template_color_ramp(mat.diffuse_ramp, expand=True) + layout.template_color_ramp(mat, "diffuse_ramp", expand=True) layout.itemS() row = layout.row() split = row.split(percentage=0.3) @@ -334,7 +334,7 @@ class MATERIAL_PT_specular(MaterialButtonsPanel): if mat.use_specular_ramp: layout.itemS() - layout.template_color_ramp(mat.specular_ramp, expand=True) + layout.template_color_ramp(mat, "specular_ramp", expand=True) layout.itemS() row = layout.row() split = row.split(percentage=0.3) diff --git a/release/ui/buttons_scene.py b/release/ui/buttons_scene.py index 3c321f11f6e..c25e6352aaf 100644 --- a/release/ui/buttons_scene.py +++ b/release/ui/buttons_scene.py @@ -240,7 +240,8 @@ class SCENE_PT_output(RenderButtonsPanel): split = layout.split() col = split.column() - col.itemR(rd, "exr_codec") + col.itemL(text="Codec:") + col.itemR(rd, "exr_codec", text="") subsplit = split.split() col = subsplit.column() diff --git a/release/ui/buttons_texture.py b/release/ui/buttons_texture.py index 3cea47a236e..c595e2b1cc2 100644 --- a/release/ui/buttons_texture.py +++ b/release/ui/buttons_texture.py @@ -96,7 +96,7 @@ class TEXTURE_PT_colors(TextureButtonsPanel): layout.itemR(tex, "use_color_ramp", text="Ramp") if tex.use_color_ramp: - layout.template_color_ramp(tex.color_ramp, expand=True) + layout.template_color_ramp(tex, "color_ramp", expand=True) split = layout.split() @@ -410,10 +410,10 @@ class TEXTURE_PT_image(TextureTypePanel): def draw(self, context): layout = self.layout - + tex = context.texture - layout.template_texture_image(tex) + layout.template_image(tex, "image", tex.image_user) class TEXTURE_PT_image_sampling(TextureTypePanel): __label__ = "Image Sampling" @@ -689,7 +689,7 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel): if pd.color_source in ('PARTICLE_SPEED', 'PARTICLE_VELOCITY'): col.itemR(pd, "speed_scale") if pd.color_source in ('PARTICLE_SPEED', 'PARTICLE_AGE'): - layout.template_color_ramp(pd.color_ramp, expand=True) + layout.template_color_ramp(pd, "color_ramp", expand=True) col = split.column() col.itemL() diff --git a/release/ui/space_userpref.py b/release/ui/space_userpref.py index cfdabadcee1..267a0b4a78b 100644 --- a/release/ui/space_userpref.py +++ b/release/ui/space_userpref.py @@ -264,7 +264,7 @@ class USERPREF_PT_system(bpy.types.Panel): sub2 = sub1.column() sub2.active = system.use_weight_color_range - sub2.template_color_ramp(system.weight_color_range, expand=True) + sub2.template_color_ramp(system, "weight_color_range", expand=True) sub1.itemS() sub1.itemS() diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index fe0f4ca5a21..f177c81b7b7 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -422,7 +422,7 @@ class VIEW3D_PT_tools_brush(PaintPanel): row.itemR(brush, "strength", slider=True) row.itemR(brush, "strength_pressure", toggle=True, text="") - col.itemR(brush, "blend") + col.itemR(brush, "blend", text="Blend") # Weight Paint Mode # @@ -508,7 +508,7 @@ class VIEW3D_PT_tools_brush_curve(PaintPanel): settings = self.paint_settings(context) brush = settings.brush - layout.template_curve_mapping(brush.curve) + layout.template_curve_mapping(brush, "curve") layout.item_menu_enumO("brush.curve_preset", property="shape") class VIEW3D_PT_sculpt_options(PaintPanel): diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 77c4e4d3475..f475dd16057 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -487,6 +487,7 @@ int uiSearchBoxhHeight(void); void uiBlockSetHandleFunc(uiBlock *block, uiBlockHandleFunc func, void *arg); void uiBlockSetButmFunc (uiBlock *block, uiMenuHandleFunc func, void *arg); void uiBlockSetFunc (uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2); +void uiBlockSetNFunc (uiBlock *block, uiButHandleFunc func, void *argN, void *arg2); void uiButSetRenameFunc (uiBut *but, uiButHandleRenameFunc func, void *arg1); void uiButSetFunc (uiBut *but, uiButHandleFunc func, void *arg1, void *arg2); @@ -596,7 +597,7 @@ void UI_exit(void); uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, struct uiStyle *style); void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout); -void uiBlockLayoutResolve(const struct bContext *C, uiBlock *block, int *x, int *y); +void uiBlockLayoutResolve(uiBlock *block, int *x, int *y); uiBlock *uiLayoutGetBlock(uiLayout *layout); @@ -641,10 +642,11 @@ void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, uiLayout *uiTemplateModifier(uiLayout *layout, struct PointerRNA *ptr); uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr); void uiTemplatePreview(uiLayout *layout, struct ID *id, struct ID *parent, struct MTex *slot); -void uiTemplateColorRamp(uiLayout *layout, struct ColorBand *coba, int expand); -void uiTemplateCurveMapping(uiLayout *layout, struct CurveMapping *cumap, int type, int compact); +void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, char *propname, int expand); +void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, char *propname, int type, int levels); void uiTemplateTriColorSet(uiLayout *layout, struct PointerRNA *ptr, char *propname); void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, char *propname); +void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *userptr, int compact); void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser); void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C); void uiTemplateOperatorSearch(uiLayout *layout); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 221618b340e..2d4b2caa845 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -622,7 +622,7 @@ void uiEndBlock(const bContext *C, uiBlock *block) } /* handle pending stuff */ - if(block->layouts.first) uiBlockLayoutResolve(C, block, NULL, NULL); + if(block->layouts.first) uiBlockLayoutResolve(block, NULL, NULL); ui_block_do_align(block); if(block->flag & UI_BLOCK_LOOP) ui_menu_block_set_keymaps(C, block); @@ -1684,6 +1684,9 @@ void uiFreeBlock(const bContext *C, uiBlock *block) ui_free_but(C, but); } + if(block->func_argN) + MEM_freeN(block->func_argN); + CTX_store_free_list(&block->contexts); BLI_freelistN(&block->saferct); @@ -2232,6 +2235,10 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short but->func= block->func; but->func_arg1= block->func_arg1; but->func_arg2= block->func_arg2; + + but->funcN= block->funcN; + if(block->func_argN) + but->func_argN= MEM_dupallocN(block->func_argN); but->pos= -1; /* cursor invisible */ @@ -2945,6 +2952,16 @@ void uiBlockSetFunc(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2 block->func_arg2= arg2; } +void uiBlockSetNFunc(uiBlock *block, uiButHandleFunc func, void *argN, void *arg2) +{ + if(block->func_argN) + MEM_freeN(block->func_argN); + + block->funcN= func; + block->func_argN= argN; + block->func_arg2= arg2; +} + void uiButSetRenameFunc(uiBut *but, uiButHandleRenameFunc func, void *arg1) { but->rename_func= func; @@ -2967,6 +2984,9 @@ void uiButSetFunc(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2) void uiButSetNFunc(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2) { + if(but->func_argN) + MEM_freeN(but->func_argN); + but->funcN= funcN; but->func_argN= argN; but->func_arg2= arg2; @@ -3003,6 +3023,8 @@ uiBut *uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, char * { uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip); but->block_create_func= func; + if(but->func_argN) + MEM_freeN(but->func_argN); but->func_argN= argN; ui_check_but(but); return but; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 1041418b059..dbf5669b326 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -246,7 +246,13 @@ static void ui_apply_but_func(bContext *C, uiBut *but) if(but->func || but->funcN || block->handle_func || but->rename_func || (but->type == BUTM && block->butm_func) || but->optype || but->rnaprop) { after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc"); - after->func= but->func; + if(ELEM(but, but->func_arg1, but->func_arg2)) { + /* exception, this will crash due to removed button otherwise */ + but->func(C, but->func_arg1, but->func_arg2); + } + else + after->func= but->func; + after->func_arg1= but->func_arg1; after->func_arg2= but->func_arg2; after->func_arg3= but->func_arg3; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 2e623114fe9..7ab99a83c4b 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -263,6 +263,9 @@ struct uiBlock { void *func_arg1; void *func_arg2; + uiButHandleNFunc funcN; + void *func_argN; + uiMenuHandleFunc butm_func; void *butm_func_arg; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b6afc4daa9b..b957ff83650 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -481,6 +481,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, i { uiLayout *sub; uiBut *but; + PropertyType type; PropertySubType subtype; int labelw; @@ -496,6 +497,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, i w= w-labelw; } + type= RNA_property_type(prop); subtype= RNA_property_subtype(prop); if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) { @@ -505,8 +507,10 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, i /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */ but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, "Browse for file or directory."); } + else if(subtype == PROP_DIRECTION) + uiDefButR(block, BUT_NORMAL, 0, name, 0, 0, 100, 100, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL); else - but= uiDefAutoButR(block, ptr, prop, index, (!icon_only)? "": NULL, icon, x, y, w, h); + but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !icon_only)? NULL: "", icon, x, y, w, h); uiBlockSetCurLayout(block, layout); return but; @@ -840,9 +844,6 @@ void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, Proper char namestr[UI_MAX_NAME_STR]; int len, w, h, slider, toggle, expand, icon_only; - if(!ptr->data || !prop) - return; - uiBlockSetCurLayout(block, layout); /* retrieve info */ @@ -913,12 +914,7 @@ void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, Proper void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int flag) { - PropertyRNA *prop; - - if(!ptr->data || !propname) - return; - - prop= RNA_struct_find_property(ptr, propname); + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); if(!prop) { ui_item_disabled(layout, propname); @@ -931,12 +927,7 @@ void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *prop void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value) { - PropertyRNA *prop; - - if(!ptr->data || !propname) - return; - - prop= RNA_struct_find_property(ptr, propname); + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); if(!prop || RNA_property_type(prop) != PROP_ENUM) { ui_item_disabled(layout, propname); @@ -949,15 +940,10 @@ void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, void uiItemEnumR_string(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, char *value) { - PropertyRNA *prop; + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); EnumPropertyItem *item; int ivalue, a, free; - if(!ptr->data || !propname) - return; - - prop= RNA_struct_find_property(ptr, propname); - if(!prop || RNA_property_type(prop) != PROP_ENUM) { ui_item_disabled(layout, propname); printf("uiItemEnumR: enum property not found: %s\n", propname); @@ -1123,9 +1109,6 @@ void uiItemPointerR(uiLayout *layout, char *name, int icon, struct PointerRNA *p int w, h; /* validate arguments */ - if(!ptr->data || !searchptr->data) - return; - prop= RNA_struct_find_property(ptr, propname); if(!prop) { @@ -2227,18 +2210,13 @@ static void ui_item_layout(uiItem *item) } } -static void ui_layout_items(const bContext *C, uiBlock *block, uiLayout *layout) -{ - ui_item_estimate(&layout->item); - ui_item_layout(&layout->item); -} - -static void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y) +static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y) { if(layout->root->handlefunc) uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv); - ui_layout_items(C, block, layout); + ui_item_estimate(&layout->item); + ui_item_layout(&layout->item); if(x) *x= layout->x; if(y) *y= layout->y; @@ -2346,7 +2324,7 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv) layout->root->argv= argv; } -void uiBlockLayoutResolve(const bContext *C, uiBlock *block, int *x, int *y) +void uiBlockLayoutResolve(uiBlock *block, int *x, int *y) { uiLayoutRoot *root; @@ -2357,7 +2335,7 @@ void uiBlockLayoutResolve(const bContext *C, uiBlock *block, int *x, int *y) for(root=block->layouts.first; root; root=root->next) { /* NULL in advance so we don't interfere when adding button */ - ui_layout_end(C, block, root->layout, x, y); + ui_layout_end(block, root->layout, x, y); ui_layout_free(root->layout); } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index dfcdea59f68..95305819e2b 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2192,7 +2192,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi block->direction= direction; - uiBlockLayoutResolve(C, block, NULL, NULL); + uiBlockLayoutResolve(block, NULL, NULL); if(pup->popup) { uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_RET_1); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 2b7d6f383bf..1c7e757fbb2 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -36,6 +36,7 @@ #include "BKE_icons.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_utildefines.h" #include "ED_screen.h" @@ -75,7 +76,7 @@ typedef struct TemplateID { } TemplateID; /* Search browse menu, assign */ -static void id_search_call_cb(struct bContext *C, void *arg_template, void *item) +static void id_search_call_cb(bContext *C, void *arg_template, void *item) { TemplateID *template= (TemplateID*)arg_template; @@ -90,7 +91,7 @@ static void id_search_call_cb(struct bContext *C, void *arg_template, void *item } /* ID Search browse menu, do the search */ -static void id_search_cb(const struct bContext *C, void *arg_template, char *str, uiSearchItems *items) +static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSearchItems *items) { TemplateID *template= (TemplateID*)arg_template; Scene *scene= CTX_data_scene(C); @@ -291,7 +292,7 @@ static void template_ID(bContext *C, uiBlock *block, TemplateID *template, Struc int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6; if(newop) { - but= uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_REGION_WIN, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL); + but= uiDefIconTextButO(block, BUT, newop, WM_OP_EXEC_REGION_WIN, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL); uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); } else { @@ -344,9 +345,6 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname StructRNA *type; int flag; - if(!ptr->data) - return; - prop= RNA_struct_find_property(ptr, propname); if(!prop || RNA_property_type(prop) != PROP_POINTER) { @@ -1241,54 +1239,499 @@ void uiTemplatePreview(uiLayout *layout, ID *id, ID *parent, MTex *slot) /********************** ColorRamp Template **************************/ -void uiTemplateColorRamp(uiLayout *layout, ColorBand *coba, int expand) +#include "BKE_texture.h" + +typedef struct RNAUpdateCb { + PointerRNA ptr; + PropertyRNA *prop; +} RNAUpdateCb; + +static void rna_update_cb(bContext *C, void *arg_cb, void *arg_unused) +{ + RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb; + + /* we call update here on the pointer property, this way the + owner of the curve mapping can still define it's own update + and notifier, even if the CurveMapping struct is shared. */ + RNA_property_update(C, &cb->ptr, cb->prop); +} + +#define B_BANDCOL 1 + +static int vergcband(const void *a1, const void *a2) +{ + const CBData *x1=a1, *x2=a2; + + if( x1->pos > x2->pos ) return 1; + else if( x1->pos < x2->pos) return -1; + return 0; +} + +static void colorband_pos_cb(bContext *C, void *cb_v, void *coba_v) +{ + ColorBand *coba= coba_v; + int a; + + if(coba->tot<2) return; + + for(a=0; atot; a++) coba->data[a].cur= a; + qsort(coba->data, coba->tot, sizeof(CBData), vergcband); + for(a=0; atot; a++) { + if(coba->data[a].cur==coba->cur) { + coba->cur= a; + break; + } + } + + rna_update_cb(C, cb_v, NULL); +} + +static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v) +{ + ColorBand *coba= coba_v; + + if(coba->tot < MAXCOLORBAND-1) coba->tot++; + coba->cur= coba->tot-1; + + colorband_pos_cb(C, cb_v, coba_v); + + ED_undo_push(C, "Add colorband"); +} + +static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v) +{ + ColorBand *coba= coba_v; + int a; + + if(coba->tot<2) return; + + for(a=coba->cur; atot; a++) { + coba->data[a]= coba->data[a+1]; + } + if(coba->cur) coba->cur--; + coba->tot--; + + ED_undo_push(C, "Delete colorband"); + + rna_update_cb(C, cb_v, NULL); +} + + +/* offset aligns from bottom, standard width 300, height 115 */ +static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb) +{ + CBData *cbd; + uiBut *bt; + + if(coba==NULL) return; + + bt= uiDefBut(block, BUT, 0, "Add", 0+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Add a new color stop to the colorband"); + uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba); + + bt= uiDefBut(block, BUT, 0, "Delete", 60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position"); + uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); + + uiDefButS(block, NUM, 0, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Choose active color stop"); + + bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", + 210+xoffs, 100+yoffs, 90, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + uiBlockEndAlign(block); + + bt= uiDefBut(block, BUT_COLORBAND, 0, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + cbd= coba->data + coba->cur; + + bt= uiDefButF(block, NUM, 0, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); + uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba); + bt= uiDefButF(block, COL, 0, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + +} + +static void colorband_buttons_small(uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb) +{ + CBData *cbd; + uiBut *bt; + float unit= (butr->xmax-butr->xmin)/14.0f; + float xs= butr->xmin; + + cbd= coba->data + coba->cur; + + + bt= uiDefBut(block, BUT, 0, "Add", xs,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband"); + uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba); + bt= uiDefBut(block, BUT, 0, "Delete", xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Delete the active position"); + uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); + + bt= uiDefButF(block, COL, 0, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", + xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + bt= uiDefBut(block, BUT_COLORBAND, 0, "", xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, ""); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + uiBlockEndAlign(block); +} + +static void colorband_buttons_layout(uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb) +{ + if(small) + colorband_buttons_small(block, coba, butr, cb); + else + colorband_buttons_large(block, coba, 0, 0, cb); +} + +void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, char *propname, int expand) { + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); + PointerRNA cptr; + RNAUpdateCb *cb; uiBlock *block; rctf rect; - if(coba) { - rect.xmin= 0; rect.xmax= 200; - rect.ymin= 0; rect.ymax= 190; - - block= uiLayoutFreeBlock(layout); - colorband_buttons(block, coba, &rect, !expand); - } + if(!prop || RNA_property_type(prop) != PROP_POINTER) + return; + + cptr= RNA_property_pointer_get(ptr, prop); + if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp)) + return; + + cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); + cb->ptr= *ptr; + cb->prop= prop; + + rect.xmin= 0; rect.xmax= 200; + rect.ymin= 0; rect.ymax= 190; + + block= uiLayoutFreeBlock(layout); + colorband_buttons_layout(block, cptr.data, &rect, !expand, cb); + + MEM_freeN(cb); } /********************* CurveMapping Template ************************/ #include "DNA_color_types.h" +#include "BKE_colortools.h" -void uiTemplateCurveMapping(uiLayout *layout, CurveMapping *cumap, int type, int compact) +static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused) { - rctf rect; + CurveMapping *cumap = cumap_v; + float d; + + /* we allow 20 times zoom */ + if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) { + d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin); + cumap->curr.xmin+= d; + cumap->curr.xmax-= d; + d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin); + cumap->curr.ymin+= d; + cumap->curr.ymax-= d; + } + + ED_region_tag_redraw(CTX_wm_region(C)); +} + +static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused) +{ + CurveMapping *cumap = cumap_v; + float d, d1; + + /* we allow 20 times zoom, but dont view outside clip */ + if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) { + d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin); + + if(cumap->flag & CUMA_DO_CLIP) + if(cumap->curr.xmin-d < cumap->clipr.xmin) + d1= cumap->curr.xmin - cumap->clipr.xmin; + cumap->curr.xmin-= d1; + + d1= d; + if(cumap->flag & CUMA_DO_CLIP) + if(cumap->curr.xmax+d > cumap->clipr.xmax) + d1= -cumap->curr.xmax + cumap->clipr.xmax; + cumap->curr.xmax+= d1; + + d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin); + + if(cumap->flag & CUMA_DO_CLIP) + if(cumap->curr.ymin-d < cumap->clipr.ymin) + d1= cumap->curr.ymin - cumap->clipr.ymin; + cumap->curr.ymin-= d1; + + d1= d; + if(cumap->flag & CUMA_DO_CLIP) + if(cumap->curr.ymax+d > cumap->clipr.ymax) + d1= -cumap->curr.ymax + cumap->clipr.ymax; + cumap->curr.ymax+= d1; + } + + ED_region_tag_redraw(CTX_wm_region(C)); +} + +static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused) +{ + CurveMapping *cumap = cumap_v; + + curvemapping_changed(cumap, 0); +} + +static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v) +{ + CurveMapping *cumap = cumap_v; + + curvemap_remove(cumap->cm+cumap->cur, SELECT); + curvemapping_changed(cumap, 0); + + rna_update_cb(C, cb_v, NULL); +} + +/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ +static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v) +{ + CurveMapping *cumap = cumap_v; + uiBlock *block; + uiBut *bt; + + block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS); + + /* use this for a fake extra empy space around the buttons */ + uiDefBut(block, LABEL, 0, "", -4, 16, 128, 106, NULL, 0, 0, 0, 0, ""); + + bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping", + 0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, ""); + uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL); + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, 0, "Min X ", 0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, ""); + uiDefButF(block, NUM, 0, "Min Y ", 0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, ""); + uiDefButF(block, NUM, 0, "Max X ", 0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, ""); + uiDefButF(block, NUM, 0, "Max Y ", 0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, ""); + + uiBlockSetDirection(block, UI_RIGHT); + + uiEndBlock(C, block); + return block; +} + +static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event) +{ + CurveMapping *cumap = cumap_v; + CurveMap *cuma= cumap->cm+cumap->cur; + + switch(event) { + case 0: + curvemap_reset(cuma, &cumap->clipr); + curvemapping_changed(cumap, 0); + break; + case 1: + cumap->curr= cumap->clipr; + break; + case 2: /* set vector */ + curvemap_sethandle(cuma, 1); + curvemapping_changed(cumap, 0); + break; + case 3: /* set auto */ + curvemap_sethandle(cuma, 0); + curvemapping_changed(cumap, 0); + break; + case 4: /* extend horiz */ + cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + curvemapping_changed(cumap, 0); + break; + case 5: /* extend extrapolate */ + cuma->flag |= CUMA_EXTEND_EXTRAPOLATE; + curvemapping_changed(cumap, 0); + break; + } + ED_region_tag_redraw(CTX_wm_region(C)); +} + +static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v) +{ + uiBlock *block; + short yco= 0, menuwidth=120; + + block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS); + uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, ""); + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 50); + + uiEndBlock(C, block); + return block; +} + +static void curvemap_buttons_redraw(bContext *C, void *arg1, void *arg2) +{ + ED_region_tag_redraw(CTX_wm_region(C)); +} + +static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v) +{ + CurveMapping *cumap = cumap_v; + int a; + + for(a=0; acm+a, &cumap->clipr); + + cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f; + cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f; + curvemapping_set_black_white(cumap, NULL, NULL); + + curvemapping_changed(cumap, 0); + + rna_update_cb(C, cb_v, NULL); +} + +/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */ +static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, RNAUpdateCb *cb) +{ + CurveMapping *cumap= ptr->data; + uiLayout *row, *sub, *split; + uiBlock *block; + uiBut *bt; + float dx= UI_UNIT_X; + int icon, size; - if(cumap) { - if(compact) { - rect.xmin= 0; rect.xmax= 150; - rect.ymin= 0; rect.ymax= 140; + block= uiLayoutGetBlock(layout); + + /* curve chooser */ + row= uiLayoutRow(layout, 0); + + if(labeltype=='v') { + /* vector */ + sub= uiLayoutRow(row, 1); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); + + if(cumap->cm[0].curve) { + bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); } - else { - rect.xmin= 0; rect.xmax= 200; - rect.ymin= 0; rect.ymax= 190; + if(cumap->cm[1].curve) { + bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); } - - curvemap_layout(layout, cumap, type, 0, 0, &rect); + if(cumap->cm[2].curve) { + bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); + } + } + else if(labeltype=='c') { + /* color */ + sub= uiLayoutRow(row, 1); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); + + if(cumap->cm[3].curve) { + bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); + } + if(cumap->cm[0].curve) { + bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); + } + if(cumap->cm[1].curve) { + bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); + } + if(cumap->cm[2].curve) { + bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); + uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL); + } + } + else + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + + /* operation buttons */ + sub= uiLayoutRow(row, 1); + + uiBlockSetEmboss(block, UI_EMBOSSN); + + bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in"); + uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL); + + bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out"); + uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL); + + bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT; + bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, 18, "Clipping Options"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + + bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points"); + uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap); + + uiBlockSetEmboss(block, UI_EMBOSS); + + uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL); + + /* curve itself */ + size= uiLayoutGetWidth(layout); + row= uiLayoutRow(layout, 0); + uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, 0, 0, ""); + + /* black/white levels */ + if(levels) { + split= uiLayoutSplit(layout, 0); + uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "black_level", UI_ITEM_R_EXPAND); + uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "white_level", UI_ITEM_R_EXPAND); + + uiLayoutRow(layout, 0); + bt=uiDefBut(block, BUT, 0, "Reset", 0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves"); + uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap); } + + uiBlockSetNFunc(block, NULL, NULL, NULL); +} + +void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, char *propname, int type, int levels) +{ + RNAUpdateCb *cb; + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); + PointerRNA cptr; + + if(!prop || RNA_property_type(prop) != PROP_POINTER) + return; + + cptr= RNA_property_pointer_get(ptr, prop); + if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping)) + return; + + cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); + cb->ptr= *ptr; + cb->prop= prop; + + curvemap_buttons_layout(layout, &cptr, type, levels, cb); + + MEM_freeN(cb); } /********************* TriColor (ThemeWireColorSet) Template ************************/ void uiTemplateTriColorSet(uiLayout *layout, PointerRNA *ptr, char *propname) { + PropertyRNA *prop= RNA_struct_find_property(ptr, propname); uiLayout *row; - PropertyRNA *prop; PointerRNA csPtr; - - if (!ptr->data) - return; - - prop= RNA_struct_find_property(ptr, propname); + if (!prop) { printf("uiTemplateTriColorSet: property not found: %s\n", propname); return; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 8940f560677..07d0d1a85c5 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1254,7 +1254,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, char *contex pt->draw_header(C, panel); - uiBlockLayoutResolve(C, block, &xco, &yco); + uiBlockLayoutResolve(block, &xco, &yco); panel->labelofs= xco - triangle; panel->layout= NULL; } @@ -1265,7 +1265,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, char *contex pt->draw(C, panel); - uiBlockLayoutResolve(C, block, &xco, &yco); + uiBlockLayoutResolve(block, &xco, &yco); panel->layout= NULL; yco -= 2*style->panelspace; @@ -1411,7 +1411,7 @@ void ED_region_header(const bContext *C, ARegion *ar) maxco= xco; } - uiBlockLayoutResolve(C, block, &xco, &yco); + uiBlockLayoutResolve(block, &xco, &yco); /* for view2d */ if(xco > maxco) diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index 57546d440b0..4cb02f3f233 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -362,7 +362,7 @@ void action_header_buttons(const bContext *C, ARegion *ar) layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, 20+3, 20, 1, U.uistyles.first); uiTemplateID(layout, (bContext*)C, &ptr, "action", "ACT_OT_new", NULL, NULL); - uiBlockLayoutResolve(C, block, &xco, NULL); + uiBlockLayoutResolve(block, &xco, NULL); xco += 8; } diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 16bc988a54b..60994757b59 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -271,14 +271,12 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot."); func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); - parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); + api_ui_item_rna_common(func); RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display."); - RNA_def_boolean(func, "compact", 0, "", "Use more compact curve mapping."); + RNA_def_boolean(func, "levels", 0, "", "Show black/white levels."); func= RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp"); - parm= RNA_def_pointer(func, "ramp", "ColorRamp", "", "Color ramp pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); + api_ui_item_rna_common(func); RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); func= RNA_def_function(srna, "template_layers", "uiTemplateLayers"); -- cgit v1.2.3 From 5129b08064817aa4bbb28011a4dc215d320ee9e4 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 18:59:13 +0000 Subject: UI * Node buttons can now use the layout engine. a few simple ones are converted. We'll keep this code in C for now, python wouldn't help much here. * For node buttons not using the layout engine, manually computing the button height is not longer needed. * Node inputs are still not RNA wrapped, would be good to have these available as well for keying, but makesrna does not have access to the bNodeTypes. --- source/blender/blenkernel/BKE_node.h | 5 +- source/blender/editors/include/ED_node.h | 5 + source/blender/editors/space_node/drawnode.c | 2675 ++++++++++----------- source/blender/editors/space_node/node_draw.c | 209 +- source/blender/makesdna/DNA_node_types.h | 2 + source/blender/makesrna/intern/rna_nodetree.c | 356 ++- source/blenderplayer/bad_level_call_stubs/stubs.c | 1 + 7 files changed, 1710 insertions(+), 1543 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index cbb37918d04..ea1707c19bf 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -42,7 +42,7 @@ struct bNode; struct bNodeLink; struct bNodeSocket; struct bNodeStack; -struct uiBlock; +struct uiLayout; struct rctf; struct ListBase; struct RenderData; @@ -52,6 +52,7 @@ struct Tex; struct GPUMaterial; struct GPUNode; struct GPUNodeStack; +struct PointerRNA; /* ************** NODE TYPE DEFINITIONS ***** */ @@ -82,7 +83,7 @@ typedef struct bNodeType { void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **); /* this line is set on startup of blender */ - int (*butfunc)(struct uiBlock *, struct bNodeTree *, struct bNode *, struct rctf *); + void (*uifunc)(struct uiLayout *, struct PointerRNA *ptr); void (*initfunc)(struct bNode *); void (*freestoragefunc)(struct bNode *); diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index bf4632dc3da..305b2a64ffe 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -31,10 +31,15 @@ struct Material; struct Scene; struct Tex; +struct bContext; +struct bNode; /* drawnode.c */ void ED_init_node_butfuncs(void); +/* node_draw.c */ +void ED_node_changed_update(struct bContext *C, struct bNode *node); + /* node_edit.c */ void ED_node_shader_default(struct Material *ma); void ED_node_composit_default(struct Scene *sce); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 05adb5b75ca..494a68fc918 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -170,9 +170,13 @@ static void node_group_alone_cb(bContext *C, void *node_v, void *unused_v) /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */ -static int node_buts_group(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_group(uiLayout *layout, PointerRNA *ptr) { - if(block && node->id) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + if(node->id) { uiBut *bt; short width; @@ -197,112 +201,95 @@ static int node_buts_group(uiBlock *block, bNodeTree *ntree, bNode *node, rctf * uiBlockEndAlign(block); } - return 19; } #endif -static int node_buts_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_value(uiLayout *layout, PointerRNA *ptr) { - if(block) { - bNodeSocket *sock= node->outputs.first; /* first socket stores value */ - - uiDefButF(block, NUM, B_NODE_EXEC, "", - (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin, 20, - sock->ns.vec, sock->ns.min, sock->ns.max, 10, 2, ""); - - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + bNodeSocket *sock= node->outputs.first; /* first socket stores value */ + + uiDefButF(block, NUM, B_NODE_EXEC, "", + (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin, 20, + sock->ns.vec, sock->ns.min, sock->ns.max, 10, 2, ""); } -static int node_buts_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_rgb(uiLayout *layout, PointerRNA *ptr) { - if(block) { - bNodeSocket *sock= node->outputs.first; /* first socket stores value */ - if(sock) { - /* enforce square box drawing */ - uiBlockSetEmboss(block, UI_EMBOSSP); - - uiDefButF(block, HSVCUBE, B_NODE_EXEC, "", - (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin, 12, - sock->ns.vec, 0.0f, 1.0f, 3, 0, ""); - uiDefButF(block, HSVCUBE, B_NODE_EXEC, "", - (short)butr->xmin, (short)butr->ymin+15, butr->xmax-butr->xmin, butr->ymax-butr->ymin -15 -15, - sock->ns.vec, 0.0f, 1.0f, 2, 0, ""); - uiDefButF(block, COL, B_NOP, "", - (short)butr->xmin, (short)butr->ymax-12, butr->xmax-butr->xmin, 12, - sock->ns.vec, 0.0, 0.0, -1, 0, ""); - /* the -1 above prevents col button to popup a color picker */ - - uiBlockSetEmboss(block, UI_EMBOSS); - } - } - return 30 + (int)(node->width-NODE_DY); -} + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + bNodeSocket *sock= node->outputs.first; /* first socket stores value */ -static int node_buts_mix_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) -{ - if(block) { - uiBut *bt; - int a_but= (ntree->type==NTREE_COMPOSIT); + if(sock) { + /* enforce square box drawing */ + uiBlockSetEmboss(block, UI_EMBOSSP); - /* blend type */ - uiBlockBeginAlign(block); - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Mix %x0|Add %x1|Subtract %x3|Multiply %x2|Screen %x4|Overlay %x9|Divide %x5|Difference %x6|Darken %x7|Lighten %x8|Dodge %x10|Burn %x11|Color %x15|Value %x14|Saturation %x13|Hue %x12|Soft Light %x16|Linear Light %x17", - (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin -(a_but?20:0), 20, - &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); - /* Alpha option, composite */ - if(a_but) - uiDefIconButS(block, TOG, B_NODE_EXEC, ICON_IMAGE_RGB_ALPHA, - (short)butr->xmax-20, (short)butr->ymin, 20, 20, - &node->custom2, 0, 0, 0, 0, "Include Alpha of 2nd input in this operation"); + uiDefButF(block, HSVCUBE, B_NODE_EXEC, "", + (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin, 12, + sock->ns.vec, 0.0f, 1.0f, 3, 0, ""); + uiDefButF(block, HSVCUBE, B_NODE_EXEC, "", + (short)butr->xmin, (short)butr->ymin+15, butr->xmax-butr->xmin, butr->xmax-butr->xmin -15 -15, + sock->ns.vec, 0.0f, 1.0f, 2, 0, ""); + uiDefButF(block, COL, B_NOP, "", + (short)butr->xmin, (short)butr->ymax-12, butr->xmax-butr->xmin, 12, + sock->ns.vec, 0.0, 0.0, -1, 0, ""); + /* the -1 above prevents col button to popup a color picker */ + + uiBlockSetEmboss(block, UI_EMBOSS); } - return 20; } -static int node_buts_time(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_mix_rgb(uiLayout *layout, PointerRNA *ptr) { - if(block) { - CurveMapping *cumap= node->storage; - short dx= (short)((butr->xmax-butr->xmin)/2); - butr->ymin += 26; + bNodeTree *ntree= (bNodeTree*)ptr->id.data; + uiLayout *row; - curvemap_buttons(block, node->storage, 's', B_NODE_EXEC, B_REDR, butr); - - if(cumap) { - //cumap->flag |= CUMA_DRAW_CFRA; - //if(node->custom1custom2) - // cumap->sample[0]= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1); - } + row= uiLayoutRow(layout, 1); - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Sta:", - (short)butr->xmin, (short)butr->ymin-22, dx, 19, - &node->custom1, 1.0, 20000.0, 0, 0, "Start frame"); - uiDefButS(block, NUM, B_NODE_EXEC, "End:", - (short)butr->xmin+dx, (short)butr->ymin-22, dx, 19, - &node->custom2, 1.0, 20000.0, 0, 0, "End frame"); - } + uiItemR(row, "", 0, ptr, "blend_type", 0); + if(ntree->type == NTREE_COMPOSIT) + uiItemR(row, "", ICON_IMAGE_RGB_ALPHA, ptr, "alpha", 0); +} + +static void node_buts_time(uiLayout *layout, PointerRNA *ptr) +{ + uiLayout *row; +#if 0 + /* XXX no context access here .. */ + bNode *node= ptr->data; + CurveMapping *cumap= node->storage; - return node->width-NODE_DY; + if(cumap) { + cumap->flag |= CUMA_DRAW_CFRA; + if(node->custom1custom2) + cumap->sample[0]= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1); + } +#endif + + uiTemplateCurveMapping(layout, ptr, "curve", 's', 0); + + row= uiLayoutRow(layout, 1); + uiItemR(row, "Sta", 0, ptr, "start", 0); + uiItemR(row, "End", 0, ptr, "end", 0); } -static int node_buts_valtorgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_valtorgb(uiLayout *layout, PointerRNA *ptr) { - if(block) { - if(node->storage) { - uiBlockColorbandButtons(block, node->storage, butr, B_NODE_EXEC); - } + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + if(node->storage) { + uiBlockColorbandButtons(block, node->storage, butr, B_NODE_EXEC); } - return 40; } -static int node_buts_curvevec(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_curvevec(uiLayout *layout, PointerRNA *ptr) { - if(block) { - curvemap_buttons(block, node->storage, 'v', B_NODE_EXEC, B_REDR, butr); - } - return (int)(node->width-NODE_DY); + uiTemplateCurveMapping(layout, ptr, "mapping", 'v', 0); } static float *_sample_col= NULL; // bad bad, 2.5 will do better? @@ -311,33 +298,31 @@ void node_curvemap_sample(float *col) _sample_col= col; } -static int node_buts_curvecol(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_curvecol(uiLayout *layout, PointerRNA *ptr) { - if(block) { - CurveMapping *cumap= node->storage; - if(_sample_col) { - cumap->flag |= CUMA_DRAW_SAMPLE; - VECCOPY(cumap->sample, _sample_col); - } - else - cumap->flag &= ~CUMA_DRAW_SAMPLE; + bNode *node= ptr->data; + CurveMapping *cumap= node->storage; - curvemap_buttons(block, node->storage, 'c', B_NODE_EXEC, B_REDR, butr); - } - return (int)(node->width-NODE_DY); + if(_sample_col) { + cumap->flag |= CUMA_DRAW_SAMPLE; + VECCOPY(cumap->sample, _sample_col); + } + else + cumap->flag &= ~CUMA_DRAW_SAMPLE; + + uiTemplateCurveMapping(layout, ptr, "mapping", 'c', 0); } -static int node_buts_normal(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_normal(uiLayout *layout, PointerRNA *ptr) { - if(block) { - bNodeSocket *sock= node->outputs.first; /* first socket stores normal */ - - uiDefButF(block, BUT_NORMAL, B_NODE_EXEC, "", - (short)butr->xmin, (short)butr->ymin, butr->xmax-butr->xmin, butr->ymax-butr->ymin, - sock->ns.vec, 0.0f, 1.0f, 0, 0, ""); - - } - return (int)(node->width-NODE_DY); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + bNodeSocket *sock= node->outputs.first; /* first socket stores normal */ + + uiDefButF(block, BUT_NORMAL, B_NODE_EXEC, "", + (short)butr->xmin, (short)butr->xmin, butr->xmax-butr->xmin, butr->xmax-butr->xmin, + sock->ns.vec, 0.0f, 1.0f, 0, 0, ""); } static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v) @@ -401,8 +386,13 @@ static void node_dynamic_update_cb(bContext *C, void *ntree_v, void *node_v) // XXX BIF_preview_changed(ID_MA); } -static int node_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_texture(uiLayout *layout, PointerRNA *ptr) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; + short multi = ( node->id && ((Tex*)node->id)->use_nodes && @@ -410,49 +400,44 @@ static int node_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf (node->type != TEX_NODE_TEXTURE) ); - if(block) { - uiBut *bt; - char *strp; - short width = (short)(butr->xmax - butr->xmin); - - /* browse button texture */ - uiBlockBeginAlign(block); - IDnames_to_pupstring(&strp, NULL, "", &(G.main->tex), NULL, NULL); - node->menunr= 0; - bt= uiDefButS(block, MENU, B_NODE_EXEC, strp, - butr->xmin, butr->ymin+(multi?30:0), 20, 19, - &node->menunr, 0, 0, 0, 0, "Browse texture"); - uiButSetFunc(bt, node_browse_tex_cb, ntree, node); - if(strp) MEM_freeN(strp); - - if(node->id) { - bt= uiDefBut(block, TEX, B_NOP, "TE:", - butr->xmin+19, butr->ymin+(multi?30:0), butr->xmax-butr->xmin-19, 19, - node->id->name+2, 0.0, 19.0, 0, 0, "Texture name"); - uiButSetFunc(bt, node_ID_title_cb, node, NULL); - } - uiBlockEndAlign(block); - - if(multi) { - char *menustr = ntreeTexOutputMenu(((Tex*)node->id)->nodetree); - uiDefButS(block, MENU, B_MATPRV, menustr, butr->xmin, butr->ymin, width, 19, &node->custom1, 0, 0, 0, 0, "Which output to use, for multi-output textures"); - free(menustr); - return 50; - } - return 20; - } - else return multi? 50: 20; + uiBut *bt; + char *strp; + short width = (short)(butr->xmax - butr->xmin); + + /* browse button texture */ + uiBlockBeginAlign(block); + IDnames_to_pupstring(&strp, NULL, "", &(G.main->tex), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NODE_EXEC, strp, + butr->xmin, butr->ymin+(multi?30:0), 20, 19, + &node->menunr, 0, 0, 0, 0, "Browse texture"); + uiButSetFunc(bt, node_browse_tex_cb, ntree, node); + if(strp) MEM_freeN(strp); + + if(node->id) { + bt= uiDefBut(block, TEX, B_NOP, "TE:", + butr->xmin+19, butr->ymin+(multi?30:0), butr->xmax-butr->xmin-19, 19, + node->id->name+2, 0.0, 19.0, 0, 0, "Texture name"); + uiButSetFunc(bt, node_ID_title_cb, node, NULL); + } + uiBlockEndAlign(block); + + if(multi) { + char *menustr = ntreeTexOutputMenu(((Tex*)node->id)->nodetree); + uiDefButS(block, MENU, B_MATPRV, menustr, butr->xmin, butr->ymin, width, 19, &node->custom1, 0, 0, 0, 0, "Which output to use, for multi-output textures"); + free(menustr); + } } -static int node_buts_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_buts_math(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Multiply %x2|Divide %x3|Sine %x4|Cosine %x5|Tangent %x6|Arcsine %x7|Arccosine %x8|Arctangent %x9|Power %x10|Logarithm %x11|Minimum %x12|Maximum %x13|Round %x14|Less Than %x15|Greater Than %x16", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); - } - return 20; + bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Multiply %x2|Divide %x3|Sine %x4|Cosine %x5|Tangent %x6|Arcsine %x7|Arccosine %x8|Arctangent %x9|Power %x10|Logarithm %x11|Minimum %x12|Maximum %x13|Round %x14|Less Than %x15|Greater Than %x16", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, ""); + uiButSetFunc(bt, node_but_title_cb, node, bt); } @@ -556,192 +541,192 @@ static void node_texmap_cb(bContext *C, void *texmap_v, void *unused_v) init_mapping(texmap_v); } -static int node_shader_buts_material(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_shader_buts_material(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; - short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1); - short dy= (short)butr->ymin; - char *strp; - - /* WATCH IT: we use this callback in material buttons, but then only want first row */ - if(butr->ymax-butr->ymin > 21.0f) dy+= 19; - - uiBlockBeginAlign(block); - /* XXX - if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT); - else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1); - else uiBlockSetCol(block, TH_BUT_SETTING2); - */ - - /* browse button */ - IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL); - node->menunr= 0; - bt= uiDefButS(block, MENU, B_NOP, strp, - butr->xmin, dy, 19, 19, - &node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW"); - uiButSetFunc(bt, node_browse_mat_cb, ntree, node); - if(strp) MEM_freeN(strp); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; + uiBut *bt; + short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1); + short dy= (short)butr->ymin; + char *strp; + + /* WATCH IT: we use this callback in material buttons, but then only want first row */ + if(butr->ymax-butr->ymin > 21.0f) dy+= 19; + + uiBlockBeginAlign(block); + /* XXX + if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT); + else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1); + else uiBlockSetCol(block, TH_BUT_SETTING2); + */ + + /* browse button */ + IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NOP, strp, + butr->xmin, dy, 19, 19, + &node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW"); + uiButSetFunc(bt, node_browse_mat_cb, ntree, node); + if(strp) MEM_freeN(strp); + + /* Add New button */ + if(node->id==NULL) { + bt= uiDefBut(block, BUT, B_NOP, "Add New", + butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, + NULL, 0.0, 0.0, 0, 0, "Add new Material"); + uiButSetFunc(bt, node_new_mat_cb, ntree, node); + } + else { + /* name button */ + short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f)); + bt= uiDefBut(block, TEX, B_NOP, "MA:", + butr->xmin+19, dy, width, 19, + node->id->name+2, 0.0, 19.0, 0, 0, "Material name"); + uiButSetFunc(bt, node_ID_title_cb, node, NULL); - /* Add New button */ - if(node->id==NULL) { - bt= uiDefBut(block, BUT, B_NOP, "Add New", - butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, - NULL, 0.0, 0.0, 0, 0, "Add new Material"); - uiButSetFunc(bt, node_new_mat_cb, ntree, node); + /* user amount */ + if(has_us) { + char str1[32]; + sprintf(str1, "%d", node->id->us); + bt= uiDefBut(block, BUT, B_NOP, str1, + butr->xmax-19, dy, 19, 19, + NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy."); + uiButSetFunc(bt, node_mat_alone_cb, node, NULL); } - else { - /* name button */ - short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f)); - bt= uiDefBut(block, TEX, B_NOP, "MA:", - butr->xmin+19, dy, width, 19, - node->id->name+2, 0.0, 19.0, 0, 0, "Material name"); - uiButSetFunc(bt, node_ID_title_cb, node, NULL); - - /* user amount */ - if(has_us) { - char str1[32]; - sprintf(str1, "%d", node->id->us); - bt= uiDefBut(block, BUT, B_NOP, str1, - butr->xmax-19, dy, 19, 19, - NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy."); - uiButSetFunc(bt, node_mat_alone_cb, node, NULL); - } - - /* WATCH IT: we use this callback in material buttons, but then only want first row */ - if(butr->ymax-butr->ymin > 21.0f) { - /* node options */ - uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC, "Diff", - butr->xmin, butr->ymin, dx, 19, - &node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse"); - uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC, "Spec", - butr->xmin+dx, butr->ymin, dx, 19, - &node->custom1, 0, 0, 0, 0, "Material Node outputs Specular"); - uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC, "Neg Normal", - butr->xmax-dx, butr->ymin, dx, 19, - &node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal"); - } + + /* WATCH IT: we use this callback in material buttons, but then only want first row */ + if(butr->ymax-butr->ymin > 21.0f) { + /* node options */ + uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC, "Diff", + butr->xmin, butr->ymin, dx, 19, + &node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse"); + uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC, "Spec", + butr->xmin+dx, butr->ymin, dx, 19, + &node->custom1, 0, 0, 0, 0, "Material Node outputs Specular"); + uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC, "Neg Normal", + butr->xmax-dx, butr->ymin, dx, 19, + &node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal"); } - uiBlockEndAlign(block); - } - return 38; + } + uiBlockEndAlign(block); } -static int node_shader_buts_mapping(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_shader_buts_mapping(uiLayout *layout, PointerRNA *ptr) { - if(block) { - TexMapping *texmap= node->storage; - short dx= (short)((butr->xmax-butr->xmin)/7.0f); - short dy= (short)(butr->ymax-19); - - uiBlockSetFunc(block, node_texmap_cb, texmap, NULL); /* all buttons get this */ - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->loc+1, -1000.0f, 1000.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->loc+2, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->rot, -1000.0f, 1000.0f, 1000, 1, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->rot+1, -1000.0f, 1000.0f, 1000, 1, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->rot+2, -1000.0f, 1000.0f, 1000, 1, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->size+1, -1000.0f, 1000.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->size+2, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 25; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->min, -10.0f, 10.0f, 100, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->min+1, -10.0f, 10.0f, 100, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->min+2, -10.0f, 10.0f, 100, 2, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->max, -10.0f, 10.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->max+1, -10.0f, 10.0f, 10, 2, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->max+2, -10.0f, 10.0f, 10, 2, ""); - uiBlockEndAlign(block); - - /* labels/options */ - - dy= (short)(butr->ymax-19); - uiDefBut(block, LABEL, B_NOP, "Loc", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - dy-= 19; - uiDefBut(block, LABEL, B_NOP, "Rot", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - dy-= 19; - uiDefBut(block, LABEL, B_NOP, "Size", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - dy-= 25; - uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - dy-= 19; - uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - - } - return 5*19 + 6; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + TexMapping *texmap= node->storage; + short dx= (short)((butr->xmax-butr->xmin)/7.0f); + short dy= (short)(butr->ymax-19); + + uiBlockSetFunc(block, node_texmap_cb, texmap, NULL); /* all buttons get this */ + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->loc+1, -1000.0f, 1000.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->loc+2, -1000.0f, 1000.0f, 10, 2, ""); + dy-= 19; + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->rot, -1000.0f, 1000.0f, 1000, 1, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->rot+1, -1000.0f, 1000.0f, 1000, 1, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->rot+2, -1000.0f, 1000.0f, 1000, 1, ""); + dy-= 19; + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->size+1, -1000.0f, 1000.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->size+2, -1000.0f, 1000.0f, 10, 2, ""); + dy-= 25; + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->min, -10.0f, 10.0f, 100, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->min+1, -10.0f, 10.0f, 100, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->min+2, -10.0f, 10.0f, 100, 2, ""); + dy-= 19; + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->max, -10.0f, 10.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->max+1, -10.0f, 10.0f, 10, 2, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->max+2, -10.0f, 10.0f, 10, 2, ""); + uiBlockEndAlign(block); + + /* labels/options */ + + dy= (short)(butr->ymax-19); + uiDefBut(block, LABEL, B_NOP, "Loc", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); + dy-= 19; + uiDefBut(block, LABEL, B_NOP, "Rot", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); + dy-= 19; + uiDefBut(block, LABEL, B_NOP, "Size", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); + dy-= 25; + uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); + dy-= 19; + uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); } -static int node_shader_buts_vect_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_shader_buts_vect_math(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; - - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Average %x2|Dot Product %x3 |Cross Product %x4|Normalize %x5", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; + + bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Average %x2|Dot Product %x3 |Cross Product %x4|Normalize %x5", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, ""); + uiButSetFunc(bt, node_but_title_cb, node, bt); } -static int node_shader_buts_geometry(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_shader_buts_geometry(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *but; - NodeGeometry *ngeo= (NodeGeometry*)node->storage; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *but; + NodeGeometry *ngeo= (NodeGeometry*)node->storage; - // XXX if(!verify_valid_uv_name(ngeo->uvname)) - // XXX uiBlockSetCol(block, TH_REDALERT); - but= uiDefBut(block, TEX, B_NODE_EXEC, "UV:", butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, ngeo->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer"); - // XXX uiButSetCompleteFunc(but, autocomplete_uv, NULL); + // XXX if(!verify_valid_uv_name(ngeo->uvname)) + // XXX uiBlockSetCol(block, TH_REDALERT); + but= uiDefBut(block, TEX, B_NODE_EXEC, "UV:", butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, ngeo->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer"); + // XXX uiButSetCompleteFunc(but, autocomplete_uv, NULL); - if(!verify_valid_vcol_name(ngeo->colname)); + if(!verify_valid_vcol_name(ngeo->colname)); // uiBlockSetCol(block, TH_REDALERT); - but= uiDefBut(block, TEX, B_NODE_EXEC, "Col:", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, ngeo->colname, 0, 31, 0, 0, "Set name of vertex color layer to use, default is active vertex color layer"); - uiButSetCompleteFunc(but, autocomplete_vcol, NULL); - } - - return 40; + but= uiDefBut(block, TEX, B_NODE_EXEC, "Col:", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, ngeo->colname, 0, 31, 0, 0, "Set name of vertex color layer to use, default is active vertex color layer"); + uiButSetCompleteFunc(but, autocomplete_vcol, NULL); } -static int node_shader_buts_dynamic(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_shader_buts_dynamic(uiLayout *layout, PointerRNA *ptr) { - if (block) { - uiBut *bt; - // XXX SpaceNode *snode= curarea->spacedata.first; - short dy= (short)butr->ymin; - int xoff=0; - - /* B_NODE_EXEC is handled in butspace.c do_node_buts */ - if(!node->id) { - char *strp; - IDnames_to_pupstring(&strp, NULL, "", &(G.main->text), NULL, NULL); - node->menunr= 0; - bt= uiDefButS(block, MENU, B_NODE_EXEC/*+node->nr*/, strp, - butr->xmin, dy, 19, 19, - &node->menunr, 0, 0, 0, 0, "Browses existing choices"); - uiButSetFunc(bt, node_browse_text_cb, ntree, node); - xoff=19; - if(strp) MEM_freeN(strp); - } - else { - bt = uiDefBut(block, BUT, B_NOP, "Update", - butr->xmin+xoff, butr->ymin+20, 50, 19, - &node->menunr, 0.0, 19.0, 0, 0, "Refresh this node (and all others that use the same script)"); - uiButSetFunc(bt, node_dynamic_update_cb, ntree, node); - - if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) { - // UI_ThemeColor(TH_REDALERT); - // XXX ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect); - // XXX snode_drawstring(snode, "Error! Check console...", butr->xmax - butr->xmin); - ; - } + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; + uiBut *bt; + // XXX SpaceNode *snode= curarea->spacedata.first; + short dy= (short)butr->ymin; + int xoff=0; + + /* B_NODE_EXEC is handled in butspace.c do_node_buts */ + if(!node->id) { + char *strp; + IDnames_to_pupstring(&strp, NULL, "", &(G.main->text), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NODE_EXEC/*+node->nr*/, strp, + butr->xmin, dy, 19, 19, + &node->menunr, 0, 0, 0, 0, "Browses existing choices"); + uiButSetFunc(bt, node_browse_text_cb, ntree, node); + xoff=19; + if(strp) MEM_freeN(strp); + } + else { + bt = uiDefBut(block, BUT, B_NOP, "Update", + butr->xmin+xoff, butr->ymin+20, 50, 19, + &node->menunr, 0.0, 19.0, 0, 0, "Refresh this node (and all others that use the same script)"); + uiButSetFunc(bt, node_dynamic_update_cb, ntree, node); + + if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) { + // UI_ThemeColor(TH_REDALERT); + // XXX ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect); + // XXX snode_drawstring(snode, "Error! Check console...", butr->xmax - butr->xmin); + ; } } - return 20+19; } /* only once called */ @@ -752,49 +737,49 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_MATERIAL: case SH_NODE_MATERIAL_EXT: - ntype->butfunc= node_shader_buts_material; + ntype->uifunc= node_shader_buts_material; break; case SH_NODE_TEXTURE: - ntype->butfunc= node_buts_texture; + ntype->uifunc= node_buts_texture; break; case SH_NODE_NORMAL: - ntype->butfunc= node_buts_normal; + ntype->uifunc= node_buts_normal; break; case SH_NODE_CURVE_VEC: - ntype->butfunc= node_buts_curvevec; + ntype->uifunc= node_buts_curvevec; break; case SH_NODE_CURVE_RGB: - ntype->butfunc= node_buts_curvecol; + ntype->uifunc= node_buts_curvecol; break; case SH_NODE_MAPPING: - ntype->butfunc= node_shader_buts_mapping; + ntype->uifunc= node_shader_buts_mapping; break; case SH_NODE_VALUE: - ntype->butfunc= node_buts_value; + ntype->uifunc= node_buts_value; break; case SH_NODE_RGB: - ntype->butfunc= node_buts_rgb; + ntype->uifunc= node_buts_rgb; break; case SH_NODE_MIX_RGB: - ntype->butfunc= node_buts_mix_rgb; + ntype->uifunc= node_buts_mix_rgb; break; case SH_NODE_VALTORGB: - ntype->butfunc= node_buts_valtorgb; + ntype->uifunc= node_buts_valtorgb; break; case SH_NODE_MATH: - ntype->butfunc= node_buts_math; + ntype->uifunc= node_buts_math; break; case SH_NODE_VECT_MATH: - ntype->butfunc= node_shader_buts_vect_math; + ntype->uifunc= node_shader_buts_vect_math; break; case SH_NODE_GEOMETRY: - ntype->butfunc= node_shader_buts_geometry; + ntype->uifunc= node_shader_buts_geometry; break; case NODE_DYNAMIC: - ntype->butfunc= node_shader_buts_dynamic; + ntype->uifunc= node_shader_buts_dynamic; break; default: - ntype->butfunc= NULL; + ntype->uifunc= NULL; } } @@ -879,112 +864,102 @@ static void image_layer_cb(bContext *C, void *ima_v, void *iuser_v) // allqueue(REDRAWNODE, 0); } -static int node_composit_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_image(uiLayout *layout, PointerRNA *ptr) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; ImageUser *iuser= node->storage; + uiBut *bt; + short dy= (short)butr->ymax-19; + char *strp; - if(block) { - uiBut *bt; - short dy= (short)butr->ymax-19; - char *strp; + uiBlockBeginAlign(block); + + /* browse button */ + IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NOP, strp, + butr->xmin, dy, 19, 19, + &node->menunr, 0, 0, 0, 0, "Browses existing choices"); + uiButSetFunc(bt, node_browse_image_cb, ntree, node); + if(strp) MEM_freeN(strp); + + /* Add New button */ + if(node->id==NULL) { + bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New", + butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, + NULL, 0.0, 0.0, 0, 0, "Add new Image"); + uiButSetFunc(bt, node_active_cb, ntree, node); + } + else { + /* name button + type */ + Image *ima= (Image *)node->id; + short xmin= (short)butr->xmin, xmax= (short)butr->xmax; + short width= xmax - xmin - 45; + short icon= ICON_IMAGE_DATA; - uiBlockBeginAlign(block); + if(ima->source==IMA_SRC_MOVIE) icon= ICON_SEQUENCE; + else if(ima->source==IMA_SRC_SEQUENCE) icon= ICON_IMAGE_COL; + else if(ima->source==IMA_SRC_GENERATED) icon= ICON_BLANK1; - /* browse button */ - IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL); - node->menunr= 0; - bt= uiDefButS(block, MENU, B_NOP, strp, - butr->xmin, dy, 19, 19, - &node->menunr, 0, 0, 0, 0, "Browses existing choices"); - uiButSetFunc(bt, node_browse_image_cb, ntree, node); - if(strp) MEM_freeN(strp); + bt= uiDefBut(block, TEX, B_NOP, "IM:", + xmin+19, dy, width, 19, + node->id->name+2, 0.0, 19.0, 0, 0, "Image name"); + uiButSetFunc(bt, node_ID_title_cb, node, NULL); - /* Add New button */ - if(node->id==NULL) { - bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New", - butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, - NULL, 0.0, 0.0, 0, 0, "Add new Image"); - uiButSetFunc(bt, node_active_cb, ntree, node); - } - else { - /* name button + type */ - Image *ima= (Image *)node->id; - short xmin= (short)butr->xmin, xmax= (short)butr->xmax; - short width= xmax - xmin - 45; - short icon= ICON_IMAGE_DATA; - - if(ima->source==IMA_SRC_MOVIE) icon= ICON_SEQUENCE; - else if(ima->source==IMA_SRC_SEQUENCE) icon= ICON_IMAGE_COL; - else if(ima->source==IMA_SRC_GENERATED) icon= ICON_BLANK1; - - bt= uiDefBut(block, TEX, B_NOP, "IM:", - xmin+19, dy, width, 19, - node->id->name+2, 0.0, 19.0, 0, 0, "Image name"); - uiButSetFunc(bt, node_ID_title_cb, node, NULL); - - /* buffer type option */ - strp= node_image_type_pup(); - bt= uiDefIconTextButS(block, MENU, B_NOP, icon, strp, - xmax-26, dy, 26, 19, - &ima->source, 0.0, 19.0, 0, 0, "Image type"); - uiButSetFunc(bt, node_image_type_cb, node, ima); - MEM_freeN(strp); + /* buffer type option */ + strp= node_image_type_pup(); + bt= uiDefIconTextButS(block, MENU, B_NOP, icon, strp, + xmax-26, dy, 26, 19, + &ima->source, 0.0, 19.0, 0, 0, "Image type"); + uiButSetFunc(bt, node_image_type_cb, node, ima); + MEM_freeN(strp); + + if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) ) { + width= (xmax-xmin)/2; - if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) ) { - width= (xmax-xmin)/2; - - dy-= 19; - uiDefButI(block, NUM, B_NODE_EXEC, "Frs:", - xmin, dy, width, 19, - &iuser->frames, 1.0, MAXFRAMEF, 0, 0, "Amount of images used in animation"); - uiDefButI(block, NUM, B_NODE_EXEC, "SFra:", - xmin+width, dy, width, 19, - &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Start frame of animation"); + dy-= 19; + uiDefButI(block, NUM, B_NODE_EXEC, "Frs:", + xmin, dy, width, 19, + &iuser->frames, 1.0, MAXFRAMEF, 0, 0, "Amount of images used in animation"); + uiDefButI(block, NUM, B_NODE_EXEC, "SFra:", + xmin+width, dy, width, 19, + &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Start frame of animation"); + dy-= 19; + uiDefButI(block, NUM, B_NODE_EXEC, "Offs:", + xmin, dy, width, 19, + &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation"); + uiDefButS(block, TOG, B_NODE_EXEC, "Cycl", + xmin+width, dy, width-20, 19, + &iuser->cycl, 0.0, 0.0, 0, 0, "Make animation go cyclic"); + uiDefIconButBitS(block, TOG, IMA_ANIM_ALWAYS, B_NODE_EXEC, ICON_AUTO, + xmax-20, dy, 20, 19, + &iuser->flag, 0.0, 0.0, 0, 0, "Always refresh Image on frame changes"); + } + if( ima->type==IMA_TYPE_MULTILAYER && ima->rr) { + RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); + if(rl) { + width= (xmax-xmin); dy-= 19; - uiDefButI(block, NUM, B_NODE_EXEC, "Offs:", + strp= layer_menu(ima->rr); + bt= uiDefButS(block, MENU, B_NODE_EXEC, strp, xmin, dy, width, 19, - &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation"); - uiDefButS(block, TOG, B_NODE_EXEC, "Cycl", - xmin+width, dy, width-20, 19, - &iuser->cycl, 0.0, 0.0, 0, 0, "Make animation go cyclic"); - uiDefIconButBitS(block, TOG, IMA_ANIM_ALWAYS, B_NODE_EXEC, ICON_AUTO, - xmax-20, dy, 20, 19, - &iuser->flag, 0.0, 0.0, 0, 0, "Always refresh Image on frame changes"); - } - if( ima->type==IMA_TYPE_MULTILAYER && ima->rr) { - RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); - if(rl) { - width= (xmax-xmin); - dy-= 19; - strp= layer_menu(ima->rr); - bt= uiDefButS(block, MENU, B_NODE_EXEC, strp, - xmin, dy, width, 19, - &iuser->layer, 0.0, 10000.0, 0, 0, "Layer"); - uiButSetFunc(bt, image_layer_cb, ima->rr, node->storage); - MEM_freeN(strp); - } + &iuser->layer, 0.0, 10000.0, 0, 0, "Layer"); + uiButSetFunc(bt, image_layer_cb, ima->rr, node->storage); + MEM_freeN(strp); } } + } - } if(node->id) { - Image *ima= (Image *)node->id; - int retval= 19; - /* for each draw we test for anim refresh event */ if(iuser->flag & IMA_ANIM_REFRESHED) { iuser->flag &= ~IMA_ANIM_REFRESHED; // addqueue(curarea->win, UI_BUT_EVENT, B_NODE_EXEC); XXX } - - if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) ) - retval+= 38; - if( ima->type==IMA_TYPE_MULTILAYER) - retval+= 19; - return retval; } - else - return 19; } /* if we use render layers from other scene, we make a nice title */ @@ -1057,9 +1032,14 @@ static void node_browse_scene_cb(bContext *C, void *ntree_v, void *node_v) } -static int node_composit_buts_renderlayers(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_renderlayers(uiLayout *layout, PointerRNA *ptr) { - if(block && node->id) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; + + if(node->id) { Scene *scene= (Scene *)node->id; uiBut *bt; char *strp; @@ -1094,7 +1074,6 @@ static int node_composit_buts_renderlayers(uiBlock *block, bNodeTree *ntree, bNo &node->custom2, 0, 0, 0, 0, "Re-render this Layer"); } - return 19; } static void node_blur_relative_cb(bContext *C, void *node, void *poin2) @@ -1126,734 +1105,719 @@ static void node_blur_update_sizey_cb(bContext *C, void *node, void *poin2) nbd->sizey= (int)(nbd->percenty*nbd->image_in_height); } -static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeBlurData *nbd= node->storage; - uiBut *bt; - short dy= butr->ymin+58; - short dx= (butr->xmax-butr->xmin)/2; - char str[256]; - - uiBlockBeginAlign(block); - sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH); - uiDefButS(block, MENU, B_NODE_EXEC,str, - butr->xmin, dy, dx*2, 19, - &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur"); - dy-=19; - if (nbd->filtertype != R_FILTER_FAST_GAUSS) { - uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh", - butr->xmin, dy, dx, 19, - &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!"); - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma", - butr->xmin+dx, dy, dx, 19, - &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values"); - } else { - uiBlockEndAlign(block); - uiBlockBeginAlign(block); - } - dy-=19; - bt= uiDefButS(block, TOG, B_NOP, "Relative", - butr->xmin, dy, dx*2, 19, - &nbd->relative, 0, 0, 0, 0, "Use relative (percent) values to define blur radius"); - uiButSetFunc(bt, node_blur_relative_cb, node, NULL); - - dy-=19; - if(nbd->relative) { - bt= uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->percentx, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizex_cb, node, NULL); - bt= uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->percenty, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizey_cb, node, NULL); - } - else { - uiDefButS(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->sizex, 0, 256, 0, 0, ""); - uiDefButS(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->sizey, 0, 256, 0, 0, ""); - } + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeBlurData *nbd= node->storage; + uiBut *bt; + short dy= butr->ymin+58; + short dx= (butr->xmax-butr->xmin)/2; + char str[256]; + + uiBlockBeginAlign(block); + sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH); + uiDefButS(block, MENU, B_NODE_EXEC,str, + butr->xmin, dy, dx*2, 19, + &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur"); + dy-=19; + if (nbd->filtertype != R_FILTER_FAST_GAUSS) { + uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh", + butr->xmin, dy, dx, 19, + &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!"); + uiDefButC(block, TOG, B_NODE_EXEC, "Gamma", + butr->xmin+dx, dy, dx, 19, + &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values"); + } else { uiBlockEndAlign(block); + uiBlockBeginAlign(block); } - return 77; + dy-=19; + bt= uiDefButS(block, TOG, B_NOP, "Relative", + butr->xmin, dy, dx*2, 19, + &nbd->relative, 0, 0, 0, 0, "Use relative (percent) values to define blur radius"); + uiButSetFunc(bt, node_blur_relative_cb, node, NULL); + + dy-=19; + if(nbd->relative) { + bt= uiDefButF(block, NUM, B_NODE_EXEC, "X:", + butr->xmin, dy, dx, 19, + &nbd->percentx, 0.0f, 1.0f, 0, 0, ""); + uiButSetFunc(bt, node_blur_update_sizex_cb, node, NULL); + bt= uiDefButF(block, NUM, B_NODE_EXEC, "Y:", + butr->xmin+dx, dy, dx, 19, + &nbd->percenty, 0.0f, 1.0f, 0, 0, ""); + uiButSetFunc(bt, node_blur_update_sizey_cb, node, NULL); + } + else { + uiDefButS(block, NUM, B_NODE_EXEC, "X:", + butr->xmin, dy, dx, 19, + &nbd->sizex, 0, 256, 0, 0, ""); + uiDefButS(block, NUM, B_NODE_EXEC, "Y:", + butr->xmin+dx, dy, dx, 19, + &nbd->sizey, 0, 256, 0, 0, ""); + } + uiBlockEndAlign(block); } -static int node_composit_buts_dblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeDBlurData *ndbd = node->storage; - short dy = butr->ymin + 171; - short dx = butr->xmax - butr->xmin; - short halfdx= (short)dx/2; - - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &ndbd->iter, 1, 32, 10, 0, "Amount of iterations"); - uiDefButC(block, TOG, B_NODE_EXEC, "Wrap", - butr->xmin, dy-= 19, dx, 19, - &ndbd->wrap, 0, 0, 0, 0, "Wrap blur"); - uiBlockEndAlign(block); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeDBlurData *ndbd = node->storage; + short dy = butr->ymin + 171; + short dx = butr->xmax - butr->xmin; + short halfdx= (short)dx/2; - dy-= 9; + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", + butr->xmin, dy, dx, 19, + &ndbd->iter, 1, 32, 10, 0, "Amount of iterations"); + uiDefButC(block, TOG, B_NODE_EXEC, "Wrap", + butr->xmin, dy-= 19, dx, 19, + &ndbd->wrap, 0, 0, 0, 0, "Wrap blur"); + uiBlockEndAlign(block); - uiDefBut(block, LABEL, B_NOP, "Center", butr->xmin, dy-= 19, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); + dy-= 9; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy-= 19, halfdx, 19, - &ndbd->center_x, 0.0f, 1.0f, 10, 0, "X center in percents"); - uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+halfdx, dy, halfdx, 19, - &ndbd->center_y, 0.0f, 1.0f, 10, 0, "Y center in percents"); - uiBlockEndAlign(block); + uiDefBut(block, LABEL, B_NOP, "Center", butr->xmin, dy-= 19, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - dy-= 9; + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "X:", + butr->xmin, dy-= 19, halfdx, 19, + &ndbd->center_x, 0.0f, 1.0f, 10, 0, "X center in percents"); + uiDefButF(block, NUM, B_NODE_EXEC, "Y:", + butr->xmin+halfdx, dy, halfdx, 19, + &ndbd->center_y, 0.0f, 1.0f, 10, 0, "Y center in percents"); + uiBlockEndAlign(block); - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->distance, -1.0f, 1.0f, 10, 0, "Amount of which the image moves"); - uiDefButF(block, NUM, B_NODE_EXEC, "Angle:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->angle, 0.0f, 360.0f, 1000, 0, "Angle in which the image will be moved"); - uiBlockEndAlign(block); + dy-= 9; - dy-= 9; + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "Distance:", + butr->xmin, dy-= 19, dx, 19, + &ndbd->distance, -1.0f, 1.0f, 10, 0, "Amount of which the image moves"); + uiDefButF(block, NUM, B_NODE_EXEC, "Angle:", + butr->xmin, dy-= 19, dx, 19, + &ndbd->angle, 0.0f, 360.0f, 1000, 0, "Angle in which the image will be moved"); + uiBlockEndAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Spin:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->spin, -360.0f, 360.0f, 1000, 0, "Angle that is used to spin the image"); + dy-= 9; - dy-= 9; + uiDefButF(block, NUM, B_NODE_EXEC, "Spin:", + butr->xmin, dy-= 19, dx, 19, + &ndbd->spin, -360.0f, 360.0f, 1000, 0, "Angle that is used to spin the image"); - uiDefButF(block, NUM, B_NODE_EXEC, "Zoom:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->zoom, 0.0f, 100.0f, 100, 0, "Amount of which the image is zoomed"); + dy-= 9; - } - return 190; + uiDefButF(block, NUM, B_NODE_EXEC, "Zoom:", + butr->xmin, dy-= 19, dx, 19, + &ndbd->zoom, 0.0f, 100.0f, 100, 0, "Amount of which the image is zoomed"); } -static int node_composit_buts_bilateralblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_bilateralblur(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeBilateralBlurData *nbbd= node->storage; - short dy= butr->ymin+38; - short dx= (butr->xmax-butr->xmin); - - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &nbbd->iter, 1, 128, 0, 0, "Amount of iterations"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Color Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_color,0.01, 3, 10, 0, "Sigma value used to modify color"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Space Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_space ,0.01, 30, 10, 0, "Sigma value used to modify space"); - - } - return 57; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeBilateralBlurData *nbbd= node->storage; + short dy= butr->ymin+38; + short dx= (butr->xmax-butr->xmin); + + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", + butr->xmin, dy, dx, 19, + &nbbd->iter, 1, 128, 0, 0, "Amount of iterations"); + dy-=19; + uiDefButF(block, NUM, B_NODE_EXEC, "Color Sigma:", + butr->xmin, dy, dx, 19, + &nbbd->sigma_color,0.01, 3, 10, 0, "Sigma value used to modify color"); + dy-=19; + uiDefButF(block, NUM, B_NODE_EXEC, "Space Sigma:", + butr->xmin, dy, dx, 19, + &nbbd->sigma_space ,0.01, 30, 10, 0, "Sigma value used to modify space"); } /* qdn: defocus node */ -static int node_composit_buts_defocus(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) -{ - if(block) { - NodeDefocus *nqd = node->storage; - short dy = butr->ymin + 209; - short dx = butr->xmax - butr->xmin; - char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0"; - - uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, ""); - uiDefButC(block, MENU, B_NODE_EXEC, mstr1, - butr->xmin, dy-19, dx, 19, - &nqd->bktype, 0, 0, 0, 0, "Bokeh type"); - if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */ - uiDefButC(block, NUM, B_NODE_EXEC, "Rotate:", - butr->xmin, dy-38, dx, 19, - &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees"); - } - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma Correct", - butr->xmin, dy-57, dx, 19, - &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process"); - if (nqd->no_zbuf==0) { - // only needed for zbuffer input - uiDefButF(block, NUM, B_NODE_EXEC, "fStop:", - butr->xmin, dy-76, dx, 19, - &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Maxblur:", - butr->xmin, dy-95, dx, 19, - &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit"); - uiDefButF(block, NUM, B_NODE_EXEC, "BThreshold:", - butr->xmin, dy-114, dx, 19, - &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); - uiDefButC(block, TOG, B_NODE_EXEC, "Preview", - butr->xmin, dy-142, dx, 19, - &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts"); - if (nqd->preview) { - /* only visible when sampling mode enabled */ - uiDefButS(block, NUM, B_NODE_EXEC, "Samples:", - butr->xmin, dy-161, dx, 19, - &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)"); - } - uiDefButS(block, TOG, B_NODE_EXEC, "No zbuffer", - butr->xmin, dy-190, dx, 19, - &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"); - if (nqd->no_zbuf) { - uiDefButF(block, NUM, B_NODE_EXEC, "Zscale:", - butr->xmin, dy-209, dx, 19, - &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"); - } +static void node_composit_buts_defocus(uiLayout *layout, PointerRNA *ptr) +{ + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeDefocus *nqd = node->storage; + short dy = butr->ymin + 209; + short dx = butr->xmax - butr->xmin; + char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0"; + + uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, ""); + uiDefButC(block, MENU, B_NODE_EXEC, mstr1, + butr->xmin, dy-19, dx, 19, + &nqd->bktype, 0, 0, 0, 0, "Bokeh type"); + if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */ + uiDefButC(block, NUM, B_NODE_EXEC, "Rotate:", + butr->xmin, dy-38, dx, 19, + &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees"); + } + uiDefButC(block, TOG, B_NODE_EXEC, "Gamma Correct", + butr->xmin, dy-57, dx, 19, + &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process"); + if (nqd->no_zbuf==0) { + // only needed for zbuffer input + uiDefButF(block, NUM, B_NODE_EXEC, "fStop:", + butr->xmin, dy-76, dx, 19, + &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"); + } + uiDefButF(block, NUM, B_NODE_EXEC, "Maxblur:", + butr->xmin, dy-95, dx, 19, + &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit"); + uiDefButF(block, NUM, B_NODE_EXEC, "BThreshold:", + butr->xmin, dy-114, dx, 19, + &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); + uiDefButC(block, TOG, B_NODE_EXEC, "Preview", + butr->xmin, dy-142, dx, 19, + &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts"); + if (nqd->preview) { + /* only visible when sampling mode enabled */ + uiDefButS(block, NUM, B_NODE_EXEC, "Samples:", + butr->xmin, dy-161, dx, 19, + &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)"); + } + uiDefButS(block, TOG, B_NODE_EXEC, "No zbuffer", + butr->xmin, dy-190, dx, 19, + &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"); + if (nqd->no_zbuf) { + uiDefButF(block, NUM, B_NODE_EXEC, "Zscale:", + butr->xmin, dy-209, dx, 19, + &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"); } - return 228; } /* qdn: glare node */ -static int node_composit_buts_glare(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) -{ - if(block) { - NodeGlare *ndg = node->storage; - short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin; - char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0"; - char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2"; - uiDefButC(block, MENU, B_NODE_EXEC, mn1, - butr->xmin, dy, dx, 19, - &ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type"); - uiDefButC(block, MENU, B_NODE_EXEC, mn2, - butr->xmin, dy-19, dx, 19, - &ndg->quality, 0, 0, 0, 0, - "Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image"); - if (ndg->type != 1) { - uiDefButC(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy-38, dx, 19, - &ndg->iter, 2, 5, 1, 0, - "higher values will generate longer/more streaks/ghosts"); - if (ndg->type != 0) - uiDefButF(block, NUM, B_NODE_EXEC, "ColMod:", - butr->xmin, dy-57, dx, 19, - &ndg->colmod, 0, 1, 10, 0, - "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Mix:", - butr->xmin, dy-76, dx, 19, - &ndg->mix, -1, 1, 10, 0, - "Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); - uiDefButF(block, NUM, B_NODE_EXEC, "Threshold:", - butr->xmin, dy-95, dx, 19, - &ndg->threshold, 0, 1000, 10, 0, - "Brightness threshold, the glarefilter will be applied only to pixels brighter than this value"); - if ((ndg->type == 2) || (ndg->type == 0)) - { - if (ndg->type == 2) { - uiDefButC(block, NUM, B_NODE_EXEC, "streaks:", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 2, 16, 1000, 0, - "Total number of streaks"); - uiDefButC(block, NUM, B_NODE_EXEC, "AngOfs:", - butr->xmin, dy-133, dx, 19, - &ndg->angle_ofs, 0, 180, 1000, 0, - "Streak angle rotation offset in degrees"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Fade:", - butr->xmin, dy-152, dx, 19, - &ndg->fade, 0.75, 1, 5, 0, - "Streak fade out factor"); +static void node_composit_buts_glare(uiLayout *layout, PointerRNA *ptr) +{ + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeGlare *ndg = node->storage; + short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin; + char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0"; + char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2"; + uiDefButC(block, MENU, B_NODE_EXEC, mn1, + butr->xmin, dy, dx, 19, + &ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type"); + uiDefButC(block, MENU, B_NODE_EXEC, mn2, + butr->xmin, dy-19, dx, 19, + &ndg->quality, 0, 0, 0, 0, + "Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image"); + if (ndg->type != 1) { + uiDefButC(block, NUM, B_NODE_EXEC, "Iterations:", + butr->xmin, dy-38, dx, 19, + &ndg->iter, 2, 5, 1, 0, + "higher values will generate longer/more streaks/ghosts"); + if (ndg->type != 0) + uiDefButF(block, NUM, B_NODE_EXEC, "ColMod:", + butr->xmin, dy-57, dx, 19, + &ndg->colmod, 0, 1, 10, 0, + "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); + } + uiDefButF(block, NUM, B_NODE_EXEC, "Mix:", + butr->xmin, dy-76, dx, 19, + &ndg->mix, -1, 1, 10, 0, + "Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); + uiDefButF(block, NUM, B_NODE_EXEC, "Threshold:", + butr->xmin, dy-95, dx, 19, + &ndg->threshold, 0, 1000, 10, 0, + "Brightness threshold, the glarefilter will be applied only to pixels brighter than this value"); + if ((ndg->type == 2) || (ndg->type == 0)) + { + if (ndg->type == 2) { + uiDefButC(block, NUM, B_NODE_EXEC, "streaks:", + butr->xmin, dy-114, dx, 19, + &ndg->angle, 2, 16, 1000, 0, + "Total number of streaks"); + uiDefButC(block, NUM, B_NODE_EXEC, "AngOfs:", + butr->xmin, dy-133, dx, 19, + &ndg->angle_ofs, 0, 180, 1000, 0, + "Streak angle rotation offset in degrees"); } - if (ndg->type == 0) - uiDefButC(block, TOG, B_NODE_EXEC, "Rot45", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 0, 0, 0, 0, - "simple star filter, add 45 degree rotation offset"); - if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow - uiDefButC(block, NUM, B_NODE_EXEC, "Size:", - butr->xmin, dy-114, dx, 19, - &ndg->size, 6, 9, 1000, 0, - "glow/glare size (not actual size, relative to initial size of bright area of pixels)"); - } - return 171; + uiDefButF(block, NUM, B_NODE_EXEC, "Fade:", + butr->xmin, dy-152, dx, 19, + &ndg->fade, 0.75, 1, 5, 0, + "Streak fade out factor"); + } + if (ndg->type == 0) + uiDefButC(block, TOG, B_NODE_EXEC, "Rot45", + butr->xmin, dy-114, dx, 19, + &ndg->angle, 0, 0, 0, 0, + "simple star filter, add 45 degree rotation offset"); + if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow + uiDefButC(block, NUM, B_NODE_EXEC, "Size:", + butr->xmin, dy-114, dx, 19, + &ndg->size, 6, 9, 1000, 0, + "glow/glare size (not actual size, relative to initial size of bright area of pixels)"); } /* qdn: tonemap node */ -static int node_composit_buts_tonemap(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeTonemap *ntm = node->storage; - short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin; - char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0"; - - uiBlockBeginAlign(block); - uiDefButI(block, MENU, B_NODE_EXEC, mn, - butr->xmin, dy, dx, 19, - &ntm->type, 0, 0, 0, 0, - "Tone mapping type"); - if (ntm->type == 0) { - uiDefButF(block, NUM, B_NODE_EXEC, "Key:", - butr->xmin, dy-19, dx, 19, - &ntm->key, 0, 1, 5, 0, - "The value the average luminance is mapped to"); - uiDefButF(block, NUM, B_NODE_EXEC, "Offset:", - butr->xmin, dy-38, dx, 19, - &ntm->offset, 0.001, 10, 5, 0, - "Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve"); - uiDefButF(block, NUM, B_NODE_EXEC, "Gamma:", - butr->xmin, dy-57, dx, 19, - &ntm->gamma, 0.001, 3, 5, 0, - "Gamma factor, if not used, set to 1"); - } - else { - uiDefButF(block, NUM, B_NODE_EXEC, "Intensity:", - butr->xmin, dy-19, dx, 19, - &ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter"); - uiDefButF(block, NUM, B_NODE_EXEC, "Contrast:", - butr->xmin, dy-38, dx, 19, - &ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image"); - uiDefButF(block, NUM, B_NODE_EXEC, "Adaptation:", - butr->xmin, dy-57, dx, 19, - &ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity"); - uiDefButF(block, NUM, B_NODE_EXEC, "ColCorrect:", - butr->xmin, dy-76, dx, 19, - &ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent"); - } - uiBlockEndAlign(block); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeTonemap *ntm = node->storage; + short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin; + char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0"; + + uiBlockBeginAlign(block); + uiDefButI(block, MENU, B_NODE_EXEC, mn, + butr->xmin, dy, dx, 19, + &ntm->type, 0, 0, 0, 0, + "Tone mapping type"); + if (ntm->type == 0) { + uiDefButF(block, NUM, B_NODE_EXEC, "Key:", + butr->xmin, dy-19, dx, 19, + &ntm->key, 0, 1, 5, 0, + "The value the average luminance is mapped to"); + uiDefButF(block, NUM, B_NODE_EXEC, "Offset:", + butr->xmin, dy-38, dx, 19, + &ntm->offset, 0.001, 10, 5, 0, + "Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve"); + uiDefButF(block, NUM, B_NODE_EXEC, "Gamma:", + butr->xmin, dy-57, dx, 19, + &ntm->gamma, 0.001, 3, 5, 0, + "Gamma factor, if not used, set to 1"); } - return 95; + else { + uiDefButF(block, NUM, B_NODE_EXEC, "Intensity:", + butr->xmin, dy-19, dx, 19, + &ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter"); + uiDefButF(block, NUM, B_NODE_EXEC, "Contrast:", + butr->xmin, dy-38, dx, 19, + &ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image"); + uiDefButF(block, NUM, B_NODE_EXEC, "Adaptation:", + butr->xmin, dy-57, dx, 19, + &ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity"); + uiDefButF(block, NUM, B_NODE_EXEC, "ColCorrect:", + butr->xmin, dy-76, dx, 19, + &ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent"); + } + uiBlockEndAlign(block); } /* qdn: lens distortion node */ -static int node_composit_buts_lensdist(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeLensDist *nld = node->storage; - short dy = butr->ymin + 19, dx = butr->xmax - butr->xmin; - uiBlockBeginAlign(block); - uiDefButS(block, TOG, B_NODE_EXEC, "Projector", - butr->xmin, dy, dx, 19, - &nld->proj, 0, 0, 0, 0, - "Enable/disable projector mode, effect is applied in horizontal direction only"); - if (!nld->proj) { - uiDefButS(block, TOG, B_NODE_EXEC, "Jitter", - butr->xmin, dy-19, dx/2, 19, - &nld->jit, 0, 0, 0, 0, - "Enable/disable jittering, faster, but also noisier"); - uiDefButS(block, TOG, B_NODE_EXEC, "Fit", - butr->xmin+dx/2, dy-19, dx/2, 19, - &nld->fit, 0, 0, 0, 0, - "For positive distortion factor only, scale image such that black areas are not visible"); - } - uiBlockEndAlign(block); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeLensDist *nld = node->storage; + short dy = butr->ymin + 19, dx = butr->xmax - butr->xmin; + uiBlockBeginAlign(block); + uiDefButS(block, TOG, B_NODE_EXEC, "Projector", + butr->xmin, dy, dx, 19, + &nld->proj, 0, 0, 0, 0, + "Enable/disable projector mode, effect is applied in horizontal direction only"); + if (!nld->proj) { + uiDefButS(block, TOG, B_NODE_EXEC, "Jitter", + butr->xmin, dy-19, dx/2, 19, + &nld->jit, 0, 0, 0, 0, + "Enable/disable jittering, faster, but also noisier"); + uiDefButS(block, TOG, B_NODE_EXEC, "Fit", + butr->xmin+dx/2, dy-19, dx/2, 19, + &nld->fit, 0, 0, 0, 0, + "For positive distortion factor only, scale image such that black areas are not visible"); } - return 38; + uiBlockEndAlign(block); } -static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) { - if(block) { - PointerRNA ptr; - short dy= butr->ymin; - short dx= (butr->xmax-butr->xmin); - - RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); - - uiBlockBeginAlign(block); - uiDefButR(block, NUM, B_NODE_EXEC, NULL, - butr->xmin, dy+76, dx, 19, - &ptr, "samples", 0, 1, 256, 0, 0, NULL); - uiDefButR(block, NUM, B_NODE_EXEC, NULL, - butr->xmin, dy+57, dx, 19, - &ptr, "min_speed", 0, 0, 1024, 0, 0, NULL); - uiDefButR(block, NUM, B_NODE_EXEC, NULL, - butr->xmin, dy+38, dx, 19, - &ptr, "max_speed", 0, 0, 1024, 0, 0, NULL); - uiDefButR(block, NUM, B_NODE_EXEC, "Blur", - butr->xmin, dy+19, dx, 19, - &ptr, "factor", 0, 0, 2, 10, 2, NULL); - uiDefButR(block, TOG, B_NODE_EXEC, NULL, - butr->xmin, dy, dx, 19, - &ptr, "curved", 0, 0, 2, 10, 2, NULL); - uiBlockEndAlign(block); - } - return 95; + uiLayout *col; + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "samples", 0); + uiItemR(col, NULL, 0, ptr, "min_speed", 0); + uiItemR(col, NULL, 0, ptr, "max_speed", 0); + uiItemR(col, "Blur", 0, ptr, "factor", 0); + + col= uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "curved", 0); } -static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_filter(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; - - /* blend type */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; + + /* blend type */ + bt=uiDefButS(block, MENU, B_NODE_EXEC, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiButSetFunc(bt, node_but_title_cb, node, bt); } -static int node_composit_buts_flip(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_flip(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; - - /* flip x\y */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Flip X %x0|Flip Y %x1|Flip X & Y %x2", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; + + /* flip x\y */ + bt=uiDefButS(block, MENU, B_NODE_EXEC, "Flip X %x0|Flip Y %x1|Flip X & Y %x2", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiButSetFunc(bt, node_but_title_cb, node, bt); } -static int node_composit_buts_crop(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeTwoXYs *ntxy= node->storage; - char elementheight = 19; - short dx= (butr->xmax-butr->xmin)/2; - short dy= butr->ymax - elementheight; - short xymin= 0, xymax= 10000; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeTwoXYs *ntxy= node->storage; + char elementheight = 19; + short dx= (butr->xmax-butr->xmin)/2; + short dy= butr->ymax - elementheight; + short xymin= 0, xymax= 10000; - uiBlockBeginAlign(block); + uiBlockBeginAlign(block); - /* crop image size toggle */ - uiDefButS(block, TOG, B_NODE_EXEC, "Crop Image Size", - butr->xmin, dy, dx*2, elementheight, - &node->custom1, 0, 0, 0, 0, "Crop the size of the input image."); - - dy-=elementheight; - - /* x1 */ - uiDefButS(block, NUM, B_NODE_EXEC, "X1:", - butr->xmin, dy, dx, elementheight, - &ntxy->x1, xymin, xymax, 0, 0, ""); - /* y1 */ - uiDefButS(block, NUM, B_NODE_EXEC, "Y1:", - butr->xmin+dx, dy, dx, elementheight, - &ntxy->y1, xymin, xymax, 0, 0, ""); - - dy-=elementheight; - - /* x2 */ - uiDefButS(block, NUM, B_NODE_EXEC, "X2:", - butr->xmin, dy, dx, elementheight, - &ntxy->x2, xymin, xymax, 0, 0, ""); - /* y2 */ - uiDefButS(block, NUM, B_NODE_EXEC, "Y2:", - butr->xmin+dx, dy, dx, elementheight, - &ntxy->y2, xymin, xymax, 0, 0, ""); + /* crop image size toggle */ + uiDefButS(block, TOG, B_NODE_EXEC, "Crop Image Size", + butr->xmin, dy, dx*2, elementheight, + &node->custom1, 0, 0, 0, 0, "Crop the size of the input image."); + + dy-=elementheight; + + /* x1 */ + uiDefButS(block, NUM, B_NODE_EXEC, "X1:", + butr->xmin, dy, dx, elementheight, + &ntxy->x1, xymin, xymax, 0, 0, ""); + /* y1 */ + uiDefButS(block, NUM, B_NODE_EXEC, "Y1:", + butr->xmin+dx, dy, dx, elementheight, + &ntxy->y1, xymin, xymax, 0, 0, ""); + + dy-=elementheight; + + /* x2 */ + uiDefButS(block, NUM, B_NODE_EXEC, "X2:", + butr->xmin, dy, dx, elementheight, + &ntxy->x2, xymin, xymax, 0, 0, ""); + /* y2 */ + uiDefButS(block, NUM, B_NODE_EXEC, "Y2:", + butr->xmin+dx, dy, dx, elementheight, + &ntxy->y2, xymin, xymax, 0, 0, ""); - uiBlockEndAlign(block); - } - return 60; + uiBlockEndAlign(block); } -static int node_composit_buts_splitviewer(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBlockBeginAlign(block); - - uiDefButS(block, ROW, B_NODE_EXEC, "X", - butr->xmin, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 0.0, 0, 0, ""); - uiDefButS(block, ROW, B_NODE_EXEC, "Y", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 1.0, 0, 0, ""); - - uiDefButS(block, NUMSLI, B_NODE_EXEC, "Split %: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 100, 10, 0, ""); - } - return 40; -} - -static int node_composit_buts_map_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) -{ - if(block) { - TexMapping *texmap= node->storage; - short xstart= (short)butr->xmin; - short dy= (short)(butr->ymax-19.0f); - short dx= (short)(butr->xmax-butr->xmin)/2; - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, ""); - dy-= 23; - uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, ""); - } - return 80; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + uiBlockBeginAlign(block); + + uiDefButS(block, ROW, B_NODE_EXEC, "X", + butr->xmin, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, + &node->custom2, 0.0, 0.0, 0, 0, ""); + uiDefButS(block, ROW, B_NODE_EXEC, "Y", + butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, + &node->custom2, 0.0, 1.0, 0, 0, ""); + + uiDefButS(block, NUMSLI, B_NODE_EXEC, "Split %: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 100, 10, 0, ""); } -static int node_composit_buts_alphaover(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_map_value(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeTwoFloats *ntf= node->storage; - - /* alpha type */ - uiDefButS(block, TOG, B_NODE_EXEC, "ConvertPremul", - butr->xmin, butr->ymin+19, butr->xmax-butr->xmin, 19, - &node->custom1, 0, 0, 0, 0, ""); - /* mix factor */ - uiDefButF(block, NUM, B_NODE_EXEC, "Premul: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19, - &ntf->x, 0.0f, 1.0f, 100, 0, ""); - } - return 38; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + TexMapping *texmap= node->storage; + short xstart= (short)butr->xmin; + short dy= (short)(butr->ymax-19.0f); + short dx= (short)(butr->xmax-butr->xmin)/2; + + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); + dy-= 19; + uiDefButF(block, NUM, B_NODE_EXEC, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, ""); + dy-= 23; + uiBlockBeginAlign(block); + uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, ""); + dy-= 19; + uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); + uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, ""); } -static int node_composit_buts_hue_sat(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_alphaover(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeHueSat *nhs= node->storage; - - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Hue: ", - butr->xmin, butr->ymin+40.0f, butr->xmax-butr->xmin, 20, - &nhs->hue, 0.0f, 1.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Sat: ", - butr->xmin, butr->ymin+20.0f, butr->xmax-butr->xmin, 20, - &nhs->sat, 0.0f, 2.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Val: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &nhs->val, 0.0f, 2.0f, 100, 0, ""); - } - return 60; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeTwoFloats *ntf= node->storage; + + /* alpha type */ + uiDefButS(block, TOG, B_NODE_EXEC, "ConvertPremul", + butr->xmin, butr->ymin+19, butr->xmax-butr->xmin, 19, + &node->custom1, 0, 0, 0, 0, ""); + /* mix factor */ + uiDefButF(block, NUM, B_NODE_EXEC, "Premul: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19, + &ntf->x, 0.0f, 1.0f, 100, 0, ""); } -static int node_composit_buts_dilateerode(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_hue_sat(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiDefButS(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom2, -100, 100, 0, 0, "Distance to grow/shrink (number of iterations)"); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeHueSat *nhs= node->storage; + + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Hue: ", + butr->xmin, butr->ymin+40.0f, butr->xmax-butr->xmin, 20, + &nhs->hue, 0.0f, 1.0f, 100, 0, ""); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Sat: ", + butr->xmin, butr->ymin+20.0f, butr->xmax-butr->xmin, 20, + &nhs->sat, 0.0f, 2.0f, 100, 0, ""); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Val: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &nhs->val, 0.0f, 2.0f, 100, 0, ""); } -static int node_composit_buts_diff_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_dilateerode(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeChroma *c= node->storage; - - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color differences below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color differences below this additional threshold are partially keyed."); - uiBlockEndAlign(block); - } - return 40; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + uiDefButS(block, NUM, B_NODE_EXEC, "Distance:", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom2, -100, 100, 0, 0, "Distance to grow/shrink (number of iterations)"); } -static int node_composit_buts_distance_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_diff_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeChroma *c= node->storage; - - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color distances below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color distances below this additional threshold are partially keyed."); - uiBlockEndAlign(block); - } - return 40; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeChroma *c= node->storage; + + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", + butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 1.0f, 100, 0, "Color differences below this threshold are keyed."); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 1.0f, 100, 0, "Color differences below this additional threshold are partially keyed."); + uiBlockEndAlign(block); } -static int node_composit_buts_color_spill(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_distance_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - short dx= (butr->xmax-butr->xmin)/3; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeChroma *c= node->storage; + + uiBlockBeginAlign(block); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", + butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 1.0f, 100, 0, "Color distances below this threshold are keyed."); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 1.0f, 100, 0, "Color distances below this additional threshold are partially keyed."); + uiBlockEndAlign(block); +} - NodeChroma *c=node->storage; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Enhance: ", - butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.5f, 100, 2, "Adjusts how much selected channel is affected by color spill algorithm"); - uiDefButS(block, ROW, B_NODE_EXEC, "R", - butr->xmin,butr->ymin,dx,20, - &node->custom1,1,1, 0, 0, "Red Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "G", - butr->xmin+dx,butr->ymin,dx,20, - &node->custom1,1,2, 0, 0, "Green Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "B", - butr->xmin+2*dx,butr->ymin,dx,20, - &node->custom1, 1, 3, 0, 0, "Blue Spill Suppression"); - uiBlockEndAlign(block); - } - return 60; +static void node_composit_buts_color_spill(uiLayout *layout, PointerRNA *ptr) +{ + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + short dx= (butr->xmax-butr->xmin)/3; + + NodeChroma *c=node->storage; + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_NODE_EXEC, "Enhance: ", + butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 0.5f, 100, 2, "Adjusts how much selected channel is affected by color spill algorithm"); + uiDefButS(block, ROW, B_NODE_EXEC, "R", + butr->xmin,butr->ymin,dx,20, + &node->custom1,1,1, 0, 0, "Red Spill Suppression"); + uiDefButS(block, ROW, B_NODE_EXEC, "G", + butr->xmin+dx,butr->ymin,dx,20, + &node->custom1,1,2, 0, 0, "Green Spill Suppression"); + uiDefButS(block, ROW, B_NODE_EXEC, "B", + butr->xmin+2*dx,butr->ymin,dx,20, + &node->custom1, 1, 3, 0, 0, "Blue Spill Suppression"); + uiBlockEndAlign(block); } -static int node_composit_buts_chroma_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - short dx=(butr->xmax-butr->xmin)/2; - NodeChroma *c= node->storage; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + short dx=(butr->xmax-butr->xmin)/2; + NodeChroma *c= node->storage; - uiBlockBeginAlign(block); + uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", - butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, - &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", - butr->xmin, butr->ymin+20, dx, 20, - &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", - butr->xmin+dx, butr->ymin+20, dx, 20, - &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); - uiBlockEndAlign(block); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", + butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, + &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", + butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); + + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", + butr->xmin, butr->ymin+20, dx, 20, + &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", + butr->xmin+dx, butr->ymin+20, dx, 20, + &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); + + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); + uiBlockEndAlign(block); - if(c->t2 > c->t1) - c->t2=c->t1; - } - return 80; + if(c->t2 > c->t1) + c->t2=c->t1; } -static int node_composit_buts_color_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_color_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeChroma *c= node->storage; - uiBlockBeginAlign(block); + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeChroma *c= node->storage; + uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "H: ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.25f, 100, 0, "Hue tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "S: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Saturation Tolerance for the color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "V: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Value Tolerance for the color"); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "H: ", + butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 0.25f, 100, 0, "Hue tolerance for colors to be considered a keying color"); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "S: ", + butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 1.0f, 100, 0, "Saturation Tolerance for the color"); + uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "V: ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t3, 0.0f, 1.0f, 100, 0, "Value Tolerance for the color"); - uiBlockEndAlign(block); - } - return 60; + uiBlockEndAlign(block); } - -static int node_composit_buts_channel_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_channel_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - short sx= (butr->xmax-butr->xmin)/4; - short cx= (butr->xmax-butr->xmin)/3; - NodeChroma *c=node->storage; - char *c1, *c2, *c3; - - /*color space selectors*/ - uiBlockBeginAlign(block); - uiDefButS(block, ROW,B_NODE_EXEC,"RGB", - butr->xmin,butr->ymin+60,sx,20,&node->custom1,1,1, 0, 0, "RGB Color Space"); - uiDefButS(block, ROW,B_NODE_EXEC,"HSV", - butr->xmin+sx,butr->ymin+60,sx,20,&node->custom1,1,2, 0, 0, "HSV Color Space"); - uiDefButS(block, ROW,B_NODE_EXEC,"YUV", - butr->xmin+2*sx,butr->ymin+60,sx,20,&node->custom1,1,3, 0, 0, "YUV Color Space"); - uiDefButS(block, ROW,B_NODE_EXEC,"YCC", - butr->xmin+3*sx,butr->ymin+60,sx,20,&node->custom1,1,4, 0, 0, "YCbCr Color Space"); - - if (node->custom1==1) { - c1="R"; c2="G"; c3="B"; - } - else if(node->custom1==2){ - c1="H"; c2="S"; c3="V"; - } - else if(node->custom1==3){ - c1="Y"; c2="U"; c3="V"; - } - else { // if(node->custom1==4){ - c1="Y"; c2="Cb"; c3="Cr"; - } - - /*channel selector */ - uiDefButS(block, ROW, B_NODE_EXEC, c1, - butr->xmin,butr->ymin+40,cx,20,&node->custom2,1, 1, 0, 0, "Channel 1"); - uiDefButS(block, ROW, B_NODE_EXEC, c2, - butr->xmin+cx,butr->ymin+40,cx,20,&node->custom2,1, 2, 0, 0, "Channel 2"); - uiDefButS(block, ROW, B_NODE_EXEC, c3, - butr->xmin+cx+cx,butr->ymin+40,cx,20,&node->custom2, 1, 3, 0, 0, "Channel 3"); - - /*tolerance sliders */ - uiDefButF(block, NUMSLI, B_NODE_EXEC, "High ", - butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Low ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed"); - uiBlockEndAlign(block); - - /*keep t2 (low) less than t1 (high) */ - if(c->t2 > c->t1) { - c->t2=c->t1; - } + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + short sx= (butr->xmax-butr->xmin)/4; + short cx= (butr->xmax-butr->xmin)/3; + NodeChroma *c=node->storage; + char *c1, *c2, *c3; + + /*color space selectors*/ + uiBlockBeginAlign(block); + uiDefButS(block, ROW,B_NODE_EXEC,"RGB", + butr->xmin,butr->ymin+60,sx,20,&node->custom1,1,1, 0, 0, "RGB Color Space"); + uiDefButS(block, ROW,B_NODE_EXEC,"HSV", + butr->xmin+sx,butr->ymin+60,sx,20,&node->custom1,1,2, 0, 0, "HSV Color Space"); + uiDefButS(block, ROW,B_NODE_EXEC,"YUV", + butr->xmin+2*sx,butr->ymin+60,sx,20,&node->custom1,1,3, 0, 0, "YUV Color Space"); + uiDefButS(block, ROW,B_NODE_EXEC,"YCC", + butr->xmin+3*sx,butr->ymin+60,sx,20,&node->custom1,1,4, 0, 0, "YCbCr Color Space"); + + if (node->custom1==1) { + c1="R"; c2="G"; c3="B"; + } + else if(node->custom1==2){ + c1="H"; c2="S"; c3="V"; + } + else if(node->custom1==3){ + c1="Y"; c2="U"; c3="V"; + } + else { // if(node->custom1==4){ + c1="Y"; c2="Cb"; c3="Cr"; + } + + /*channel selector */ + uiDefButS(block, ROW, B_NODE_EXEC, c1, + butr->xmin,butr->ymin+40,cx,20,&node->custom2,1, 1, 0, 0, "Channel 1"); + uiDefButS(block, ROW, B_NODE_EXEC, c2, + butr->xmin+cx,butr->ymin+40,cx,20,&node->custom2,1, 2, 0, 0, "Channel 2"); + uiDefButS(block, ROW, B_NODE_EXEC, c3, + butr->xmin+cx+cx,butr->ymin+40,cx,20,&node->custom2, 1, 3, 0, 0, "Channel 3"); + + /*tolerance sliders */ + uiDefButF(block, NUMSLI, B_NODE_EXEC, "High ", + butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque"); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Low ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed"); + uiBlockEndAlign(block); + + /*keep t2 (low) less than t1 (high) */ + if(c->t2 > c->t1) { + c->t2=c->t1; } - return 80; } -static int node_composit_buts_luma_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_luma_matte(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeChroma *c=node->storage; - - /*tolerance sliders */ - uiDefButF(block, NUMSLI, B_NODE_EXEC, "High ", - butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Low ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed"); - uiBlockEndAlign(block); - - /*keep t2 (low) less than t1 (high) */ - if(c->t2 > c->t1) { - c->t2=c->t1; - } + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + NodeChroma *c=node->storage; + + /*tolerance sliders */ + uiDefButF(block, NUMSLI, B_NODE_EXEC, "High ", + butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, + &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque"); + uiDefButF(block, NUMSLI, B_NODE_EXEC, "Low ", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed"); + uiBlockEndAlign(block); + + /*keep t2 (low) less than t1 (high) */ + if(c->t2 > c->t1) { + c->t2=c->t1; } - return 40; } -static int node_composit_buts_map_uv(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_map_uv(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiDefButS(block, NUM, B_NODE_EXEC, "Alpha:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 100, 0, 0, "Conversion percentage of UV differences to Alpha"); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + uiDefButS(block, NUM, B_NODE_EXEC, "Alpha:", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 100, 0, 0, "Conversion percentage of UV differences to Alpha"); } -static int node_composit_buts_id_mask(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_id_mask(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiDefButS(block, NUM, B_NODE_EXEC, "ID:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 10000, 0, 0, "Pass Index number to convert to Alpha"); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + uiDefButS(block, NUM, B_NODE_EXEC, "ID:", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 10000, 0, 0, "Pass Index number to convert to Alpha"); } /* allocate sufficient! */ @@ -1880,58 +1844,58 @@ static void node_set_image_cb(bContext *C, void *ntree_v, void *node_v) nodeSetActive(ntree, node); } -static int node_composit_buts_file_output(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_file_output(uiLayout *layout, PointerRNA *ptr) { - if(block) { - NodeImageFile *nif= node->storage; - uiBut *bt; - short x= (short)butr->xmin; - short y= (short)butr->ymin; - short w= (short)butr->xmax-butr->xmin; - char str[320]; - - node_imagetype_string(str); - - uiBlockBeginAlign(block); - - bt = uiDefIconBut(block, BUT, B_NODE_SETIMAGE, ICON_FILESEL, - x, y+60, 20, 20, - 0, 0, 0, 0, 0, "Open Fileselect to get Backbuf image"); - uiButSetFunc(bt, node_set_image_cb, ntree, node); - - uiDefBut(block, TEX, B_NOP, "", - 20+x, y+60, w-20, 20, - nif->name, 0.0f, 240.0f, 0, 0, ""); - - uiDefButS(block, MENU, B_NOP, str, - x, y+40, w, 20, - &nif->imtype, 0.0f, 1.0f, 0, 0, ""); - - if(nif->imtype==R_OPENEXR) { - uiDefButBitS(block, TOG, R_OPENEXR_HALF, B_REDR, "Half", - x, y+20, w/2, 20, - &nif->subimtype, 0, 0, 0, 0, ""); - - uiDefButS(block, MENU,B_NOP, "Codec %t|None %x0|Pxr24 (lossy) %x1|ZIP (lossless) %x2|PIZ (lossless) %x3|RLE (lossless) %x4", - x+w/2, y+20, w/2, 20, - &nif->codec, 0, 0, 0, 0, ""); - } - else { - uiDefButS(block, NUM, B_NOP, "Quality: ", - x, y+20, w, 20, - &nif->quality, 10.0f, 100.0f, 10, 0, ""); - } - - /* start frame, end frame */ - uiDefButI(block, NUM, B_NODE_EXEC, "SFra: ", - x, y, w/2, 20, - &nif->sfra, 1, MAXFRAMEF, 10, 0, ""); - uiDefButI(block, NUM, B_NODE_EXEC, "EFra: ", - x+w/2, y, w/2, 20, - &nif->efra, 1, MAXFRAMEF, 10, 0, ""); - + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; + NodeImageFile *nif= node->storage; + uiBut *bt; + short x= (short)butr->xmin; + short y= (short)butr->ymin; + short w= (short)butr->xmax-butr->xmin; + char str[320]; + + node_imagetype_string(str); + + uiBlockBeginAlign(block); + + bt = uiDefIconBut(block, BUT, B_NODE_SETIMAGE, ICON_FILESEL, + x, y+60, 20, 20, + 0, 0, 0, 0, 0, "Open Fileselect to get Backbuf image"); + uiButSetFunc(bt, node_set_image_cb, ntree, node); + + uiDefBut(block, TEX, B_NOP, "", + 20+x, y+60, w-20, 20, + nif->name, 0.0f, 240.0f, 0, 0, ""); + + uiDefButS(block, MENU, B_NOP, str, + x, y+40, w, 20, + &nif->imtype, 0.0f, 1.0f, 0, 0, ""); + + if(nif->imtype==R_OPENEXR) { + uiDefButBitS(block, TOG, R_OPENEXR_HALF, B_REDR, "Half", + x, y+20, w/2, 20, + &nif->subimtype, 0, 0, 0, 0, ""); + + uiDefButS(block, MENU,B_NOP, "Codec %t|None %x0|Pxr24 (lossy) %x1|ZIP (lossless) %x2|PIZ (lossless) %x3|RLE (lossless) %x4", + x+w/2, y+20, w/2, 20, + &nif->codec, 0, 0, 0, 0, ""); + } + else { + uiDefButS(block, NUM, B_NOP, "Quality: ", + x, y+20, w, 20, + &nif->quality, 10.0f, 100.0f, 10, 0, ""); } - return 80; + + /* start frame, end frame */ + uiDefButI(block, NUM, B_NODE_EXEC, "SFra: ", + x, y, w/2, 20, + &nif->sfra, 1, MAXFRAMEF, 10, 0, ""); + uiDefButI(block, NUM, B_NODE_EXEC, "EFra: ", + x+w/2, y, w/2, 20, + &nif->efra, 1, MAXFRAMEF, 10, 0, ""); } static void node_scale_cb(bContext *C, void *node_v, void *unused_v) @@ -1952,65 +1916,66 @@ static void node_scale_cb(bContext *C, void *node_v, void *unused_v) } } -static int node_composit_buts_scale(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_scale(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt= uiDefButS(block, MENU, B_NODE_EXEC, "Relative %x0|Absolute %x1|Scene Size % %x2|", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, "Scale new image to absolute pixel size, size relative to the incoming image, or using the 'percent' size of the scene"); - uiButSetFunc(bt, node_scale_cb, node, NULL); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt= uiDefButS(block, MENU, B_NODE_EXEC, "Relative %x0|Absolute %x1|Scene Size % %x2|", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 0, 0, 0, "Scale new image to absolute pixel size, size relative to the incoming image, or using the 'percent' size of the scene"); + uiButSetFunc(bt, node_scale_cb, node, NULL); } -static int node_composit_buts_invert(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_invert(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC, "RGB", - butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC, "A", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiBlockEndAlign(block); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC, "RGB", + butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC, "A", + butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20, + &node->custom1, 0, 0, 0, 0, ""); + uiBlockEndAlign(block); } -static int node_composit_buts_premulkey(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_premulkey(uiLayout *layout, PointerRNA *ptr) { - if(block) { - uiBut *bt; - - /* blend type */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Key to Premul %x0|Premul to Key %x1", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, "Conversion between premultiplied alpha and key alpha"); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; + + /* blend type */ + bt=uiDefButS(block, MENU, B_NODE_EXEC, "Key to Premul %x0|Premul to Key %x1", + butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, + &node->custom1, 0, 0, 0, 0, "Conversion between premultiplied alpha and key alpha"); } -static int node_composit_buts_view_levels(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_composit_buts_view_levels(uiLayout *layout, PointerRNA *ptr) { - if(block) { - short sx= (butr->xmax-butr->xmin)/5; - - /*color space selectors*/ - uiBlockBeginAlign(block); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"C", - butr->xmin,butr->ymin,sx,20,&node->custom1,1,1, 0, 0, "Combined RGB"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"R", - butr->xmin+sx,butr->ymin,sx,20,&node->custom1,1,2, 0, 0, "Red Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"G", - butr->xmin+2*sx,butr->ymin,sx,20,&node->custom1,1,3, 0, 0, "Green Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"B", - butr->xmin+3*sx,butr->ymin,sx,20,&node->custom1,1,4, 0, 0, "Blue Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"L", - butr->xmin+4*sx,butr->ymin,sx,20,&node->custom1,1,5, 0, 0, "Luminenc Channel"); - uiBlockEndAlign(block); - } - return 20; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + short sx= (butr->xmax-butr->xmin)/5; + + /*color space selectors*/ + uiBlockBeginAlign(block); + uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"C", + butr->xmin,butr->ymin,sx,20,&node->custom1,1,1, 0, 0, "Combined RGB"); + uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"R", + butr->xmin+sx,butr->ymin,sx,20,&node->custom1,1,2, 0, 0, "Red Channel"); + uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"G", + butr->xmin+2*sx,butr->ymin,sx,20,&node->custom1,1,3, 0, 0, "Green Channel"); + uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"B", + butr->xmin+3*sx,butr->ymin,sx,20,&node->custom1,1,4, 0, 0, "Blue Channel"); + uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"L", + butr->xmin+4*sx,butr->ymin,sx,20,&node->custom1,1,5, 0, 0, "Luminenc Channel"); + uiBlockEndAlign(block); } @@ -2021,181 +1986,181 @@ static void node_composit_set_butfunc(bNodeType *ntype) /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */ case CMP_NODE_IMAGE: - ntype->butfunc= node_composit_buts_image; + ntype->uifunc= node_composit_buts_image; break; case CMP_NODE_R_LAYERS: - ntype->butfunc= node_composit_buts_renderlayers; + ntype->uifunc= node_composit_buts_renderlayers; break; case CMP_NODE_NORMAL: - ntype->butfunc= node_buts_normal; + ntype->uifunc= node_buts_normal; break; case CMP_NODE_CURVE_VEC: - ntype->butfunc= node_buts_curvevec; + ntype->uifunc= node_buts_curvevec; break; case CMP_NODE_CURVE_RGB: - ntype->butfunc= node_buts_curvecol; + ntype->uifunc= node_buts_curvecol; break; case CMP_NODE_VALUE: - ntype->butfunc= node_buts_value; + ntype->uifunc= node_buts_value; break; case CMP_NODE_RGB: - ntype->butfunc= node_buts_rgb; + ntype->uifunc= node_buts_rgb; break; case CMP_NODE_FLIP: - ntype->butfunc= node_composit_buts_flip; + ntype->uifunc= node_composit_buts_flip; break; case CMP_NODE_SPLITVIEWER: - ntype->butfunc= node_composit_buts_splitviewer; + ntype->uifunc= node_composit_buts_splitviewer; break; case CMP_NODE_MIX_RGB: - ntype->butfunc= node_buts_mix_rgb; + ntype->uifunc= node_buts_mix_rgb; break; case CMP_NODE_VALTORGB: - ntype->butfunc= node_buts_valtorgb; + ntype->uifunc= node_buts_valtorgb; break; case CMP_NODE_CROP: - ntype->butfunc= node_composit_buts_crop; + ntype->uifunc= node_composit_buts_crop; break; case CMP_NODE_BLUR: - ntype->butfunc= node_composit_buts_blur; + ntype->uifunc= node_composit_buts_blur; break; case CMP_NODE_DBLUR: - ntype->butfunc= node_composit_buts_dblur; + ntype->uifunc= node_composit_buts_dblur; break; case CMP_NODE_BILATERALBLUR: - ntype->butfunc= node_composit_buts_bilateralblur; + ntype->uifunc= node_composit_buts_bilateralblur; break; /* qdn: defocus node */ case CMP_NODE_DEFOCUS: - ntype->butfunc = node_composit_buts_defocus; + ntype->uifunc = node_composit_buts_defocus; break; /* qdn: glare node */ case CMP_NODE_GLARE: - ntype->butfunc = node_composit_buts_glare; + ntype->uifunc = node_composit_buts_glare; break; /* qdn: tonemap node */ case CMP_NODE_TONEMAP: - ntype->butfunc = node_composit_buts_tonemap; + ntype->uifunc = node_composit_buts_tonemap; break; /* qdn: lens distortion node */ case CMP_NODE_LENSDIST: - ntype->butfunc = node_composit_buts_lensdist; + ntype->uifunc = node_composit_buts_lensdist; break; case CMP_NODE_VECBLUR: - ntype->butfunc= node_composit_buts_vecblur; + ntype->uifunc= node_composit_buts_vecblur; break; case CMP_NODE_FILTER: - ntype->butfunc= node_composit_buts_filter; + ntype->uifunc= node_composit_buts_filter; break; case CMP_NODE_MAP_VALUE: - ntype->butfunc= node_composit_buts_map_value; + ntype->uifunc= node_composit_buts_map_value; break; case CMP_NODE_TIME: - ntype->butfunc= node_buts_time; + ntype->uifunc= node_buts_time; break; case CMP_NODE_ALPHAOVER: - ntype->butfunc= node_composit_buts_alphaover; + ntype->uifunc= node_composit_buts_alphaover; break; case CMP_NODE_HUE_SAT: - ntype->butfunc= node_composit_buts_hue_sat; + ntype->uifunc= node_composit_buts_hue_sat; break; case CMP_NODE_TEXTURE: - ntype->butfunc= node_buts_texture; + ntype->uifunc= node_buts_texture; break; case CMP_NODE_DILATEERODE: - ntype->butfunc= node_composit_buts_dilateerode; + ntype->uifunc= node_composit_buts_dilateerode; break; case CMP_NODE_OUTPUT_FILE: - ntype->butfunc= node_composit_buts_file_output; + ntype->uifunc= node_composit_buts_file_output; break; case CMP_NODE_DIFF_MATTE: - ntype->butfunc=node_composit_buts_diff_matte; + ntype->uifunc=node_composit_buts_diff_matte; break; case CMP_NODE_DIST_MATTE: - ntype->butfunc=node_composit_buts_distance_matte; + ntype->uifunc=node_composit_buts_distance_matte; break; case CMP_NODE_COLOR_SPILL: - ntype->butfunc=node_composit_buts_color_spill; + ntype->uifunc=node_composit_buts_color_spill; break; case CMP_NODE_CHROMA_MATTE: - ntype->butfunc=node_composit_buts_chroma_matte; + ntype->uifunc=node_composit_buts_chroma_matte; break; case CMP_NODE_COLOR_MATTE: - ntype->butfunc=node_composit_buts_color_matte; + ntype->uifunc=node_composit_buts_color_matte; break; case CMP_NODE_SCALE: - ntype->butfunc= node_composit_buts_scale; + ntype->uifunc= node_composit_buts_scale; break; case CMP_NODE_CHANNEL_MATTE: - ntype->butfunc= node_composit_buts_channel_matte; + ntype->uifunc= node_composit_buts_channel_matte; break; case CMP_NODE_LUMA_MATTE: - ntype->butfunc= node_composit_buts_luma_matte; + ntype->uifunc= node_composit_buts_luma_matte; break; case CMP_NODE_MAP_UV: - ntype->butfunc= node_composit_buts_map_uv; + ntype->uifunc= node_composit_buts_map_uv; break; case CMP_NODE_ID_MASK: - ntype->butfunc= node_composit_buts_id_mask; + ntype->uifunc= node_composit_buts_id_mask; break; case CMP_NODE_MATH: - ntype->butfunc= node_buts_math; + ntype->uifunc= node_buts_math; break; case CMP_NODE_INVERT: - ntype->butfunc= node_composit_buts_invert; + ntype->uifunc= node_composit_buts_invert; break; case CMP_NODE_PREMULKEY: - ntype->butfunc= node_composit_buts_premulkey; + ntype->uifunc= node_composit_buts_premulkey; break; case CMP_NODE_VIEW_LEVELS: - ntype->butfunc=node_composit_buts_view_levels; + ntype->uifunc=node_composit_buts_view_levels; break; default: - ntype->butfunc= NULL; + ntype->uifunc= NULL; } } /* ****************** BUTTON CALLBACKS FOR TEXTURE NODES ***************** */ -static int node_texture_buts_bricks(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_texture_buts_bricks(uiLayout *layout, PointerRNA *ptr) { - if(block) { - short w = butr->xmax-butr->xmin; - short ofw = 32; - - uiBlockBeginAlign(block); - - /* Offset */ - uiDefButF( - block, NUM, B_NODE_EXEC, "Offset", - butr->xmin, butr->ymin+20, w-ofw, 20, - &node->custom3, - 0, 1, 0.25, 2, - "Offset amount" ); - uiDefButS( - block, NUM, B_NODE_EXEC, "", - butr->xmin+w-ofw, butr->ymin+20, ofw, 20, - &node->custom1, - 2, 99, 0, 0, - "Offset every N rows" ); - - /* Squash */ - uiDefButF( - block, NUM, B_NODE_EXEC, "Squash", - butr->xmin, butr->ymin+0, w-ofw, 20, - &node->custom4, - 0, 99, 0.25, 2, - "Stretch amount" ); - uiDefButS( - block, NUM, B_NODE_EXEC, "", - butr->xmin+w-ofw, butr->ymin+0, ofw, 20, - &node->custom2, - 2, 99, 0, 0, - "Stretch every N rows" ); - - uiBlockEndAlign(block); - } - return 40; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + short w = butr->xmax-butr->xmin; + short ofw = 32; + + uiBlockBeginAlign(block); + + /* Offset */ + uiDefButF( + block, NUM, B_NODE_EXEC, "Offset", + butr->xmin, butr->ymin+20, w-ofw, 20, + &node->custom3, + 0, 1, 0.25, 2, + "Offset amount" ); + uiDefButS( + block, NUM, B_NODE_EXEC, "", + butr->xmin+w-ofw, butr->ymin+20, ofw, 20, + &node->custom1, + 2, 99, 0, 0, + "Offset every N rows" ); + + /* Squash */ + uiDefButF( + block, NUM, B_NODE_EXEC, "Squash", + butr->xmin, butr->ymin+0, w-ofw, 20, + &node->custom4, + 0, 99, 0.25, 2, + "Stretch amount" ); + uiDefButS( + block, NUM, B_NODE_EXEC, "", + butr->xmin+w-ofw, butr->ymin+0, ofw, 20, + &node->custom2, + 2, 99, 0, 0, + "Stretch every N rows" ); + + uiBlockEndAlign(block); } /* Copied from buttons_shading.c -- needs unifying */ @@ -2206,208 +2171,196 @@ static char* noisebasis_menu() return nbmenu; } -static int node_texture_buts_proc(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_texture_buts_proc(uiLayout *layout, PointerRNA *ptr) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; Tex *tex = (Tex *)node->storage; short x,y,w,h; - if( block ) { - x = butr->xmin; - y = butr->ymin; - w = butr->xmax - x; - h = butr->ymax - y; - } - else - return 0; + x = butr->xmin; + y = butr->ymin; + w = butr->xmax - x; + h = butr->ymax - y; switch( tex->type ) { case TEX_BLEND: - if( block ) { - uiBlockBeginAlign( block ); - uiDefButS( block, MENU, B_NODE_EXEC, - "Linear %x0|Quad %x1|Ease %x2|Diag %x3|Sphere %x4|Halo %x5|Radial %x6", - x, y+20, w, 20, &tex->stype, 0, 1, 0, 0, "Blend Type" ); - uiDefButBitS(block, TOG, TEX_FLIPBLEND, B_NODE_EXEC, "Flip XY", x, y, w, 20, - &tex->flag, 0, 0, 0, 0, "Flips the direction of the progression 90 degrees"); - uiBlockEndAlign( block ); - } - return 40; - + uiBlockBeginAlign( block ); + uiDefButS( block, MENU, B_NODE_EXEC, + "Linear %x0|Quad %x1|Ease %x2|Diag %x3|Sphere %x4|Halo %x5|Radial %x6", + x, y+20, w, 20, &tex->stype, 0, 1, 0, 0, "Blend Type" ); + uiDefButBitS(block, TOG, TEX_FLIPBLEND, B_NODE_EXEC, "Flip XY", x, y, w, 20, + &tex->flag, 0, 0, 0, 0, "Flips the direction of the progression 90 degrees"); + uiBlockEndAlign( block ); + break; case TEX_MARBLE: - if( block ) { - uiBlockBeginAlign(block); + uiBlockBeginAlign(block); + + uiDefButS(block, ROW, B_NODE_EXEC, "Soft", 0*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SOFT, 0, 0, "Uses soft marble"); + uiDefButS(block, ROW, B_NODE_EXEC, "Sharp", 1*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARP, 0, 0, "Uses more clearly defined marble"); + uiDefButS(block, ROW, B_NODE_EXEC, "Sharper", 2*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARPER, 0, 0, "Uses very clearly defined marble"); - uiDefButS(block, ROW, B_NODE_EXEC, "Soft", 0*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SOFT, 0, 0, "Uses soft marble"); - uiDefButS(block, ROW, B_NODE_EXEC, "Sharp", 1*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARP, 0, 0, "Uses more clearly defined marble"); - uiDefButS(block, ROW, B_NODE_EXEC, "Sharper", 2*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARPER, 0, 0, "Uses very clearly defined marble"); - - uiDefButS(block, ROW, B_NODE_EXEC, "Soft noise", 0*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); - uiDefButS(block, ROW, B_NODE_EXEC, "Hard noise", 1*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); - - uiDefButS(block, ROW, B_NODE_EXEC, "Sin", 0*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 0.0, 0, 0, "Uses a sine wave to produce bands."); - uiDefButS(block, ROW, B_NODE_EXEC, "Saw", 1*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 1.0, 0, 0, "Uses a saw wave to produce bands"); - uiDefButS(block, ROW, B_NODE_EXEC, "Tri", 2*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 2.0, 0, 0, "Uses a triangle wave to produce bands"); - - uiBlockEndAlign(block); - } - return 60; + uiDefButS(block, ROW, B_NODE_EXEC, "Soft noise", 0*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_NODE_EXEC, "Hard noise", 1*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + + uiDefButS(block, ROW, B_NODE_EXEC, "Sin", 0*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 0.0, 0, 0, "Uses a sine wave to produce bands."); + uiDefButS(block, ROW, B_NODE_EXEC, "Saw", 1*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 1.0, 0, 0, "Uses a saw wave to produce bands"); + uiDefButS(block, ROW, B_NODE_EXEC, "Tri", 2*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 2.0, 0, 0, "Uses a triangle wave to produce bands"); + + uiBlockEndAlign(block); + break; case TEX_WOOD: - if( block ) { - uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+64, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); - - uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_TEXPRV, "Bands", x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_BANDNOISE, 0, 0, "Uses standard noise"); - uiDefButS(block, ROW, B_TEXPRV, "Rings", w/2+x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_RINGNOISE, 0, 0, "Lets Noise return RGB value"); - - uiDefButS(block, ROW, B_NODE_EXEC, "Sin", 0*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SIN, 0, 0, "Uses a sine wave to produce bands."); - uiDefButS(block, ROW, B_NODE_EXEC, "Saw", 1*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SAW, 0, 0, "Uses a saw wave to produce bands"); - uiDefButS(block, ROW, B_NODE_EXEC, "Tri", 2*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_TRI, 0, 0, "Uses a triangle wave to produce bands"); - - uiDefButS(block, ROW, B_NODE_EXEC, "Soft noise", 0*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); - uiDefButS(block, ROW, B_NODE_EXEC, "Hard noise", 1*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); - uiBlockEndAlign(block); - } - return 80; + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+64, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); + + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_TEXPRV, "Bands", x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_BANDNOISE, 0, 0, "Uses standard noise"); + uiDefButS(block, ROW, B_TEXPRV, "Rings", w/2+x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_RINGNOISE, 0, 0, "Lets Noise return RGB value"); + + uiDefButS(block, ROW, B_NODE_EXEC, "Sin", 0*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SIN, 0, 0, "Uses a sine wave to produce bands."); + uiDefButS(block, ROW, B_NODE_EXEC, "Saw", 1*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SAW, 0, 0, "Uses a saw wave to produce bands"); + uiDefButS(block, ROW, B_NODE_EXEC, "Tri", 2*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_TRI, 0, 0, "Uses a triangle wave to produce bands"); + + uiDefButS(block, ROW, B_NODE_EXEC, "Soft noise", 0*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_NODE_EXEC, "Hard noise", 1*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + uiBlockEndAlign(block); + break; case TEX_CLOUDS: - if( block ) { - uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+60, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); - - uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_TEXPRV, "B/W", x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_DEFAULT, 0, 0, "Uses standard noise"); - uiDefButS(block, ROW, B_TEXPRV, "Color", w/2+x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_COLOR, 0, 0, "Lets Noise return RGB value"); - uiDefButS(block, ROW, B_TEXPRV, "Soft", x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); - uiDefButS(block, ROW, B_TEXPRV, "Hard", w/2+x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); - uiBlockEndAlign(block); - - uiDefButS(block, NUM, B_TEXPRV, "Depth:", x, y, w, 18, &tex->noisedepth, 0.0, 6.0, 0, 0, "Sets the depth of the cloud calculation"); - } - return 80; + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+60, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); + + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_TEXPRV, "B/W", x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_DEFAULT, 0, 0, "Uses standard noise"); + uiDefButS(block, ROW, B_TEXPRV, "Color", w/2+x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_COLOR, 0, 0, "Lets Noise return RGB value"); + uiDefButS(block, ROW, B_TEXPRV, "Soft", x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_TEXPRV, "Hard", w/2+x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + uiBlockEndAlign(block); + + uiDefButS(block, NUM, B_TEXPRV, "Depth:", x, y, w, 18, &tex->noisedepth, 0.0, 6.0, 0, 0, "Sets the depth of the cloud calculation"); + break; case TEX_DISTNOISE: - if( block ) { - uiBlockBeginAlign(block); - uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+18, w, 18, &tex->noisebasis2, 0,0,0,0, "Sets the noise basis to distort"); - uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis which does the distortion"); - uiBlockEndAlign(block); - } - return 36; + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+18, w, 18, &tex->noisebasis2, 0,0,0,0, "Sets the noise basis to distort"); + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis which does the distortion"); + uiBlockEndAlign(block); + break; } - return 0; } -static int node_texture_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_texture_buts_image(uiLayout *layout, PointerRNA *ptr) { + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + bNodeTree *ntree= ptr->id.data; + rctf *butr= &node->butr; char *strp; uiBut *bt; + + uiBlockBeginAlign(block); - if( block ) { - uiBlockBeginAlign(block); - - /* browse button */ - IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL); - node->menunr= 0; - bt= uiDefButS(block, MENU, B_NOP, strp, - butr->xmin, butr->ymin, 19, 19, - &node->menunr, 0, 0, 0, 0, "Browses existing choices"); - uiButSetFunc(bt, node_browse_image_cb, ntree, node); - if(strp) MEM_freeN(strp); + /* browse button */ + IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NOP, strp, + butr->xmin, butr->ymin, 19, 19, + &node->menunr, 0, 0, 0, 0, "Browses existing choices"); + uiButSetFunc(bt, node_browse_image_cb, ntree, node); + if(strp) MEM_freeN(strp); + + /* Add New button */ + if(node->id==NULL) { + bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New", + butr->xmin+19, butr->ymin, (short)(butr->xmax-butr->xmin-19.0f), 19, + NULL, 0.0, 0.0, 0, 0, "Add new Image"); + uiButSetFunc(bt, node_active_cb, ntree, node); + } + else { + /* name button */ + short xmin= (short)butr->xmin, xmax= (short)butr->xmax; + short width= xmax - xmin - 19; - /* Add New button */ - if(node->id==NULL) { - bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New", - butr->xmin+19, butr->ymin, (short)(butr->xmax-butr->xmin-19.0f), 19, - NULL, 0.0, 0.0, 0, 0, "Add new Image"); - uiButSetFunc(bt, node_active_cb, ntree, node); - } - else { - /* name button */ - short xmin= (short)butr->xmin, xmax= (short)butr->xmax; - short width= xmax - xmin - 19; - - bt= uiDefBut(block, TEX, B_NOP, "IM:", - xmin+19, butr->ymin, width, 19, - node->id->name+2, 0.0, 19.0, 0, 0, "Image name"); - uiButSetFunc(bt, node_ID_title_cb, node, NULL); - } + bt= uiDefBut(block, TEX, B_NOP, "IM:", + xmin+19, butr->ymin, width, 19, + node->id->name+2, 0.0, 19.0, 0, 0, "Image name"); + uiButSetFunc(bt, node_ID_title_cb, node, NULL); } - return 20; } -static int node_texture_buts_output(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +static void node_texture_buts_output(uiLayout *layout, PointerRNA *ptr) { - if( block ) { - uiBut *bt; - short width; - char *name = ((TexNodeOutput*)node->storage)->name; - - uiBlockBeginAlign(block); - - width = (short)(butr->xmax - butr->xmin); - - bt = uiDefBut( - block, TEX, B_NOP, - "Name:", - butr->xmin, butr->ymin, - width, 19, - name, 0, 31, - 0, 0, - "Name this output" - ); - - uiBlockEndAlign(block); - } - return 19; + uiBlock *block= uiLayoutFreeBlock(layout); + bNode *node= ptr->data; + rctf *butr= &node->butr; + uiBut *bt; + short width; + char *name = ((TexNodeOutput*)node->storage)->name; + + uiBlockBeginAlign(block); + + width = (short)(butr->xmax - butr->xmin); + + bt = uiDefBut( + block, TEX, B_NOP, + "Name:", + butr->xmin, butr->ymin, + width, 19, + name, 0, 31, + 0, 0, + "Name this output" + ); + + uiBlockEndAlign(block); } /* only once called */ static void node_texture_set_butfunc(bNodeType *ntype) { if( ntype->type >= TEX_NODE_PROC && ntype->type < TEX_NODE_PROC_MAX ) { - ntype->butfunc = node_texture_buts_proc; + ntype->uifunc = node_texture_buts_proc; } else switch(ntype->type) { case TEX_NODE_MATH: - ntype->butfunc = node_buts_math; + ntype->uifunc = node_buts_math; break; case TEX_NODE_MIX_RGB: - ntype->butfunc = node_buts_mix_rgb; + ntype->uifunc = node_buts_mix_rgb; break; case TEX_NODE_VALTORGB: - ntype->butfunc = node_buts_valtorgb; + ntype->uifunc = node_buts_valtorgb; break; case TEX_NODE_CURVE_RGB: - ntype->butfunc= node_buts_curvecol; + ntype->uifunc= node_buts_curvecol; break; case TEX_NODE_CURVE_TIME: - ntype->butfunc = node_buts_time; + ntype->uifunc = node_buts_time; break; case TEX_NODE_TEXTURE: - ntype->butfunc = node_buts_texture; + ntype->uifunc = node_buts_texture; break; case TEX_NODE_BRICKS: - ntype->butfunc = node_texture_buts_bricks; + ntype->uifunc = node_texture_buts_bricks; break; case TEX_NODE_IMAGE: - ntype->butfunc = node_texture_buts_image; + ntype->uifunc = node_texture_buts_image; break; case TEX_NODE_OUTPUT: - ntype->butfunc = node_texture_buts_output; + ntype->uifunc = node_texture_buts_output; break; default: - ntype->butfunc= NULL; + ntype->uifunc= NULL; } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index a872413b4e1..a87a141972b 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -81,6 +81,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "RNA_access.h" + #include "CMP_node.h" #include "SHD_node.h" @@ -91,6 +93,50 @@ extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); extern void ui_draw_tria_icon(float x, float y, float aspect, char dir); +void ED_node_changed_update(bContext *C, bNode *node) +{ + SpaceNode *snode= CTX_wm_space_node(C); + + if(!snode) + return; + + if(snode->treetype==NTREE_SHADER) { + WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, snode->id); + } + else if(snode->treetype==NTREE_COMPOSIT) { + NodeTagChanged(snode->edittree, node); + /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ + + /* not the best implementation of the world... but we need it to work now :) */ + if(node->type==CMP_NODE_R_LAYERS && node->custom2) { + /* add event for this window (after render curarea can be changed) */ + //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); + + //composite_node_render(snode, node); + //snode_handle_recalc(snode); + + /* add another event, a render can go fullscreen and open new window */ + //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); + } + else { + node= node_tree_get_editgroup(snode->nodetree); + if(node) + NodeTagIDChanged(snode->nodetree, node->id); + } + WM_event_add_notifier(C, NC_SCENE|ND_NODES, CTX_data_scene(C)); + } + else if(snode->treetype==NTREE_TEXTURE) { + WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); + } + +} + +static void do_node_internal_buttons(bContext *C, void *node_v, int event) +{ + if(event==B_NODE_EXEC) + ED_node_changed_update(C, node_v); +} + static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax) { @@ -110,10 +156,14 @@ static void node_scaling_widget(int color_id, float aspect, float xmin, float ym } /* based on settings in node, sets drawing rect info. each redraw! */ -static void node_update(bNode *node) +static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) { + uiLayout *layout; + PointerRNA ptr; bNodeSocket *nsock; float dy= node->locy; + int buty; + char str[32]; /* header */ dy-= NODE_DY; @@ -121,7 +171,7 @@ static void node_update(bNode *node) /* little bit space in top */ if(node->outputs.first) dy-= NODE_DYS/2; - + /* output sockets */ for(nsock= node->outputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { @@ -130,9 +180,9 @@ static void node_update(bNode *node) dy-= NODE_DY; } } - - node->prvr.xmin= node->butr.xmin= node->locx + NODE_DYS; - node->prvr.xmax= node->butr.xmax= node->locx + node->width- NODE_DYS; + + node->prvr.xmin= node->locx + NODE_DYS; + node->prvr.xmax= node->locx + node->width- NODE_DYS; /* preview rect? */ if(node->flag & NODE_PREVIEW) { @@ -176,16 +226,35 @@ static void node_update(bNode *node) /* XXX ugly hack, typeinfo for group is generated */ if(node->type == NODE_GROUP) - ; // XXX node->typeinfo->butfunc= node_buts_group; + ; // XXX node->typeinfo->uifunc= node_buts_group; + + /* ui block */ + sprintf(str, "node buttons %p", node); + node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS); + uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node); /* buttons rect? */ - if((node->flag & NODE_OPTIONS) && node->typeinfo->butfunc) { + if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) { dy-= NODE_DYS/2; - node->butr.ymax= dy; - node->butr.ymin= dy - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL); - dy= node->butr.ymin - NODE_DYS/2; + + /* set this for uifunc() that don't use layout engine yet */ + node->butr.xmin= 0; + node->butr.xmax= node->width - 2*NODE_DYS; + node->butr.ymin= 0; + node->butr.ymax= 0; + + RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); + + layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, + node->locx+NODE_DYS, dy, node->butr.xmax, 20, U.uistyles.first); + + node->typeinfo->uifunc(layout, &ptr); + uiBlockEndAlign(node->block); + uiBlockLayoutResolve(node->block, NULL, &buty); + + dy= buty - NODE_DYS/2; } - + /* input sockets */ for(nsock= node->inputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { @@ -198,7 +267,7 @@ static void node_update(bNode *node) /* little bit space in end */ if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 ) dy-= NODE_DYS/2; - + node->totr.xmin= node->locx; node->totr.xmax= node->locx + node->width; node->totr.ymax= node->locy; @@ -206,11 +275,12 @@ static void node_update(bNode *node) } /* based on settings in node, sets drawing rect info. each redraw! */ -static void node_update_hidden(bNode *node) +static void node_update_hidden(const bContext *C, bNode *node) { bNodeSocket *nsock; float rad, drad, hiddenrad= HIDDEN_RAD; int totin=0, totout=0, tot; + char str[32]; /* calculate minimal radius */ for(nsock= node->inputs.first; nsock; nsock= nsock->next) @@ -251,6 +321,11 @@ static void node_update_hidden(bNode *node) rad+= drad; } } + + /* ui block */ + sprintf(str, "node buttons %p", node); + node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS); + uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node); } static int node_get_colorid(bNode *node) @@ -275,7 +350,7 @@ static int node_get_colorid(bNode *node) /* based on settings in node, sets drawing rect info. each redraw! */ /* note: this assumes only 1 group at a time is drawn (linked data) */ /* in node->totr the entire boundbox for the group is stored */ -static void node_update_group(bNode *gnode) +static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode) { bNodeTree *ngroup= (bNodeTree *)gnode->id; bNode *node; @@ -288,9 +363,9 @@ static void node_update_group(bNode *gnode) node->locx+= gnode->locx; node->locy+= gnode->locy; if(node->flag & NODE_HIDDEN) - node_update_hidden(node); + node_update_hidden(C, node); else - node_update(node); + node_update(C, ntree, node); node->locx-= gnode->locx; node->locy-= gnode->locy; } @@ -575,61 +650,15 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) } -static void do_node_internal_buttons(bContext *C, void *node_v, int event) -{ - SpaceNode *snode= CTX_wm_space_node(C); - - if(event==B_NODE_EXEC) { - if(snode->treetype==NTREE_SHADER) { - WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, snode->id); - } - else if(snode->treetype==NTREE_COMPOSIT) { - bNode *node= node_v; - - NodeTagChanged(snode->edittree, node); - /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ - - /* not the best implementation of the world... but we need it to work now :) */ - if(node->type==CMP_NODE_R_LAYERS && node->custom2) { - /* add event for this window (after render curarea can be changed) */ - //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); - - //composite_node_render(snode, node); - //snode_handle_recalc(snode); - - /* add another event, a render can go fullscreen and open new window */ - //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); - } - else { - node= node_tree_get_editgroup(snode->nodetree); - if(node) - NodeTagIDChanged(snode->nodetree, node->id); - } - WM_event_add_notifier(C, NC_SCENE|ND_NODES, CTX_data_scene(C)); - } - else if(snode->treetype==NTREE_TEXTURE) { - WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); - } - } - -} - static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node) { bNodeSocket *sock; - uiBlock *block; uiBut *bt; rctf *rct= &node->totr; float /*slen,*/ iconofs; int /*ofs,*/ color_id= node_get_colorid(node); char showname[128]; /* 128 used below */ View2D *v2d = &ar->v2d; - char str[32]; - - /* make unique block name, also used for handling blocks in editnode.c */ - sprintf(str, "node buttons %p", node); - block= uiBeginBlock(C, ar, str, UI_EMBOSS); - uiBlockSetHandleFunc(block, do_node_internal_buttons, node); uiSetRoundBox(15-4); ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT); @@ -715,7 +744,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN else BLI_strncpy(showname, node->name, 128); - uiDefBut(block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), + uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), (int)(iconofs - rct->xmin-18.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); /* body */ @@ -743,7 +772,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* hurmf... another candidate for callback, have to see how this works first */ - if(node->id && block && snode->treetype==NTREE_SHADER) + if(node->id && node->block && snode->treetype==NTREE_SHADER) nodeShaderSynchronizeID(node, 0); /* socket inputs, buttons */ @@ -751,38 +780,38 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { socket_circle_draw(sock, NODE_SOCKSIZE); - if(block && sock->link==NULL) { + if(node->block && sock->link==NULL) { float *butpoin= sock->ns.vec; if(sock->type==SOCK_VALUE) { - bt= uiDefButF(block, NUM, B_NODE_EXEC, sock->name, + bt= uiDefButF(node->block, NUM, B_NODE_EXEC, sock->name, (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17, butpoin, sock->ns.min, sock->ns.max, 10, 2, ""); uiButSetFunc(bt, node_sync_cb, snode, node); } else if(sock->type==SOCK_VECTOR) { - uiDefBlockBut(block, socket_vector_menu, sock, sock->name, + uiDefBlockBut(node->block, socket_vector_menu, sock, sock->name, (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17, ""); } - else if(block && sock->type==SOCK_RGBA) { + else if(node->block && sock->type==SOCK_RGBA) { short labelw= (short)node->width-NODE_DY-40, width; if(labelw>0) width= 40; else width= (short)node->width-NODE_DY; - bt= uiDefButF(block, COL, B_NODE_EXEC, "", + bt= uiDefButF(node->block, COL, B_NODE_EXEC, "", (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15, butpoin, 0, 0, 0, 0, ""); uiButSetFunc(bt, node_sync_cb, snode, node); - if(labelw>0) uiDefBut(block, LABEL, 0, sock->name, + if(labelw>0) uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15, NULL, 0, 0, 0, 0, ""); } } else { - uiDefBut(block, LABEL, 0, sock->name, (short)(sock->locx+3.0f), (short)(sock->locy-9.0f), + uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+3.0f), (short)(sock->locy-9.0f), (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); } } @@ -803,7 +832,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN slen= snode->aspect*UI_GetStringWidth(sock->name+ofs); } - uiDefBut(block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), + uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); } } @@ -813,33 +842,19 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if(node->preview && node->preview->rect) node_draw_preview(node->preview, &node->prvr); - /* buttons */ - if(node->flag & NODE_OPTIONS) { - if(block) { - if(node->typeinfo->butfunc) { - node->typeinfo->butfunc(block, snode->nodetree, node, &node->butr); - } - } - } - - uiEndBlock(C, block); - uiDrawBlock(C, block); + uiEndBlock(C, node->block); + uiDrawBlock(C, node->block); + node->block= NULL; } static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node) { - uiBlock *block; bNodeSocket *sock; rctf *rct= &node->totr; float dx, centy= 0.5f*(rct->ymax+rct->ymin); float hiddenrad= 0.5f*(rct->ymax-rct->ymin); int color_id= node_get_colorid(node); - char str[32], showname[128]; /* 128 is used below */ - - /* make unique block name, also used for handling blocks in editnode.c */ - sprintf(str, "node buttons %p", node); - block= uiBeginBlock(C, ar, str, UI_EMBOSS); - uiBlockSetHandleFunc(block, do_node_internal_buttons, node); + char showname[128]; /* 128 is used below */ /* shadow */ uiSetRoundBox(15); @@ -884,7 +899,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b else BLI_strncpy(showname, node->name, 128); - uiDefBut(block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), + uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); } @@ -910,9 +925,9 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b socket_circle_draw(sock, NODE_SOCKSIZE); } - uiEndBlock(C, block); - uiDrawBlock(C, block); - + uiEndBlock(C, node->block); + uiDrawBlock(C, node->block); + node->block= NULL; } static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree) @@ -1081,11 +1096,11 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) /* for now, we set drawing coordinates on each redraw */ for(node= snode->nodetree->nodes.first; node; node= node->next) { if(node->flag & NODE_GROUP_EDIT) - node_update_group(node); + node_update_group(C, snode->nodetree, node); else if(node->flag & NODE_HIDDEN) - node_update_hidden(node); + node_update_hidden(C, node); else - node_update(node); + node_update(C, snode->nodetree, node); } node_draw_nodetree(C, ar, snode, snode->nodetree); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b10de02dbb4..e70221df9ab 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -40,6 +40,7 @@ struct bNodeLink; struct bNodeType; struct bNodeGroup; struct AnimData; +struct uiBlock; #define NODE_MAXSTR 32 @@ -131,6 +132,7 @@ typedef struct bNode { rctf butr; /* optional buttons area */ rctf prvr; /* optional preview area */ bNodePreview *preview; /* optional preview image */ + struct uiBlock *block; /* runtime during drawing */ struct bNodeType *typeinfo; /* lookup of callbacks and defaults */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 99f61c7a724..25fc8e966dc 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -25,6 +25,7 @@ #include #include +#include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" @@ -37,8 +38,81 @@ #include "BKE_node.h" #include "BKE_image.h" +static EnumPropertyItem node_blend_type_items[] = { + { 0, "MIX", 0, "Mix", ""}, + { 1, "ADD", 0, "Add", ""}, + { 3, "SUBTRACT", 0, "Subtract", ""}, + { 2, "MULTIPLY", 0, "Multiply", ""}, + { 4, "SCREEN", 0, "Screen", ""}, + { 9, "OVERLAY", 0, "Overlay", ""}, + { 5, "DIVIDE", 0, "Divide", ""}, + { 6, "DIFFERENCE", 0, "Difference", ""}, + { 7, "DARKEN", 0, "Darken", ""}, + { 8, "LIGHTEN", 0, "Lighten", ""}, + {10, "DODGE", 0, "Dodge", ""}, + {11, "BURN", 0, "Burn", ""}, + {15, "COLOR", 0, "Color", ""}, + {14, "VALUE", 0, "Value", ""}, + {13, "SATURATION", 0, "Saturation", ""}, + {12, "HUE", 0, "Hue", ""}, + {16, "SOFT_LIGHT", 0, "Soft Light", ""}, + {17, "LINEAR_LIGHT", 0, "Linear Light",""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_flip_items[] = { + {0, "X", 0, "Flip X", ""}, + {1, "Y", 0, "Flip Y", ""}, + {2, "XY", 0, "Flip X & Y", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_math_items[] = { + { 0, "ADD", 0, "Add", ""}, + { 1, "SUBTRACT", 0, "Subtract", ""}, + { 2, "MULTIPLY", 0, "Multiply", ""}, + { 3, "DIVIDE", 0, "Divide", ""}, + { 4, "SINE", 0, "Sine", ""}, + { 5, "COSINE", 0, "Cosine", ""}, + { 6, "TANGENT", 0, "Tangent", ""}, + { 7, "ARCSINE", 0, "Arcsine", ""}, + { 8, "ARCCOSINE", 0, "Arccosine", ""}, + { 9, "ARCTANGENT", 0, "Arctangent", ""}, + {10, "POWER", 0, "Power", ""}, + {11, "LOGARITHM", 0, "Logarithm", ""}, + {12, "MINIMUM", 0, "Minimum", ""}, + {13, "MAXIMUM", 0, "Maximum", ""}, + {14, "ROUND", 0, "Round", ""}, + {15, "LESS_THAN", 0, "Less Than", ""}, + {16, "GREATER_THAN", 0, "Greater Than", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_vec_math_items[] = { + {0, "ADD", 0, "Add", ""}, + {1, "SUBTRACT", 0, "Subtract", ""}, + {2, "AVERAGE", 0, "Average", ""}, + {3, "DOT_PRODUCT", 0, "Dot Product", ""}, + {4, "CROSS_PRODUCT", 0, "Cross Product", ""}, + {5, "NORMALIZE", 0, "Normalize", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_filter_items[] = { + {0, "SOFTEN", 0, "Soften", ""}, + {1, "SHARPEN", 0, "Sharpen", ""}, + {2, "LAPLACE", 0, "Laplace", ""}, + {3, "SOBEL", 0, "Sobel", ""}, + {4, "PREWITT", 0, "Prewitt", ""}, + {5, "KIRSCH", 0, "Kirsch", ""}, + {6, "SHADOW", 0, "Shadow", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME +#include "ED_node.h" + static StructRNA *rna_Node_refine(struct PointerRNA *ptr) { bNode *node = (bNode*)ptr->data; @@ -66,6 +140,53 @@ static char *rna_Node_path(PointerRNA *ptr) return BLI_sprintfN("nodes[%d]", index); } +static void rna_Node_update(bContext *C, PointerRNA *ptr) +{ + bNode *node= (bNode*)ptr->data; + + ED_node_changed_update(C, node); +} + +static void rna_Node_update_name(bContext *C, PointerRNA *ptr) +{ + bNode *node= (bNode*)ptr->data; + const char *name; + + if(node->id) { + BLI_strncpy(node->name, node->id->name+2, NODE_MAXSTR); + } + else { + switch(node->typeinfo->type) { + case SH_NODE_MIX_RGB: + case CMP_NODE_MIX_RGB: + case TEX_NODE_MIX_RGB: + if(RNA_enum_name(node_blend_type_items, node->custom1, &name)) + BLI_strncpy(node->name, name, NODE_MAXSTR); + break; + case CMP_NODE_FILTER: + if(RNA_enum_name(node_filter_items, node->custom1, &name)) + BLI_strncpy(node->name, name, NODE_MAXSTR); + break; + case CMP_NODE_FLIP: + if(RNA_enum_name(node_flip_items, node->custom1, &name)) + BLI_strncpy(node->name, name, NODE_MAXSTR); + break; + case SH_NODE_MATH: + case CMP_NODE_MATH: + case TEX_NODE_MATH: + if(RNA_enum_name(node_math_items, node->custom1, &name)) + BLI_strncpy(node->name, name, NODE_MAXSTR); + break; + case SH_NODE_VECT_MATH: + if(RNA_enum_name(node_vec_math_items, node->custom1, &name)) + BLI_strncpy(node->name, name, NODE_MAXSTR); + break; + } + } + + rna_Node_update(C, ptr); +} + #else #define MaxNodes 1000 @@ -183,53 +304,22 @@ static void def_math(StructRNA *srna) { PropertyRNA *prop; - static EnumPropertyItem items[] = { - { 0, "ADD", 0, "Add", ""}, - { 1, "SUBTRACT", 0, "Subtract", ""}, - { 2, "MULTIPLY", 0, "Multiply", ""}, - { 3, "DIVIDE", 0, "Divide", ""}, - { 4, "SINE", 0, "Sine", ""}, - { 5, "COSINE", 0, "Cosine", ""}, - { 6, "TANGENT", 0, "Tangent", ""}, - { 7, "ARCSINE", 0, "Arcsine", ""}, - { 8, "ARCCOSINE", 0, "Arccosine", ""}, - { 9, "ARCTANGENT", 0, "Arctangent", ""}, - {10, "POWER", 0, "Power", ""}, - {11, "LOGARITHM", 0, "Logarithm", ""}, - {12, "MINIMUM", 0, "Minimum", ""}, - {13, "MAXIMUM", 0, "Maximum", ""}, - {14, "ROUND", 0, "Round", ""}, - {15, "LESS_THAN", 0, "Less Than", ""}, - {16, "GREATER_THAN", 0, "Greater Than", ""}, - - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); - RNA_def_property_enum_items(prop, items); + RNA_def_property_enum_items(prop, node_math_items); RNA_def_property_ui_text(prop, "Operation", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); } static void def_vector_math(StructRNA *srna) { PropertyRNA *prop; - static EnumPropertyItem items[] = { - {0, "ADD", 0, "Add", ""}, - {1, "SUBTRACT", 0, "Subtract", ""}, - {2, "AVERAGE", 0, "Average", ""}, - {3, "DOT_PRODUCT", 0, "Dot Product", ""}, - {4, "CROSS_PRODUCT", 0, "Cross Product", ""}, - {5, "NORMALIZE", 0, "Normalize", ""}, - - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); - RNA_def_property_enum_items(prop, items); + RNA_def_property_enum_items(prop, node_vec_math_items); RNA_def_property_ui_text(prop, "Operation", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); } static void def_rgb_curve(StructRNA *srna) @@ -240,6 +330,7 @@ static void def_rgb_curve(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_vector_curve(StructRNA *srna) @@ -250,6 +341,7 @@ static void def_vector_curve(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_time(StructRNA *srna) @@ -260,59 +352,44 @@ static void def_time(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Curve", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "start", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text(prop, "Start Frame", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "end", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_ui_text(prop, "End Frame", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_val_to_rgb(StructRNA *srna) { - /*PropertyRNA *prop;*/ + PropertyRNA *prop; - /* TODO: uncomment when ColorBand is wrapped *//* - prop = RNA_def_property(srna, "color_band", PROP_POINTER, PROP_NONE); + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); - RNA_def_property_struct_type(prop, "ColorBand"); - RNA_def_property_ui_text(prop, "Color Band", "");*/ + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_mix_rgb(StructRNA *srna) { PropertyRNA *prop; - static EnumPropertyItem blend_type_items[] = { - { 0, "MIX", 0, "Mix", ""}, - { 1, "ADD", 0, "Add", ""}, - { 3, "SUBTRACT", 0, "Subtract", ""}, - { 2, "MULTIPLY", 0, "Multiply", ""}, - { 4, "SCREEN", 0, "Screen", ""}, - { 9, "OVERLAY", 0, "Overlay", ""}, - { 5, "DIVIDE", 0, "Divide", ""}, - { 6, "DIFFERENCE", 0, "Difference", ""}, - { 7, "DARKEN", 0, "Darken", ""}, - { 8, "LIGHTEN", 0, "Lighten", ""}, - {10, "DODGE", 0, "Dodge", ""}, - {11, "BURN", 0, "Burn", ""}, - {15, "COLOR", 0, "Color", ""}, - {14, "VALUE", 0, "Value", ""}, - {13, "SATURATION", 0, "Saturation", ""}, - {12, "HUE", 0, "Hue", ""}, - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); - RNA_def_property_enum_items(prop, blend_type_items); + RNA_def_property_enum_items(prop, node_blend_type_items); RNA_def_property_ui_text(prop, "Blend Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); prop = RNA_def_property(srna, "alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", 1); - RNA_def_property_ui_text(prop, "Diffuse", "Include alpha of second input in this operation"); + RNA_def_property_ui_text(prop, "Alpha", "Include alpha of second input in this operation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_texture(StructRNA *srna) @@ -324,10 +401,12 @@ static void def_texture(StructRNA *srna) RNA_def_property_struct_type(prop, "Texture"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Texture", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); prop = RNA_def_property(srna, "node_output", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text(prop, "Node Output", "For node-based textures, which output node to use"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -342,18 +421,22 @@ static void def_sh_material(StructRNA *srna) RNA_def_property_struct_type(prop, "Material"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Material", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); prop = RNA_def_property(srna, "diffuse", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_DIFF); RNA_def_property_ui_text(prop, "Diffuse", "Material Node outputs Diffuse"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "specular", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_SPEC); RNA_def_property_ui_text(prop, "Specular", "Material Node outputs Specular"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "invert_normal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_NEG); RNA_def_property_ui_text(prop, "Invert Normal", "Material Node uses inverted normal"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_mapping(StructRNA *srna) @@ -364,6 +447,7 @@ static void def_sh_mapping(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "TexMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_geometry(StructRNA *srna) @@ -375,10 +459,12 @@ static void def_sh_geometry(StructRNA *srna) prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "uvname"); RNA_def_property_ui_text(prop, "UV Layer", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "color_layer", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "colname"); RNA_def_property_ui_text(prop, "Vertex Color Layer", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -391,6 +477,7 @@ static void def_cmp_alpha_over(StructRNA *srna) prop = RNA_def_property(srna, "convert_premul", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "convert_premul", "TODO: don't know what this is"); + RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoFloats", "storage"); @@ -398,6 +485,7 @@ static void def_cmp_alpha_over(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Premul", "Mix Factor"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_blur(StructRNA *srna) @@ -422,58 +510,70 @@ static void def_cmp_blur(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "sizex"); RNA_def_property_range(prop, 0, 256); RNA_def_property_ui_text(prop, "Size X", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "sizey", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sizey"); RNA_def_property_range(prop, 1, 256); RNA_def_property_ui_text(prop, "Size Y", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "samples"); RNA_def_property_range(prop, 1, 256); RNA_def_property_ui_text(prop, "Samples", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max_speed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "maxspeed"); RNA_def_property_range(prop, 1, 1024); RNA_def_property_ui_text(prop, "Max Speed", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "min_speed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "minspeed"); RNA_def_property_range(prop, 1, 1024); RNA_def_property_ui_text(prop, "Min Speed", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "relative", 1); RNA_def_property_ui_text(prop, "Relative", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac"); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Factor", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "factor_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "percentx"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Relative Size X", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "factor_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "percenty"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Relative Size Y", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "filtertype"); RNA_def_property_enum_items(prop, filter_type_items); RNA_def_property_ui_text(prop, "Filter Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "bokeh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bokeh", 1); RNA_def_property_ui_text(prop, "Bokeh", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "gamma", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gamma", 1); RNA_def_property_ui_text(prop, "Gamma", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: @@ -490,21 +590,11 @@ static void def_cmp_filter(StructRNA *srna) { PropertyRNA *prop; - static EnumPropertyItem type_items[] = { - {0, "SOFTEN", 0, "Soften", ""}, - {1, "SHARPEN", 0, "Sharpen", ""}, - {2, "LAPLACE", 0, "Laplace", ""}, - {3, "SOBEL", 0, "Sobel", ""}, - {4, "PREWITT", 0, "Prewitt", ""}, - {5, "KIRSCH", 0, "Kirsch", ""}, - {6, "SHADOW", 0, "Shadow", ""}, - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); - RNA_def_property_enum_items(prop, type_items); + RNA_def_property_enum_items(prop, node_filter_items); RNA_def_property_ui_text(prop, "Filter Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); } static void def_cmp_map_value(StructRNA *srna) @@ -517,29 +607,35 @@ static void def_cmp_map_value(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Offset", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "size"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Size", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN); RNA_def_property_ui_text(prop, "Use Minimum", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX); RNA_def_property_ui_text(prop, "Use Maximum", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Minimum", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Maximum", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_vector_blur(StructRNA *srna) @@ -551,22 +647,27 @@ static void def_cmp_vector_blur(StructRNA *srna) prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "samples"); RNA_def_property_ui_text(prop, "Samples", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "min_speed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "minspeed"); RNA_def_property_ui_text(prop, "Min Speed", "Minimum speed for a pixel to be blurred; used to separate background from foreground"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max_speed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "maxspeed"); - RNA_def_property_ui_text(prop, "Min Speed", "Maximum speed, or zero for none"); + RNA_def_property_ui_text(prop, "Max Speed", "Maximum speed, or zero for none"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac"); RNA_def_property_ui_text(prop, "Blur Factor", "Scaling factor for motion vectors; actually 'shutter speed' in frames"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "curved", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "curved", 1); RNA_def_property_ui_text(prop, "Curved", "Interpolate between frames in a bezier curve, rather than linearly"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_image(StructRNA *srna) @@ -586,6 +687,7 @@ static void def_cmp_image(StructRNA *srna) RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Image", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); RNA_def_struct_sdna_from(srna, "ImageUser", "storage"); @@ -595,24 +697,29 @@ static void def_cmp_image(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "frames"); RNA_def_property_range(prop, 1, MAXFRAMEF); RNA_def_property_ui_text(prop, "Frames", "Number of images used in animation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "start", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sfra"); RNA_def_property_range(prop, 1, MAXFRAMEF); RNA_def_property_ui_text(prop, "Start Frame", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "offset", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "offset"); RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF); RNA_def_property_ui_text(prop, "Offset", "Offsets the number of the frame to use in the animation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cycl", 1); RNA_def_property_ui_text(prop, "Cyclic", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "auto_refresh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS); RNA_def_property_ui_text(prop, "Auto-Refresh", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* } */ @@ -622,6 +729,7 @@ static void def_cmp_image(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "layer"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Layer", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* } */ @@ -638,16 +746,19 @@ static void def_cmp_render_layers(StructRNA *srna) RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Scene", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); /* TODO: layers in menu */ prop = RNA_def_property(srna, "layer", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text(prop, "Layer", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: comments indicate this might be a hack */ prop = RNA_def_property(srna, "re_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", 1); RNA_def_property_ui_text(prop, "Re-render", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_output_file(StructRNA *srna) @@ -711,11 +822,13 @@ static void def_cmp_output_file(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "sfra"); RNA_def_property_range(prop, 1, MAXFRAMEF); RNA_def_property_ui_text(prop, "Start Frame", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "end", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "efra"); RNA_def_property_range(prop, 1, MAXFRAMEF); RNA_def_property_ui_text(prop, "End Frame", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_dilate_erode(StructRNA *srna) @@ -725,6 +838,7 @@ static void def_cmp_dilate_erode(StructRNA *srna) prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_scale(StructRNA *srna) @@ -742,6 +856,7 @@ static void def_cmp_scale(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text(prop, "Space", "Coordinate space to scale relative to"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_diff_matte(StructRNA *srna) @@ -756,11 +871,13 @@ static void def_cmp_diff_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Tolerance", "Color distances below this threshold are keyed."); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Falloff", "Color distances below this additional threshold are partially keyed."); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_color_matte(StructRNA *srna) @@ -775,16 +892,19 @@ static void def_cmp_color_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "H", "Hue tolerance for colors to be considered a keying color"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "s", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "S", "Saturation Tolerance for the color"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "v", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "V", "Value Tolerance for the color"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_distance_matte(StructRNA *srna) @@ -799,11 +919,13 @@ static void def_cmp_distance_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Tolerance", "Color distances below this threshold are keyed."); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Falloff", "Color distances below this additional threshold are partially keyed."); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_color_spill(StructRNA *srna) @@ -821,6 +943,7 @@ static void def_cmp_color_spill(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, channel_items); RNA_def_property_ui_text(prop, "Channel", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); @@ -828,6 +951,7 @@ static void def_cmp_color_spill(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 0.5f); RNA_def_property_ui_text(prop, "Amount", "How much the selected channel is affected by"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_chroma_matte(StructRNA *srna) @@ -840,26 +964,31 @@ static void def_cmp_chroma_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 1.0f, 80.0f); RNA_def_property_ui_text(prop, "Acceptance", "Tolerance for a color to be considered a keying color"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "cutoff", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 30.0f); RNA_def_property_ui_text(prop, "Cutoff", "Tolerance below which colors will be considered as exact matches"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fsize"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Lift", "Alpha lift"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fstrength"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gain", "Alpha gain"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "shadow_adjust", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Shadow Adjust", "Adjusts the brightness of any shadows captured"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: if(c->t2 > c->t1) @@ -883,10 +1012,12 @@ static void def_cmp_channel_matte(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_ui_text(prop, "Color Space", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: channel must be 1, 2 or 3 */ prop = RNA_def_property(srna, "channel", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); + RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_property_ui_text(prop, "Channel", ""); RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); @@ -895,11 +1026,13 @@ static void def_cmp_channel_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "low", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: if(c->t2 > c->t1) @@ -911,17 +1044,11 @@ static void def_cmp_flip(StructRNA *srna) { PropertyRNA *prop; - static EnumPropertyItem axis_items[] = { - {0, "X", 0, "X", ""}, - {1, "Y", 0, "Y", ""}, - {2, "XY", 0, "X & Y", ""}, - {0, NULL, 0, NULL, NULL} - }; - prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); - RNA_def_property_enum_items(prop, axis_items); + RNA_def_property_enum_items(prop, node_flip_items); RNA_def_property_ui_text(prop, "Axis", ""); + RNA_def_property_update(prop, 0, "rna_Node_update_name"); } static void def_cmp_splitviewer(StructRNA *srna) @@ -938,12 +1065,14 @@ static void def_cmp_splitviewer(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Axis", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: percentage */ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_PERCENTAGE); RNA_def_property_float_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Factor", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_id_mask(StructRNA *srna) @@ -954,6 +1083,7 @@ static void def_cmp_id_mask(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Index", "Pass index number to convert to alpha"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_map_uv(StructRNA *srna) @@ -965,6 +1095,7 @@ static void def_cmp_map_uv(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Alpha", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_defocus(StructRNA *srna) @@ -988,50 +1119,60 @@ static void def_cmp_defocus(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "bktype"); RNA_def_property_enum_items(prop, bokeh_items); RNA_def_property_ui_text(prop, "Bokeh Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: angle in degrees */ prop = RNA_def_property(srna, "angle", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "rotation"); RNA_def_property_range(prop, 0, 90); RNA_def_property_ui_text(prop, "Angle", "Bokeh shape rotation offset in degrees"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "gamma_correction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gamco", 1); RNA_def_property_ui_text(prop, "Gamma Correction", "Enable gamma correction before and after main process"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO */ prop = RNA_def_property(srna, "f_stop", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fstop"); RNA_def_property_range(prop, 0.0f, 128.0f); RNA_def_property_ui_text(prop, "fStop", "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max_blur", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "maxblur"); RNA_def_property_range(prop, 0.0f, 10000.0f); RNA_def_property_ui_text(prop, "Max Blur", "blur limit, maximum CoC radius, 0=no limit"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bthresh"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Threshold", "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "preview", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "preview", 1); RNA_def_property_ui_text(prop, "Preview", "Enable sampling mode, useful for preview when using low samplecounts"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "samples"); RNA_def_property_range(prop, 16, 256); RNA_def_property_ui_text(prop, "Samples", "Number of samples (16=grainy, higher=less noise)"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "use_zbuffer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "no_zbuf", 1); RNA_def_property_ui_text(prop, "Use Z-Buffer", "Disable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "z_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "scale"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text(prop, "Z-Scale", "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_luma_matte(StructRNA *srna) @@ -1044,11 +1185,13 @@ static void def_cmp_luma_matte(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "low", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: keep low less than high */ @@ -1061,10 +1204,12 @@ static void def_cmp_invert(StructRNA *srna) prop = RNA_def_property(srna, "rgb", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_CHAN_RGB); RNA_def_property_ui_text(prop, "RGB", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_CHAN_A); RNA_def_property_ui_text(prop, "Alpha", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_crop(StructRNA *srna) @@ -1074,6 +1219,7 @@ static void def_cmp_crop(StructRNA *srna) prop = RNA_def_property(srna, "crop_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Crop Image Size", "Whether to crop the size of the input image"); + RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoXYs", "storage"); @@ -1081,21 +1227,25 @@ static void def_cmp_crop(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "x1"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "X1", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "x2", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "x2"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "X2", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "y1", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "y1"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Y1", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "y2", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "y2"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Y2", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_dblur(StructRNA *srna) @@ -1108,40 +1258,48 @@ static void def_cmp_dblur(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 1, 128); RNA_def_property_ui_text(prop, "Iterations", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "wrap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "wrap", 1); RNA_def_property_ui_text(prop, "Wrap", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "center_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "center_x"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Center X", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "center_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "center_y"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Center Y", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "distance"); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_ui_text(prop, "Distance", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "angle"); RNA_def_property_range(prop, 0.0f, 360.0f); RNA_def_property_ui_text(prop, "Angle", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "spin", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spin"); RNA_def_property_range(prop, -360.0f, 360.0f); RNA_def_property_ui_text(prop, "Spin", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "zoom"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Zoom", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_bilateral_blur(StructRNA *srna) @@ -1154,16 +1312,19 @@ static void def_cmp_bilateral_blur(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 1, 128); RNA_def_property_ui_text(prop, "Iterations", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "sigma_color", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sigma_color"); RNA_def_property_range(prop, 0.01f, 3.0f); RNA_def_property_ui_text(prop, "Color Sigma", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "sigma_space", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sigma_space"); RNA_def_property_range(prop, 0.01f, 30.0f); RNA_def_property_ui_text(prop, "Space Sigma", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_premul_key(StructRNA *srna) @@ -1180,6 +1341,7 @@ static void def_cmp_premul_key(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Mapping", "Conversion between premultiplied alpha and key alpha"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -1208,55 +1370,66 @@ static void def_cmp_glare(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Glare Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "quality"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Quality", "If not set to high quality, the effect will be applied to a low-res copy of the source image"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 2, 5); RNA_def_property_ui_text(prop, "Iterations", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "color_modulation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colmod"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color Modulation", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "mix", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "mix"); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_ui_text(prop, "Mix", "-1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "threshold"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text(prop, "Threshold", "The glare filter will only be applied to pixels brighter than this value"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "streaks", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "angle"); RNA_def_property_range(prop, 2, 16); RNA_def_property_ui_text(prop, "Streaks", "Total number of streaks"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "angle_offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "angle_ofs"); RNA_def_property_range(prop, 0.0f, 180.0f); RNA_def_property_ui_text(prop, "Angle Offset", "Streak angle offset in degrees"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "fade", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fade"); RNA_def_property_range(prop, 0.75f, 1.0f); RNA_def_property_ui_text(prop, "Fade", "Streak fade-out factor"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "rotate_45", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "angle", 1); RNA_def_property_ui_text(prop, "Rotate 45", "Simple star filter: add 45 degree rotation offset"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "size"); RNA_def_property_range(prop, 6, 9); RNA_def_property_ui_text(prop, "Size", "Glow/glare size (not actual size; relative to initial size of bright area of pixels)"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO */ } @@ -1277,6 +1450,7 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Tonemap Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: if type==0 { */ @@ -1284,16 +1458,19 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "key"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Key", "The value the average luminance is mapped to"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "offset"); RNA_def_property_range(prop, 0.001f, 10.0f); RNA_def_property_ui_text(prop, "Offset", "Normally always 1, but can be used as an extra control to alter the brightness curve"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "gamma"); RNA_def_property_range(prop, 0.001f, 3.0f); RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1"); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: } else { */ @@ -1301,21 +1478,25 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "f"); RNA_def_property_range(prop, -8.0f, 8.0f); RNA_def_property_ui_text(prop, "Intensity", "If less than zero, darkens image; otherwise, makes it brighter"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "m"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Contrast", "Set to 0 to use estimate from input image"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "adaptation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "a"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Adaptation", "If 0, global; if 1, based on pixel intensity"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "correction", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "c"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color Correction", "If 0, same for all channels; if 1, each independent"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_cmp_lensdist(StructRNA *srna) @@ -1327,16 +1508,19 @@ static void def_cmp_lensdist(StructRNA *srna) prop = RNA_def_property(srna, "projector", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "proj", 1); RNA_def_property_ui_text(prop, "Projector", "Enable/disable projector mode. Effect is applied in horizontal direction only."); + RNA_def_property_update(prop, 0, "rna_Node_update"); /* TODO: if proj mode is off { */ prop = RNA_def_property(srna, "jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "jit", 1); RNA_def_property_ui_text(prop, "Jitter", "Enable/disable jittering; faster, but also noisier"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "fit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "fit", 1); RNA_def_property_ui_text(prop, "Fit", "For positive distortion factor only: scale image such that black areas are not visible"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -1352,6 +1536,7 @@ static void def_tex_output(StructRNA *srna) prop = RNA_def_property(srna, "output_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Output Name", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_tex_image(StructRNA *srna) @@ -1362,6 +1547,7 @@ static void def_tex_image(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "ImageUser"); RNA_def_property_ui_text(prop, "Settings", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_tex_bricks(StructRNA *srna) @@ -1372,21 +1558,25 @@ static void def_tex_bricks(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Offset Amount", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "offset_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 2, 99); RNA_def_property_ui_text(prop, "Offset Frequency", "Offset every N rows"); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "squash", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_range(prop, 0.0f, 99.0f); RNA_def_property_ui_text(prop, "Squash Amount", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "squash_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, 2, 99); RNA_def_property_ui_text(prop, "Squash Frequency", "Squash every N rows"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } /* -------------------------------------------------------------------------- */ diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index c1585a71ac1..4c32f86e501 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -95,6 +95,7 @@ char *ED_info_stats_string(struct Scene *scene){return NULL;} void ED_area_tag_redraw(struct ScrArea *sa){} void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op){} void ED_node_texture_default(struct Tex *tx){} +void ED_node_changed_update(struct bContext *C, struct bNode *node); int text_file_modified(struct Text *text){return 0;} void ED_node_shader_default(struct Material *ma){} void ED_screen_animation_timer_update(struct bContext *C, int redraws){} -- cgit v1.2.3 From f8abfce7ce022e4a7ac53a68477f56e4b740e91e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 19:27:08 +0000 Subject: Image Panels * The image panels in the image editor and texture buttons should be more complete now, with working new/open, refreshes, and using the layout engine. * Paint panels in image editor are now consistent with the ones in the 3d view toolbar. * Curves panel also uses layout engine, and doesn't look squashed anymore. --- release/ui/space_image.py | 109 +++ source/blender/blenkernel/intern/image.c | 17 +- source/blender/blenkernel/intern/paint.c | 27 +- source/blender/editors/include/ED_image.h | 3 - .../editors/interface/interface_templates.c | 13 - source/blender/editors/space_image/image_buttons.c | 778 ++++++--------------- source/blender/editors/space_image/image_ops.c | 21 +- source/blender/editors/uvedit/uvedit_ops.c | 2 +- source/blender/makesrna/intern/rna_color.c | 6 +- source/blender/makesrna/intern/rna_image.c | 116 ++- source/blender/makesrna/intern/rna_space.c | 11 +- source/blender/makesrna/intern/rna_texture.c | 14 +- source/blender/makesrna/intern/rna_ui_api.c | 14 +- 13 files changed, 510 insertions(+), 621 deletions(-) diff --git a/release/ui/space_image.py b/release/ui/space_image.py index 0d0fd86ef8c..02ebd864b8e 100644 --- a/release/ui/space_image.py +++ b/release/ui/space_image.py @@ -277,6 +277,24 @@ class IMAGE_HT_header(bpy.types.Header): if show_uvedit or sima.image_painting: layout.itemR(sima, "update_automatically", text="") +class IMAGE_PT_image_properties(bpy.types.Panel): + __space_type__ = 'IMAGE_EDITOR' + __region_type__ = 'UI' + __label__ = "Image" + + def poll(self, context): + sima = context.space_data + return (sima.image) + + def draw(self, context): + layout = self.layout + + sima = context.space_data + ima = sima.image + iuser = sima.image_user + + layout.template_image(sima, "image", iuser, compact=True) + class IMAGE_PT_game_properties(bpy.types.Panel): __space_type__ = 'IMAGE_EDITOR' __region_type__ = 'UI' @@ -368,6 +386,92 @@ class IMAGE_PT_view_properties(bpy.types.Panel): #col.itemR(uvedit, "draw_edges") #col.itemR(uvedit, "draw_faces") +class IMAGE_PT_paint(bpy.types.Panel): + __space_type__ = 'IMAGE_EDITOR' + __region_type__ = 'UI' + __label__ = "Paint" + + def poll(self, context): + sima = context.space_data + return sima.show_paint + + def draw(self, context): + layout = self.layout + + settings = context.tool_settings.image_paint + brush = settings.brush + + col = layout.split().column() + row = col.row() + row.template_list(settings, "brushes", settings, "active_brush_index", rows=2) + + col.template_ID(settings, "brush", new="brush.add") + + row = layout.row(align=True) + row.item_enumR(settings, "tool", 'DRAW') + row.item_enumR(settings, "tool", 'SOFTEN') + row.item_enumR(settings, "tool", 'CLONE') + row.item_enumR(settings, "tool", 'SMEAR') + + col = layout.column() + col.itemR(brush, "color", text="") + + row = col.row(align=True) + row.itemR(brush, "size", slider=True) + row.itemR(brush, "size_pressure", toggle=True, text="") + + row = col.row(align=True) + row.itemR(brush, "strength", slider=True) + row.itemR(brush, "strength_pressure", toggle=True, text="") + + col.itemR(brush, "blend", text="Blend") + +class IMAGE_PT_paint_stroke(bpy.types.Panel): + __space_type__ = 'IMAGE_EDITOR' + __region_type__ = 'UI' + __label__ = "Paint Stroke" + __default_closed__ = True + + def poll(self, context): + sima = context.space_data + return sima.show_paint + + def draw(self, context): + layout = self.layout + + settings = context.tool_settings.image_paint + brush = settings.brush + + layout.itemR(brush, "airbrush") + col = layout.column() + col.active = brush.airbrush + col.itemR(brush, "rate", slider=True) + + layout.itemR(brush, "space") + row = layout.row(align=True) + row.active = brush.space + row.itemR(brush, "spacing", text="Distance", slider=True) + row.itemR(brush, "spacing_pressure", toggle=True, text="") + +class IMAGE_PT_paint_curve(bpy.types.Panel): + __space_type__ = 'IMAGE_EDITOR' + __region_type__ = 'UI' + __label__ = "Paint Curve" + __default_closed__ = True + + def poll(self, context): + sima = context.space_data + return sima.show_paint + + def draw(self, context): + layout = self.layout + + settings = context.tool_settings.image_paint + brush = settings.brush + + layout.template_curve_mapping(brush, "curve") + layout.item_menu_enumO("brush.curve_preset", property="shape") + bpy.types.register(IMAGE_MT_view) bpy.types.register(IMAGE_MT_select) bpy.types.register(IMAGE_MT_image) @@ -377,5 +481,10 @@ bpy.types.register(IMAGE_MT_uvs_mirror) bpy.types.register(IMAGE_MT_uvs_weldalign) bpy.types.register(IMAGE_MT_uvs) bpy.types.register(IMAGE_HT_header) +bpy.types.register(IMAGE_PT_image_properties) +bpy.types.register(IMAGE_PT_paint) +bpy.types.register(IMAGE_PT_paint_stroke) +bpy.types.register(IMAGE_PT_paint_curve) bpy.types.register(IMAGE_PT_game_properties) bpy.types.register(IMAGE_PT_view_properties) + diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index cdb175ed661..e955f10f3e3 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -277,7 +277,7 @@ static Image *image_alloc(const char *name, short source, short type) ima->xrep= ima->yrep= 1; ima->aspx= ima->aspy= 1.0; - ima->gen_x= 256; ima->gen_y= 256; + ima->gen_x= 1024; ima->gen_y= 1024; ima->gen_type= 1; /* no defines yet? */ ima->source= source; @@ -1472,9 +1472,11 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) iuser->ok= 1; break; case IMA_SIGNAL_SRC_CHANGE: - if(ima->type==IMA_TYPE_MULTILAYER) - image_free_buffers(ima); - else if(ima->source==IMA_SRC_GENERATED) { + if(ima->type == IMA_TYPE_UV_TEST) + if(ima->source != IMA_SRC_GENERATED) + ima->type= IMA_TYPE_IMAGE; + + if(ima->source==IMA_SRC_GENERATED) { if(ima->gen_x==0 || ima->gen_y==0) { ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); if(ibuf) { @@ -1483,6 +1485,9 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) } } } + + image_free_buffers(ima); + ima->ok= 1; if(iuser) iuser->ok= 1; @@ -2090,8 +2095,8 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) else if(ima->source == IMA_SRC_GENERATED) { /* generated is: ibuf is allocated dynamically */ /* UV testgrid or black or solid etc */ - if(ima->gen_x==0) ima->gen_x= 256; - if(ima->gen_y==0) ima->gen_y= 256; + if(ima->gen_x==0) ima->gen_x= 1024; + if(ima->gen_y==0) ima->gen_y= 1024; ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 0, ima->gen_type, color); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ima->ok= IMA_OK_LOADED; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 7c5b2b82b4b..f17d2fbdcac 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -46,19 +46,24 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; Paint *paint_get_active(Scene *sce) { - if(sce && sce->basact && sce->basact->object) { + if(sce) { ToolSettings *ts = sce->toolsettings; - - switch(sce->basact->object->mode) { - case OB_MODE_SCULPT: - return &ts->sculpt->paint; - case OB_MODE_VERTEX_PAINT: - return &ts->vpaint->paint; - case OB_MODE_WEIGHT_PAINT: - return &ts->wpaint->paint; - case OB_MODE_TEXTURE_PAINT: - return &ts->imapaint.paint; + + if(sce->basact && sce->basact->object) { + switch(sce->basact->object->mode) { + case OB_MODE_SCULPT: + return &ts->sculpt->paint; + case OB_MODE_VERTEX_PAINT: + return &ts->vpaint->paint; + case OB_MODE_WEIGHT_PAINT: + return &ts->wpaint->paint; + case OB_MODE_TEXTURE_PAINT: + return &ts->imapaint.paint; + } } + + /* default to image paint */ + return &ts->imapaint.paint; } return NULL; diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 566105109b2..a4263f7bd77 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -53,9 +53,6 @@ int ED_space_image_show_paint(struct SpaceImage *sima); int ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit); int ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit); -void ED_image_uiblock_panel(const struct bContext *C, struct uiBlock *block, struct Image **ima_pp, - struct ImageUser *iuser, short redraw, short imagechanged); - /* image_render.c, export for screen_ops.c, render operator */ void ED_space_image_output(struct bContext *C); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1c7e757fbb2..66873917e8a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2125,17 +2125,4 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C) uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_REC, "Anim Player", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback"); } -/************************* Image Template **************************/ - -#include "ED_image.h" - -void uiTemplateTextureImage(uiLayout *layout, bContext *C, Tex *tex) -{ - uiBlock *block; - - if(tex) { - block= uiLayoutFreeBlock(layout); - ED_image_uiblock_panel(C, block, &tex->ima, &tex->iuser, 0, 0); - } -} diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 456e802194e..f3607ed7276 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -100,8 +100,6 @@ #define B_FACESEL_PAINT_TEST 11 #define B_SIMA_RECORD 12 #define B_SIMA_PLAY 13 -#define B_SIMARANGE 14 -#define B_SIMACURVES 15 #define B_SIMANOTHING 16 #define B_SIMABRUSHCHANGE 17 @@ -116,10 +114,8 @@ #define B_SIMACLONEDELETE 26 /* XXX */ -static int okee() {return 0;} static int simaFaceDraw_Check() {return 0;} static int simaUVSel_Check() {return 0;} -static int is_uv_tface_editing_allowed_silent() {return 0;} /* XXX */ /* proto */ @@ -135,13 +131,6 @@ static void do_image_panel_events(bContext *C, void *arg, int event) switch(event) { case B_REDR: break; - case B_SIMACURVES: - curvemapping_do_ibuf(sima->cumap, ED_space_image_buffer(sima)); - break; - case B_SIMARANGE: - curvemapping_set_black_white(sima->cumap, NULL, NULL); - curvemapping_do_ibuf(sima->cumap, ED_space_image_buffer(sima)); - break; case B_TRANS_IMAGE: image_editvertex_buts(C, NULL); break; @@ -149,12 +138,11 @@ static void do_image_panel_events(bContext *C, void *arg, int event) image_editcursor_buts(C, &ar->v2d, NULL); break; } + /* all events now */ WM_event_add_notifier(C, NC_IMAGE, sima->image); } - - static void image_info(Image *ima, ImBuf *ibuf, char *str) { int ofs= 0; @@ -168,12 +156,12 @@ static void image_info(Image *ima, ImBuf *ibuf, char *str) } if(ima->source==IMA_SRC_MOVIE) { - ofs= sprintf(str, "Movie "); + ofs= sprintf(str, "Movie"); if(ima->anim) ofs+= sprintf(str+ofs, "%d frs", IMB_anim_get_duration(ima->anim)); } else - ofs= sprintf(str, "Image "); + ofs= sprintf(str, "Image"); ofs+= sprintf(str+ofs, ": size %d x %d,", ibuf->x, ibuf->y); @@ -246,10 +234,6 @@ static void image_editvertex_buts(const bContext *C, uiBlock *block) EditFace *efa; MTFace *tf; - if(obedit==NULL || obedit->type!=OB_MESH) return; - - if( is_uv_tface_editing_allowed_silent()==0 ) return; - image_transform_but_attr(sima, &imx, &imy, &step, &digits); em= BKE_mesh_get_editmesh((Mesh *)obedit->data); @@ -354,8 +338,6 @@ static void image_editcursor_buts(const bContext *C, View2D *v2d, uiBlock *block int imx= 256, imy= 256; int step, digits; - if( is_uv_tface_editing_allowed_silent()==0 ) return; - image_transform_but_attr(sima, &imx, &imy, &step, &digits); if(block) { // do the buttons @@ -388,59 +370,6 @@ static void image_editcursor_buts(const bContext *C, View2D *v2d, uiBlock *block #if 0 static void image_panel_view_properties(const bContext *C, Panel *pa) { - SpaceImage *sima= CTX_wm_space_image(C); - ARegion *ar= CTX_wm_region(C); - Object *obedit= CTX_data_edit_object(C); - uiBlock *block; - - block= uiLayoutFreeBlock(pa->layout); - uiBlockSetHandleFunc(block, do_image_panel_events, NULL); - - uiDefButBitI(block, TOG, SI_DRAW_TILE, B_REDR, "Repeat Image", 10,160,140,19, &sima->flag, 0, 0, 0, 0, "Repeat/Tile the image display"); - uiDefButBitI(block, TOG, SI_COORDFLOATS, B_REDR, "Normalized Coords", 165,160,145,19, &sima->flag, 0, 0, 0, 0, "Display coords from 0.0 to 1.0 rather then in pixels"); - - if (sima->image) { - uiDefBut(block, LABEL, B_NOP, "Image Display:", 10,140,140,19, 0, 0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_REDR, "AspX:", 10,120,140,19, &sima->image->aspx, 0.1, 5000.0, 100, 0, "X Display Aspect for this image, does not affect renderingm 0 disables."); - uiDefButF(block, NUM, B_REDR, "AspY:", 10,100,140,19, &sima->image->aspy, 0.1, 5000.0, 100, 0, "X Display Aspect for this image, does not affect rendering 0 disables."); - uiBlockEndAlign(block); - } - - if (obedit && obedit->type==OB_MESH) { - Mesh *me= obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - - if(EM_texFaceCheck(em)) { - uiDefBut(block, LABEL, B_NOP, "Draw Type:", 10, 80,120,19, 0, 0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButC(block, ROW, B_REDR, "Outline", 10,60,58,19, &sima->dt_uv, 0.0, SI_UVDT_OUTLINE, 0, 0, "Outline Wire UV drawtype"); - uiDefButC(block, ROW, B_REDR, "Dash", 68, 60,58,19, &sima->dt_uv, 0.0, SI_UVDT_DASH, 0, 0, "Dashed Wire UV drawtype"); - uiDefButC(block, ROW, B_REDR, "Black", 126, 60,58,19, &sima->dt_uv, 0.0, SI_UVDT_BLACK, 0, 0, "Black Wire UV drawtype"); - uiDefButC(block, ROW, B_REDR, "White", 184,60,58,19, &sima->dt_uv, 0.0, SI_UVDT_WHITE, 0, 0, "White Wire UV drawtype"); - - uiBlockEndAlign(block); - uiDefButBitI(block, TOG, SI_SMOOTH_UV, B_REDR, "Smooth", 250,60,60,19, &sima->flag, 0, 0, 0, 0, "Display smooth lines in the UV view"); - - - uiDefButBitI(block, TOG, ME_DRAWFACES, B_REDR, "Faces", 10,30,60,19, &me->drawflag, 0, 0, 0, 0, "Displays all faces as shades in the 3d view and UV editor"); - uiDefButBitI(block, TOG, ME_DRAWEDGES, B_REDR, "Edges", 70, 30,60,19, &me->drawflag, 0, 0, 0, 0, "Displays selected edges using hilights in the 3d view and UV editor"); - - uiDefButBitI(block, TOG, SI_DRAWSHADOW, B_REDR, "Final Shadow", 130, 30,110,19, &sima->flag, 0, 0, 0, 0, "Draw the final result from the objects modifiers"); - uiDefButBitI(block, TOG, SI_DRAW_OTHER, B_REDR, "Other Objs", 230, 30, 80, 19, &sima->flag, 0, 0, 0, 0, "Also draw all 3d view selected mesh objects that use this image"); - - uiDefButBitI(block, TOG, SI_DRAW_STRETCH, B_REDR, "UV Stretch", 10,0,100,19, &sima->flag, 0, 0, 0, 0, "Difference between UV's and the 3D coords (blue for low distortion, red is high)"); - if (sima->flag & SI_DRAW_STRETCH) { - uiBlockBeginAlign(block); - uiDefButC(block, ROW, B_REDR, "Area", 120,0,60,19, &sima->dt_uvstretch, 0.0, SI_UVDT_STRETCH_AREA, 0, 0, "Area distortion between UV's and 3D coords"); - uiDefButC(block, ROW, B_REDR, "Angle", 180,0,60,19, &sima->dt_uvstretch, 0.0, SI_UVDT_STRETCH_ANGLE, 0, 0, "Angle distortion between UV's and 3D coords"); - uiBlockEndAlign(block); - } - } - - BKE_mesh_end_editmesh(me, em); - } - image_editcursor_buts(C, &ar->v2d, block); } #endif @@ -565,104 +494,33 @@ void brush_buttons(const bContext *C, uiBlock *block, short fromsima, #endif } -static int image_panel_paint_poll(const bContext *C, PanelType *pt) -{ - SpaceImage *sima= CTX_wm_space_image(C); - - return (sima->image && (sima->flag & SI_DRAWTOOL)); -} - -static void image_panel_paintcolor(const bContext *C, Panel *pa) -{ - SpaceImage *sima= CTX_wm_space_image(C); - ToolSettings *settings= CTX_data_tool_settings(C); - Brush *brush= paint_brush(&settings->imapaint.paint); - uiBlock *block; - static float hsv[3], old[3]; // used as temp mem for picker - static char hexcol[128]; - - if(!sima->image || (sima->flag & SI_DRAWTOOL)==0) - return; - - block= uiLayoutFreeBlock(pa->layout); - uiBlockSetHandleFunc(block, do_image_panel_events, NULL); - - if(brush) - uiBlockPickerButtons(block, brush->rgb, hsv, old, hexcol, 'f', B_REDR); -} - -static void image_panel_paint(const bContext *C, Panel *pa) -{ - SpaceImage *sima= CTX_wm_space_image(C); - uiBlock *block; - - if(!sima->image || (sima->flag & SI_DRAWTOOL)==0) - return; - - block= uiLayoutFreeBlock(pa->layout); - uiBlockSetHandleFunc(block, do_image_panel_events, NULL); - - brush_buttons(C, block, 1, B_SIMANOTHING, B_SIMABRUSHCHANGE, B_SIMABRUSHBROWSE, B_SIMABRUSHLOCAL, B_SIMABRUSHDELETE, B_KEEPDATA, B_SIMABTEXBROWSE, B_SIMABTEXDELETE); -} - -static void image_panel_curves_reset(bContext *C, void *cumap_v, void *ibuf_v) +static int image_panel_poll(const bContext *C, PanelType *pt) { SpaceImage *sima= CTX_wm_space_image(C); - CurveMapping *cumap = cumap_v; - int a; - - for(a=0; acm+a, &cumap->clipr); - - cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f; - cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f; - curvemapping_set_black_white(cumap, NULL, NULL); - - curvemapping_changed(cumap, 0); - curvemapping_do_ibuf(cumap, ibuf_v); + ImBuf *ibuf= ED_space_image_buffer(sima); - WM_event_add_notifier(C, NC_IMAGE, sima->image); + return (ibuf != NULL); } - static void image_panel_curves(const bContext *C, Panel *pa) { + bScreen *sc= CTX_wm_screen(C); SpaceImage *sima= CTX_wm_space_image(C); ImBuf *ibuf; - uiBlock *block; - uiBut *bt; + PointerRNA simaptr; + int levels; - /* and we check for spare */ ibuf= ED_space_image_buffer(sima); - block= uiLayoutFreeBlock(pa->layout); - uiBlockSetHandleFunc(block, do_image_panel_events, NULL); - - if (ibuf) { - rctf rect; - + if(ibuf) { if(sima->cumap==NULL) sima->cumap= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f); - - rect.xmin= 110; rect.xmax= 310; - rect.ymin= 10; rect.ymax= 200; - curvemap_buttons(block, sima->cumap, 'c', B_SIMACURVES, B_REDR, &rect); - - /* curvemap min/max only works for RGBA */ - if(ibuf->channels==4) { - bt=uiDefBut(block, BUT, B_SIMARANGE, "Reset", 10, 160, 90, 19, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves"); - uiButSetFunc(bt, image_panel_curves_reset, sima->cumap, ibuf); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_SIMARANGE, "Min R:", 10, 120, 90, 19, sima->cumap->black, -1000.0f, 1000.0f, 10, 2, "Black level"); - uiDefButF(block, NUM, B_SIMARANGE, "Min G:", 10, 100, 90, 19, sima->cumap->black+1, -1000.0f, 1000.0f, 10, 2, "Black level"); - uiDefButF(block, NUM, B_SIMARANGE, "Min B:", 10, 80, 90, 19, sima->cumap->black+2, -1000.0f, 1000.0f, 10, 2, "Black level"); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_SIMARANGE, "Max R:", 10, 50, 90, 19, sima->cumap->white, -1000.0f, 1000.0f, 10, 2, "White level"); - uiDefButF(block, NUM, B_SIMARANGE, "Max G:", 10, 30, 90, 19, sima->cumap->white+1, -1000.0f, 1000.0f, 10, 2, "White level"); - uiDefButF(block, NUM, B_SIMARANGE, "Max B:", 10, 10, 90, 19, sima->cumap->white+2, -1000.0f, 1000.0f, 10, 2, "White level"); - } + + /* curvemap black/white levels only works for RGBA */ + levels= (ibuf->channels==4); + + RNA_pointer_create(&sc->id, &RNA_SpaceImageEditor, sima, &simaptr); + uiTemplateCurveMapping(pa->layout, &simaptr, "curves", 'c', levels); } } @@ -799,81 +657,11 @@ static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PREVI uiBlockSetDrawExtraFunc(block, preview_cb); } - -static void image_panel_gpencil(short cntrl) // IMAGE_HANDLER_GREASEPENCIL -{ - uiBlock *block; - SpaceImage *sima; - - sima= curarea->spacedata.first; - - block= uiBeginBlock(C, ar, "image_panel_gpencil", UI_EMBOSS); - uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl); - uiSetPanelHandler(IMAGE_HANDLER_GREASEPENCIL); // for close and esc - if (uiNewPanel(C, ar, block, "Grease Pencil", "SpaceImage", 100, 30, 318, 204)==0) return; - - /* allocate memory for gpd if drawing enabled (this must be done first or else we crash) */ - if (sima->flag & SI_DISPGP) { - if (sima->gpd == NULL) - gpencil_data_setactive(curarea, gpencil_data_addnew()); - } - - if (sima->flag & SI_DISPGP) { - bGPdata *gpd= sima->gpd; - short newheight; - - /* this is a variable height panel, newpanel doesnt force new size on existing panels */ - /* so first we make it default height */ - uiNewPanelHeight(block, 204); - - /* draw button for showing gpencil settings and drawings */ - uiDefButBitI(block, TOG, SI_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &sima->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Image/UV Editor (draw using Shift-LMB)"); - - /* extend the panel if the contents won't fit */ - newheight= draw_gpencil_panel(block, gpd, curarea); - uiNewPanelHeight(block, newheight); - } - else { - uiDefButBitI(block, TOG, SI_DISPGP, B_REDR, "Use Grease Pencil", 10, 225, 150, 20, &sima->flag, 0, 0, 0, 0, "Display freehand annotations overlay over this Image/UV Editor"); - uiDefBut(block, LABEL, 1, " ", 160, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, ""); - } -} #endif /* ********************* callbacks for standard image buttons *************** */ -/* called from fileselect or button */ -static void load_image_cb(bContext *C, char *str, void *ima_pp_v, void *iuser_v) -{ - Image **ima_pp= (Image **)ima_pp_v; - Image *ima= NULL; - - ima= BKE_add_image_file(str, 0); - if(ima) { - if(*ima_pp) { - (*ima_pp)->id.us--; - } - *ima_pp= ima; - - BKE_image_signal(ima, iuser_v, IMA_SIGNAL_RELOAD); - WM_event_add_notifier(C, NC_IMAGE, ima); - - /* button event gets lost when it goes via filewindow */ -// if(G.buts && G.buts->lockpoin) { -// Tex *tex= G.buts->lockpoin; -// if(GS(tex->id.name)==ID_TE) { -// BIF_preview_changed(ID_TE); -// allqueue(REDRAWBUTSSHADING, 0); -// allqueue(REDRAWVIEW3D, 0); -// allqueue(REDRAWOOPS, 0); -// } -// } - } - - ED_undo_push(C, "Load image"); -} - static char *layer_menu(RenderResult *rr, short *curlay) { RenderLayer *rl; @@ -937,92 +725,6 @@ static void set_frames_cb(bContext *C, void *ima_v, void *iuser_v) } } -static void image_src_change_cb(bContext *C, void *ima_v, void *iuser_v) -{ - BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_SRC_CHANGE); -} - -/* buttons have 2 arg callbacks, filewindow has 3 args... so thats why the wrapper below */ -static void image_browse_cb1(bContext *C, void *ima_pp_v, void *iuser_v) -{ - Image **ima_pp= (Image **)ima_pp_v; - ImageUser *iuser= iuser_v; - - if(ima_pp) { - Image *ima= *ima_pp; - - if(iuser->menunr== -2) { - // XXX activate_databrowse_args(&ima->id, ID_IM, 0, &iuser->menunr, image_browse_cb1, ima_pp, iuser); - } - else if (iuser->menunr>0) { - Image *newima= (Image*) BLI_findlink(&CTX_data_main(C)->image, iuser->menunr-1); - - if (newima && newima!=ima) { - *ima_pp= newima; - id_us_plus(&newima->id); - if(ima) ima->id.us--; - - BKE_image_signal(newima, iuser, IMA_SIGNAL_USER_NEW_IMAGE); - - ED_undo_push(C, "Browse image"); - } - } - } -} - -static void image_browse_cb(bContext *C, void *ima_pp_v, void *iuser_v) -{ - image_browse_cb1(C, ima_pp_v, iuser_v); -} - -static void image_reload_cb(bContext *C, void *ima_v, void *iuser_v) -{ - if(ima_v) { - BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_RELOAD); - } -} - -static void image_field_test(bContext *C, void *ima_v, void *iuser_v) -{ - Image *ima= ima_v; - - if(ima) { - ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v); - if(ibuf) { - short nr= 0; - if( !(ima->flag & IMA_FIELDS) && (ibuf->flags & IB_fields) ) nr= 1; - if( (ima->flag & IMA_FIELDS) && !(ibuf->flags & IB_fields) ) nr= 1; - if(nr) { - BKE_image_signal(ima, iuser_v, IMA_SIGNAL_FREE); - } - } - } -} - -static void image_unlink_cb(bContext *C, void *ima_pp_v, void *unused) -{ - Image **ima_pp= (Image **)ima_pp_v; - - if(ima_pp && *ima_pp) { - Image *ima= *ima_pp; - /* (for time being, texturefaces are no users, conflict in design...) */ - if(ima->id.us>1) - ima->id.us--; - *ima_pp= NULL; - } -} - -static void image_load_fs_cb(bContext *C, void *ima_pp_v, void *iuser_v) -{ - ScrArea *sa= CTX_wm_area(C); -// Image **ima_pp= (Image **)ima_pp_v; - - if(sa->spacetype==SPACE_IMAGE) - WM_operator_name_call(C, "IMAGE_OT_open", WM_OP_INVOKE_REGION_WIN, NULL); - else - printf("not supported yet\n"); -} - /* 5 layer button callbacks... */ static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v) { @@ -1077,6 +779,7 @@ static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v) } } +#if 0 static void image_pack_cb(bContext *C, void *ima_v, void *iuser_v) { if(ima_v) { @@ -1106,282 +809,270 @@ static void image_pack_cb(bContext *C, void *ima_v, void *iuser_v) } } } +#endif -static void image_load_cb(bContext *C, void *ima_pp_v, void *iuser_v) -{ - if(ima_pp_v) { - Image *ima= *((Image **)ima_pp_v); - ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v); - char str[FILE_MAX]; - - /* name in ima has been changed by button! */ - BLI_strncpy(str, ima->name, FILE_MAX); - if(ibuf) BLI_strncpy(ima->name, ibuf->name, FILE_MAX); - - load_image_cb(C, str, ima_pp_v, iuser_v); - } -} - +#if 0 static void image_freecache_cb(bContext *C, void *ima_v, void *unused) { Scene *scene= CTX_data_scene(C); BKE_image_free_anim_ibufs(ima_v, scene->r.cfra); WM_event_add_notifier(C, NC_IMAGE, ima_v); } +#endif -static void image_generated_change_cb(bContext *C, void *ima_v, void *iuser_v) -{ - BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_FREE); -} - +#if 0 static void image_user_change(bContext *C, void *iuser_v, void *unused) { Scene *scene= CTX_data_scene(C); BKE_image_user_calc_imanr(iuser_v, scene->r.cfra, 0); } +#endif -static void uiblock_layer_pass_buttons(uiBlock *block, RenderResult *rr, ImageUser *iuser, int event, int x, int y, int w) +static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, int w) { + uiBlock *block= uiLayoutGetBlock(layout); uiBut *but; RenderLayer *rl= NULL; int wmenu1, wmenu2; char *strp; + uiLayoutRow(layout, 1); + /* layer menu is 1/3 larger than pass */ wmenu1= (3*w)/5; wmenu2= (2*w)/5; /* menu buts */ strp= layer_menu(rr, &iuser->layer); - but= uiDefButS(block, MENU, event, strp, x, y, wmenu1, 20, &iuser->layer, 0,0,0,0, "Select Layer"); + but= uiDefButS(block, MENU, 0, strp, 0, 0, wmenu1, 20, &iuser->layer, 0,0,0,0, "Select Layer"); uiButSetFunc(but, image_multi_cb, rr, iuser); MEM_freeN(strp); rl= BLI_findlink(&rr->layers, iuser->layer - (rr->rectf?1:0)); /* fake compo layer, return NULL is meant to be */ strp= pass_menu(rl, &iuser->pass); - but= uiDefButS(block, MENU, event, strp, x+wmenu1, y, wmenu2, 20, &iuser->pass, 0,0,0,0, "Select Pass"); + but= uiDefButS(block, MENU, 0, strp, 0, 0, wmenu2, 20, &iuser->pass, 0,0,0,0, "Select Pass"); uiButSetFunc(but, image_multi_cb, rr, iuser); MEM_freeN(strp); } -static void uiblock_layer_pass_arrow_buttons(uiBlock *block, RenderResult *rr, ImageUser *iuser, int imagechanged) +static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser) { + uiBlock *block= uiLayoutGetBlock(layout); + uiLayout *row; uiBut *but; + row= uiLayoutRow(layout, 1); + if(rr==NULL || iuser==NULL) return; if(rr->layers.first==NULL) { - uiDefBut(block, LABEL, 0, "No Layers in Render Result,", 10, 107, 300, 20, NULL, 1, 0, 0, 0, ""); + uiItemL(row, "No Layers in Render Result.", 0); return; } - - uiBlockBeginAlign(block); /* decrease, increase arrows */ - but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_LEFT, 10,107,17,20, NULL, 0, 0, 0, 0, "Previous Layer"); + but= uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT, 0,0,17,20, NULL, 0, 0, 0, 0, "Previous Layer"); uiButSetFunc(but, image_multi_declay_cb, rr, iuser); - but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_RIGHT, 27,107,18,20, NULL, 0, 0, 0, 0, "Next Layer"); + but= uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT, 0,0,18,20, NULL, 0, 0, 0, 0, "Next Layer"); uiButSetFunc(but, image_multi_inclay_cb, rr, iuser); - uiblock_layer_pass_buttons(block, rr, iuser, imagechanged, 45, 107, 230); + uiblock_layer_pass_buttons(row, rr, iuser, 230); /* decrease, increase arrows */ - but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_LEFT, 275,107,17,20, NULL, 0, 0, 0, 0, "Previous Pass"); + but= uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT, 0,0,17,20, NULL, 0, 0, 0, 0, "Previous Pass"); uiButSetFunc(but, image_multi_decpass_cb, rr, iuser); - but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_RIGHT, 292,107,18,20, NULL, 0, 0, 0, 0, "Next Pass"); + but= uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT, 0,0,18,20, NULL, 0, 0, 0, 0, "Next Pass"); uiButSetFunc(but, image_multi_incpass_cb, rr, iuser); uiBlockEndAlign(block); - } // XXX HACK! -static int packdummy=0; +// static int packdummy=0; + +typedef struct RNAUpdateCb { + PointerRNA ptr; + PropertyRNA *prop; + ImageUser *iuser; +} RNAUpdateCb; + +static void rna_update_cb(bContext *C, void *arg_cb, void *arg_unused) +{ + RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb; + + /* ideally this would be done by RNA itself, but there we have + no image user available, so we just update this flag here */ + cb->iuser->ok= 1; -/* The general Image panel with the loadsa callbacks! */ -void ED_image_uiblock_panel(const bContext *C, uiBlock *block, Image **ima_pp, ImageUser *iuser, - short redraw, short imagechanged) + /* we call update here on the pointer property, this way the + owner of the image pointer can still define it's own update + and notifier */ + RNA_property_update(C, &cb->ptr, cb->prop); +} + +void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, PointerRNA *userptr, int compact) { + PropertyRNA *prop; + PointerRNA imaptr; + RNAUpdateCb *cb; + Image *ima; + ImageUser *iuser; + ImBuf *ibuf; Scene *scene= CTX_data_scene(C); - SpaceImage *sima= CTX_wm_space_image(C); - Image *ima= *ima_pp; + uiLayout *row, *split, *col; + uiBlock *block; uiBut *but; - char str[128], *strp; + char str[128]; + + if(!ptr->data) + return; - /* different stuff when we show viewer */ - if(ima && ima->source==IMA_SRC_VIEWER) { - ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser); - - image_info(ima, ibuf, str); - uiDefBut(block, LABEL, 0, ima->id.name+2, 10, 180, 300, 20, NULL, 1, 0, 0, 0, ""); - uiDefBut(block, LABEL, 0, str, 10, 160, 300, 20, NULL, 1, 0, 0, 0, ""); - - if(ima->type==IMA_TYPE_COMPOSITE) { - iuser= ntree_get_active_iuser(scene->nodetree); - if(iuser) { - uiBlockBeginAlign(block); - uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record", 10,120,100,20, 0, 0, 0, 0, 0, ""); - uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play", 110,120,100,20, 0, 0, 0, 0, 0, ""); - but= uiDefBut(block, BUT, B_NOP, "Free Cache", 210,120,100,20, 0, 0, 0, 0, 0, ""); - uiButSetFunc(but, image_freecache_cb, ima, NULL); - - if(iuser->frames) - sprintf(str, "(%d) Frames:", iuser->framenr); - else strcpy(str, "Frames:"); - uiBlockBeginAlign(block); - uiDefButI(block, NUM, imagechanged, str, 10, 90,150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use"); - uiDefButI(block, NUM, imagechanged, "StartFr:", 160,90,150,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie"); - } - } - else if(ima->type==IMA_TYPE_R_RESULT) { - /* browse layer/passes */ - uiblock_layer_pass_arrow_buttons(block, RE_GetResult(RE_GetRender(scene->id.name)), iuser, imagechanged); - } + prop= RNA_struct_find_property(ptr, propname); + if(!prop) { + printf("uiTemplateImage: property not found: %s\n", propname); return; } - - /* the main ima source types */ + + block= uiLayoutGetBlock(layout); + + imaptr= RNA_property_pointer_get(ptr, prop); + ima= imaptr.data; + iuser= userptr->data; + + cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); + cb->ptr= *ptr; + cb->prop= prop; + cb->iuser= iuser; + + if(!compact) + uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL); + + // XXX missing: reload, pack + if(ima) { -// XXX uiSetButLock(ima->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); - uiBlockBeginAlign(block); - uiBlockSetFunc(block, image_src_change_cb, ima, iuser); - uiDefButS(block, ROW, imagechanged, "Still", 0, 180, 105, 20, &ima->source, 0.0, IMA_SRC_FILE, 0, 0, "Single Image file"); - uiDefButS(block, ROW, imagechanged, "Movie", 105, 180, 105, 20, &ima->source, 0.0, IMA_SRC_MOVIE, 0, 0, "Movie file"); - uiDefButS(block, ROW, imagechanged, "Sequence", 210, 180, 105, 20, &ima->source, 0.0, IMA_SRC_SEQUENCE, 0, 0, "Multiple Image files, as a sequence"); - uiDefButS(block, ROW, imagechanged, "Generated", 315, 180, 105, 20, &ima->source, 0.0, IMA_SRC_GENERATED, 0, 0, "Generated Image"); - uiBlockSetFunc(block, NULL, NULL, NULL); - } - else - uiDefBut(block, LABEL, 0, " ", 0, 180, 440, 20, 0, 0, 0, 0, 0, ""); /* for align in panel */ - - /* Browse */ - IMAnames_to_pupstring(&strp, NULL, NULL, &(CTX_data_main(C)->image), NULL, &iuser->menunr); - - uiBlockBeginAlign(block); - but= uiDefButS(block, MENU, imagechanged, strp, 0,155,40,20, &iuser->menunr, 0, 0, 0, 0, "Selects an existing Image or Movie"); - uiButSetFunc(but, image_browse_cb, ima_pp, iuser); - - MEM_freeN(strp); - - /* name + options, or only load */ - if(ima) { - int drawpack= (ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE && ima->ok); - - but= uiDefBut(block, TEX, B_IDNAME, "IM:", 40, 155, 220, 20, ima->id.name+2, 0.0, 21.0, 0, 0, "Current Image Datablock name."); - uiButSetFunc(but, test_idbutton_cb, ima->id.name, NULL); - but= uiDefBut(block, BUT, imagechanged, "Reload", 260, 155, 70, 20, NULL, 0, 0, 0, 0, "Reloads Image or Movie"); - uiButSetFunc(but, image_reload_cb, ima, iuser); - - but= uiDefIconBut(block, BUT, imagechanged, ICON_X, 330, 155, 40, 20, 0, 0, 0, 0, 0, "Unlink Image block"); - uiButSetFunc(but, image_unlink_cb, ima_pp, NULL); - sprintf(str, "%d", ima->id.us); - uiDefBut(block, BUT, B_NOP, str, 370, 155, 40, 20, 0, 0, 0, 0, 0, "Only displays number of users of Image block"); - uiBlockEndAlign(block); - - uiBlockBeginAlign(block); - but= uiDefIconBut(block, BUT, imagechanged, ICON_FILESEL, 0, 130, 40, 20, 0, 0, 0, 0, 0, "Open Fileselect to load new Image"); - uiButSetFunc(but, image_load_fs_cb, ima_pp, iuser); - but= uiDefBut(block, TEX, imagechanged, "", 40,130, 340+(drawpack?0:20),20, ima->name, 0.0, 239.0, 0, 0, "Image/Movie file name, change to load new"); - uiButSetFunc(but, image_load_cb, ima_pp, iuser); - uiBlockEndAlign(block); - - if(drawpack) { - if (ima->packedfile) packdummy = 1; - else packdummy = 0; - but= uiDefIconButBitI(block, TOG, 1, redraw, ICON_PACKAGE, 380, 130, 40, 20, &packdummy, 0, 0, 0, 0, "Toggles Packed status of this Image"); - uiButSetFunc(but, image_pack_cb, ima, iuser); - } - - } - else { - but= uiDefBut(block, BUT, imagechanged, "Load", 33, 155, 200,20, NULL, 0, 0, 0, 0, "Load new Image of Movie"); - uiButSetFunc(but, image_load_fs_cb, ima_pp, iuser); - } - uiBlockEndAlign(block); - - if(ima) { - ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser); - - /* check for re-render, only buttons */ - if(imagechanged==B_IMAGECHANGED) { - if(iuser->flag & IMA_ANIM_REFRESHED) { - iuser->flag &= ~IMA_ANIM_REFRESHED; - WM_event_add_notifier(C, NC_IMAGE, ima); - } - } - - /* multilayer? */ - if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) { - uiblock_layer_pass_arrow_buttons(block, ima->rr, iuser, imagechanged); - } - else { - image_info(ima, ibuf, str); - uiDefBut(block, LABEL, 0, str, 10, 112, 300, 20, NULL, 1, 0, 0, 0, ""); - } - - /* exception, let's do because we only use this panel 3 times in blender... but not real good code! */ - if( (paint_facesel_test(CTX_data_active_object(C))) && sima && &sima->iuser==iuser) - return; - /* left side default per-image options, right half the additional options */ - - /* fields */ - - but= uiDefButBitS(block, OPTION, IMA_FIELDS, imagechanged, "Fields", 0, 80, 200, 20, &ima->flag, 0, 0, 0, 0, "Click to enable use of fields in Image"); - uiButSetFunc(but, image_field_test, ima, iuser); - uiDefButBitS(block, OPTION, IMA_STD_FIELD, B_NOP, "Odd", 0, 55, 200, 20, &ima->flag, 0, 0, 0, 0, "Standard Field Toggle"); + uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL); + + if(ima->source == IMA_SRC_VIEWER) { + ibuf= BKE_image_get_ibuf(ima, iuser); + image_info(ima, ibuf, str); + + uiItemL(layout, ima->id.name+2, 0); + uiItemL(layout, str, 0); + + if(ima->type==IMA_TYPE_COMPOSITE) { + // XXX not working yet +#if 0 + iuser= ntree_get_active_iuser(scene->nodetree); + if(iuser) { + uiBlockBeginAlign(block); + uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record", 10,120,100,20, 0, 0, 0, 0, 0, ""); + uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play", 110,120,100,20, 0, 0, 0, 0, 0, ""); + but= uiDefBut(block, BUT, B_NOP, "Free Cache", 210,120,100,20, 0, 0, 0, 0, 0, ""); + uiButSetFunc(but, image_freecache_cb, ima, NULL); + + if(iuser->frames) + sprintf(str, "(%d) Frames:", iuser->framenr); + else strcpy(str, "Frames:"); + uiBlockBeginAlign(block); + uiDefButI(block, NUM, imagechanged, str, 10, 90,150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use"); + uiDefButI(block, NUM, imagechanged, "StartFr:", 160,90,150,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie"); + } +#endif + } + else if(ima->type==IMA_TYPE_R_RESULT) { + /* browse layer/passes */ + uiblock_layer_pass_arrow_buttons(layout, RE_GetResult(RE_GetRender(scene->id.name)), iuser); + } + } + else { + row= uiLayoutRow(layout, 0); + uiItemR(row, NULL, 0, &imaptr, "source", (compact)? 0: UI_ITEM_R_EXPAND); + + if(ima->source != IMA_SRC_GENERATED) { + row= uiLayoutRow(layout, 0); + uiItemR(row, "", 0, &imaptr, "filename", 0); + //uiItemO(row, "Reload", 0, "image.reload"); + } + + // XXX what was this for? +#if 0 + /* check for re-render, only buttons */ + if(imagechanged==B_IMAGECHANGED) { + if(iuser->flag & IMA_ANIM_REFRESHED) { + iuser->flag &= ~IMA_ANIM_REFRESHED; + WM_event_add_notifier(C, NC_IMAGE, ima); + } + } +#endif + + /* multilayer? */ + if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) { + uiblock_layer_pass_arrow_buttons(layout, ima->rr, iuser); + } + else if(ima->source != IMA_SRC_GENERATED) { + ibuf= BKE_image_get_ibuf(ima, iuser); + image_info(ima, ibuf, str); + uiItemL(layout, str, 0); + } - - uiBlockSetFunc(block, image_reload_cb, ima, iuser); - uiDefButBitS(block, OPTION, IMA_ANTIALI, B_NOP, "Anti-Aliasing", 0, 5, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles Image anti-aliasing, only works with solid colors"); - uiDefButBitS(block, OPTION, IMA_DO_PREMUL, imagechanged, "Premultiply", 0, -20, 200, 20, &ima->flag, 0, 0, 0, 0, "Toggles premultiplying alpha"); - - - if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { - sprintf(str, "(%d) Frames:", iuser->framenr); - - //uiBlockBeginAlign(block); - uiBlockSetFunc(block, image_user_change, iuser, NULL); - - if(ima->anim) { - uiBlockBeginAlign(block); - uiDefButI(block, NUM, imagechanged, str, 220, 80, 160, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use"); - but= uiDefBut(block, BUT, redraw, "<", 380, 80, 40, 20, 0, 0, 0, 0, 0, "Copies number of frames in movie file to Frames: button"); - uiButSetFunc(but, set_frames_cb, ima, iuser); - uiBlockEndAlign(block); - } - else - uiDefButI(block, NUM, imagechanged, str, 220, 80, 200, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use"); - - uiDefButI(block, NUM, imagechanged, "Start Frame:", 220, 55, 200, 20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie"); - uiDefButI(block, NUM, imagechanged, "Offset:", 220, 30, 200, 20, &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation"); - uiDefButS(block, NUM, imagechanged, "Fields:", 0, 30, 200, 20, &iuser->fie_ima, 1.0, 200.0, 0, 0, "The number of fields per rendered frame (2 fields is 1 image)"); - - uiDefButBitS(block, OPTION, IMA_ANIM_ALWAYS, B_NOP, "Auto Refresh", 220, 5, 200, 20, &iuser->flag, 0, 0, 0, 0, "Always refresh Image on frame changes"); - - uiDefButS(block, OPTION, imagechanged, "Cyclic", 220, -20, 200, 20, &iuser->cycl, 0.0, 1.0, 0, 0, "Cycle the images in the movie"); - - uiBlockSetFunc(block, NULL, iuser, NULL); - } - else if(ima->source==IMA_SRC_GENERATED) { - - uiDefBut(block, LABEL, 0, "Size:", 220, 80, 200, 20, 0, 0, 0, 0, 0, ""); - - uiBlockBeginAlign(block); - uiBlockSetFunc(block, image_generated_change_cb, ima, iuser); - uiDefButS(block, NUM, imagechanged, "X:", 220, 55,200,20, &ima->gen_x, 1.0, 5000.0, 0, 0, "Image size x"); - uiDefButS(block, NUM, imagechanged, "Y:", 220, 35,200,20, &ima->gen_y, 1.0, 5000.0, 0, 0, "Image size y"); - uiBlockEndAlign(block); - - uiDefButS(block, OPTION, imagechanged, "UV Test grid", 220,10,200,20, &ima->gen_type, 0.0, 1.0, 0, 0, ""); - uiBlockSetFunc(block, NULL, NULL, NULL); - } - } - uiBlockEndAlign(block); -} + if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + split= uiLayoutSplit(layout, 0); + + col= uiLayoutColumn(split, 0); + + sprintf(str, "(%d) Frames:", iuser->framenr); + row= uiLayoutRow(col, 1); + uiItemR(col, str, 0, userptr, "frames", 0); + if(ima->anim) { + block= uiLayoutGetBlock(row); + but= uiDefBut(block, BUT, 0, "<", 0, 0, UI_UNIT_X*2, UI_UNIT_Y, 0, 0, 0, 0, 0, "Set the number of frames from the movie or sequence."); + uiButSetFunc(but, set_frames_cb, ima, iuser); + } + + uiItemR(col, "Start", 0, userptr, "start_frame", 0); + uiItemR(col, NULL, 0, userptr, "offset", 0); + + col= uiLayoutColumn(split, 0); + uiItemR(col, "Fields", 0, userptr, "fields_per_frame", 0); + uiItemR(col, NULL, 0, userptr, "auto_refresh", 0); + uiItemR(col, NULL, 0, userptr, "cyclic", 0); + } + else if(ima->source==IMA_SRC_GENERATED) { + split= uiLayoutSplit(layout, 0); + + col= uiLayoutColumn(split, 1); + uiItemR(col, "X", 0, &imaptr, "generated_width", 0); + uiItemR(col, "Y", 0, &imaptr, "generated_height", 0); + + col= uiLayoutColumn(split, 0); + uiItemR(col, NULL, 0, &imaptr, "generated_type", UI_ITEM_R_EXPAND); + } + + if(ima->source != IMA_SRC_GENERATED) { + uiItemS(layout); + + split= uiLayoutSplit(layout, 0); + + col= uiLayoutColumn(split, 0); + uiItemR(col, NULL, 0, &imaptr, "fields", 0); + row= uiLayoutRow(col, 0); + uiItemR(row, "Odd", 0, &imaptr, "odd_fields", 0); + uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "fields")); + + col= uiLayoutColumn(split, 0); + uiItemR(col, NULL, 0, &imaptr, "antialias", 0); + uiItemR(col, NULL, 0, &imaptr, "premultiply", 0); + } + } + + uiBlockSetNFunc(block, NULL, NULL, NULL); + } + + MEM_freeN(cb); +} void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser) { - uiBlock *block= uiLayoutFreeBlock(layout); Scene *scene= CTX_data_scene(C); RenderResult *rr; @@ -1389,55 +1080,46 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser if(ima && iuser) { rr= BKE_image_get_renderresult(scene, ima); - if(rr) { - uiBlockBeginAlign(block); - uiblock_layer_pass_buttons(block, rr, iuser, 0, 0, 0, 160); - uiBlockEndAlign(block); - } + if(rr) + uiblock_layer_pass_buttons(layout, rr, iuser, 160); } } -static void image_panel_properties(const bContext *C, Panel *pa) +static int image_panel_uv_poll(const bContext *C, PanelType *pt) { - SpaceImage *sima= CTX_wm_space_image(C); + Object *obedit= CTX_data_edit_object(C); + return ED_uvedit_test(obedit); +} + +static void image_panel_uv(const bContext *C, Panel *pa) +{ + ARegion *ar= CTX_wm_region(C); uiBlock *block; block= uiLayoutFreeBlock(pa->layout); uiBlockSetHandleFunc(block, do_image_panel_events, NULL); - /* note, it draws no bottom half in facemode, for vertex buttons */ - ED_image_uiblock_panel(C, block, &sima->image, &sima->iuser, B_REDR, B_REDR); image_editvertex_buts(C, block); + image_editcursor_buts(C, &ar->v2d, block); } void image_buttons_register(ARegionType *art) { PanelType *pt; - pt= MEM_callocN(sizeof(PanelType), "spacetype image panel properties"); - strcpy(pt->idname, "IMAGE_PT_properties"); - strcpy(pt->label, "Image Properties"); - pt->draw= image_panel_properties; - BLI_addtail(&art->paneltypes, pt); - - pt= MEM_callocN(sizeof(PanelType), "spacetype image panel paint"); - strcpy(pt->idname, "IMAGE_PT_paint"); - strcpy(pt->label, "Paint"); - pt->draw= image_panel_paint; - pt->poll= image_panel_paint_poll; - BLI_addtail(&art->paneltypes, pt); - - pt= MEM_callocN(sizeof(PanelType), "spacetype image panel paint color"); - strcpy(pt->idname, "IMAGE_PT_paint_color"); - strcpy(pt->label, "Paint Color"); - pt->draw= image_panel_paintcolor; - pt->poll= image_panel_paint_poll; + pt= MEM_callocN(sizeof(PanelType), "spacetype image panel uv"); + strcpy(pt->idname, "IMAGE_PT_uv"); + strcpy(pt->label, "UV"); + pt->draw= image_panel_uv; + pt->poll= image_panel_uv_poll; BLI_addtail(&art->paneltypes, pt); pt= MEM_callocN(sizeof(PanelType), "spacetype image panel curves"); strcpy(pt->idname, "IMAGE_PT_curves"); strcpy(pt->label, "Curves"); pt->draw= image_panel_curves; + pt->poll= image_panel_poll; + pt->flag |= PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); pt= MEM_callocN(sizeof(PanelType), "spacetype image panel gpencil"); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 806d0d7ce52..d54dd56d1e8 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -628,9 +628,14 @@ static int open_exec(bContext *C, wmOperator *op) if(!ima) return OPERATOR_CANCELLED; + + /* already set later */ + ima->id.us--; - BKE_image_signal(ima, &sima->iuser, IMA_SIGNAL_RELOAD); - ED_space_image_set(C, sima, scene, obedit, ima); + // XXX other users? + BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD); + if(sima) + ED_space_image_set(C, sima, scene, obedit, ima); return OPERATOR_FINISHED; } @@ -651,13 +656,12 @@ static int open_invoke(bContext *C, wmOperator *op, wmEvent *event) void IMAGE_OT_open(wmOperatorType *ot) { /* identifiers */ - ot->name= "Open Image"; + ot->name= "Open"; ot->idname= "IMAGE_OT_open"; /* api callbacks */ ot->exec= open_exec; ot->invoke= open_invoke; - ot->poll= ED_operator_image_active; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -1051,8 +1055,12 @@ static int new_exec(bContext *C, wmOperator *op) color[3]= RNA_float_get(op->ptr, "alpha"); ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color); - BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE); - ED_space_image_set(C, sima, scene, obedit, ima); + ima->id.us--; /* already set later */ + + if(sima) { // XXX other users? + BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE); + ED_space_image_set(C, sima, scene, obedit, ima); + } return OPERATOR_FINISHED; } @@ -1066,7 +1074,6 @@ void IMAGE_OT_new(wmOperatorType *ot) /* api callbacks */ ot->exec= new_exec; ot->invoke= WM_operator_props_popup; - ot->poll= ED_operator_image_active; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 9051300e117..cb05109d984 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -77,7 +77,7 @@ int ED_uvedit_test(Object *obedit) EditMesh *em; int ret; - if(obedit->type != OB_MESH) + if(!obedit || obedit->type != OB_MESH) return 0; em = BKE_mesh_get_editmesh(obedit->data); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 420add2622a..4cef6fa481f 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -216,13 +216,15 @@ static void rna_def_curvemapping(BlenderRNA *brna) RNA_def_property_struct_type(prop, "CurveMap"); RNA_def_property_ui_text(prop, "Curves", ""); - prop= RNA_def_property(srna, "black_level", PROP_FLOAT, PROP_COLOR); + prop= RNA_def_property(srna, "black_level", PROP_FLOAT, PROP_RGB); RNA_def_property_float_sdna(prop, NULL, "black"); + RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Black Level", "For RGB curves, the color that black is mapped to"); RNA_def_property_float_funcs(prop, NULL, "rna_CurveMapping_black_level_set", NULL); - prop= RNA_def_property(srna, "white_level", PROP_FLOAT, PROP_COLOR); + prop= RNA_def_property(srna, "white_level", PROP_FLOAT, PROP_RGB); RNA_def_property_float_sdna(prop, NULL, "white"); + RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "White Level", "For RGB curves, the color that white is mapped to"); RNA_def_property_float_funcs(prop, NULL, "rna_CurveMapping_white_level_set", NULL); } diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 4d04f4ee1f3..ad96eaa99ad 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -37,6 +37,14 @@ #include "WM_types.h" +static EnumPropertyItem image_source_items[]= { + {IMA_SRC_FILE, "FILE", 0, "File", "Single image file"}, + {IMA_SRC_SEQUENCE, "SEQUENCE", 0, "Sequence", "Multiple image files, as a sequence"}, + {IMA_SRC_MOVIE, "MOVIE", 0, "Movie", "Movie file"}, + {IMA_SRC_GENERATED, "GENERATED", 0, "Generated", "Generated image"}, + {IMA_SRC_VIEWER, "VIEWER", 0, "Viewer", "Compositing node viewer"}, + {0, NULL, 0, NULL, NULL}}; + #ifdef RNA_RUNTIME #include "IMB_imbuf_types.h" @@ -66,6 +74,76 @@ static int rna_Image_dirty_get(PointerRNA *ptr) return 0; } +static void rna_Image_source_update(bContext *C, PointerRNA *ptr) +{ + Image *ima= ptr->id.data; + BKE_image_signal(ima, NULL, IMA_SIGNAL_SRC_CHANGE); +} + +static void rna_Image_fields_update(bContext *C, PointerRNA *ptr) +{ + Image *ima= ptr->id.data; + ImBuf *ibuf; + + ibuf= BKE_image_get_ibuf(ima, NULL); + + if(ibuf) { + short nr= 0; + + if(!(ima->flag & IMA_FIELDS) && (ibuf->flags & IB_fields)) nr= 1; + if((ima->flag & IMA_FIELDS) && !(ibuf->flags & IB_fields)) nr= 1; + + if(nr) + BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); + } +} + +static void rna_Image_reload_update(bContext *C, PointerRNA *ptr) +{ + Image *ima= ptr->id.data; + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + printf("reload %p\n", ima); +} + +static void rna_Image_generated_update(bContext *C, PointerRNA *ptr) +{ + Image *ima= ptr->id.data; + BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); +} + +static void rna_ImageUser_update(bContext *C, PointerRNA *ptr) +{ + Scene *scene= CTX_data_scene(C); + ImageUser *iuser= ptr->data; + + BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0); +} + +static EnumPropertyItem *rna_Image_source_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + Image *ima= (Image*)ptr->data; + EnumPropertyItem *item= NULL; + int totitem= 0; + + if(C==NULL) /* needed for doc generation */ + return image_source_items; + + if(ima->source == IMA_SRC_VIEWER) { + RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_VIEWER); + } + else { + RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_FILE); + RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_SEQUENCE); + RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_MOVIE); + RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_GENERATED); + } + + RNA_enum_item_end(&item, &totitem); + *free= 1; + + return item; +} + #else static void rna_def_imageuser(BlenderRNA *brna) @@ -79,29 +157,35 @@ static void rna_def_imageuser(BlenderRNA *brna) prop= RNA_def_property(srna, "auto_refresh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS); RNA_def_property_ui_text(prop, "Auto Refresh", "Always refresh image on frame changes."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); /* animation */ prop= RNA_def_property(srna, "cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cycl", 0); RNA_def_property_ui_text(prop, "Cyclic", "Cycle the images in the movie."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); prop= RNA_def_property(srna, "frames", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, MAXFRAMEF); RNA_def_property_ui_text(prop, "Frames", "Sets the number of images of a movie to use."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); prop= RNA_def_property(srna, "offset", PROP_INT, PROP_NONE); RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF); RNA_def_property_ui_text(prop, "Offset", "Offsets the number of the frame to use in the animation."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); prop= RNA_def_property(srna, "start_frame", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "sfra"); RNA_def_property_range(prop, 1.0f, MAXFRAMEF); RNA_def_property_ui_text(prop, "Start Frame", "Sets the global starting frame of the movie."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); prop= RNA_def_property(srna, "fields_per_frame", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "fie_ima"); RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF); RNA_def_property_ui_text(prop, "Fields per Frame", "The number of fields per rendered frame (2 fields is 1 image)."); + RNA_def_property_update(prop, 0, "rna_ImageUser_update"); prop= RNA_def_property(srna, "multilayer_layer", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "layer"); @@ -121,17 +205,10 @@ static void rna_def_image(BlenderRNA *brna) static const EnumPropertyItem prop_type_items[]= { {IMA_TYPE_IMAGE, "IMAGE", 0, "Image", ""}, {IMA_TYPE_MULTILAYER, "MULTILAYER", 0, "Multilayer", ""}, - {IMA_TYPE_UV_TEST, "UVTEST", 0, "UV Test", ""}, - {IMA_TYPE_R_RESULT, "RENDERRESULT", 0, "Render Result", ""}, + {IMA_TYPE_UV_TEST, "UV_TEST", 0, "UV Test", ""}, + {IMA_TYPE_R_RESULT, "RENDER_RESULT", 0, "Render Result", ""}, {IMA_TYPE_COMPOSITE, "COMPOSITING", 0, "Compositing", ""}, {0, NULL, 0, NULL, NULL}}; - static const EnumPropertyItem prop_source_items[]= { - {IMA_SRC_FILE, "FILE", 0, "File", "Single image file"}, - {IMA_SRC_SEQUENCE, "SEQUENCE", 0, "Sequence", "Multiple image files, as a sequence"}, - {IMA_SRC_MOVIE, "MOVIE", 0, "Movie", "Movie file"}, - {IMA_SRC_GENERATED, "GENERATED", 0, "Generated", "Generated image"}, - {IMA_SRC_VIEWER, "VIEWER", 0, "Viewer", "Compositing node viewer"}, - {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_generated_type_items[]= { {0, "BLANK", 0, "Blank", "Generate a blank image"}, {1, "UVTESTGRID", 0, "UV Test Grid", "Generated grid to test UV mappings"}, @@ -147,19 +224,18 @@ static void rna_def_image(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "name"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* imagechanged */ RNA_def_property_ui_text(prop, "Filename", "Image/Movie file name."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_reload_update"); prop= RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_source_items); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* imagechanged */ + RNA_def_property_enum_items(prop, image_source_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Image_source_itemf"); RNA_def_property_ui_text(prop, "Source", "Where the image comes from."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_source_update"); prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_type_items); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* imagechanged */ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Type", "How to generate the image."); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); @@ -171,12 +247,12 @@ static void rna_def_image(BlenderRNA *brna) prop= RNA_def_property(srna, "fields", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS); RNA_def_property_ui_text(prop, "Fields", "Use fields of the image."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_fields_update"); prop= RNA_def_property(srna, "odd_fields", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_STD_FIELD); RNA_def_property_ui_text(prop, "Odd Fields", "Standard field toggle."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_reload_update"); prop= RNA_def_property(srna, "antialias", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANTIALI); @@ -198,19 +274,19 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "gen_type"); RNA_def_property_enum_items(prop, prop_generated_type_items); RNA_def_property_ui_text(prop, "Generated Type", "Generated image type."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_generated_update"); prop= RNA_def_property(srna, "generated_width", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "gen_x"); RNA_def_property_range(prop, 1, 16384); RNA_def_property_ui_text(prop, "Generated Width", "Generated image width."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_generated_update"); prop= RNA_def_property(srna, "generated_height", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "gen_y"); RNA_def_property_range(prop, 1, 16384); RNA_def_property_ui_text(prop, "Generated Height", "Generated image height."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_generated_update"); /* realtime properties */ prop= RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 6b6e8b5b98e..30c5d4988b3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -212,6 +212,15 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *C, P return dc_rgb_items; } +static void rna_SpaceImageEditor_curves_update(bContext *C, PointerRNA *ptr) +{ + SpaceImage *sima= (SpaceImage*)ptr->data; + + curvemapping_do_ibuf(sima->cumap, ED_space_image_buffer(sima)); + WM_event_add_notifier(C, NC_IMAGE, sima->image); +} + + /* Space Text Editor */ static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) @@ -809,7 +818,7 @@ static void rna_def_space_image(BlenderRNA *brna) prop= RNA_def_property(srna, "curves", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "cumap"); RNA_def_property_ui_text(prop, "Curves", "Color curve mapping to use for displaying the image."); - RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, NULL); + RNA_def_property_update(prop, NC_SPACE|ND_SPACE_IMAGE, "rna_SpaceImageEditor_curves_update"); prop= RNA_def_property(srna, "image_pin", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "pin", 0); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 7a81138a3be..6fb9a9ca57b 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1073,6 +1073,11 @@ static void rna_def_texture_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_TEXTURE, NULL); + prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "iuser"); + RNA_def_property_ui_text(prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed."); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + /* filtering */ prop= RNA_def_property(srna, "filter", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "texfilter"); @@ -1116,6 +1121,11 @@ static void rna_def_texture_environment_map(BlenderRNA *brna) rna_def_environment_map_common(srna); + prop= RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "iuser"); + RNA_def_property_ui_text(prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed."); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + prop= RNA_def_property(srna, "environment_map", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "env"); RNA_def_property_struct_type(prop, "EnvironmentMap"); @@ -1641,9 +1651,7 @@ static void rna_def_texture(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Contrast", ""); RNA_def_property_update(prop, NC_TEXTURE, NULL); - /* XXX: would be nicer to have this as a color selector? - but the values can go past [0,1]. */ - prop= RNA_def_property(srna, "rgb_factor", PROP_FLOAT, PROP_NONE); + prop= RNA_def_property(srna, "rgb_factor", PROP_FLOAT, PROP_RGB); RNA_def_property_float_sdna(prop, NULL, "rfac"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0, 2); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 60994757b59..3110e631a65 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -292,11 +292,18 @@ void RNA_api_ui_layout(StructRNA *srna) parm= RNA_def_pointer(func, "image_user", "ImageUser", "", ""); RNA_def_property_flag(parm, PROP_REQUIRED); + func= RNA_def_function(srna, "template_image", "uiTemplateImage"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + parm= RNA_def_pointer(func, "image_user", "ImageUser", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_boolean(func, "compact", 0, "", "Use more compact layout."); + func= RNA_def_function(srna, "template_list", "uiTemplateList"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); parm= RNA_def_pointer(func, "active_data", "AnyType", "", "Data from which to take property for the active element."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_string(func, "active_property", "", 0, "", "Identifier of property in data, for the active element."); RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display.", 0, INT_MAX); @@ -314,11 +321,6 @@ void RNA_api_ui_layout(StructRNA *srna) func= RNA_def_function(srna, "view3d_select_faceselmenu", "uiTemplate_view3d_select_faceselmenu"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - - func= RNA_def_function(srna, "template_texture_image", "uiTemplateTextureImage"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - parm= RNA_def_pointer(func, "texture", "Texture", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); } #endif -- cgit v1.2.3 From 21e2f27532db7a9107d91fad79250cb5dd5103f5 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Wed, 16 Sep 2009 19:27:23 +0000 Subject: Tiny fix for mistake in toolbar. --- release/ui/space_view3d_toolbar.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index f177c81b7b7..4a5f2ae642c 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -67,9 +67,12 @@ class VIEW3D_PT_tools_meshedit(View3DPanel): col = layout.column(align=True) col.itemL(text="Modeling:") col.itemO("mesh.extrude") + col.itemO("mesh.extrude_repeat", text="Extrude Repeat") col.itemO("mesh.subdivide") col.itemO("mesh.spin") col.itemO("mesh.screw") + col.itemO("mesh.merge") + col.itemO("mesh.rip_move") col = layout.column(align=True) col.itemL(text="Shading:") @@ -288,7 +291,7 @@ class VIEW3D_PT_tools_posemode(View3DPanel): col.itemO("pose.reveal", text="Reveal") col = layout.column(align=True) - layout.itemL(text="Keyframes:") + col.itemL(text="Keyframes:") col.itemO("anim.insert_keyframe_menu", text="Insert") col.itemO("anim.delete_keyframe_v3d", text="Remove") -- cgit v1.2.3 From b6c6610630220de3fd39ee0c117451e436c889e0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 16 Sep 2009 19:36:17 +0000 Subject: UI * Removed some legacy code which is not needed anymore now. * Move some test_*poin_but functions to logic space code, since that's the only place using it still. * uiIconFromID now uses RNA info to lookup the icon, to avoid code duplication, and means it works for more ID types. --- source/blender/editors/include/UI_interface.h | 24 - .../editors/interface/interface_templates.c | 27 +- source/blender/editors/interface/interface_utils.c | 1077 +------------------- .../blender/editors/space_buttons/space_buttons.c | 65 -- source/blender/editors/space_graph/graph_buttons.c | 21 +- source/blender/editors/space_logic/logic_window.c | 101 ++ 6 files changed, 159 insertions(+), 1156 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index f475dd16057..848432b5f42 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -418,7 +418,6 @@ typedef void (*uiIDPoinFunc)(struct bContext *C, struct ID *id, int event); uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, char *str, short x1, short y1, short x2, short y2, void *idpp, char *tip); -int uiDefIDPoinButs(uiBlock *block, struct Main *main, struct ID *parid, struct ID *id, int id_code, short *pin_p, int x, int y, uiIDPoinFunc func, int events); int uiIconFromID(struct ID *id); @@ -531,29 +530,6 @@ void UI_add_region_handlers(struct ListBase *handlers); void UI_add_area_handlers(struct ListBase *handlers); void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *menu); -/* Legacy code - * Callbacks and utils to get 2.48 work */ - -void test_idbutton_cb(struct bContext *C, void *namev, void *arg2); -void test_scriptpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_actionpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_obpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_meshobpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_meshpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_matpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_scenepoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_grouppoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_texpoin_but(struct bContext *C, char *name, struct ID **idpp); -void test_imapoin_but(struct bContext *C, char *name, struct ID **idpp); -void autocomplete_bone(struct bContext *C, char *str, void *arg_v); -void autocomplete_vgroup(struct bContext *C, char *str, void *arg_v); - -struct rctf; -void curvemap_buttons(uiBlock *block, struct CurveMapping *cumap, char labeltype, short event, short redraw, struct rctf *rect); -void curvemap_layout(uiLayout *layout, struct CurveMapping *cumap, char labeltype, short event, short redraw, struct rctf *rect); -void colorband_buttons(uiBlock *block, struct ColorBand *coba, struct rctf *rect, int small); - - /* Module * * init and exit should be called before using this module. init_userdef must diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 66873917e8a..b27425f958d 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -762,6 +762,22 @@ static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short } } +static void test_obpoin_but(bContext *C, char *name, ID **idpp) +{ + ID *id; + + id= CTX_data_main(C)->object.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_lib_extern(id); /* checks lib data, sets correct flag for saving then */ + return; + } + id= id->next; + } + *idpp= NULL; +} + /* draw panel showing settings for a constraint */ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) { @@ -956,11 +972,11 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) /* subtarget */ if (is_armature_target(ct->tar)) { but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone"); - uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar); + //uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar); } else if (is_geom_target(ct->tar)) { but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar); + //uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar); } else { strcpy(ct->subtarget, ""); @@ -1762,9 +1778,6 @@ void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, char *propname) int groups, cols, layers; int group, col, layer, row; - if (!ptr->data) - return; - prop= RNA_struct_find_property(ptr, propname); if (!prop) { printf("uiTemplateLayer: layers property not found: %s\n", propname); @@ -2036,7 +2049,7 @@ ListBase uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, char *pr /************************* Operator Search Template **************************/ -static void operator_call_cb(struct bContext *C, void *arg1, void *arg2) +static void operator_call_cb(bContext *C, void *arg1, void *arg2) { wmOperatorType *ot= arg2; @@ -2044,7 +2057,7 @@ static void operator_call_cb(struct bContext *C, void *arg1, void *arg2) WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL); } -static void operator_search_cb(const struct bContext *C, void *arg, char *str, uiSearchItems *items) +static void operator_search_cb(const bContext *C, void *arg, char *str, uiSearchItems *items) { wmOperatorType *ot = WM_operatortype_first(); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 539c71cc497..00dec9a06c2 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -23,31 +23,13 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include +#include #include #include -#include "MEM_guardedalloc.h" - -#include "DNA_action_types.h" -#include "DNA_color_types.h" -#include "DNA_listBase.h" -#include "DNA_material_types.h" -#include "DNA_lamp_types.h"" #include "DNA_object_types.h" -#include "DNA_screen_types.h" -#include "DNA_texture_types.h" -#include "DNA_windowmanager_types.h" - -#include "BLI_blenlib.h" -#include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_idprop.h" -#include "BKE_icons.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_texture.h" #include "BKE_utildefines.h" #include "RNA_access.h" @@ -55,18 +37,6 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "ED_screen.h" -#include "ED_util.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "interface_intern.h" - -#define DEF_BUT_WIDTH 150 -#define DEF_ICON_BUT_WIDTH 20 -#define DEF_BUT_HEIGHT 20 - /*************************** RNA Utilities ******************************/ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, char *name, int icon, int x1, int y1, int x2, int y2) @@ -177,1047 +147,38 @@ void uiDefAutoButsRNA(const bContext *C, uiLayout *layout, PointerRNA *ptr, int else col= NULL; - /* temp hack to show normal button for spin/screw */ - if(strcmp(name, "Axis")==0) { - uiDefButR(uiLayoutGetBlock(col), BUT_NORMAL, 0, name, 0, 0, 100, 100, ptr, "axis", -1, 0, 0, -1, -1, NULL); - } - else uiItemFullR(col, "", 0, ptr, prop, -1, 0, 0); + uiItemFullR(col, "", 0, ptr, prop, -1, 0, 0); } RNA_STRUCT_END; } /***************************** ID Utilities *******************************/ -/* note, C code version, will be replaced with version in interface_templates.c */ - -typedef struct uiIDPoinParams { - uiIDPoinFunc func; - ListBase *lb; - ID *id; - short id_code; - short browsenr; -} uiIDPoinParams; - -static void idpoin_cb(bContext *C, void *arg_params, void *arg_event) -{ - uiIDPoinParams *params= (uiIDPoinParams*)arg_params; - ListBase *lb= params->lb; - uiIDPoinFunc func= params->func; - ID *id= params->id, *idtest; - int nr, event= GET_INT_FROM_POINTER(arg_event); - - if(event == UI_ID_BROWSE && params->browsenr == 32767) - event= UI_ID_ADD_NEW; - else if(event == UI_ID_BROWSE && params->browsenr == 32766) - event= UI_ID_OPEN; - - switch(event) { - case UI_ID_RENAME: - if(id) test_idbutton(id->name+2); - else return; - break; - case UI_ID_BROWSE: { - /* ID can be NULL, if nothing was assigned yet */ - if(lb->first==NULL) return; - - if(params->browsenr== -2) { - /* XXX implement or find a replacement (ID can be NULL!) - * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, ¶ms->browsenr, do_global_buttons); */ - return; - } - if(params->browsenr < 0) - return; - - for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) { - if(nr==params->browsenr) { - if(id == idtest) - return; - - id= idtest; - - break; - } - } - break; - } - case UI_ID_DELETE: - id= NULL; - break; - case UI_ID_FAKE_USER: - if(id) { - if(id->flag & LIB_FAKEUSER) id->us++; - else id->us--; - } - else return; - break; - case UI_ID_PIN: - break; - case UI_ID_ADD_NEW: - break; - case UI_ID_OPEN: - break; - case UI_ID_ALONE: - if(!id || id->us < 1) - return; - break; - case UI_ID_LOCAL: - if(!id || id->us < 1) - return; - break; - case UI_ID_AUTO_NAME: - break; - } - - if(func) - func(C, id, event); -} - -/* ***************************** ID Search browse menu ********************** */ - -static void id_search_call_cb(struct bContext *C, void *arg_params, void *item) -{ - uiIDPoinParams *params= (uiIDPoinParams*)arg_params; - - if(item && params->func) - params->func(C, item, UI_ID_BROWSE); - -} - -static void id_search_cb(const struct bContext *C, void *arg_params, char *str, uiSearchItems *items) -{ - uiIDPoinParams *params= (uiIDPoinParams*)arg_params; - ID *id; - - for(id= params->lb->first; id; id= id->next) { - int iconid= 0; - - - /* icon */ - switch(GS(id->name)) - { - case ID_MA: /* fall through */ - case ID_TE: /* fall through */ - case ID_IM: /* fall through */ - case ID_WO: /* fall through */ - case ID_LA: /* fall through */ - iconid= BKE_icon_getid(id); - break; - default: - break; - } - - if(BLI_strcasestr(id->name+2, str)) { - if(0==uiSearchItemAdd(items, id->name+2, id, iconid)) - break; - } - } -} - -static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_params) -{ - static char search[256]; - static uiIDPoinParams params; - wmEvent event; - wmWindow *win= CTX_wm_window(C); - uiBlock *block; - uiBut *but; - - /* clear initial search string, then all items show */ - search[0]= 0; - /* params is malloced, can be freed by parent button */ - params= *((uiIDPoinParams*)arg_params); - - block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); - uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1); - - /* fake button, it holds space for search items */ - uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL); - - but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, ""); - uiButSetSearchFunc(but, id_search_cb, ¶ms, id_search_call_cb, NULL); - - uiBoundsBlock(block, 6); - uiBlockSetDirection(block, UI_DOWN); - uiEndBlock(C, block); - - event= *(win->eventstate); /* XXX huh huh? make api call */ - event.type= EVT_BUT_OPEN; - event.val= KM_PRESS; - event.customdata= but; - event.customdatafree= FALSE; - wm_event_add(win, &event); - - return block; -} - -/* ****************** */ - -int uiDefIDPoinButs(uiBlock *block, Main *bmain, ID *parid, ID *id, int id_code, short *pin_p, int x, int y, uiIDPoinFunc func, int events) -{ - uiBut *but; - uiIDPoinParams *params, *dup_params; - char str1[10]; - int len, add_addbutton=0; - - /* setup struct that we will pass on with the buttons */ - params= MEM_callocN(sizeof(uiIDPoinParams), "uiIDPoinParams"); - params->lb= wich_libbase(bmain, id_code); - params->id= id; - params->id_code= id_code; - params->func= func; - - /* create buttons */ - uiBlockBeginAlign(block); - - /* XXX solve? - if(id && id->us>1) - uiBlockSetCol(block, TH_BUT_SETTING1); - - if((events & UI_ID_PIN) && *pin_p) - uiBlockSetCol(block, TH_BUT_SETTING2); - */ - - /* pin button */ - if(id && (events & UI_ID_PIN)) { - but= uiDefIconButS(block, ICONTOG, (events & UI_ID_PIN), ICON_KEY_DEHLT, x, y ,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, pin_p, 0, 0, 0, 0, "Keeps this view displaying the current data regardless of what object is selected"); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_PIN)); - x+= DEF_ICON_BUT_WIDTH; - } - - /* browse menu */ - if(events & UI_ID_BROWSE) { - uiDefBlockButN(block, id_search_menu, MEM_dupallocN(params), "", x, y, DEF_ICON_BUT_WIDTH, DEF_BUT_HEIGHT, "Browse ID data"); - x+= DEF_ICON_BUT_WIDTH; - } - - - - /* text button with name */ - if(id) { - /* XXX solve? - if(id->us > 1) - uiBlockSetCol(block, TH_BUT_SETTING1); - */ - /* pinned data? - if((events & UI_ID_PIN) && *pin_p) - uiBlockSetCol(block, TH_BUT_SETTING2); - */ - /* redalert overrides pin color - if(id->us<=0) - uiBlockSetCol(block, TH_REDALERT); - */ - uiBlockSetButLock(block, id->lib!=0, "Can't edit external libdata"); - - /* name button */ - text_idbutton(id, str1); - - if(GS(id->name)==ID_IP) len= 110; - else if((y) && (GS(id->name)==ID_AC)) len= 100; // comes from button panel (poselib) - else if(y) len= 140; // comes from button panel - else len= 120; - - but= uiDefBut(block, TEX, 0, str1,x, y, (short)len, DEF_BUT_HEIGHT, id->name+2, 0.0, 21.0, 0, 0, "Displays current Datablock name. Click to change."); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_RENAME)); - - x+= len; - - uiBlockClearButLock(block); - - /* lib make local button */ - if(id->lib) { - if(id->flag & LIB_INDIRECT) uiDefIconBut(block, BUT, 0, 0 /* XXX ICON_DATALIB */,x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Indirect Library Datablock. Cannot change."); - else { - but= uiDefIconBut(block, BUT, 0, 0 /* XXX ICON_PARLIB */, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, - (events & UI_ID_LOCAL)? "Direct linked Library Datablock. Click to make local.": "Direct linked Library Datablock, cannot make local."); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE)); - } - - x+= DEF_ICON_BUT_WIDTH; - } - - /* number of users / make local button */ - if((events & UI_ID_ALONE) && id->us>1) { - int butwidth; - - uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't make pinned data single-user"); - - sprintf(str1, "%d", id->us); - butwidth= (id->us<10)? DEF_ICON_BUT_WIDTH: DEF_ICON_BUT_WIDTH+10; - - but= uiDefBut(block, BUT, 0, str1, x, y, butwidth, DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy."); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ALONE)); - x+= butwidth; - - uiBlockClearButLock(block); - } - - /* add button */ - if(events & UI_ID_ADD_NEW) { - uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't unlink pinned data"); - if(parid && parid->lib); - else { - dup_params= MEM_dupallocN(params); - but= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, &dup_params->browsenr, params->browsenr, 32767.0, 0, 0, "Add new data block"); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); - x+= DEF_ICON_BUT_WIDTH; - } - - uiBlockClearButLock(block); - } - - /* delete button */ - if(events & UI_ID_DELETE) { - uiBlockSetButLock(block, (events & UI_ID_PIN) && *pin_p, "Can't unlink pinned data"); - if(parid && parid->lib); - else { - but= uiDefIconBut(block, BUT, 0, ICON_X, x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Deletes link to this Datablock"); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_DELETE)); - x+= DEF_ICON_BUT_WIDTH; - } - - uiBlockClearButLock(block); - } - - /* auto name button */ - if(events & UI_ID_AUTO_NAME) { - if(parid && parid->lib); - else { - but= uiDefIconBut(block, BUT, 0, ICON_AUTO,x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, 0, 0, 0, 0, 0, "Generates an automatic name"); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_AUTO_NAME)); - x+= DEF_ICON_BUT_WIDTH; - } - } - - /* fake user button */ - if(events & UI_ID_FAKE_USER) { - but= uiDefButBitS(block, TOG, LIB_FAKEUSER, 0, "F", x,y,DEF_ICON_BUT_WIDTH,DEF_BUT_HEIGHT, &id->flag, 0, 0, 0, 0, "Saves this datablock even if it has no users"); - uiButSetNFunc(but, idpoin_cb, MEM_dupallocN(params), SET_INT_IN_POINTER(UI_ID_FAKE_USER)); - x+= DEF_ICON_BUT_WIDTH; - } - } - /* add new button */ - else if(add_addbutton) { - if(parid) uiBlockSetButLock(block, parid->lib!=0, "Can't edit external libdata"); - dup_params= MEM_dupallocN(params); - but= uiDefButS(block, TOG, 0, "Add New", x, y, 110, DEF_BUT_HEIGHT, &dup_params->browsenr, params->browsenr, 32767.0, 0, 0, "Add new data block"); - uiButSetNFunc(but, idpoin_cb, dup_params, SET_INT_IN_POINTER(UI_ID_ADD_NEW)); - x+= 110; - } - - uiBlockEndAlign(block); - - MEM_freeN(params); - return x; -} - -/* currently only object-data types */ int uiIconFromID(ID *id) { - if (id==NULL) - return 0; - - switch(GS(id->name)) { - case ID_OB: - { - Object *ob= (Object *)id; - - switch(ob->type) { - case OB_EMPTY: - return ICON_EMPTY_DATA; - case OB_CURVE: - return ICON_CURVE_DATA; - case OB_SURF: - return ICON_SURFACE_DATA; - case OB_FONT: - return ICON_FONT_DATA; - } - - return uiIconFromID(ob->data); - } - case ID_ME: - return ICON_MESH_DATA; - case ID_AR: - return ICON_ARMATURE_DATA; - case ID_MB: - return ICON_META_DATA; - case ID_CA: - return ICON_CAMERA_DATA; - case ID_LT: - return ICON_LATTICE_DATA; - case ID_CU: - return ICON_CURVE_DATA; - case ID_LA: - { - Lamp *la= (Lamp *)id; - switch(la->type) { - case LA_LOCAL: - return ICON_LAMP_POINT; - case LA_SUN: - return ICON_LAMP_SUN; - case LA_SPOT: - return ICON_LAMP_SPOT; - case LA_HEMI: - return ICON_LAMP_HEMI; - case LA_AREA: - return ICON_LAMP_AREA; - } - return ICON_LAMP_DATA; - } - } - - return 0; -} - -/* ****************************** default button callbacks ******************* */ -/* ************ LEGACY WARNING, only to get things work with 2.48 code! ****** */ - -void test_idbutton_cb(struct bContext *C, void *namev, void *arg2) -{ - char *name= namev; - - test_idbutton(name+2); -} - - -void test_scriptpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - id= CTX_data_main(C)->text.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_actionpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - id= CTX_data_main(C)->action.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - id_us_plus(id); - *idpp= id; - return; - } - id= id->next; - } - *idpp= NULL; -} - - -void test_obpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - -// XXX if(idpp == (ID **)&(emptytex.object)) { -// error("You must add a texture first"); -// *idpp= 0; -// return; -// } - - id= CTX_data_main(C)->object.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_lib_extern(id); /* checks lib data, sets correct flag for saving then */ - return; - } - id= id->next; - } - *idpp= NULL; -} - -/* tests for an object of type OB_MESH */ -void test_meshobpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - id = CTX_data_main(C)->object.first; - while(id) { - Object *ob = (Object *)id; - if(ob->type == OB_MESH && strcmp(name, id->name + 2) == 0) { - *idpp = id; - /* checks lib data, sets correct flag for saving then */ - id_lib_extern(id); - return; - } - id = id->next; - } - *idpp = NULL; -} - -void test_meshpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->mesh.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_matpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->mat.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_scenepoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->scene.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_grouppoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->group.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_texpoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->tex.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -void test_imapoin_but(struct bContext *C, char *name, ID **idpp) -{ - ID *id; - - if( *idpp ) (*idpp)->us--; - - id= CTX_data_main(C)->image.first; - while(id) { - if( strcmp(name, id->name+2)==0 ) { - *idpp= id; - id_us_plus(id); - return; - } - id= id->next; - } - *idpp= NULL; -} - -/* autocomplete callback for buttons */ -void autocomplete_bone(struct bContext *C, char *str, void *arg_v) -{ - Object *ob= (Object *)arg_v; - - if(ob==NULL || ob->pose==NULL) return; - - /* search if str matches the beginning of name */ - if(str[0]) { - AutoComplete *autocpl= autocomplete_begin(str, 32); - bPoseChannel *pchan; - - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) - autocomplete_do_name(autocpl, pchan->name); - - autocomplete_end(autocpl, str); - } -} - -/* autocomplete callback for buttons */ -void autocomplete_vgroup(struct bContext *C, char *str, void *arg_v) -{ - Object *ob= (Object *)arg_v; - - if(ob==NULL) return; - - /* search if str matches the beginning of a name */ - if(str[0]) { - AutoComplete *autocpl= autocomplete_begin(str, 32); - bDeformGroup *dg; - - for(dg= ob->defbase.first; dg; dg= dg->next) - if(dg->name!=str) - autocomplete_do_name(autocpl, dg->name); - - autocomplete_end(autocpl, str); - } -} - - -/* ----------- custom button group ---------------------- */ - -static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused) -{ - CurveMapping *cumap = cumap_v; - float d; - - /* we allow 20 times zoom */ - if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) { - d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin); - cumap->curr.xmin+= d; - cumap->curr.xmax-= d; - d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin); - cumap->curr.ymin+= d; - cumap->curr.ymax-= d; - } -} - -static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused) -{ - CurveMapping *cumap = cumap_v; - float d, d1; - - /* we allow 20 times zoom, but dont view outside clip */ - if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) { - d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin); - - if(cumap->flag & CUMA_DO_CLIP) - if(cumap->curr.xmin-d < cumap->clipr.xmin) - d1= cumap->curr.xmin - cumap->clipr.xmin; - cumap->curr.xmin-= d1; - - d1= d; - if(cumap->flag & CUMA_DO_CLIP) - if(cumap->curr.xmax+d > cumap->clipr.xmax) - d1= -cumap->curr.xmax + cumap->clipr.xmax; - cumap->curr.xmax+= d1; - - d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin); - - if(cumap->flag & CUMA_DO_CLIP) - if(cumap->curr.ymin-d < cumap->clipr.ymin) - d1= cumap->curr.ymin - cumap->clipr.ymin; - cumap->curr.ymin-= d1; - - d1= d; - if(cumap->flag & CUMA_DO_CLIP) - if(cumap->curr.ymax+d > cumap->clipr.ymax) - d1= -cumap->curr.ymax + cumap->clipr.ymax; - cumap->curr.ymax+= d1; - } -} - -static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused) -{ - CurveMapping *cumap = cumap_v; - - curvemapping_changed(cumap, 0); -} - -static void curvemap_buttons_delete(bContext *C, void *cumap_v, void *unused) -{ - CurveMapping *cumap = cumap_v; - - curvemap_remove(cumap->cm+cumap->cur, SELECT); - curvemapping_changed(cumap, 0); -} - -/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ -static uiBlock *curvemap_clipping_func(struct bContext *C, struct ARegion *ar, void *cumap_v) -{ - CurveMapping *cumap = cumap_v; - uiBlock *block; - uiBut *bt; - - block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS); - - /* use this for a fake extra empy space around the buttons */ - uiDefBut(block, LABEL, 0, "", -4, 16, 128, 106, NULL, 0, 0, 0, 0, ""); - - bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping", - 0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, ""); - uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, 0, "Min X ", 0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, ""); - uiDefButF(block, NUM, 0, "Min Y ", 0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, ""); - uiDefButF(block, NUM, 0, "Max X ", 0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, ""); - uiDefButF(block, NUM, 0, "Max Y ", 0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, ""); - - uiBlockSetDirection(block, UI_RIGHT); - - uiEndBlock(C, block); - return block; -} - - -static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event) -{ - CurveMapping *cumap = cumap_v; - CurveMap *cuma= cumap->cm+cumap->cur; - - switch(event) { - case 0: - curvemap_reset(cuma, &cumap->clipr); - curvemapping_changed(cumap, 0); - break; - case 1: - cumap->curr= cumap->clipr; - break; - case 2: /* set vector */ - curvemap_sethandle(cuma, 1); - curvemapping_changed(cumap, 0); - break; - case 3: /* set auto */ - curvemap_sethandle(cuma, 0); - curvemapping_changed(cumap, 0); - break; - case 4: /* extend horiz */ - cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE; - curvemapping_changed(cumap, 0); - break; - case 5: /* extend extrapolate */ - cuma->flag |= CUMA_EXTEND_EXTRAPOLATE; - curvemapping_changed(cumap, 0); - break; - } - ED_region_tag_redraw(CTX_wm_region(C)); -} - -static uiBlock *curvemap_tools_func(struct bContext *C, struct ARegion *ar, void *cumap_v) -{ - uiBlock *block; - short yco= 0, menuwidth=120; - - block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS); - uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v); - - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, ""); - - uiBlockSetDirection(block, UI_RIGHT); - uiTextBoundsBlock(block, 50); - - uiEndBlock(C, block); - return block; -} - -/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */ -void curvemap_buttons(uiBlock *block, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect) -{ - uiBut *bt; - float dx, fy= rect->ymax-18.0f; - int icon; - short xco, yco; - - yco= (short)(rect->ymax-18.0f); - - /* curve choice options + tools/settings, 8 icons + spacer */ - dx= (rect->xmax-rect->xmin)/(9.0f); - - uiBlockBeginAlign(block); - if(labeltype=='v') { /* vector */ - xco= (short)rect->xmin; - if(cumap->cm[0].curve) - uiDefButI(block, ROW, redraw, "X", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); - xco= (short)(rect->xmin+1.0f*dx); - if(cumap->cm[1].curve) - uiDefButI(block, ROW, redraw, "Y", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); - xco= (short)(rect->xmin+2.0f*dx); - if(cumap->cm[2].curve) - uiDefButI(block, ROW, redraw, "Z", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); - } - else if(labeltype=='c') { /* color */ - xco= (short)rect->xmin; - if(cumap->cm[3].curve) - uiDefButI(block, ROW, redraw, "C", xco, yco+2, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, ""); - xco= (short)(rect->xmin+1.0f*dx); - if(cumap->cm[0].curve) - uiDefButI(block, ROW, redraw, "R", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); - xco= (short)(rect->xmin+2.0f*dx); - if(cumap->cm[1].curve) - uiDefButI(block, ROW, redraw, "G", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); - xco= (short)(rect->xmin+3.0f*dx); - if(cumap->cm[2].curve) - uiDefButI(block, ROW, redraw, "B", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); - } - /* else no channels ! */ - uiBlockEndAlign(block); - - xco= (short)(rect->xmin+4.5f*dx); - uiBlockSetEmboss(block, UI_EMBOSSN); - bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in"); - uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL); - - xco= (short)(rect->xmin+5.25f*dx); - bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out"); - uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL); - - xco= (short)(rect->xmin+6.0f*dx); - bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, xco, yco, dx, 18, "Tools"); - - xco= (short)(rect->xmin+7.0f*dx); - if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT; - bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, xco, yco, dx, 18, "Clipping Options"); - - xco= (short)(rect->xmin+8.0f*dx); - bt= uiDefIconBut(block, BUT, event, ICON_X, xco, yco, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points"); - uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL); - - uiBlockSetEmboss(block, UI_EMBOSS); - - uiDefBut(block, BUT_CURVE, event, "", - rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin, - cumap, 0.0f, 1.0f, 0, 0, ""); -} - -/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */ -void curvemap_layout(uiLayout *layout, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect) -{ - uiLayout *row; - uiBlock *block; - uiBut *bt; - float dx, fy= rect->ymax-18.0f; - int icon; - - block= uiLayoutGetBlock(layout); - - /* curve choice options + tools/settings, 8 icons + spacer */ - dx= UI_UNIT_X; - - row= uiLayoutRow(layout, 0); - uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); - - if(labeltype=='v') { /* vector */ - row= uiLayoutRow(layout, 1); - - if(cumap->cm[0].curve) - uiDefButI(block, ROW, redraw, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); - if(cumap->cm[1].curve) - uiDefButI(block, ROW, redraw, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); - if(cumap->cm[2].curve) - uiDefButI(block, ROW, redraw, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); - } - else if(labeltype=='c') { /* color */ - row= uiLayoutRow(layout, 1); - - if(cumap->cm[3].curve) - uiDefButI(block, ROW, redraw, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, ""); - if(cumap->cm[0].curve) - uiDefButI(block, ROW, redraw, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, ""); - if(cumap->cm[1].curve) - uiDefButI(block, ROW, redraw, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, ""); - if(cumap->cm[2].curve) - uiDefButI(block, ROW, redraw, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, ""); - } - - row= uiLayoutRow(row, 1); - - uiBlockSetEmboss(block, UI_EMBOSSN); - bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in"); - uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL); - - bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out"); - uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL); - - bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, 0, 0, dx, 18, "Tools"); - - if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT; - bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, 0, 0, dx, 18, "Clipping Options"); - - bt= uiDefIconBut(block, BUT, event, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points"); - uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL); - - uiBlockSetEmboss(block, UI_EMBOSS); - - row= uiLayoutRow(layout, 0); - uiDefBut(block, BUT_CURVE, event, "", - rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin, - cumap, 0.0f, 1.0f, 0, 0, ""); -} - - -#define B_BANDCOL 1 - -static int vergcband(const void *a1, const void *a2) -{ - const CBData *x1=a1, *x2=a2; + Object *ob; + PointerRNA ptr; + short idcode; - if( x1->pos > x2->pos ) return 1; - else if( x1->pos < x2->pos) return -1; - return 0; -} - -static void colorband_pos_cb(bContext *C, void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - int a; - - if(coba->tot<2) return; + if(id==NULL) + return 0; - for(a=0; atot; a++) coba->data[a].cur= a; - qsort(coba->data, coba->tot, sizeof(CBData), vergcband); - for(a=0; atot; a++) { - if(coba->data[a].cur==coba->cur) { - // XXX if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); /* button cur */ - coba->cur= a; - break; - } - } - - WM_event_add_notifier(C, NC_TEXTURE, NULL); -} + idcode= GS(id->name); -static void colorband_cb(bContext *C, void *coba_v, void *unused_v) -{ - WM_event_add_notifier(C, NC_TEXTURE, NULL); -} - -static void colorband_add_cb(bContext *C, void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - - if(coba->tot < MAXCOLORBAND-1) coba->tot++; - coba->cur= coba->tot-1; - - colorband_pos_cb(C, coba, NULL); - ED_undo_push(C, "Add colorband"); - WM_event_add_notifier(C, NC_TEXTURE, NULL); -} + /* exception for objects */ + if(idcode == ID_OB) { + ob= (Object*)id; -static void colorband_del_cb(bContext *C, void *coba_v, void *unused_v) -{ - ColorBand *coba= coba_v; - int a; - - if(coba->tot<2) return; - - for(a=coba->cur; atot; a++) { - coba->data[a]= coba->data[a+1]; + if(ob->type == OB_EMPTY) + return ICON_EMPTY_DATA; + else + return uiIconFromID(ob->data); } - if(coba->cur) coba->cur--; - coba->tot--; - - ED_undo_push(C, "Delete colorband"); - // XXX BIF_preview_changed(ID_TE); - WM_event_add_notifier(C, NC_TEXTURE, NULL); -} - -/* offset aligns from bottom, standard width 300, height 115 */ -static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, int redraw) -{ - CBData *cbd; - uiBut *bt; - - if(coba==NULL) return; - - bt= uiDefBut(block, BUT, redraw, "Add", 0+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Add a new color stop to the colorband"); - uiButSetFunc(bt, colorband_add_cb, coba, NULL); - bt= uiDefBut(block, BUT, redraw, "Delete", 60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position"); - uiDefButS(block, NUM, redraw, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Choose active color stop"); - - uiButSetFunc(bt, colorband_del_cb, coba, NULL); - - bt= uiDefButS(block, MENU, redraw, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", - 210+xoffs, 100+yoffs, 90, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); - uiButSetFunc(bt, colorband_cb, coba, NULL); - uiBlockEndAlign(block); - - bt= uiDefBut(block, BUT_COLORBAND, redraw, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); - uiButSetFunc(bt, colorband_cb, coba, NULL); - - cbd= coba->data + coba->cur; - - bt= uiDefButF(block, NUM, redraw, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); - uiButSetFunc(bt, colorband_pos_cb, coba, NULL); - bt= uiDefButF(block, COL, redraw, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiButSetFunc(bt, colorband_cb, coba, NULL); - bt= uiDefButF(block, NUMSLI, redraw, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); - uiButSetFunc(bt, colorband_cb, coba, NULL); - -} + /* otherwise get it through RNA, creating the pointer + will set the right type, also with subclassing */ + RNA_id_pointer_create(id, &ptr); -static void colorband_buttons_small(uiBlock *block, ColorBand *coba, rctf *butr, int event) -{ - CBData *cbd; - uiBut *bt; - float unit= (butr->xmax-butr->xmin)/14.0f; - float xs= butr->xmin; - - cbd= coba->data + coba->cur; - - - bt= uiDefBut(block, BUT, event, "Add", xs,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband"); - uiButSetFunc(bt, colorband_add_cb, coba, NULL); - bt= uiDefBut(block, BUT, event, "Delete", xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Delete the active position"); - uiButSetFunc(bt, colorband_del_cb, coba, NULL); - - uiDefButF(block, COL, event, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiDefButF(block, NUMSLI, event, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); - - uiDefButS(block, MENU, event, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", - xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); - - uiDefBut(block, BUT_COLORBAND, event, "", xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, ""); - uiBlockEndAlign(block); -} - -void colorband_buttons(uiBlock *block, ColorBand *coba, rctf *butr, int small) -{ - if(small) - colorband_buttons_small(block, coba, butr, 0); - else - colorband_buttons_large(block, coba, 0, 0, 0); + return (ptr.type)? RNA_struct_ui_icon(ptr.type): 0; } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index d4ad77daca7..c8ced42c2d2 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -259,58 +259,6 @@ static void buttons_header_area_draw(const bContext *C, ARegion *ar) UI_view2d_view_restore(C); } -#if 0 -/* add handlers, stuff you only do once or on area/region changes */ -static void buttons_context_area_init(wmWindowManager *wm, ARegion *ar) -{ - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); -} - -#define CONTEXTY 30 - -static void buttons_context_area_draw(const bContext *C, ARegion *ar) -{ - SpaceButs *sbuts= CTX_wm_space_buts(C); - uiStyle *style= U.uistyles.first; - uiBlock *block; - uiLayout *layout; - View2D *v2d= &ar->v2d; - float col[3]; - int x, y, w, h; - - buttons_context_compute(C, sbuts); - - w= v2d->cur.xmax - v2d->cur.xmin; - h= v2d->cur.ymax - v2d->cur.ymin; - UI_view2d_view_ortho(C, v2d); - - /* create UI */ - block= uiBeginBlock(C, ar, "buttons_context", UI_EMBOSS); - layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_PANEL, - style->panelspace, h - (h-UI_UNIT_Y)/2, w, 20, style); - - buttons_context_draw(C, layout); - - uiBlockLayoutResolve(C, block, &x, &y); - uiEndBlock(C, block); - - /* draw */ - UI_SetTheme(SPACE_BUTS, RGN_TYPE_WINDOW); /* XXX */ - - UI_GetThemeColor3fv(TH_BACK, col); - glClearColor(col[0], col[1], col[2], 0.0); - glClear(GL_COLOR_BUFFER_BIT); - - UI_view2d_totRect_set(v2d, x, -y); - UI_view2d_view_ortho(C, v2d); - - uiDrawBlock(C, block); - - /* restore view matrix */ - UI_view2d_view_restore(C); -} -#endif - /* reused! */ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn) { @@ -424,19 +372,6 @@ void ED_spacetype_buttons(void) art->draw= buttons_header_area_draw; BLI_addhead(&st->regiontypes, art); -#if 0 - /* regions: context */ - art= MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); - art->regionid = RGN_TYPE_CHANNELS; - art->minsizey= CONTEXTY; - art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES; - art->init= buttons_context_area_init; - art->draw= buttons_context_area_draw;; - art->listener= buttons_area_listener; - - BLI_addhead(&st->regiontypes, art); -#endif - BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 9aa02b45950..09008f8d2d1 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -46,15 +46,16 @@ #include "BLI_editVert.h" #include "BLI_rand.h" -#include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" @@ -250,6 +251,22 @@ static int graph_panel_drivers_poll(const bContext *C, PanelType *pt) return graph_panel_context(C, NULL, NULL); } +static void test_obpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + id= CTX_data_main(C)->object.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_lib_extern(id); /* checks lib data, sets correct flag for saving then */ + return; + } + id= id->next; + } + *idpp= NULL; +} + /* driver settings for active F-Curve (only for 'Drivers' mode) */ static void graph_panel_drivers(const bContext *C, Panel *pa) { diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 4afa56582a2..cd02f2c6304 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -965,6 +965,107 @@ static void verify_logicbutton_func(bContext *C, void *data1, void *data2) } } +static void test_scriptpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + id= CTX_data_main(C)->text.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + return; + } + id= id->next; + } + *idpp= NULL; +} + +static void test_actionpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + id= CTX_data_main(C)->action.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + id_us_plus(id); + *idpp= id; + return; + } + id= id->next; + } + *idpp= NULL; +} + + +static void test_obpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + id= CTX_data_main(C)->object.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_lib_extern(id); /* checks lib data, sets correct flag for saving then */ + return; + } + id= id->next; + } + *idpp= NULL; +} + +static void test_meshpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + if( *idpp ) (*idpp)->us--; + + id= CTX_data_main(C)->mesh.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_us_plus(id); + return; + } + id= id->next; + } + *idpp= NULL; +} + +static void test_matpoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + if( *idpp ) (*idpp)->us--; + + id= CTX_data_main(C)->mat.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_us_plus(id); + return; + } + id= id->next; + } + *idpp= NULL; +} + +static void test_scenepoin_but(struct bContext *C, char *name, ID **idpp) +{ + ID *id; + + if( *idpp ) (*idpp)->us--; + + id= CTX_data_main(C)->scene.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + id_us_plus(id); + return; + } + id= id->next; + } + *idpp= NULL; +} /** * Draws a toggle for pulse mode, a frequency field and a toggle to invert -- cgit v1.2.3 From 6e4d4a8a1266834ac5ec7e079c734563caa14628 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 16 Sep 2009 19:47:58 +0000 Subject: fix bugs with file transfer --- release/io/netrender/master.py | 11 ++++++----- release/io/netrender/slave.py | 8 ++++---- release/io/netrender/utils.py | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 13e8b399d6c..29cec4e2232 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -323,8 +323,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if render_file: self.server.stats("", "Sending file to render node") - f = open(render_file.path, 'rb') + f = open(render_file.filepath, 'rb') + self.send_head() shutil.copyfileobj(f, self.wfile) f.close() @@ -444,7 +445,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): render_file = job.files_map.get(job_file, None) if render_file: - main_file = job.files[0] + main_file = job.files[0][0] # filename of the first file main_path, main_name = os.path.split(main_file) @@ -462,12 +463,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): f.close() del buf - render_file.path = file_path # set the new path + render_file.filepath = file_path # set the new path if job.testStart(): - self.send_head(headers=headers) + self.send_head(http.client.OK) else: - self.send_head(http.client.ACCEPTED, headers=headers) + self.send_head(http.client.ACCEPTED) else: # invalid file self.send_head(http.client.NO_CONTENT) else: # job not found diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index cec5439fc63..3a4e77abc54 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -26,12 +26,12 @@ def testCancel(conn, job_id): else: return False -def testFile(conn, JOB_PREFIX, file_path, main_path = None): +def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None): job_full_path = prefixPath(JOB_PREFIX, file_path, main_path) if not os.path.exists(job_full_path): temp_path = JOB_PREFIX + "slave.temp.blend" - conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id, "job-file":file_path}) + conn.request("GET", "file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) response = conn.getresponse() if response.status != http.client.OK: @@ -86,14 +86,14 @@ def render_slave(engine, scene): job_path = job.files[0][0] # data in files have format (path, start, end) main_path, main_file = os.path.split(job_path) - job_full_path = testFile(conn, JOB_PREFIX, job_path) + job_full_path = testFile(conn, job.id, slave_id, JOB_PREFIX, job_path) print("Fullpath", job_full_path) print("File:", main_file, "and %i other files" % (len(job.files) - 1,)) engine.update_stats("", "Render File", main_file, "for job", job.id) for file_path, start, end in job.files[1:]: print("\t", file_path) - testFile(conn, JOB_PREFIX, file_path, main_path) + testFile(conn, job.id, slave_id, JOB_PREFIX, file_path, main_path) frame_args = [] diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index 72a29472748..46c2011b188 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -59,8 +59,8 @@ def prefixPath(prefix_directory, file_path, prefix_path): if not os.path.exists(full_path): p, n = os.path.split(full_path) - if main_path and p.startswith(main_path): - directory = prefix_directory + p[len(main_path):] + if prefix_path and p.startswith(prefix_path): + directory = prefix_directory + p[len(prefix_path):] full_path = directory + n if not os.path.exists(directory): os.mkdir(directory) -- cgit v1.2.3 From f26ac206c9acd9f1593cde2dc822c9e344507e97 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Wed, 16 Sep 2009 19:58:01 +0000 Subject: *Changed image field order property to enum, making it consistent with the corresponding render option *Tiny edit to image panel. --- source/blender/editors/space_image/image_buttons.c | 39 ++++++++++++---------- source/blender/makesrna/intern/rna_image.c | 17 ++++++---- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index f3607ed7276..78687958c60 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1014,13 +1014,31 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn image_info(ima, ibuf, str); uiItemL(layout, str, 0); } - + + if(ima->source != IMA_SRC_GENERATED) { + uiItemS(layout); + + split= uiLayoutSplit(layout, 0); + + col= uiLayoutColumn(split, 0); + uiItemR(col, NULL, 0, &imaptr, "fields", 0); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, &imaptr, "field_order", UI_ITEM_R_EXPAND); + uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "fields")); + + col= uiLayoutColumn(split, 0); + uiItemR(col, NULL, 0, &imaptr, "antialias", 0); + uiItemR(col, NULL, 0, &imaptr, "premultiply", 0); + } + if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + uiItemS(layout); + split= uiLayoutSplit(layout, 0); col= uiLayoutColumn(split, 0); - sprintf(str, "(%d) Frames:", iuser->framenr); + sprintf(str, "(%d) Frames", iuser->framenr); row= uiLayoutRow(col, 1); uiItemR(col, str, 0, userptr, "frames", 0); if(ima->anim) { @@ -1048,22 +1066,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn uiItemR(col, NULL, 0, &imaptr, "generated_type", UI_ITEM_R_EXPAND); } - if(ima->source != IMA_SRC_GENERATED) { - uiItemS(layout); - - split= uiLayoutSplit(layout, 0); - - col= uiLayoutColumn(split, 0); - uiItemR(col, NULL, 0, &imaptr, "fields", 0); - row= uiLayoutRow(col, 0); - uiItemR(row, "Odd", 0, &imaptr, "odd_fields", 0); - uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "fields")); - - col= uiLayoutColumn(split, 0); - uiItemR(col, NULL, 0, &imaptr, "antialias", 0); - uiItemR(col, NULL, 0, &imaptr, "premultiply", 0); - } - } + } uiBlockSetNFunc(block, NULL, NULL, NULL); } diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index ad96eaa99ad..8614e6f4ef3 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -217,6 +217,10 @@ static void rna_def_image(BlenderRNA *brna) {0, "UV", 0, "UV Coordinates", "Use UV coordinates for mapping the image"}, {IMA_REFLECT, "REFLECTION", 0, "Reflection", "Use reflection mapping for mapping the image"}, {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_field_order_items[]= { + {0, "EVEN", 0, "Even", "Even Fields first"}, + {IMA_STD_FIELD, "Odd", 0, "Odd", "Odd Fields first"}, + {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Image", "ID"); RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image."); @@ -242,18 +246,19 @@ static void rna_def_image(BlenderRNA *brna) prop= RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "packedfile"); RNA_def_property_ui_text(prop, "Packed File", ""); - + + prop= RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_field_order_items); + RNA_def_property_ui_text(prop, "Field Order", "Order of video fields. Select which lines are displayed first."); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL); + /* booleans */ prop= RNA_def_property(srna, "fields", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS); RNA_def_property_ui_text(prop, "Fields", "Use fields of the image."); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_fields_update"); - prop= RNA_def_property(srna, "odd_fields", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_STD_FIELD); - RNA_def_property_ui_text(prop, "Odd Fields", "Standard field toggle."); - RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_reload_update"); - prop= RNA_def_property(srna, "antialias", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANTIALI); RNA_def_property_ui_text(prop, "Anti-alias", "Toggles image anti-aliasing, only works with solid colors"); -- cgit v1.2.3 From 90d8088e53293d1f36d9063d5898dd8bd3ddf878 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Wed, 16 Sep 2009 20:07:05 +0000 Subject: 2.5: Test Commit, converted Filter Composite Node to use layout engine. :) Will do other Nodes in the next few days. --- source/blender/editors/space_node/drawnode.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 494a68fc918..466d1aaa281 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1449,16 +1449,7 @@ static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_filter(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - uiBut *bt; - - /* blend type */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); + uiItemR(layout, "", 0, ptr, "filter_type", 0); } static void node_composit_buts_flip(uiLayout *layout, PointerRNA *ptr) -- cgit v1.2.3 From 591a30dab030a90218f37a0c4a8c4474663c7155 Mon Sep 17 00:00:00 2001 From: Remigiusz Fiedler Date: Wed, 16 Sep 2009 22:12:23 +0000 Subject: bugfix for LineIntersectLine() - was imperfect calculation for points marking shortest distance for non-crossing lines in 3d --- source/blender/blenlib/intern/arithb.c | 2 +- source/blender/python/generic/Mathutils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index 339a7250295..b7f56e6ca1c 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -4715,7 +4715,7 @@ int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float VecSubf(c, v3t, v1); VecSubf(a, v2, v1); - VecSubf(b, v4t, v3); + VecSubf(b, v4t, v3t); Crossf(ab, a, b); Crossf(cb, c, b); diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c index d354aea6614..431f1987383 100644 --- a/source/blender/python/generic/Mathutils.c +++ b/source/blender/python/generic/Mathutils.c @@ -912,7 +912,7 @@ static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ) PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); return NULL; } - if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size) { + if( vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) { PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); return NULL; } -- cgit v1.2.3 From 4a15b40c37fc36a041c2d20dbcadbcf9d258c583 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 16 Sep 2009 22:27:27 +0000 Subject: * fix compilation on osx --- intern/ghost/intern/GHOST_SystemCarbon.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp index fb1b96fcbc7..57d6f6c06cc 100644 --- a/intern/ghost/intern/GHOST_SystemCarbon.cpp +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -788,21 +788,21 @@ OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event) switch(tabletProximityRecord.pointerType) { case 1: /* stylus */ - ct.Active = 1; + ct.Active = GHOST_kTabletModeStylus; break; case 2: /* puck, not supported so far */ - ct.Active = 0; + ct.Active = GHOST_kTabletModeNone; break; case 3: /* eraser */ - ct.Active = 2; + ct.Active = GHOST_kTabletModeEraser; break; default: - ct.Active = 0; + ct.Active = GHOST_kTabletModeNone; break; } } else { // pointer is leaving - return to mouse - ct.Active = 0; + ct.Active = GHOST_kTabletModeNone; } } } -- cgit v1.2.3 From 1934ee422a47f7dcc5e63cfff5811873798561d8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 17 Sep 2009 00:14:47 +0000 Subject: rna function api was overwriting useful errors with keyword errors. fix some missing checks in the python interface. --- release/ui/buttons_data_mesh.py | 3 ++- release/ui/buttons_material.py | 5 +++-- source/blender/python/intern/bpy_rna.c | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/release/ui/buttons_data_mesh.py b/release/ui/buttons_data_mesh.py index 33b3960b381..8796d7a46a8 100644 --- a/release/ui/buttons_data_mesh.py +++ b/release/ui/buttons_data_mesh.py @@ -102,7 +102,8 @@ class DATA_PT_shape_keys(DataButtonsPanel): kb = ob.active_shape_key row = layout.row() - row.template_list(key, "keys", ob, "active_shape_key_index", rows=2) + if key: # XXX - looks crappy + row.template_list(key, "keys", ob, "active_shape_key_index", rows=2) col = row.column() diff --git a/release/ui/buttons_material.py b/release/ui/buttons_material.py index 9f1c216c36b..8b58c2b8953 100644 --- a/release/ui/buttons_material.py +++ b/release/ui/buttons_material.py @@ -65,8 +65,9 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel): elif mat: split.template_ID(space, "pin_id") split.itemS() - - layout.itemR(mat, "type", expand=True) + + if mat: + layout.itemR(mat, "type", expand=True) class MATERIAL_PT_shading(MaterialButtonsPanel): __label__ = "Shading" diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 65c701c0041..50e32f34594 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1994,8 +1994,10 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw) /* Check if we gave args that dont exist in the function * printing the error is slow but it should only happen when developing. - * the if below is quick, checking if it passed less keyword args then we gave */ - if(kw && (PyDict_Size(kw) > kw_tot)) { + * the if below is quick, checking if it passed less keyword args then we gave. + * (Dont overwrite the error if we have one, otherwise can skip important messages and confuse with args) + */ + if(err == 0 && kw && (PyDict_Size(kw) > kw_tot)) { PyObject *key, *value; Py_ssize_t pos = 0; -- cgit v1.2.3 From 68f4465cdc0925ec22584e404a895982f6a74de0 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 17 Sep 2009 10:14:56 +0000 Subject: 2.5 - Animation Utility Function Added a utility function to check which transforms for an object or bone are animated, returning these as bitflags and/or optionally retrieving the relevant F-Curves too. Beware that this method may not be working correctly yet, but it shouldn't hurt anyone in the meantime :) Also, split RNA-path building function up into a version which only creates the path up to the given struct, with the other parts being added later. --- source/blender/blenkernel/BKE_action.h | 30 ++++++++- source/blender/blenkernel/intern/action.c | 100 +++++++++++++++++++++++++++- source/blender/blenkernel/intern/anim_sys.c | 2 +- source/blender/blenlib/BLI_listbase.h | 4 ++ source/blender/blenlib/intern/listbase.c | 14 ++++ source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_access.c | 21 ++++-- 7 files changed, 163 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 4724ee19aaa..f079cc08281 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -51,7 +51,7 @@ struct ID; extern "C" { #endif -/* Action API ----------------- */ +/* Action Lib Stuff ----------------- */ /* Allocate a new bAction with the given name */ struct bAction *add_empty_action(const char name[]); @@ -65,6 +65,31 @@ void free_action(struct bAction *act); // XXX is this needed? void make_local_action(struct bAction *act); + +/* Action API ----------------- */ + +/* types of transforms applied to the given item + * - these are the return falgs for action_get_item_transforms() + */ +typedef enum eAction_TransformFlags { + /* location */ + ACT_TRANS_LOC = (1<<0), + /* rotation */ + ACT_TRANS_ROT = (1<<1), + /* scaling */ + ACT_TRANS_SCALE = (1<<2), + + /* all flags */ + ACT_TRANS_ALL = (ACT_TRANS_LOC|ACT_TRANS_ROT|ACT_TRANS_SCALE), +} eAction_TransformFlags; + +/* Return flags indicating which transforms the given object/posechannel has + * - if 'curves' is provided, a list of links to these curves are also returned + * whose nodes WILL NEED FREEING + */ +short action_get_item_transforms(struct bAction *act, struct Object *ob, struct bPoseChannel *pchan, ListBase *curves); + + /* Some kind of bounding box operation on the action */ void calc_action_range(const struct bAction *act, float *start, float *end, short incl_modifiers); @@ -73,6 +98,9 @@ short action_has_motion(const struct bAction *act); /* Action Groups API ----------------- */ +/* Get the active action-group for an Action */ +struct bActionGroup *get_active_actiongroup(struct bAction *act); + /* Make the given Action Group the active one */ void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 2bde61818bf..1ff5d9b5c01 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -212,9 +212,10 @@ bAction *copy_action (bAction *src) return dst; } +/* *************** Action Groups *************** */ /* Get the active action-group for an Action */ -static bActionGroup *get_active_actiongroup (bAction *act) +bActionGroup *get_active_actiongroup (bAction *act) { bActionGroup *agrp= NULL; @@ -404,7 +405,7 @@ bActionGroup *action_groups_find_named (bAction *act, const char name[]) return NULL; } -/* ************************ Pose channels *************** */ +/* *************** Pose channels *************** */ /* usually used within a loop, so we got a N^2 slowdown */ bPoseChannel *get_pose_channel(const bPose *pose, const char *name) @@ -818,7 +819,7 @@ void pose_remove_group (Object *ob) } } -/* ************** time ****************** */ +/* ************** F-Curve Utilities for Actions ****************** */ /* Check if the given action has any keyframes */ short action_has_motion(const bAction *act) @@ -916,6 +917,99 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ } } + +/* Return flags indicating which transforms the given object/posechannel has + * - if 'curves' is provided, a list of links to these curves are also returned + */ +short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves) +{ + PointerRNA ptr; + FCurve *fcu; + char *basePath=NULL; + short flags=0; + + /* build PointerRNA from provided data to obtain the paths to use */ + if (pchan) + RNA_pointer_create((ID *)ob, &RNA_PoseChannel, pchan, &ptr); + else if (ob) + RNA_id_pointer_create((ID *)ob, &ptr); + else + return 0; + + /* get the basic path to the properties of interest */ + basePath= RNA_path_from_ID_to_struct(&ptr); + if (basePath == NULL) + return 0; + + /* search F-Curves for the given properties + * - we cannot use the groups, since they may not be grouped in that way... + */ + for (fcu= act->curves.first; fcu; fcu= fcu->next) { + char *bPtr=NULL, *pPtr=NULL; + + /* if enough flags have been found, we can stop checking unless we're also getting the curves */ + if ((flags == ACT_TRANS_ALL) && (curves == NULL)) + break; + + /* just in case... */ + if (fcu->rna_path == NULL) + continue; + + /* step 1: check for matching base path */ + bPtr= strstr(fcu->rna_path, basePath); + + if (bPtr) { + /* step 2: check for some property with transforms + * - to speed things up, only check for the ones not yet found + * unless we're getting the curves too + * - if we're getting the curves, the BLI_genericNodeN() creates a LinkData + * node wrapping the F-Curve, which then gets added to the list + * - once a match has been found, the curve cannot possibly be any other one + */ + if ((curves) || (flags & ACT_TRANS_LOC) == 0) { + pPtr= strstr(fcu->rna_path, "location"); + if ((pPtr) && (pPtr >= bPtr)) { + flags |= ACT_TRANS_LOC; + + if (curves) + BLI_addtail(curves, BLI_genericNodeN(fcu)); + continue; + } + } + + if ((curves) || (flags & ACT_TRANS_SCALE) == 0) { + pPtr= strstr(fcu->rna_path, "scale"); + if ((pPtr) && (pPtr >= bPtr)) { + flags |= ACT_TRANS_SCALE; + + if (curves) + BLI_addtail(curves, BLI_genericNodeN(fcu)); + continue; + } + } + + if ((curves) || (flags & ACT_TRANS_ROT) == 0) { + pPtr= strstr(fcu->rna_path, "rotation"); + if ((pPtr) && (pPtr >= bPtr)) { + flags |= ACT_TRANS_ROT; + + if (curves) + BLI_addtail(curves, BLI_genericNodeN(fcu)); + continue; + } + } + } + } + + /* free basePath */ + MEM_freeN(basePath); + + /* return flags found */ + return flags; +} + +/* ************** Pose Management Tools ****************** */ + /* Copy the data from the action-pose (src) into the pose */ /* both args are assumed to be valid */ /* exported to game engine */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 643aa6bc779..522297da1d7 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1485,7 +1485,7 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) } /* nodes */ - // TODO... + EVAL_ANIM_IDS(main->nodetree.first, ADT_RECALC_ANIM); /* textures */ EVAL_ANIM_IDS(main->tex.first, ADT_RECALC_ANIM); diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index d0b106b59c3..21b4c83bd88 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -34,6 +34,7 @@ //#include "DNA_listbase.h" struct ListBase; +struct LinkData; #ifdef __cplusplus extern "C" { @@ -56,6 +57,9 @@ int BLI_countlist(struct ListBase *listbase); void BLI_freelinkN(struct ListBase *listbase, void *vlink); void BLI_duplicatelist(struct ListBase *list1, struct ListBase *list2); /* copy from 2 to 1 */ +/* create a generic list node containing link to provided data */ +struct LinkData *BLI_genericNodeN(void *data); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 3194593374f..b3a4722d6d9 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -359,3 +359,17 @@ void BLI_duplicatelist(ListBase *list1, ListBase *list2) /* copy from 2 to 1 */ } } +/* create a generic list node containing link to provided data */ +LinkData *BLI_genericNodeN (void *data) +{ + LinkData *ld; + + if (data == NULL) + return NULL; + + /* create new link, and make it hold the given data */ + ld= MEM_callocN(sizeof(LinkData), "BLI_genericNodeN()"); + ld->data= data; + + return ld; +} diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 40f640473db..b1f5292f9d4 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -692,6 +692,7 @@ char *RNA_path_back(const char *path); int RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop); +char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); #if 0 diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 738d52bfbcd..55893b42a92 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2387,12 +2387,11 @@ char *RNA_path_back(const char *path) return result; } -char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) +char *RNA_path_from_ID_to_struct(PointerRNA *ptr) { - char *ptrpath=NULL, *path; - const char *propname; + char *ptrpath=NULL; - if(!ptr->id.data || !ptr->data || !prop) + if(!ptr->id.data || !ptr->data) return NULL; if(!RNA_struct_is_ID(ptr->type)) { @@ -2418,6 +2417,20 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) else return NULL; } + + return ptrpath; +} + +char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) +{ + const char *propname; + char *ptrpath, *path; + + if(!ptr->id.data || !ptr->data || !prop) + return NULL; + + /* path from ID to the struct holding this property */ + ptrpath= RNA_path_from_ID_to_struct(ptr); propname= RNA_property_identifier(prop); -- cgit v1.2.3 From a911fd88af5ffb2a377ade4e14b918f138ecaee2 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Thu, 17 Sep 2009 11:17:49 +0000 Subject: Update MSVC project files. --- projectfiles_vc9/blender/editors/ED_editors.vcproj | 2 +- projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/projectfiles_vc9/blender/editors/ED_editors.vcproj b/projectfiles_vc9/blender/editors/ED_editors.vcproj index 81d80436a00..948a26c49b5 100644 --- a/projectfiles_vc9/blender/editors/ED_editors.vcproj +++ b/projectfiles_vc9/blender/editors/ED_editors.vcproj @@ -379,7 +379,7 @@ > diff --git a/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj b/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj index 8dd1982deca..a9d78d8b69a 100644 --- a/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj +++ b/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj @@ -810,6 +810,10 @@ RelativePath="..\..\..\source\blender\makesrna\intern\rna_text.c" > + + -- cgit v1.2.3 From 7783c286b9ac3622972ba979f80789aee8fabaed Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 17 Sep 2009 14:35:08 +0000 Subject: UI: fix display of shape key list to show with no items, list template should also accept None. --- release/ui/buttons_data_mesh.py | 3 +-- source/blender/makesrna/intern/rna_ui_api.c | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/release/ui/buttons_data_mesh.py b/release/ui/buttons_data_mesh.py index 8796d7a46a8..33b3960b381 100644 --- a/release/ui/buttons_data_mesh.py +++ b/release/ui/buttons_data_mesh.py @@ -102,8 +102,7 @@ class DATA_PT_shape_keys(DataButtonsPanel): kb = ob.active_shape_key row = layout.row() - if key: # XXX - looks crappy - row.template_list(key, "keys", ob, "active_shape_key_index", rows=2) + row.template_list(key, "keys", ob, "active_shape_key_index", rows=2) col = row.column() diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 3110e631a65..17846651c3b 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -301,7 +301,10 @@ void RNA_api_ui_layout(StructRNA *srna) func= RNA_def_function(srna, "template_list", "uiTemplateList"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - api_ui_item_rna_common(func); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); + parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); + RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_pointer(func, "active_data", "AnyType", "", "Data from which to take property for the active element."); RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); parm= RNA_def_string(func, "active_property", "", 0, "", "Identifier of property in data, for the active element."); -- cgit v1.2.3 From 09652d8c05f30015518205ea6bb7ac0ee3d3745f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 17 Sep 2009 14:37:08 +0000 Subject: Fix #19371: vertex group dropdown crash, own fault in commit yesterday. --- source/blender/editors/interface/interface_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index dbf5669b326..246058ceacc 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -246,7 +246,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but) if(but->func || but->funcN || block->handle_func || but->rename_func || (but->type == BUTM && block->butm_func) || but->optype || but->rnaprop) { after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc"); - if(ELEM(but, but->func_arg1, but->func_arg2)) { + if(but->func && ELEM(but, but->func_arg1, but->func_arg2)) { /* exception, this will crash due to removed button otherwise */ but->func(C, but->func_arg1, but->func_arg2); } -- cgit v1.2.3 From fbbda4c06e6ae642e5702bb39aff92a0ea007a75 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 17 Sep 2009 14:46:22 +0000 Subject: Warning fixes for blenkernel and editors. Note sure what to do with this one, and personally think we should avoid using macros for this kind of thing: V_GROW(edges); source/blender/editors/mesh/loopcut.c:232: warning: value computed is not used --- source/blender/blenkernel/intern/fcurve.c | 2 ++ source/blender/blenkernel/intern/implicit.c | 4 +++- source/blender/blenkernel/intern/modifier.c | 15 ++------------- source/blender/blenkernel/intern/object.c | 6 +++--- source/blender/blenkernel/intern/particle.c | 3 ++- source/blender/blenkernel/intern/particle_system.c | 1 - source/blender/blenkernel/intern/text.c | 6 ++---- source/blender/blenkernel/intern/writeffmpeg.c | 4 ++-- source/blender/editors/mesh/editmesh_tools.c | 5 ++--- source/blender/editors/mesh/loopcut.c | 4 +--- source/blender/editors/object/object_select.c | 2 ++ source/blender/editors/physics/editparticle.c | 1 - source/blender/editors/preview/previewrender.c | 1 - source/blender/editors/space_image/image_draw.c | 2 +- source/blender/editors/space_view3d/drawvolume.c | 1 - source/blender/editors/space_view3d/view3d_buttons.c | 4 ++-- source/blender/makesrna/intern/rna_pose.c | 2 ++ source/blender/render/intern/source/volumetric.c | 4 +--- 18 files changed, 27 insertions(+), 40 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 54d2f85457f..f7f79e9772f 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1026,6 +1026,7 @@ static void berekeny (float f1, float f2, float f3, float f4, float *o, int b) } } +#if 0 static void berekenx (float *f, float *o, int b) { float t, c0, c1, c2, c3; @@ -1041,6 +1042,7 @@ static void berekenx (float *f, float *o, int b) o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3; } } +#endif /* -------------------------- */ diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 956a5851827..ae2acd6aef7 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -496,6 +496,7 @@ DO_INLINE void mulsub_fmatrix_fvector(float to[3], float matrix[3][3], float fro // SPARSE SYMMETRIC big matrix with 3x3 matrix entries /////////////////////////// /* printf a big matrix on console: for debug output */ +#if 0 static void print_bfmatrix(fmatrix3x3 *m3) { unsigned int i = 0; @@ -505,6 +506,8 @@ static void print_bfmatrix(fmatrix3x3 *m3) print_fmatrix(m3[i].m); } } +#endif + /* create big matrix */ DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs) { @@ -1417,7 +1420,6 @@ static void hair_velocity_smoothing(float smoothfac, lfVector *lF, lfVector *lX, int i = 0; int j = 0; int k = 0; - lfVector temp; INIT_MINMAX(gmin, gmax); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 4f2264a052f..c64c48b9ce7 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -8503,6 +8503,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->initData = smoothModifier_initData; mti->copyData = smoothModifier_copyData; mti->requiredDataMask = smoothModifier_requiredDataMask; + mti->isDisabled = smoothModifier_isDisabled; mti->deformVerts = smoothModifier_deformVerts; mti->deformVertsEM = smoothModifier_deformVertsEM; @@ -8513,6 +8514,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->initData = castModifier_initData; mti->copyData = castModifier_copyData; mti->requiredDataMask = castModifier_requiredDataMask; + mti->isDisabled = castModifier_isDisabled; mti->foreachObjectLink = castModifier_foreachObjectLink; mti->updateDepgraph = castModifier_updateDepgraph; mti->deformVerts = castModifier_deformVerts; @@ -9137,19 +9139,6 @@ int modifiers_indexInObject(Object *ob, ModifierData *md_seek) return i; } -static int modifiers_usesPointCache(Object *ob) -{ - ModifierData *md = ob->modifiers.first; - - for (; md; md=md->next) { - ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->flags & eModifierTypeFlag_UsesPointCache) { - return 1; - } - } - return 0; -} - void modifier_freeTemporaryData(ModifierData *md) { if(md->type == eModifierType_Armature) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ed4e82cb3c6..35514e9697e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2562,7 +2562,7 @@ int ray_hit_boundbox(struct BoundBox *bb, float ray_start[3], float ray_normal[3 static int pc_cmp(void *a, void *b) { LinkData *ad = a, *bd = b; - if((int)ad->data > (int)bd->data) + if(GET_INT_FROM_POINTER(ad->data) > GET_INT_FROM_POINTER(bd->data)) return 1; else return 0; } @@ -2576,14 +2576,14 @@ int object_insert_ptcache(Object *ob) for(link=ob->pc_ids.first, i = 0; link; link=link->next, i++) { - int index =(int)link->data; + int index = GET_INT_FROM_POINTER(link->data); if(i < index) break; } link = MEM_callocN(sizeof(LinkData), "PCLink"); - link->data = (void *)i; + link->data = SET_INT_IN_POINTER(i); BLI_addtail(&ob->pc_ids, link); return i; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 2d3e3210afc..cce18e99157 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -81,7 +81,6 @@ #include "RE_render_ext.h" -static void key_from_object(Object *ob, ParticleKey *key); static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fuv, float *orco, ParticleTexture *ptex, int event); static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, @@ -3039,6 +3038,7 @@ void psys_key_to_object(Object *ob, ParticleKey *key, float imat[][4]){ VECSUB(key->vel,key->vel,key->co); QuatMul(key->rot,q,key->rot); } +#if 0 static void key_from_object(Object *ob, ParticleKey *key){ float q[4]; @@ -3051,6 +3051,7 @@ static void key_from_object(Object *ob, ParticleKey *key){ VECSUB(key->vel,key->vel,key->co); QuatMul(key->rot,q,key->rot); } +#endif static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[][4]) { diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 72b580a4543..26d23399316 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -122,7 +122,6 @@ static int get_current_display_percentage(ParticleSystem *psys) void psys_reset(ParticleSystem *psys, int mode) { - ParticleSettings *part= psys->part; PARTICLE_P; if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) { diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 350b0acba9d..270cd873ff5 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -596,17 +596,15 @@ static TextLine *txt_new_line(char *str) return tmp; } -static TextLine *txt_new_linen(char *str, int n) +static TextLine *txt_new_linen(const char *str, int n) { TextLine *tmp; - if(!str) str= ""; - tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); tmp->line= MEM_mallocN(n+1, "textline_string"); tmp->format= NULL; - BLI_strncpy(tmp->line, str, n+1); + BLI_strncpy(tmp->line, (str)? str: "", n+1); tmp->len= strlen(tmp->line); tmp->next= tmp->prev= NULL; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 9e86dcbe491..a90924055b3 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -148,7 +148,7 @@ static int write_audio_frame(void) #else pkt.pts = c->coded_frame->pts; #endif - fprintf(stderr, "Audio Frame PTS: %lld\n", pkt.pts); + fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts); pkt.stream_index = audio_stream->index; pkt.flags |= PKT_FLAG_KEY; @@ -265,7 +265,7 @@ static void write_video_frame(RenderData *rd, AVFrame* frame) #else packet.pts = c->coded_frame->pts; #endif - fprintf(stderr, "Video Frame PTS: %lld\n", packet.pts); + fprintf(stderr, "Video Frame PTS: %d\n", (int)packet.pts); } else { fprintf(stderr, "Video Frame PTS: not set\n"); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 7698faf3178..1d2b97b3f29 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -482,11 +482,10 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) / static int removedoublesflag_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); - ToolSettings *ts= CTX_data_tool_settings(C); EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - char msg[100]; + /*char msg[100]; - int cnt = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit")); + int cnt = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));*/ /*XXX this messes up last operator panel if(cnt) diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index dfdb713d345..f83ab04d785 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -129,7 +129,7 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select) float (*edges)[2][3] = NULL; V_DYNDECLARE(edges); float co[2][3]; - int looking=1, i, j=0, tot=0; + int looking=1, i, tot=0; if (!startedge) return; @@ -318,7 +318,6 @@ static int ringsel_cancel (bContext *C, wmOperator *op) static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) { - ScrArea *sa = CTX_wm_area(C); tringselOpData *lcd; EditEdge *edge; int dist = 75; @@ -347,7 +346,6 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) { - ScrArea *sa = CTX_wm_area(C); tringselOpData *lcd; EditEdge *edge; int dist = 75; diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 432aaf2d2cb..98603ee843a 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -30,6 +30,8 @@ #include #include +#include "MEM_guardedalloc.h" + #include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_modifier_types.h" diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index 5acdcb40613..85ec215a326 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -3911,7 +3911,6 @@ static int specials_menu_invoke(bContext *C, wmOperator *op, wmEvent *event) { Scene *scene= CTX_data_scene(C); ParticleEditSettings *pset=PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, CTX_data_active_object(C)); uiPopupMenu *pup; uiLayout *layout; diff --git a/source/blender/editors/preview/previewrender.c b/source/blender/editors/preview/previewrender.c index 710ac3d6553..7a4cc1c7865 100644 --- a/source/blender/editors/preview/previewrender.c +++ b/source/blender/editors/preview/previewrender.c @@ -635,7 +635,6 @@ void BIF_view3d_previewrender_clear(ScrArea *sa) /* afterqueue call */ void BIF_view3d_previewrender(Scene *scene, ScrArea *sa) { - bContext *C= NULL; View3D *v3d= sa->spacedata.first; RegionView3D *rv3d= NULL; // XXX Render *re; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index cf9bac1ebee..fa736a29ce8 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -541,7 +541,7 @@ void draw_image_grease_pencil(bContext *C, short onlyv2d) } else { /* assume that UI_view2d_restore(C) has been called... */ - SpaceImage *sima= (SpaceImage *)CTX_wm_space_data(C); + //SpaceImage *sima= (SpaceImage *)CTX_wm_space_data(C); /* draw grease-pencil ('screen' strokes) */ //if (sima->flag & SI_DISPGP) diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 0bdc65b5461..ef3627e2b12 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -169,7 +169,6 @@ static int larger_pow2(int n) void draw_volume(Scene *scene, ARegion *ar, View3D *v3d, Base *base, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow) { - Object *ob = base->object; RegionView3D *rv3d= ar->regiondata; float viewnormal[3]; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 7d4e3337fe3..286b0ca0898 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -476,6 +476,7 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d, } } +#if 0 /* assumes armature active */ static void validate_bonebutton_cb(bContext *C, void *bonev, void *namev) { @@ -494,10 +495,10 @@ static void validate_bonebutton_cb(bContext *C, void *bonev, void *namev) ED_armature_bone_rename(ob->data, oldname, newname); // editarmature.c } } +#endif static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float lim) { - uiBut *but; bArmature *arm; bPoseChannel *pchan; Bone *bone= NULL; @@ -586,7 +587,6 @@ static void v3d_editarmature_buts(uiBlock *block, View3D *v3d, Object *ob, float { bArmature *arm= ob->data; EditBone *ebone; - uiBut *but; TransformProperties *tfp= v3d->properties_storage; ebone= arm->edbo->first; diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index b5c0716bed1..cb566fb473f 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -323,6 +323,7 @@ static void rna_Pose_active_bone_group_index_range(PointerRNA *ptr, int *min, in *max= MAX2(0, *max); } +#if 0 static void rna_pose_bgroup_name_index_get(PointerRNA *ptr, char *value, int index) { bPose *pose= (bPose*)ptr->data; @@ -373,6 +374,7 @@ static void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *r BLI_strncpy(result, "", maxlen); } +#endif #else diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index bc425c8a1a3..b2692c25b99 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -422,7 +422,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float hitco[3], *atten_co; float p; float scatter_fac; - float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; @@ -683,7 +682,6 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct float hitco[3]; float tr[3] = {1.0,1.0,1.0}; Isect is; - float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); float *startco, *endco; float density=0.f; @@ -749,4 +747,4 @@ void shade_volume_inside(ShadeInput *shi, ShadeResult *shr) shi->mat = mat_backup; shi->obi = obi_backup; shi->obr = obi_backup->obr; -} \ No newline at end of file +} -- cgit v1.2.3 From 91e5ac872e281c1bbf1719cc1ae5d29a8bf129ba Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Thu, 17 Sep 2009 15:06:03 +0000 Subject: Wrapped some more Nodes: * Composite: Flip, Crop, Map UV, Lens Distortion. --- source/blender/editors/space_node/drawnode.c | 97 +++++++-------------------- source/blender/makesrna/intern/rna_nodetree.c | 5 +- 2 files changed, 25 insertions(+), 77 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 466d1aaa281..9cfae9a7ef5 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1409,27 +1409,19 @@ static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) /* qdn: lens distortion node */ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiLayout *row, *col; + bNode *node= ptr->data; - rctf *butr= &node->butr; NodeLensDist *nld = node->storage; - short dy = butr->ymin + 19, dx = butr->xmax - butr->xmin; - uiBlockBeginAlign(block); - uiDefButS(block, TOG, B_NODE_EXEC, "Projector", - butr->xmin, dy, dx, 19, - &nld->proj, 0, 0, 0, 0, - "Enable/disable projector mode, effect is applied in horizontal direction only"); + + col= uiLayoutColumn(layout, 1); + + uiItemR(col, NULL, 0, ptr, "projector", UI_ITEM_R_TOGGLE); if (!nld->proj) { - uiDefButS(block, TOG, B_NODE_EXEC, "Jitter", - butr->xmin, dy-19, dx/2, 19, - &nld->jit, 0, 0, 0, 0, - "Enable/disable jittering, faster, but also noisier"); - uiDefButS(block, TOG, B_NODE_EXEC, "Fit", - butr->xmin+dx/2, dy-19, dx/2, 19, - &nld->fit, 0, 0, 0, 0, - "For positive distortion factor only, scale image such that black areas are not visible"); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "jitter", UI_ITEM_R_TOGGLE); + uiItemR(row, NULL, 0, ptr, "fit", UI_ITEM_R_TOGGLE); } - uiBlockEndAlign(block); } @@ -1454,59 +1446,24 @@ static void node_composit_buts_filter(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_flip(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - uiBut *bt; - - /* flip x\y */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Flip X %x0|Flip Y %x1|Flip X & Y %x2", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiButSetFunc(bt, node_but_title_cb, node, bt); + uiItemR(layout, "", 0, ptr, "axis", 0); } static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeTwoXYs *ntxy= node->storage; - char elementheight = 19; - short dx= (butr->xmax-butr->xmin)/2; - short dy= butr->ymax - elementheight; - short xymin= 0, xymax= 10000; - - uiBlockBeginAlign(block); - - /* crop image size toggle */ - uiDefButS(block, TOG, B_NODE_EXEC, "Crop Image Size", - butr->xmin, dy, dx*2, elementheight, - &node->custom1, 0, 0, 0, 0, "Crop the size of the input image."); - - dy-=elementheight; - - /* x1 */ - uiDefButS(block, NUM, B_NODE_EXEC, "X1:", - butr->xmin, dy, dx, elementheight, - &ntxy->x1, xymin, xymax, 0, 0, ""); - /* y1 */ - uiDefButS(block, NUM, B_NODE_EXEC, "Y1:", - butr->xmin+dx, dy, dx, elementheight, - &ntxy->y1, xymin, xymax, 0, 0, ""); - - dy-=elementheight; - - /* x2 */ - uiDefButS(block, NUM, B_NODE_EXEC, "X2:", - butr->xmin, dy, dx, elementheight, - &ntxy->x2, xymin, xymax, 0, 0, ""); - /* y2 */ - uiDefButS(block, NUM, B_NODE_EXEC, "Y2:", - butr->xmin+dx, dy, dx, elementheight, - &ntxy->y2, xymin, xymax, 0, 0, ""); - - uiBlockEndAlign(block); + uiLayout *row, *col; + + col= uiLayoutColumn(layout, 1); + + uiItemR(col, NULL, 0, ptr, "crop_size", UI_ITEM_R_TOGGLE); + + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "x1", 0); + uiItemR(row, NULL, 0, ptr, "y1", 0); + + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "x2", 0); + uiItemR(row, NULL, 0, ptr, "y2", 0); } static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) @@ -1791,13 +1748,7 @@ static void node_composit_buts_luma_matte(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_map_uv(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiDefButS(block, NUM, B_NODE_EXEC, "Alpha:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 100, 0, 0, "Conversion percentage of UV differences to Alpha"); + uiItemR(layout, NULL, 0, ptr, "alpha", 0); } static void node_composit_buts_id_mask(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 25fc8e966dc..f2caf1a4d52 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1089,8 +1089,7 @@ static void def_cmp_id_mask(StructRNA *srna) static void def_cmp_map_uv(StructRNA *srna) { PropertyRNA *prop; - - /* TODO: percentage */ + prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_PERCENTAGE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); @@ -1510,8 +1509,6 @@ static void def_cmp_lensdist(StructRNA *srna) RNA_def_property_ui_text(prop, "Projector", "Enable/disable projector mode. Effect is applied in horizontal direction only."); RNA_def_property_update(prop, 0, "rna_Node_update"); - /* TODO: if proj mode is off { */ - prop = RNA_def_property(srna, "jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "jit", 1); RNA_def_property_ui_text(prop, "Jitter", "Enable/disable jittering; faster, but also noisier"); -- cgit v1.2.3 From 613a034b45fd3025c15775300a887a1628d82000 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Thu, 17 Sep 2009 16:47:04 +0000 Subject: -Added Loop Cut to toolbar -Adjusted some UV Editor panels slightly -Made a few nodes clearer. The Crop node was especially confusing. --- release/ui/space_image.py | 24 ++++++++++++-------- release/ui/space_view3d_toolbar.py | 2 +- source/blender/editors/space_node/drawnode.c | 33 +++++++++++++++------------- source/blender/makesrna/intern/rna_image.c | 2 +- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/release/ui/space_image.py b/release/ui/space_image.py index 02ebd864b8e..161e29194ed 100644 --- a/release/ui/space_image.py +++ b/release/ui/space_image.py @@ -314,13 +314,7 @@ class IMAGE_PT_game_properties(bpy.types.Panel): split = layout.split() col = split.column() - col.itemR(ima, "clamp_x") - col.itemR(ima, "clamp_y") - col.itemR(ima, "mapping", expand=True) - col.itemR(ima, "tiles") - - col = split.column() - + sub = col.column(align=True) sub.itemR(ima, "animated") @@ -329,11 +323,21 @@ class IMAGE_PT_game_properties(bpy.types.Panel): subsub.itemR(ima, "animation_start", text="Start") subsub.itemR(ima, "animation_end", text="End") subsub.itemR(ima, "animation_speed", text="Speed") - - sub = col.row(align=True) + + col.itemR(ima, "tiles") + sub = col.column(align=True) sub.active = ima.tiles or ima.animated sub.itemR(ima, "tiles_x", text="X") sub.itemR(ima, "tiles_y", text="Y") + + col = split.column() + col.itemL(text="Clamp:") + col.itemR(ima, "clamp_x", text="X") + col.itemR(ima, "clamp_y", text="Y") + col.itemS() + col.itemR(ima, "mapping", expand=True) + + class IMAGE_PT_view_properties(bpy.types.Panel): __space_type__ = 'IMAGE_EDITOR' @@ -368,7 +372,9 @@ class IMAGE_PT_view_properties(bpy.types.Panel): col.itemR(uvedit, "normalized_coordinates", text="Normalized") if show_uvedit: + col = layout.column() + col.itemL(text="UVs:") row = col.row() row.itemR(uvedit, "edge_draw_type", expand=True) diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 4a5f2ae642c..cbea6466a85 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -67,8 +67,8 @@ class VIEW3D_PT_tools_meshedit(View3DPanel): col = layout.column(align=True) col.itemL(text="Modeling:") col.itemO("mesh.extrude") - col.itemO("mesh.extrude_repeat", text="Extrude Repeat") col.itemO("mesh.subdivide") + col.itemO("mesh.loopcut") col.itemO("mesh.spin") col.itemO("mesh.screw") col.itemO("mesh.merge") diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 9cfae9a7ef5..fadcda67d5b 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1414,14 +1414,15 @@ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) bNode *node= ptr->data; NodeLensDist *nld = node->storage; - col= uiLayoutColumn(layout, 1); + col= uiLayoutColumn(layout, 0); - uiItemR(col, NULL, 0, ptr, "projector", UI_ITEM_R_TOGGLE); + uiItemR(col, NULL, 0, ptr, "projector", 0); if (!nld->proj) { - row= uiLayoutRow(col, 0); - uiItemR(row, NULL, 0, ptr, "jitter", UI_ITEM_R_TOGGLE); - uiItemR(row, NULL, 0, ptr, "fit", UI_ITEM_R_TOGGLE); + col = uiLayoutColumn(col, 0); + uiItemR(col, NULL, 0, ptr, "jitter", 0); + uiItemR(col, NULL, 0, ptr, "fit", 0); } +// uiLayoutSetActive(col, RNA_boolean_get(&imaptr, "projector")); } @@ -1431,9 +1432,13 @@ static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) col= uiLayoutColumn(layout, 1); uiItemR(col, NULL, 0, ptr, "samples", 0); - uiItemR(col, NULL, 0, ptr, "min_speed", 0); - uiItemR(col, NULL, 0, ptr, "max_speed", 0); uiItemR(col, "Blur", 0, ptr, "factor", 0); + + col= uiLayoutColumn(layout, 1); + uiItemL(col, "Speed:", 0); + uiItemR(col, "Min", 0, ptr, "min_speed", 0); + uiItemR(col, "Max", 0, ptr, "max_speed", 0); + col= uiLayoutColumn(layout, 0); uiItemR(col, NULL, 0, ptr, "curved", 0); @@ -1455,15 +1460,13 @@ static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) col= uiLayoutColumn(layout, 1); - uiItemR(col, NULL, 0, ptr, "crop_size", UI_ITEM_R_TOGGLE); - - row= uiLayoutRow(col, 0); - uiItemR(row, NULL, 0, ptr, "x1", 0); - uiItemR(row, NULL, 0, ptr, "y1", 0); + uiItemR(col, NULL, 0, ptr, "crop_size", 0); - row= uiLayoutRow(col, 0); - uiItemR(row, NULL, 0, ptr, "x2", 0); - uiItemR(row, NULL, 0, ptr, "y2", 0); + col= uiLayoutColumn(layout, 1); + uiItemR(row, "Left", 0, ptr, "x1", 0); + uiItemR(row, "Right", 0, ptr, "x2", 0); + uiItemR(row, "Up", 0, ptr, "y1", 0); + uiItemR(row, "Down", 0, ptr, "y2", 0); } static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 8614e6f4ef3..13ec9aea9bb 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -211,7 +211,7 @@ static void rna_def_image(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_generated_type_items[]= { {0, "BLANK", 0, "Blank", "Generate a blank image"}, - {1, "UVTESTGRID", 0, "UV Test Grid", "Generated grid to test UV mappings"}, + {1, "UVGRID", 0, "UV Grid", "Generated grid to test UV mappings"}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_mapping_items[]= { {0, "UV", 0, "UV Coordinates", "Use UV coordinates for mapping the image"}, -- cgit v1.2.3 From a08b16436ded1e43332f6c7326e2dfeb3fc5f4a7 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Thu, 17 Sep 2009 17:31:50 +0000 Subject: 2.5: Adding a crop node caused crash, wrong layout deceleration was used. --- source/blender/editors/space_node/drawnode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index fadcda67d5b..a9f53c9efd9 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1409,7 +1409,7 @@ static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) /* qdn: lens distortion node */ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) { - uiLayout *row, *col; + uiLayout *col; bNode *node= ptr->data; NodeLensDist *nld = node->storage; @@ -1456,17 +1456,17 @@ static void node_composit_buts_flip(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) { - uiLayout *row, *col; + uiLayout *col; col= uiLayoutColumn(layout, 1); uiItemR(col, NULL, 0, ptr, "crop_size", 0); col= uiLayoutColumn(layout, 1); - uiItemR(row, "Left", 0, ptr, "x1", 0); - uiItemR(row, "Right", 0, ptr, "x2", 0); - uiItemR(row, "Up", 0, ptr, "y1", 0); - uiItemR(row, "Down", 0, ptr, "y2", 0); + uiItemR(col, "Left", 0, ptr, "x1", 0); + uiItemR(col, "Right", 0, ptr, "x2", 0); + uiItemR(col, "Up", 0, ptr, "y1", 0); + uiItemR(col, "Down", 0, ptr, "y2", 0); } static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) -- cgit v1.2.3 From a133907c9273ab3f41a0b91c0e4955f800bee820 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Thu, 17 Sep 2009 17:42:08 +0000 Subject: -Shuffled some user prefs around to make better use of the available space in Preferences. -Temporarily disabled the Themes tab until we figure out how to manage themes properly. --- release/ui/space_userpref.py | 123 ++++++++++++--------------- source/blender/makesrna/intern/rna_userdef.c | 107 +++++++++++++++++------ 2 files changed, 136 insertions(+), 94 deletions(-) diff --git a/release/ui/space_userpref.py b/release/ui/space_userpref.py index 267a0b4a78b..c148506214a 100644 --- a/release/ui/space_userpref.py +++ b/release/ui/space_userpref.py @@ -1,4 +1,4 @@ - + import bpy class USERPREF_HT_header(bpy.types.Header): @@ -195,7 +195,7 @@ class USERPREF_PT_edit(bpy.types.Panel): sub1 = sub.column() sub1.itemL(text="Keyframing:") sub1.itemR(edit, "use_visual_keying") - sub1.itemR(edit, "new_interpolation_type") + sub1.itemR(edit, "new_interpolation_type", text="New F-Curves") sub1.itemS() sub1.itemR(edit, "auto_keying_enable", text="Auto Keyframing") sub2 = sub1.column() @@ -203,13 +203,16 @@ class USERPREF_PT_edit(bpy.types.Panel): sub2.row().itemR(edit, "auto_keying_mode", expand=True) sub2.itemR(edit, "auto_keyframe_insert_available", text="Only Insert Available") sub2.itemR(edit, "auto_keyframe_insert_needed", text="Only Insert Needed") + sub1.itemS() sub1.itemS() sub1.itemS() + sub1.itemL(text="Undo:") sub1.itemR(edit, "global_undo") sub1.itemR(edit, "undo_steps", text="Steps") sub1.itemR(edit, "undo_memory_limit", text="Memory Limit") + sub1.itemS() sub1.itemS() sub1.itemS() @@ -218,7 +221,7 @@ class USERPREF_PT_edit(bpy.types.Panel): sub = col.split(percentage=0.85) sub1 = sub.column() - sub1.itemL(text="Duplicate:") + sub1.itemL(text="Duplicate Data:") sub1.itemR(edit, "duplicate_mesh", text="Mesh") sub1.itemR(edit, "duplicate_surface", text="Surface") sub1.itemR(edit, "duplicate_curve", text="Curve") @@ -246,63 +249,64 @@ class USERPREF_PT_system(bpy.types.Panel): userpref = context.user_preferences system = userpref.system - lan = userpref.language split = layout.split() col = split.column() - sub = col.split(percentage=0.85) + sub = col.split(percentage=0.9) sub1 = sub.column() - sub1.itemR(system, "emulate_numpad") + sub1.itemL(text="General:") + sub1.itemR(system, "dpi") + sub1.itemR(system, "frame_server_port") + sub1.itemR(system, "scrollback", text="Console Scrollback") + sub1.itemR(system, "emulate_numpad") + sub1.itemR(system, "auto_run_python_scripts") + + sub1.itemS() sub1.itemS() sub1.itemS() - #Weight Colors + sub1.itemL(text="Sound:") + sub1.row().itemR(system, "audio_device", expand=True) + sub2 = sub1.column() + sub2.active = system.audio_device != 'AUDIO_DEVICE_NULL' + sub2.itemR(system, "enable_all_codecs") + sub2.itemR(system, "game_sound") + sub2.itemR(system, "audio_channels", text="Channels") + sub2.itemR(system, "audio_mixing_buffer", text="Mixing Buffer") + sub2.itemR(system, "audio_sample_rate", text="Sample Rate") + sub2.itemR(system, "audio_sample_format", text="Sample Format") + + col = split.column() + sub = col.split(percentage=0.9) + + sub1 = sub .column() sub1.itemL(text="Weight Colors:") sub1.itemR(system, "use_weight_color_range", text="Use Custom Range") - sub2 = sub1.column() sub2.active = system.use_weight_color_range sub2.template_color_ramp(system, "weight_color_range", expand=True) + + sub1.itemS() sub1.itemS() sub1.itemS() - #sequencer - sub1.itemL(text="Sequencer:") - sub1.itemR(system, "prefetch_frames") - sub1.itemR(system, "memory_cache_limit") - - col = split.column() - sub = col.split(percentage=0.85) + sub1.itemR(system, "language") + sub1.itemL(text="Translate:") + sub1.itemR(system, "translate_tooltips", text="Tooltips") + sub1.itemR(system, "translate_buttons", text="Labels") + sub1.itemR(system, "translate_toolbox", text="Toolbox") - sub1 = sub .column() - #System - sub1.itemL(text="System:") - sub1.itemR(lan, "dpi") - sub1.itemR(system, "auto_run_python_scripts") - sub1.itemR(system, "frame_server_port") - sub1.itemR(system, "filter_file_extensions") - sub1.itemR(system, "hide_dot_files_datablocks") - sub1.itemR(lan, "scrollback", text="Console Scrollback") - sub1.itemS() sub1.itemS() - sub1.itemL(text="Sound:") - sub1.itemR(system, "audio_device") - sub2 = sub1.column() - sub2.active = system.audio_device != 'AUDIO_DEVICE_NULL' - sub2.itemR(system, "enable_all_codecs") - sub2.itemR(system, "game_sound") - sub2.itemR(system, "audio_channels") - sub2.itemR(system, "audio_mixing_buffer") - sub2.itemR(system, "audio_sample_rate") - sub2.itemR(system, "audio_sample_format") + + sub1.itemR(system, "use_textured_fonts") col = split.column() - sub = col.split(percentage=0.85) + sub = col.split(percentage=0.9) sub1 = sub.column() - #OpenGL + sub1.itemL(text="OpenGL:") sub1.itemR(system, "clip_alpha", slider=True) sub1.itemR(system, "use_mipmaps") @@ -311,7 +315,15 @@ class USERPREF_PT_system(bpy.types.Panel): sub1.itemL(text="Textures:") sub1.itemR(system, "gl_texture_limit", text="Limit Size") sub1.itemR(system, "texture_time_out", text="Time Out") - sub1.itemR(system, "texture_collection_rate", text="Collection Rate") + sub1.itemR(system, "texture_collection_rate", text="Collection Rate") + + sub1.itemS() + sub1.itemS() + sub1.itemS() + + sub1.itemL(text="Sequencer:") + sub1.itemR(system, "prefetch_frames") + sub1.itemR(system, "memory_cache_limit") class USERPREF_PT_filepaths(bpy.types.Panel): __space_type__ = 'USER_PREFERENCES' @@ -328,7 +340,7 @@ class USERPREF_PT_filepaths(bpy.types.Panel): userpref = context.user_preferences paths = userpref.filepaths - split = layout.split() + split = layout.split(percentage=0.6) col = split.column() col.itemL(text="File Paths:") @@ -366,6 +378,8 @@ class USERPREF_PT_filepaths(bpy.types.Panel): sub2.itemR(paths, "use_relative_paths") sub2.itemR(paths, "compress_file") sub2.itemR(paths, "load_ui") + sub2.itemR(paths, "filter_file_extensions") + sub2.itemR(paths, "hide_dot_files_datablocks") sub2.itemS() sub2.itemS() sub2.itemL(text="Auto Save:") @@ -377,36 +391,6 @@ class USERPREF_PT_filepaths(bpy.types.Panel): sub3.enabled = paths.auto_save_temporary_files sub3.itemR(paths, "auto_save_time", text="Timer (mins)") -class USERPREF_PT_language(bpy.types.Panel): - __space_type__ = 'USER_PREFERENCES' - __label__ = "Language" - __show_header__ = False - - def poll(self, context): - userpref = context.user_preferences - return (userpref.active_section == 'LANGUAGE_COLORS') - - def draw(self, context): - layout = self.layout - - userpref = context.user_preferences - lan = userpref.language - - split = layout.split() - col = split.column() - - col.itemR(lan, "language") - col.itemL(text="Translate:") - col.itemR(lan, "translate_tooltips", text="Tooltips") - col.itemR(lan, "translate_buttons", text="Labels") - col.itemR(lan, "translate_toolbox", text="Toolbox") - col.itemS() - col.itemS() - col.itemR(lan, "use_textured_fonts") - - col = split.column() - - bpy.types.register(USERPREF_HT_header) bpy.types.register(USERPREF_MT_view) bpy.types.register(USERPREF_PT_tabs) @@ -414,5 +398,4 @@ bpy.types.register(USERPREF_PT_view) bpy.types.register(USERPREF_PT_edit) bpy.types.register(USERPREF_PT_system) bpy.types.register(USERPREF_PT_filepaths) -bpy.types.register(USERPREF_PT_language) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b38475469b0..fcc0d7f8a61 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -109,11 +109,6 @@ static PointerRNA rna_UserDef_edit_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_UserPreferencesEdit, ptr->data); } -static PointerRNA rna_UserDef_language_get(PointerRNA *ptr) -{ - return rna_pointer_inherit_refine(ptr, &RNA_UserPreferencesLanguage, ptr->data); -} - static PointerRNA rna_UserDef_filepaths_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_UserPreferencesFilePaths, ptr->data); @@ -2120,12 +2115,84 @@ static void rna_def_userdef_system(BlenderRNA *brna) {USER_DRAW_OVERLAP, "OVERLAP", 0, "Overlap", "Redraw all overlapping regions, minimal memory usage but more redraws."}, {USER_DRAW_FULL, "FULL", 0, "Full", "Do a full redraw each time, slow, only use for reference or when all else fails."}, {0, NULL, 0, NULL, NULL}}; + + /* hardcoded here, could become dynamic somehow */ + static EnumPropertyItem language_items[] = { + {0, "ENGLISH", 0, "English", ""}, + {1, "JAPANESE", 0, "Japanese", ""}, + {2, "DUTCH", 0, "Dutch", ""}, + {3, "ITALIAN", 0, "Italian", ""}, + {4, "GERMAN", 0, "German", ""}, + {5, "FINNISH", 0, "Finnish", ""}, + {6, "SWEDISH", 0, "Swedish", ""}, + {7, "FRENCH", 0, "French", ""}, + {8, "SPANISH", 0, "Spanish", ""}, + {9, "CATALAN", 0, "Catalan", ""}, + {10, "CZECH", 0, "Czech", ""}, + {11, "BRAZILIAN_PORTUGUESE", 0, "Brazilian Portuguese", ""}, + {12, "SIMPLIFIED_CHINESE", 0, "Simplified Chinese", ""}, + {13, "RUSSIAN", 0, "Russian", ""}, + {14, "CROATIAN", 0, "Croatian", ""}, + {15, "SERBIAN", 0, "Serbian", ""}, + {16, "UKRAINIAN", 0, "Ukrainian", ""}, + {17, "POLISH", 0, "Polish", ""}, + {18, "ROMANIAN", 0, "Romanian", ""}, + {19, "ARABIC", 0, "Arabic", ""}, + {20, "BULGARIAN", 0, "Bulgarian", ""}, + {21, "GREEK", 0, "Greek", ""}, + {22, "KOREAN", 0, "Korean", ""}, + {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "UserPreferencesSystem", NULL); RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); RNA_def_struct_ui_text(srna, "System & OpenGL", "Graphics driver and operating system settings."); + /* Language */ + + prop= RNA_def_property(srna, "international_fonts", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE); + RNA_def_property_ui_text(prop, "International Fonts", "Use international fonts."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "dpi"); + RNA_def_property_range(prop, 48, 128); + RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "scrollback"); + RNA_def_property_range(prop, 32, 32768); + RNA_def_property_ui_text(prop, "Scrollback", "Maximum number of lines to store for the console buffer."); + + /* Language Selection */ + + prop= RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, language_items); + RNA_def_property_ui_text(prop, "Language", "Language use for translation."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "translate_tooltips", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_TOOLTIPS); + RNA_def_property_ui_text(prop, "Translate Tooltips", "Translate Tooltips."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "translate_buttons", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_BUTTONS); + RNA_def_property_ui_text(prop, "Translate Buttons", "Translate button labels."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "translate_toolbox", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_MENUS); + RNA_def_property_ui_text(prop, "Translate Toolbox", "Translate toolbox menu."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop= RNA_def_property(srna, "use_textured_fonts", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_USETEXTUREFONT); + RNA_def_property_ui_text(prop, "Textured Fonts", "Use textures for drawing international fonts."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* System & OpenGL */ prop= RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE); @@ -2174,14 +2241,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_SOUND); RNA_def_property_ui_text(prop, "Game Sound", "Enables sounds to be played in games."); - prop= RNA_def_property(srna, "filter_file_extensions", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS); - RNA_def_property_ui_text(prop, "Filter File Extensions", "Display only files with extensions in the image select window."); - - prop= RNA_def_property(srna, "hide_dot_files_datablocks", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT); - RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/datablocks that start with a dot(.*)"); - prop= RNA_def_property(srna, "clip_alpha", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "glalphaclip"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -2261,7 +2320,15 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); RNA_def_struct_ui_text(srna, "File Paths", "Default paths for external files."); - + + prop= RNA_def_property(srna, "hide_dot_files_datablocks", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT); + RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/datablocks that start with a dot(.*)"); + + prop= RNA_def_property(srna, "filter_file_extensions", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS); + RNA_def_property_ui_text(prop, "Filter File Extensions", "Display only files with extensions in the image select window."); + prop= RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS); RNA_def_property_ui_text(prop, "Relative Paths", "Default relative path option for the file selector."); @@ -2340,10 +2407,9 @@ void RNA_def_userdef(BlenderRNA *brna) static EnumPropertyItem user_pref_sections[] = { {0, "VIEW_CONTROLS", 0, "View", ""}, {1, "EDIT_METHODS", 0, "Editing", ""}, - {2, "LANGUAGE_COLORS", 0, "Language", ""}, + {2, "FILE_PATHS", 0, "File", ""}, {3, "SYSTEM_OPENGL", 0, "System", ""}, - {4, "FILE_PATHS", 0, "File", ""}, - {5, "THEMES", 0, "Themes", ""}, +// {4, "THEMES", 0, "Themes", ""}, // Leave this out until we figure out a way to manage themes in the prefs. {0, NULL, 0, NULL, NULL}}; rna_def_userdef_dothemes(brna); @@ -2381,12 +2447,6 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_UserDef_edit_get", NULL, NULL); RNA_def_property_ui_text(prop, "Edit Methods", "Settings for interacting with Blender data."); - prop= RNA_def_property(srna, "language", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_struct_type(prop, "UserPreferencesLanguage"); - RNA_def_property_pointer_funcs(prop, "rna_UserDef_language_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Language & Font", "User interface translation settings."); - prop= RNA_def_property(srna, "filepaths", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "UserPreferencesFilePaths"); @@ -2401,7 +2461,6 @@ void RNA_def_userdef(BlenderRNA *brna) rna_def_userdef_view(brna); rna_def_userdef_edit(brna); - rna_def_userdef_language(brna); rna_def_userdef_filepaths(brna); rna_def_userdef_system(brna); -- cgit v1.2.3 From bf34328634266a347e2872e01a06960638a900a4 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Thu, 17 Sep 2009 17:44:54 +0000 Subject: Forgot to delete unused code. --- source/blender/makesrna/intern/rna_userdef.c | 81 ---------------------------- 1 file changed, 81 deletions(-) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index fcc0d7f8a61..d9ce215f899 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1959,87 +1959,6 @@ static void rna_def_userdef_edit(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Duplicate Particle", "Causes particle systems to be duplicated with the object."); } -static void rna_def_userdef_language(BlenderRNA *brna) -{ - PropertyRNA *prop; - StructRNA *srna; - - /* hardcoded here, could become dynamic somehow */ - static EnumPropertyItem language_items[] = { - {0, "ENGLISH", 0, "English", ""}, - {1, "JAPANESE", 0, "Japanese", ""}, - {2, "DUTCH", 0, "Dutch", ""}, - {3, "ITALIAN", 0, "Italian", ""}, - {4, "GERMAN", 0, "German", ""}, - {5, "FINNISH", 0, "Finnish", ""}, - {6, "SWEDISH", 0, "Swedish", ""}, - {7, "FRENCH", 0, "French", ""}, - {8, "SPANISH", 0, "Spanish", ""}, - {9, "CATALAN", 0, "Catalan", ""}, - {10, "CZECH", 0, "Czech", ""}, - {11, "BRAZILIAN_PORTUGUESE", 0, "Brazilian Portuguese", ""}, - {12, "SIMPLIFIED_CHINESE", 0, "Simplified Chinese", ""}, - {13, "RUSSIAN", 0, "Russian", ""}, - {14, "CROATIAN", 0, "Croatian", ""}, - {15, "SERBIAN", 0, "Serbian", ""}, - {16, "UKRAINIAN", 0, "Ukrainian", ""}, - {17, "POLISH", 0, "Polish", ""}, - {18, "ROMANIAN", 0, "Romanian", ""}, - {19, "ARABIC", 0, "Arabic", ""}, - {20, "BULGARIAN", 0, "Bulgarian", ""}, - {21, "GREEK", 0, "Greek", ""}, - {22, "KOREAN", 0, "Korean", ""}, - {0, NULL, 0, NULL, NULL}}; - - srna= RNA_def_struct(brna, "UserPreferencesLanguage", NULL); - RNA_def_struct_sdna(srna, "UserDef"); - RNA_def_struct_nested(brna, srna, "UserPreferences"); - RNA_def_struct_ui_text(srna, "Language & Font", "User interface translation settings."); - - prop= RNA_def_property(srna, "international_fonts", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE); - RNA_def_property_ui_text(prop, "International Fonts", "Use international fonts."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "dpi"); - RNA_def_property_range(prop, 48, 128); - RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "scrollback"); - RNA_def_property_range(prop, 32, 32768); - RNA_def_property_ui_text(prop, "Scrollback", "Maximum number of lines to store for the console buffer."); - - /* Language Selection */ - - prop= RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, language_items); - RNA_def_property_ui_text(prop, "Language", "Language use for translation."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "translate_tooltips", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_TOOLTIPS); - RNA_def_property_ui_text(prop, "Translate Tooltips", "Translate Tooltips."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "translate_buttons", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_BUTTONS); - RNA_def_property_ui_text(prop, "Translate Buttons", "Translate button labels."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "translate_toolbox", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_MENUS); - RNA_def_property_ui_text(prop, "Translate Toolbox", "Translate toolbox menu."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop= RNA_def_property(srna, "use_textured_fonts", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_USETEXTUREFONT); - RNA_def_property_ui_text(prop, "Textured Fonts", "Use textures for drawing international fonts."); - RNA_def_property_update(prop, 0, "rna_userdef_update"); -} - static void rna_def_userdef_system(BlenderRNA *brna) { PropertyRNA *prop; -- cgit v1.2.3 From b572ae2a8bdd4adfc1641a43ca02061b9ae6eff9 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Thu, 17 Sep 2009 18:40:37 +0000 Subject: netrender: Disable windows' blocking crash reports in child process. (windows only) Get server port as well as ip address from master broadcast (broadcast is on a fixed port). --- release/io/netrender/master.py | 2 +- release/io/netrender/operators.py | 5 +++-- release/io/netrender/slave.py | 24 ++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 29cec4e2232..8f59ef37069 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -632,5 +632,5 @@ def runMaster(address, broadcast, path, update_stats, test_break): if broadcast: if time.time() - start_time >= 10: # need constant here print("broadcasting address") - s.sendto(bytes("%s:%i" % address, encoding='utf8'), 0, ('',address[1])) + s.sendto(bytes("%i" % address[1], encoding='utf8'), 0, ('', 8000)) start_time = time.time() diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index 928c2b9efaf..e6888731437 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -339,14 +339,15 @@ class netclientscan(bpy.types.Operator): s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.settimeout(30) - s.bind(('', netsettings.server_port)) + s.bind(('', 8000)) try: - buf, address = s.recvfrom(128) + buf, address = s.recvfrom(64) print("received:", buf) netsettings.server_address = address[0] + netsettings.server_port = int(str(buf, encoding='utf8')) except socket.timeout: print("no server info") diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index 3a4e77abc54..1f4ef3a3616 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -9,6 +9,22 @@ CANCEL_POLL_SPEED = 2 MAX_TIMEOUT = 10 INCREMENT_TIMEOUT = 1 +if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5 + import ctypes + def SetErrorMode(): + val = ctypes.windll.kernel32.SetErrorMode(0x0002) + ctypes.windll.kernel32.SetErrorMode(val | 0x0002) + return val + + def RestoreErrorMode(val): + ctypes.windll.kernel32.SetErrorMode(val) +else: + def SetErrorMode(): + return 0 + + def RestoreErrorMode(val): + pass + def slave_Info(): sysname, nodename, release, version, machine, processor = platform.uname() slave = netrender.model.RenderSlave() @@ -100,10 +116,14 @@ def render_slave(engine, scene): for frame in job.frames: print("frame", frame.number) frame_args += ["-f", str(frame.number)] - + + + start_t = time.time() - process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + val = SetErrorMode() + process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + RestoreErrorMode(val) headers = {"job-id":job.id, "slave-id":slave_id} -- cgit v1.2.3 From 69e919530e179c0ac251534003e3ab8f540e82fe Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 17 Sep 2009 21:36:02 +0000 Subject: Keymaps now have a poll() function, rather than adding/removing their handlers based on notifiers, which is simpler and more reliable. This fixes for example editmode or uv edit keymaps not working when creating a new 3dview or image space. --- source/blender/blenloader/intern/readfile.c | 1 - .../blender/editors/animation/anim_channels_edit.c | 2 +- source/blender/editors/animation/anim_markers.c | 2 +- source/blender/editors/animation/anim_ops.c | 2 +- source/blender/editors/armature/armature_ops.c | 8 +- source/blender/editors/curve/curve_ops.c | 8 +- source/blender/editors/gpencil/gpencil_ops.c | 2 +- source/blender/editors/include/ED_transform.h | 3 +- source/blender/editors/interface/view2d_ops.c | 4 +- source/blender/editors/mesh/mesh_ops.c | 5 +- source/blender/editors/metaball/mball_ops.c | 7 +- source/blender/editors/object/object_ops.c | 16 ++- source/blender/editors/physics/ed_pointcache.c | 2 +- source/blender/editors/physics/editparticle.c | 5 +- source/blender/editors/screen/area.c | 14 +-- source/blender/editors/screen/screen_ops.c | 6 +- source/blender/editors/space_action/action_ops.c | 6 +- source/blender/editors/space_action/space_action.c | 8 +- .../blender/editors/space_buttons/space_buttons.c | 6 +- .../blender/editors/space_console/space_console.c | 6 +- source/blender/editors/space_file/space_file.c | 22 ++-- source/blender/editors/space_graph/graph_ops.c | 8 +- source/blender/editors/space_graph/space_graph.c | 16 +-- source/blender/editors/space_image/space_image.c | 41 ++----- source/blender/editors/space_logic/space_logic.c | 10 +- source/blender/editors/space_nla/nla_ops.c | 12 +- source/blender/editors/space_nla/space_nla.c | 16 +-- source/blender/editors/space_node/node_ops.c | 2 +- source/blender/editors/space_node/space_node.c | 4 +- .../blender/editors/space_outliner/outliner_ops.c | 2 +- .../editors/space_outliner/space_outliner.c | 4 +- source/blender/editors/space_script/script_ops.c | 2 +- source/blender/editors/space_script/space_script.c | 4 +- .../editors/space_sequencer/sequencer_ops.c | 2 +- .../editors/space_sequencer/space_sequencer.c | 4 +- source/blender/editors/space_sound/space_sound.c | 4 +- source/blender/editors/space_text/space_text.c | 8 +- source/blender/editors/space_time/space_time.c | 4 +- source/blender/editors/space_time/time_ops.c | 2 +- source/blender/editors/space_view3d/space_view3d.c | 132 +++++++-------------- source/blender/editors/space_view3d/view3d_ops.c | 6 +- source/blender/editors/transform/transform_ops.c | 2 +- source/blender/editors/uvedit/uvedit_ops.c | 5 +- source/blender/makesdna/DNA_view3d_types.h | 4 +- source/blender/makesdna/DNA_windowmanager_types.h | 3 + source/blender/windowmanager/WM_api.h | 16 +-- .../blender/windowmanager/intern/wm_event_system.c | 32 +++-- source/blender/windowmanager/intern/wm_keymap.c | 39 +++--- source/blender/windowmanager/intern/wm_operators.c | 2 +- source/blender/windowmanager/intern/wm_window.c | 6 +- source/blender/windowmanager/wm_event_system.h | 2 +- 51 files changed, 253 insertions(+), 276 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index bb7262c01d4..6518db2dc91 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4826,7 +4826,6 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) rv3d->ri= NULL; rv3d->sms= NULL; rv3d->smooth_timer= NULL; - rv3d->lastmode= 0; } } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 72d8f71bc26..4afecdb55c0 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1572,7 +1572,7 @@ void ED_operatortypes_animchannels(void) void ED_keymap_animchannels(wmWindowManager *wm) { - ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0); + wmKeyMap *keymap = WM_keymap_find(wm, "Animation_Channels", 0, 0); /* selection */ /* click-select */ diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index d33eece52c9..06fa3b715e0 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -992,7 +992,7 @@ void ED_operatortypes_marker(void) /* called in screen_ops.c:ED_keymap_screen() */ void ED_marker_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Markers", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Markers", 0, 0); WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index fedbe12c0e6..186bdc3b762 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -406,7 +406,7 @@ void ED_operatortypes_anim(void) void ED_keymap_anim(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Animation", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Animation", 0, 0); /* frame management */ /* NOTE: 'ACTIONMOUSE' not 'LEFTMOUSE', as user may have swapped mouse-buttons */ diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 389a0a5174a..4a61c8ddaf8 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -202,11 +202,12 @@ void ED_operatortypes_armature(void) void ED_keymap_armature(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; wmKeymapItem *kmi; /* Armature ------------------------ */ - keymap= WM_keymap_listbase(wm, "Armature", 0, 0); + keymap= WM_keymap_find(wm, "Armature", 0, 0); + keymap->poll= ED_operator_editarmature; /* only set in editmode armature, by space_view3d listener */ // WM_keymap_add_item(keymap, "ARMATURE_OT_hide", HKEY, KM_PRESS, 0, 0); @@ -280,7 +281,8 @@ void ED_keymap_armature(wmWindowManager *wm) /* Pose ------------------------ */ /* only set in posemode, by space_view3d listener */ - keymap= WM_keymap_listbase(wm, "Pose", 0, 0); + keymap= WM_keymap_find(wm, "Pose", 0, 0); + keymap->poll= ED_operator_posemode; WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, 0, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 8a90dace40b..77c5ed1de2c 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -163,7 +163,10 @@ void ED_operatortypes_curve(void) void ED_keymap_curve(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Font", 0, 0); + wmKeyMap *keymap; + + keymap= WM_keymap_find(wm, "Font", 0, 0); + keymap->poll= ED_operator_editfont; /* only set in editmode font, by space_view3d listener */ RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", BKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_BOLD); @@ -212,7 +215,8 @@ void ED_keymap_curve(wmWindowManager *wm) WM_keymap_add_item(keymap, "FONT_OT_text_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last! /* only set in editmode curve, by space_view3d listener */ - keymap= WM_keymap_listbase(wm, "Curve", 0, 0); + keymap= WM_keymap_find(wm, "Curve", 0, 0); + keymap->poll= ED_operator_editsurfcurve; WM_keymap_add_item(keymap, "OBJECT_OT_curve_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "CURVE_OT_vertex_add", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index d33ad16dfb1..d311b39b9a3 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -47,7 +47,7 @@ void ED_keymap_gpencil(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Grease Pencil", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Grease Pencil", 0, 0); wmKeymapItem *kmi; /* Draw */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 984def760ae..96425f725e9 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -41,8 +41,9 @@ struct Object; struct uiLayout; struct EnumPropertyItem; struct wmOperatorType; +struct wmKeyMap; -void transform_keymap_for_space(struct wmWindowManager *wm, struct ListBase *keymap, int spaceid); +void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *keymap, int spaceid); void transform_operatortypes(void); /* ******************** Macros & Prototypes *********************** */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 3e009884dee..33838418842 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1409,7 +1409,7 @@ void ui_view2d_operatortypes(void) void UI_view2d_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "View2D", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "View2D", 0, 0); /* pan/scroll */ WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); @@ -1445,7 +1445,7 @@ void UI_view2d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0); /* Alternative keymap for buttons listview */ - keymap= WM_keymap_listbase(wm, "View2D Buttons List", 0, 0); + keymap= WM_keymap_find(wm, "View2D Buttons List", 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 6da42f28af4..f22adc597c7 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -349,9 +349,12 @@ void ED_operatortypes_mesh(void) /* note mesh keymap also for other space? */ void ED_keymap_mesh(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "EditMesh", 0, 0); + wmKeyMap *keymap; wmKeymapItem *kmi; + keymap= WM_keymap_find(wm, "EditMesh", 0, 0); + keymap->poll= ED_operator_editmesh; + WM_keymap_add_item(keymap, "MESH_OT_loopcut", ACTIONMOUSE, KM_PRESS, KM_CTRL, RKEY); /* selecting */ diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index b469bb3e400..dd8a18f385c 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -34,6 +34,8 @@ #include "DNA_listBase.h" #include "DNA_windowmanager_types.h" +#include "ED_screen.h" + #include "mball_intern.h" void ED_operatortypes_metaball(void) @@ -51,7 +53,10 @@ void ED_operatortypes_metaball(void) void ED_keymap_metaball(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Metaball", 0, 0); + wmKeyMap *keymap; + + keymap= WM_keymap_find(wm, "Metaball", 0, 0); + keymap->poll= ED_operator_editmball; WM_keymap_add_item(keymap, "OBJECT_OT_metaball_add", AKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index dce09d47b2c..fdfe6ed501c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -184,11 +184,19 @@ void ED_operatortypes_object(void) } } +static int object_mode_poll(bContext *C) +{ + Object *ob= CTX_data_active_object(C); + return (!ob || ob->mode == OB_MODE_OBJECT); +} + void ED_keymap_object(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Object Non-modal", 0, 0); + wmKeyMap *keymap; wmKeymapItem *kmi; + keymap= WM_keymap_find(wm, "Object Non-modal", 0, 0); + /* Note: this keymap works disregarding mode */ WM_keymap_add_item(keymap, "OBJECT_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_posemode_toggle", TABKEY, KM_PRESS, KM_CTRL, 0); @@ -203,7 +211,8 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_center_set", CKEY, KM_PRESS, KM_ALT|KM_SHIFT|KM_CTRL, 0); /* Note: this keymap gets disabled in non-objectmode, */ - keymap= WM_keymap_listbase(wm, "Object Mode", 0, 0); + keymap= WM_keymap_find(wm, "Object Mode", 0, 0); + keymap->poll= object_mode_poll; WM_keymap_add_item(keymap, "OBJECT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0); @@ -246,7 +255,8 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); /* Lattice */ - keymap= WM_keymap_listbase(wm, "Lattice", 0, 0); + keymap= WM_keymap_find(wm, "Lattice", 0, 0); + keymap->poll= ED_operator_editlattice; WM_keymap_add_item(keymap, "LATTICE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); } diff --git a/source/blender/editors/physics/ed_pointcache.c b/source/blender/editors/physics/ed_pointcache.c index f2c7b64032f..ed3aaf0cfd1 100644 --- a/source/blender/editors/physics/ed_pointcache.c +++ b/source/blender/editors/physics/ed_pointcache.c @@ -347,7 +347,7 @@ void ED_operatortypes_pointcache(void) //void ED_keymap_pointcache(wmWindowManager *wm) //{ -// ListBase *keymap= WM_keymap_listbase(wm, "Pointcache", 0, 0); +// wmKeyMap *keymap= WM_keymap_find(wm, "Pointcache", 0, 0); // // WM_keymap_add_item(keymap, "PHYSICS_OT_bake_all", AKEY, KM_PRESS, 0, 0); // WM_keymap_add_item(keymap, "PHYSICS_OT_free_all", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index 85ec215a326..6d1f2e5057b 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -3973,7 +3973,10 @@ void ED_operatortypes_particle(void) void ED_keymap_particle(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Particle", 0, 0); + wmKeyMap *keymap; + + keymap= WM_keymap_find(wm, "Particle", 0, 0); + keymap->poll= PE_poll; WM_keymap_add_item(keymap, "PARTICLE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PARTICLE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 07d0d1a85c5..87901d75494 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -824,24 +824,24 @@ static void ed_default_handlers(wmWindowManager *wm, ListBase *handlers, int fla UI_add_region_handlers(handlers); } if(flag & ED_KEYMAP_VIEW2D) { - ListBase *keymap= WM_keymap_listbase(wm, "View2D", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "View2D", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_MARKERS) { - ListBase *keymap= WM_keymap_listbase(wm, "Markers", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Markers", 0, 0); WM_event_add_keymap_handler(handlers, keymap); // XXX need boundbox check urgently!!! } if(flag & ED_KEYMAP_ANIMATION) { - ListBase *keymap= WM_keymap_listbase(wm, "Animation", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Animation", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_FRAMES) { - ListBase *keymap= WM_keymap_listbase(wm, "Frames", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Frames", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_GPENCIL) { - ListBase *keymap= WM_keymap_listbase(wm, "Grease Pencil", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Grease Pencil", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } } @@ -1353,7 +1353,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, char *contex void ED_region_panels_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; // XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file) // scrollbars for button regions @@ -1366,7 +1366,7 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); - keymap= WM_keymap_listbase(wm, "View2D Buttons List", 0, 0); + keymap= WM_keymap_find(wm, "View2D Buttons List", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 0bb1969ce3c..605bd8682f5 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3291,10 +3291,10 @@ static void keymap_modal_set(wmWindowManager *wm) /* called in spacetypes.c */ void ED_keymap_screen(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; /* Screen General ------------------------------------------------ */ - keymap= WM_keymap_listbase(wm, "Screen", 0, 0); + keymap= WM_keymap_find(wm, "Screen", 0, 0); /* standard timers */ @@ -3361,7 +3361,7 @@ void ED_keymap_screen(wmWindowManager *wm) /* Anim Playback ------------------------------------------------ */ - keymap= WM_keymap_listbase(wm, "Frames", 0, 0); + keymap= WM_keymap_find(wm, "Frames", 0, 0); /* frame offsets */ RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index cd4a7b30eff..00b22232608 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -91,7 +91,7 @@ void action_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void action_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) +static void action_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) { wmKeymapItem *kmi; @@ -166,7 +166,7 @@ static void action_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) void action_keymap(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; /* channels */ /* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module. @@ -175,7 +175,7 @@ void action_keymap(wmWindowManager *wm) */ /* keyframes */ - keymap= WM_keymap_listbase(wm, "Action_Keys", SPACE_ACTION, 0); + keymap= WM_keymap_find(wm, "Action_Keys", SPACE_ACTION, 0); action_keymap_keyframes(wm, keymap); } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index b7a3df563ea..bceee73d5f0 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -153,12 +153,12 @@ static SpaceLink *action_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void action_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Action_Keys", SPACE_ACTION, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Action_Keys", SPACE_ACTION, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -216,12 +216,12 @@ static void action_main_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Animation_Channels", 0, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Animation_Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index c8ced42c2d2..381beaa0295 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -138,11 +138,11 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "Buttons Generic", SPACE_BUTS, 0); + keymap= WM_keymap_find(wm, "Buttons Generic", SPACE_BUTS, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -216,7 +216,7 @@ void buttons_operatortypes(void) void buttons_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Buttons Generic", SPACE_BUTS, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Buttons Generic", SPACE_BUTS, 0); WM_keymap_add_item(keymap, "BUTTONS_OT_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0); } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index dfaaa269970..6526b569bbb 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -147,12 +147,12 @@ static SpaceLink *console_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void console_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Console", SPACE_CONSOLE, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -231,7 +231,7 @@ void console_operatortypes(void) void console_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Console", SPACE_CONSOLE, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); #ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 27948618d03..99d649b28cc 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -255,15 +255,15 @@ static void file_listener(ScrArea *sa, wmNotifier *wmn) /* add handlers, stuff you only do once or on area/region changes */ static void file_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymaps */ - keymap= WM_keymap_listbase(wm, "File", SPACE_FILE, 0); + keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "FileMain", SPACE_FILE, 0); + keymap= WM_keymap_find(wm, "FileMain", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -375,7 +375,7 @@ void file_keymap(struct wmWindowManager *wm) { wmKeymapItem *kmi; /* keys for all areas */ - ListBase *keymap= WM_keymap_listbase(wm, "File", SPACE_FILE, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_add_bookmark", BKEY, KM_PRESS, KM_CTRL, 0); @@ -386,7 +386,7 @@ void file_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "FILE_OT_delete", XKEY, KM_PRESS, 0, 0); /* keys for main area */ - keymap= WM_keymap_listbase(wm, "FileMain", SPACE_FILE, 0); + keymap= WM_keymap_find(wm, "FileMain", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0); @@ -407,7 +407,7 @@ void file_keymap(struct wmWindowManager *wm) RNA_int_set(kmi->ptr, "increment",-100); /* keys for button area (top) */ - keymap= WM_keymap_listbase(wm, "FileButtons", SPACE_FILE, 0); + keymap= WM_keymap_find(wm, "FileButtons", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0); RNA_int_set(kmi->ptr, "increment", 1); @@ -426,12 +426,12 @@ void file_keymap(struct wmWindowManager *wm) static void file_channel_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); /* own keymaps */ - keymap= WM_keymap_listbase(wm, "File", SPACE_FILE, 0); + keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -462,15 +462,15 @@ static void file_header_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void file_ui_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "File", SPACE_FILE, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "FileButtons", SPACE_FILE, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "FileButtons", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index fc4c05915c9..b7d67c85ab9 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -141,7 +141,7 @@ void graphedit_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) +static void graphedit_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) { wmKeymapItem *kmi; @@ -232,10 +232,10 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap) void graphedit_keymap(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; /* keymap for all regions */ - keymap= WM_keymap_listbase(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); WM_keymap_add_item(keymap, "GRAPH_OT_properties", NKEY, KM_PRESS, 0, 0); /* channels */ @@ -245,7 +245,7 @@ void graphedit_keymap(wmWindowManager *wm) */ /* keyframes */ - keymap= WM_keymap_listbase(wm, "GraphEdit Keys", SPACE_IPO, 0); + keymap= WM_keymap_find(wm, "GraphEdit Keys", SPACE_IPO, 0); graphedit_keymap_keyframes(wm, keymap); } diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 8887d464f30..e0b961b38f1 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -203,14 +203,14 @@ static SpaceLink *graph_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "GraphEdit Keys", SPACE_IPO, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "GraphEdit Keys", SPACE_IPO, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -281,14 +281,14 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar) static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Animation_Channels", 0, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Animation_Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -352,11 +352,11 @@ static void graph_header_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index c57bc5773b0..e57a059265f 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -204,7 +204,7 @@ void image_operatortypes(void) void image_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Image Generic", SPACE_IMAGE, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_new", NKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "IMAGE_OT_open", OKEY, KM_PRESS, KM_ALT, 0); @@ -212,7 +212,7 @@ void image_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "IMAGE_OT_save", SKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0); - keymap= WM_keymap_listbase(wm, "Image", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "Image", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); @@ -398,23 +398,22 @@ static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar, Scene *sce /* add handlers, stuff you only do once or on area/region changes */ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; // image space manages own v2d // UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* image paint polls for mode */ - keymap= WM_keymap_listbase(wm, "ImagePaint", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "ImagePaint", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - /* XXX need context here? - keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap);*/ + keymap= WM_keymap_find(wm, "UVEdit", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); /* own keymaps */ - keymap= WM_keymap_listbase(wm, "Image Generic", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_listbase(wm, "Image", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "Image", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -457,29 +456,11 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers);*/ } -static void image_modal_keymaps(wmWindowManager *wm, ARegion *ar, int stype) -{ - ListBase *keymap; - - keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0); - - if(stype==NS_EDITMODE_MESH) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); -} - static void image_main_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch(wmn->category) { - case NC_SCENE: - switch(wmn->data) { - case ND_MODE: - image_modal_keymaps(wmn->wm, ar, wmn->subtype); - break; - } - break; + /* nothing yet */ } } @@ -488,11 +469,11 @@ static void image_main_area_listener(ARegion *ar, wmNotifier *wmn) /* add handlers, stuff you only do once or on area/region changes */ static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "Image Generic", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 3c46522bba2..7043d625ab0 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -188,7 +188,7 @@ void logic_operatortypes(void) void logic_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Logic Generic", SPACE_LOGIC, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); WM_keymap_add_item(keymap, "LOGIC_OT_properties", NKEY, KM_PRESS, 0, 0); } @@ -234,12 +234,12 @@ static int logic_context(const bContext *C, const char *member, bContextDataResu /* add handlers, stuff you only do once or on area/region changes */ static void logic_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymaps */ - keymap= WM_keymap_listbase(wm, "Logic Generic", SPACE_LOGIC, 0); + keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -276,11 +276,11 @@ static void logic_main_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "Logic Generic", SPACE_LOGIC, 0); + keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index ad5f5174690..5ea2e99ad6a 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -167,7 +167,7 @@ void nla_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap) +static void nla_keymap_channels (wmWindowManager *wm, wmKeyMap *keymap) { /* NLA-specific (different to standard channels keymap) -------------------------- */ /* selection */ @@ -210,7 +210,7 @@ static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap) RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1); } -static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap) +static void nla_keymap_main (wmWindowManager *wm, wmKeyMap *keymap) { wmKeymapItem *kmi; @@ -284,10 +284,10 @@ static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap) void nla_keymap(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; /* keymap for all regions */ - keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); WM_keymap_add_item(keymap, "NLA_OT_properties", NKEY, KM_PRESS, 0, 0); /* channels */ @@ -297,11 +297,11 @@ void nla_keymap(wmWindowManager *wm) * * However, those operations which involve clicking on channels and/or the placement of them in the view are implemented here instead */ - keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Channels", SPACE_NLA, 0); nla_keymap_channels(wm, keymap); /* data */ - keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Data", SPACE_NLA, 0); nla_keymap_main(wm, keymap); } diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 89d4e7cddf2..06ee34a6573 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -208,15 +208,15 @@ static SpaceLink *nla_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ // TODO: cannot use generic copy, need special NLA version - keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "NLA Channels", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -254,14 +254,14 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "NLA Data", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -354,11 +354,11 @@ static void nla_header_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 4c2fbf7b9dc..f47e9aa2a6f 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -69,7 +69,7 @@ void node_operatortypes(void) void node_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Node", SPACE_NODE, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Node", SPACE_NODE, 0); /* mouse select in nodes used to be both keys, it's UI elements... */ RNA_enum_set(WM_keymap_add_item(keymap, "NODE_OT_select", ACTIONMOUSE, KM_PRESS, 0, 0)->ptr, "select_type", NODE_SELECT_MOUSE); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index d3a445b18c0..12a5f33e119 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -245,12 +245,12 @@ static void node_channel_area_draw(const bContext *C, ARegion *ar) /* Initialise main area, setting handlers. */ static void node_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Node", SPACE_NODE, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Node", SPACE_NODE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 2e11eb379b4..a35b91249db 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -76,7 +76,7 @@ void outliner_operatortypes(void) void outliner_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Outliner", SPACE_OUTLINER, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Outliner", SPACE_OUTLINER, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 5058a167a29..e7e6c2d0128 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -72,12 +72,12 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Outliner", SPACE_OUTLINER, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Outliner", SPACE_OUTLINER, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_script/script_ops.c b/source/blender/editors/space_script/script_ops.c index 270cc1ffd8f..0e6ea9cf4fd 100644 --- a/source/blender/editors/space_script/script_ops.c +++ b/source/blender/editors/space_script/script_ops.c @@ -65,7 +65,7 @@ void script_operatortypes(void) void script_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Script", SPACE_SCRIPT, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Script", SPACE_SCRIPT, 0); /* TODO - this is just while we have no way to load a text datablock */ RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", PKEY, KM_PRESS, KM_CTRL|KM_SHIFT|KM_ALT, 0)->ptr, "path", "test.py"); diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index 99233cc5020..a0e73082701 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -133,12 +133,12 @@ static SpaceLink *script_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void script_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Script", SPACE_SCRIPT, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Script", SPACE_SCRIPT, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 74f22b86b75..ac125c10b2d 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -105,7 +105,7 @@ void sequencer_operatortypes(void) void sequencer_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Sequencer", SPACE_SEQ, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Sequencer", SPACE_SEQ, 0); wmKeymapItem *kmi; WM_keymap_add_item(keymap, "SEQUENCER_OT_properties", NKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 26ffd88ae67..c2756b05946 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -185,12 +185,12 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Sequencer", SPACE_SEQ, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Sequencer", SPACE_SEQ, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_sound/space_sound.c b/source/blender/editors/space_sound/space_sound.c index f8ef2b21ae7..6713e19b6de 100644 --- a/source/blender/editors/space_sound/space_sound.c +++ b/source/blender/editors/space_sound/space_sound.c @@ -142,12 +142,12 @@ static SpaceLink *sound_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void sound_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Sound", SPACE_SOUND, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Sound", SPACE_SOUND, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 1f919fc9cd7..e068c1a70bb 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -208,7 +208,9 @@ static void text_operatortypes(void) static void text_keymap(struct wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Text", SPACE_TEXT, 0); + wmKeyMap *keymap; + + keymap= WM_keymap_find(wm, "Text", SPACE_TEXT, 0); #ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); @@ -329,12 +331,12 @@ static int text_context(const bContext *C, const char *member, bContextDataResul /* add handlers, stuff you only do once or on area/region changes */ static void text_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Text", SPACE_TEXT, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "Text", SPACE_TEXT, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 8f7486f81d9..0f05eb0149d 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -202,12 +202,12 @@ static void time_draw_keyframes(const bContext *C, SpaceTime *stime, ARegion *ar /* add handlers, stuff you only do once or on area/region changes */ static void time_main_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "TimeLine", SPACE_TIME, 0); /* XXX weak? */ + keymap= WM_keymap_find(wm, "TimeLine", SPACE_TIME, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c index a833cca095c..2b073f269bf 100644 --- a/source/blender/editors/space_time/time_ops.c +++ b/source/blender/editors/space_time/time_ops.c @@ -142,7 +142,7 @@ void time_operatortypes(void) void time_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "TimeLine", SPACE_TIME, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "TimeLine", SPACE_TIME, 0); WM_keymap_add_item(keymap, "TIME_OT_start_frame_set", SKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index b5e5de928b5..15e12e73b49 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -275,101 +275,60 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) return (SpaceLink *)v3dn; } -static void view3d_modal_keymaps(wmWindowManager *wm, ARegion *ar, int stype) -{ - RegionView3D *rv3d= ar->regiondata; - ListBase *keymap; - - /* copy last mode, then we can re-init the region maps */ - rv3d->lastmode= stype; - - keymap= WM_keymap_listbase(wm, "Object Mode", 0, 0); - if(ELEM(stype, 0, NS_MODE_OBJECT)) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "EditMesh", 0, 0); - if(stype==NS_EDITMODE_MESH) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Curve", 0, 0); - if(stype==NS_EDITMODE_CURVE) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Armature", 0, 0); - if(stype==NS_EDITMODE_ARMATURE) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Pose", 0, 0); - if(stype==NS_MODE_POSE) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Metaball", 0, 0); - if(stype==NS_EDITMODE_MBALL) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Lattice", 0, 0); - if(stype==NS_EDITMODE_LATTICE) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - /* armature sketching needs to take over mouse */ - keymap= WM_keymap_listbase(wm, "Armature_Sketch", 0, 0); - if(stype==NS_EDITMODE_ARMATURE) - WM_event_add_keymap_handler_priority(&ar->handlers, keymap, 10); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - keymap= WM_keymap_listbase(wm, "Particle", 0, 0); - if(stype==NS_MODE_PARTICLE) - WM_event_add_keymap_handler(&ar->handlers, keymap); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); - - /* editfont keymap swallows all... */ - keymap= WM_keymap_listbase(wm, "Font", 0, 0); - if(stype==NS_EDITMODE_TEXT) - WM_event_add_keymap_handler_priority(&ar->handlers, keymap, 10); - else - WM_event_remove_keymap_handler(&ar->handlers, keymap); -} - /* add handlers, stuff you only do once or on area/region changes */ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) { - RegionView3D *rv3d= ar->regiondata; - ListBase *keymap; + wmKeyMap *keymap; /* own keymap */ - keymap= WM_keymap_listbase(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_listbase(wm, "View3D", SPACE_VIEW3D, 0); + + keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* object ops. */ - keymap= WM_keymap_listbase(wm, "Object Non-modal", 0, 0); + keymap= WM_keymap_find(wm, "Object Non-modal", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* pose is not modal, operator poll checks for this */ - keymap= WM_keymap_listbase(wm, "Pose", 0, 0); + keymap= WM_keymap_find(wm, "Pose", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - /* modal ops keymaps */ - view3d_modal_keymaps(wm, ar, rv3d->lastmode); /* operator poll checks for modes */ - keymap= WM_keymap_listbase(wm, "ImagePaint", 0, 0); + keymap= WM_keymap_find(wm, "ImagePaint", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Object Mode", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "EditMesh", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Armature", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Pose", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Metaball", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Lattice", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + /* armature sketching needs to take over mouse */ + keymap= WM_keymap_find(wm, "Armature_Sketch", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Particle", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + /* editfont keymap swallows all... */ + keymap= WM_keymap_find(wm, "Font", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -444,7 +403,6 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) ED_region_tag_redraw(ar); break; case ND_MODE: - view3d_modal_keymaps(wmn->wm, ar, wmn->subtype); ED_region_tag_redraw(ar); break; } @@ -516,7 +474,7 @@ static void view3d_main_area_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap= WM_keymap_listbase(wm, "View3D Generic", SPACE_VIEW3D, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); @@ -552,11 +510,11 @@ static void view3d_header_area_listener(ARegion *ar, wmNotifier *wmn) /* add handlers, stuff you only do once or on area/region changes */ static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -618,16 +576,14 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) /* add handlers, stuff you only do once or on area/region changes */ static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar) { - ListBase *keymap; + wmKeyMap *keymap; ED_region_panels_init(wm, ar); - keymap= WM_keymap_listbase(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } - - static void view3d_tools_area_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, 1, CTX_data_mode_string(C), -1); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index e179809adc9..9ffdef478b3 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -103,14 +103,16 @@ void view3d_operatortypes(void) void view3d_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "View3D Generic", SPACE_VIEW3D, 0); + wmKeyMap *keymap; wmKeymapItem *km; + keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_properties", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_toolbar", TKEY, KM_PRESS, 0, 0); /* only for region 3D window */ - keymap= WM_keymap_listbase(wm, "View3D", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); /* paint poll checks mode */ WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 8d7e8f20ad5..7dfae33bc39 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -621,7 +621,7 @@ void transform_operatortypes(void) WM_operatortype_append(TFM_OT_select_orientation); } -void transform_keymap_for_space(struct wmWindowManager *wm, struct ListBase *keymap, int spaceid) +void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *keymap, int spaceid) { wmKeymapItem *km; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index cb05109d984..611eee00d79 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3072,7 +3072,10 @@ void ED_operatortypes_uvedit(void) void ED_keymap_uvedit(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0); + wmKeyMap *keymap; + + keymap= WM_keymap_find(wm, "UVEdit", 0, 0); + keymap->poll= ED_operator_uvedit; /* pick selection */ WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index e221524eac2..d42ccd62694 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -89,9 +89,7 @@ typedef struct RegionView3D { float camdx, camdy; /* camera view offsets, 1.0 = viewplane moves entire width/height */ float pixsize; float ofs[3]; - short camzoom, viewbut; - - int lastmode; /* for modal keymap switching, int because it stores notifier code */ + short camzoom, viewbut, pad[2]; short rflag, viewlock; short persp; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 4274cb7ebc0..00fbc04844c 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -265,6 +265,9 @@ typedef struct wmKeyMap { short pad; void *items; /* struct EnumPropertyItem for now */ + + /* verify if the keymap is enabled in the current context */ + int (*poll)(struct bContext *); } wmKeyMap; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 6610c5d8931..b2edbc324ea 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -83,12 +83,12 @@ void WM_paint_cursor_end(struct wmWindowManager *wm, void *handle); /* keymap */ void WM_keymap_init (struct bContext *C); -wmKeymapItem *WM_keymap_verify_item(ListBase *lb, char *idname, short type, +wmKeymapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier); -wmKeymapItem *WM_keymap_add_item(ListBase *lb, char *idname, short type, +wmKeymapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier); -void WM_keymap_tweak (ListBase *lb, short type, short val, int modifier, short keymodifier); -ListBase *WM_keymap_listbase (struct wmWindowManager *wm, const char *nameid, +void WM_keymap_tweak (wmKeyMap *keymap, short type, short val, int modifier, short keymodifier); +wmKeyMap *WM_keymap_find (struct wmWindowManager *wm, const char *nameid, short spaceid, short regionid); wmKeyMap *WM_modalkeymap_add(struct wmWindowManager *wm, const char *nameid, struct EnumPropertyItem *items); @@ -104,13 +104,13 @@ void WM_key_event_operator_change(const struct bContext *C, const char *opname, /* handlers */ -struct wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap); +struct wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap); /* boundbox, optional subwindow boundbox for offset */ -struct wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bb, rcti *swinbb); +struct wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bb, rcti *swinbb); /* priority not implemented, it adds in begin */ -struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority); +struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority); -void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap); +void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap); struct wmEventHandler *WM_event_add_ui_handler(const struct bContext *C, ListBase *handlers, int (*func)(struct bContext *C, struct wmEvent *event, void *userdata), diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9d5bd13ea25..22c5788b0ae 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1014,16 +1014,19 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) action= WM_HANDLER_BREAK; if(handler->keymap) { + wmKeyMap *keymap= handler->keymap; wmKeymapItem *kmi; - for(kmi= handler->keymap->first; kmi; kmi= kmi->next) { - if(wm_eventmatch(event, kmi)) { - - event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ - - action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); - if(action==WM_HANDLER_BREAK) /* not wm_event_always_pass(event) here, it denotes removed handler */ - break; + if(!keymap->poll || keymap->poll(C)) { + for(kmi= keymap->keymap.first; kmi; kmi= kmi->next) { + if(wm_eventmatch(event, kmi)) { + + event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ + + action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + if(action==WM_HANDLER_BREAK) /* not wm_event_always_pass(event) here, it denotes removed handler */ + break; + } } } } @@ -1304,10 +1307,15 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOp return handler; } -wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap) +wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; + if(!keymap) { + printf("WM_event_add_keymap_handler called with NULL keymap\n"); + return NULL; + } + /* only allow same keymap once */ for(handler= handlers->first; handler; handler= handler->next) if(handler->keymap==keymap) @@ -1321,7 +1329,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, ListBase *keymap } /* priorities not implemented yet, for time being just insert in begin of list */ -wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBase *keymap, int priority) +wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority) { wmEventHandler *handler; @@ -1334,7 +1342,7 @@ wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, ListBas return handler; } -wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *keymap, rcti *bblocal, rcti *bbwin) +wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin) { wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap); @@ -1345,7 +1353,7 @@ wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, ListBase *key return handler; } -void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap) +void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 5566aeba260..7d25fb8172e 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -96,17 +96,17 @@ static void keymap_properties_set(wmKeymapItem *kmi) } /* if item was added, then bail out */ -wmKeymapItem *WM_keymap_verify_item(ListBase *lb, char *idname, short type, short val, int modifier, short keymodifier) +wmKeymapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier) { wmKeymapItem *kmi; - for(kmi= lb->first; kmi; kmi= kmi->next) + for(kmi= keymap->keymap.first; kmi; kmi= kmi->next) if(strncmp(kmi->idname, idname, OP_MAX_TYPENAME)==0) break; if(kmi==NULL) { kmi= MEM_callocN(sizeof(wmKeymapItem), "keymap entry"); - BLI_addtail(lb, kmi); + BLI_addtail(&keymap->keymap, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); keymap_event_set(kmi, type, val, modifier, keymodifier); @@ -116,11 +116,11 @@ wmKeymapItem *WM_keymap_verify_item(ListBase *lb, char *idname, short type, shor } /* always add item */ -wmKeymapItem *WM_keymap_add_item(ListBase *lb, char *idname, short type, short val, int modifier, short keymodifier) +wmKeymapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier) { wmKeymapItem *kmi= MEM_callocN(sizeof(wmKeymapItem), "keymap entry"); - BLI_addtail(lb, kmi); + BLI_addtail(&keymap->keymap, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); keymap_event_set(kmi, type, val, modifier, keymodifier); @@ -134,14 +134,14 @@ wmKeymapItem *WM_keymap_add_item(ListBase *lb, char *idname, short type, short v space/region ids are same as DNA_space_types.h */ /* gets free'd in wm.c */ -static wmKeyMap *wm_keymap_add(wmWindowManager *wm, const char *nameid, short spaceid, short regionid) +wmKeyMap *WM_keymap_find(wmWindowManager *wm, const char *nameid, short spaceid, short regionid) { wmKeyMap *km; for(km= wm->keymaps.first; km; km= km->next) if(km->spaceid==spaceid && km->regionid==regionid) if(0==strncmp(nameid, km->nameid, KMAP_MAX_NAME)) - break; + return km; if(km==NULL) { km= MEM_callocN(sizeof(struct wmKeyMap), "keymap list"); @@ -154,19 +154,13 @@ static wmKeyMap *wm_keymap_add(wmWindowManager *wm, const char *nameid, short sp return km; } -ListBase *WM_keymap_listbase(wmWindowManager *wm, const char *nameid, short spaceid, short regionid) -{ - wmKeyMap *km= wm_keymap_add(wm, nameid, spaceid, regionid); - return &km->keymap; -} - /* ****************** modal keymaps ************ */ /* modal maps get linked to a running operator, and filter the keys before sending to modal() callback */ wmKeyMap *WM_modalkeymap_add(wmWindowManager *wm, const char *nameid, EnumPropertyItem *items) { - wmKeyMap *km= wm_keymap_add(wm, nameid, 0, 0); + wmKeyMap *km= WM_keymap_find(wm, nameid, 0, 0); km->is_modal= 1; km->items= items; @@ -242,15 +236,18 @@ static char *wm_keymap_item_to_string(wmKeymapItem *kmi, char *str, int len) return str; } -static wmKeymapItem *wm_keymap_item_find_handlers(ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, int compare_props) +static wmKeymapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, int compare_props) { wmEventHandler *handler; + wmKeyMap *keymap; wmKeymapItem *kmi; /* find keymap item in handlers */ for(handler=handlers->first; handler; handler=handler->next) { - if(handler->keymap) { - for(kmi=handler->keymap->first; kmi; kmi=kmi->next) { + keymap= handler->keymap; + + if(keymap && (!keymap->poll || keymap->poll((bContext*)C))) { + for(kmi=keymap->keymap.first; kmi; kmi=kmi->next) { if(strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0]) { if(compare_props) { if(kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) @@ -272,11 +269,11 @@ static wmKeymapItem *wm_keymap_item_find(const bContext *C, const char *opname, /* look into multiple handler lists to find the item */ if(CTX_wm_window(C)) - found= wm_keymap_item_find_handlers(&CTX_wm_window(C)->handlers, opname, opcontext, properties, compare_props); + found= wm_keymap_item_find_handlers(C, &CTX_wm_window(C)->handlers, opname, opcontext, properties, compare_props); if(CTX_wm_area(C) && found==NULL) - found= wm_keymap_item_find_handlers(&CTX_wm_area(C)->handlers, opname, opcontext, properties, compare_props); + found= wm_keymap_item_find_handlers(C, &CTX_wm_area(C)->handlers, opname, opcontext, properties, compare_props); if(found==NULL) { if(ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) { @@ -287,12 +284,12 @@ static wmKeymapItem *wm_keymap_item_find(const bContext *C, const char *opname, break; if(ar) - found= wm_keymap_item_find_handlers(&ar->handlers, opname, opcontext, properties, compare_props); + found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props); } } else { if(CTX_wm_region(C)) - found= wm_keymap_item_find_handlers(&CTX_wm_region(C)->handlers, opname, opcontext, properties, compare_props); + found= wm_keymap_item_find_handlers(C, &CTX_wm_region(C)->handlers, opname, opcontext, properties, compare_props); } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 86a02e2731a..2e2d463bbd9 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2098,7 +2098,7 @@ void wm_operatortype_init(void) /* default keymap for windows and screens, only call once per WM */ void wm_window_keymap(wmWindowManager *wm) { - ListBase *keymap= WM_keymap_listbase(wm, "Window", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm, "Window", 0, 0); /* items to make WM work */ WM_keymap_verify_item(keymap, "WM_OT_jobs_timer", TIMERJOBS, KM_ANY, KM_ANY, 0); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index d70516ef02e..cbb5bed4c00 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -331,7 +331,7 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, char *title, wmWindow /* called in wm_check, also inits stuff after file read */ void wm_window_add_ghostwindows(wmWindowManager *wm) { - ListBase *keymap; + wmKeyMap *keymap; wmWindow *win; /* no commandline prefsize? then we set this */ @@ -367,10 +367,10 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state"); /* add keymap handlers (1 handler for all keys in map!) */ - keymap= WM_keymap_listbase(wm, "Window", 0, 0); + keymap= WM_keymap_find(wm, "Window", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); - keymap= WM_keymap_listbase(wm, "Screen", 0, 0); + keymap= WM_keymap_find(wm, "Screen", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); wm_window_title(wm, win); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 9a3bba9af1d..4360e49e371 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -43,7 +43,7 @@ typedef struct wmEventHandler { int type, flag; /* type default=0, rest is custom */ /* keymap handler */ - ListBase *keymap; /* pointer to builtin/custom keymaps */ + wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ rcti *bblocal, *bbwin; /* optional local and windowspace bb */ -- cgit v1.2.3 From 08e2da590f812860ae14fff4d4e22e98cbd3528c Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Thu, 17 Sep 2009 22:00:49 +0000 Subject: Particles cleanup, optimizations and some small new stuff. New stuff - Bending springs for hair dynamics. Code cleanup & optimization - Disabled reactor particles temporarily for cleanup, it's a clumsy system that will be replaced with something better. - Removed child seams, something better will come here too :) - Normal particle drawing data is now saved between redraws if the particles don't move between redraws. * For example rotating the 3d view is now realtime even with 1M particles. - Many random values for particles now come from a lookup table making things much faster. - Most accessed small point cache functions are now much faster as macros. - Lot's of general code cleanup. - Nothing big should have changed so if something doesn't work like it used to it's probably just a typo somewhere :) --- release/ui/buttons_particle.py | 1 + source/blender/blenkernel/BKE_boids.h | 4 +- source/blender/blenkernel/BKE_particle.h | 124 +- source/blender/blenkernel/intern/anim.c | 15 +- source/blender/blenkernel/intern/boids.c | 82 +- source/blender/blenkernel/intern/cloth.c | 81 +- source/blender/blenkernel/intern/depsgraph.c | 4 +- source/blender/blenkernel/intern/modifier.c | 21 +- source/blender/blenkernel/intern/particle.c | 519 ++++----- source/blender/blenkernel/intern/particle_system.c | 1210 ++++++++++---------- source/blender/blenkernel/intern/pointcache.c | 233 +++- source/blender/blenloader/intern/readfile.c | 2 + source/blender/editors/physics/editparticle.c | 25 +- source/blender/editors/space_view3d/drawobject.c | 133 +-- source/blender/makesdna/DNA_particle_types.h | 14 +- source/blender/makesrna/intern/rna_particle.c | 23 +- .../blender/render/intern/source/convertblender.c | 35 +- source/blender/render/intern/source/pointdensity.c | 5 +- 18 files changed, 1285 insertions(+), 1246 deletions(-) diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py index 1bbd64c9b0f..e72bd38e563 100644 --- a/release/ui/buttons_particle.py +++ b/release/ui/buttons_particle.py @@ -255,6 +255,7 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel): sub = col.column(align=True) sub.itemR(cloth, "pin_stiffness", text="Stiffness") sub.itemR(cloth, "mass") + sub.itemR(cloth, "bending_stiffness", text="Bending") col.itemL(text="Damping:") sub = col.column(align=True) sub.itemR(cloth, "spring_damping", text="Spring") diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h index acceff863b9..fb65c9c8920 100644 --- a/source/blender/blenkernel/BKE_boids.h +++ b/source/blender/blenkernel/BKE_boids.h @@ -35,9 +35,7 @@ #include "DNA_boid_types.h" typedef struct BoidBrainData { - Scene *scene; - struct Object *ob; - struct ParticleSystem *psys; + struct ParticleSimulationData *sim; struct ParticleSettings *part; float timestep, cfra, dfra; float wanted_co[3], wanted_speed; diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index c22778f5a30..5850ddaca08 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -61,6 +61,23 @@ struct BVHTreeRayHit; #define PARTICLE_P ParticleData *pa; int p #define LOOP_PARTICLES for(p=0, pa=psys->particles; ptotpart; p++, pa++) +#define LOOP_EXISTING_PARTICLES for(p=0, pa=psys->particles; ptotpart; p++, pa++) if(!(pa->flag & PARS_UNEXIST)) +#define LOOP_SHOWN_PARTICLES for(p=0, pa=psys->particles; ptotpart; p++, pa++) if(!(pa->flag & (PARS_UNEXIST|PARS_NO_DISP))) + +#define PSYS_FRAND_COUNT 1024 +#define PSYS_FRAND(seed) psys->frand[(seed) % PSYS_FRAND_COUNT] + +/* fast but sure way to get the modifier*/ +#define PARTICLE_PSMD ParticleSystemModifierData *psmd = sim->psmd ? sim->psmd : psys_get_modifier(sim->ob, sim->psys) + +/* common stuff that many particle functions need */ +typedef struct ParticleSimulationData { + struct Scene *scene; + struct Object *ob; + struct ParticleSystem *psys; + struct ParticleSystemModifierData *psmd; + float timestep; +} ParticleSimulationData; typedef struct ParticleEffectorCache { struct ParticleEffectorCache *next, *prev; @@ -118,11 +135,8 @@ typedef struct ParticleCacheKey{ typedef struct ParticleThreadContext { /* shared */ - struct Scene *scene; - struct Object *ob; + struct ParticleSimulationData sim; struct DerivedMesh *dm; - struct ParticleSystemModifierData *psmd; - struct ParticleSystem *psys; struct Material *ma; /* distribution */ @@ -166,8 +180,7 @@ typedef struct ParticleBillboardData int lock, num; int totnum; short align, uv_split, anim, split_offset; -} -ParticleBillboardData; +} ParticleBillboardData; /* container for moving data between deflet_particle and particle_intersect_face */ typedef struct ParticleCollision @@ -179,40 +192,40 @@ typedef struct ParticleCollision float co1[3], co2[3]; // ray start and end points float ray_len; // original length of co2-co1, needed for collision time evaluation float t; // time of previous collision, needed for substracting face velocity -} -ParticleCollision; +} ParticleCollision; + +typedef struct ParticleDrawData { + float *vdata, *vd; /* vertice data */ + float *ndata, *nd; /* normal data */ + float *cdata, *cd; /* color data */ + float *vedata, *ved; /* velocity data */ + float *ma_r, *ma_g, *ma_b; + int tot_vec_size, flag; + int totpoint, totve; +} ParticleDrawData; + +#define PARTICLE_DRAW_DATA_UPDATED 1 /* ----------- functions needed outside particlesystem ---------------- */ /* particle.c */ int count_particles(struct ParticleSystem *psys); int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur); -int psys_count_keys(struct ParticleSystem *psys); -char *psys_menu_string(struct Object *ob, int for_sb); struct ParticleSystem *psys_get_current(struct Object *ob); +/* for rna */ short psys_get_current_num(struct Object *ob); void psys_set_current_num(Object *ob, int index); struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); -//struct ParticleSystem *psys_get(struct Object *ob, int index); -struct ParticleData *psys_get_selected_particle(struct ParticleSystem *psys, int *index); -struct ParticleKey *psys_get_selected_key(struct ParticleSystem *psys, int pa_index, int *key_index); -void psys_change_act(void *ob_v, void *act_v); -struct Object *psys_get_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); -void psys_disable_all(struct Object *ob); -void psys_enable_all(struct Object *ob); -int psys_ob_has_hair(struct Object *ob); + +struct Object *psys_get_lattice(struct ParticleSimulationData *sim); + int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); -void psys_free_boid_rules(struct ListBase *list); +/* free */ void psys_free_settings(struct ParticleSettings *part); -void free_child_path_cache(struct ParticleSystem *psys); void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit); -void free_hair(struct Object *ob, struct ParticleSystem *psys, int dynamics); -void free_keyed_keys(struct ParticleSystem *psys); -void psys_free_particles(struct ParticleSystem *psys); void psys_free(struct Object * ob, struct ParticleSystem * psys); -void psys_free_children(struct ParticleSystem *psys); void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy, int timeoffset); void psys_render_restore(struct Object *ob, struct ParticleSystem *psys); @@ -234,45 +247,38 @@ struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part); void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *part, int recalc); void make_local_particlesettings(struct ParticleSettings *part); -struct LinkNode *psys_using_settings(struct Scene *scene, struct ParticleSettings *part, int flush_update); void psys_reset(struct ParticleSystem *psys, int mode); -void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys); +void psys_find_parents(struct ParticleSimulationData *sim); -void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra); +void psys_cache_paths(struct ParticleSimulationData *sim, float cfra); void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra); -void psys_cache_child_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); +void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate); int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb); -float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size); -float psys_get_timestep(struct ParticleSettings *part); +float psys_get_timestep(struct ParticleSimulationData *sim); float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime); float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time); -void psys_get_particle_on_path(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel); -int psys_get_particle_state(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always); +void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, int vel); +int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always); + +/* for anim.c */ void psys_get_dupli_texture(struct Object *ob, struct ParticleSettings *part, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, float *uv, float *orco); -void psys_get_dupli_path_transform(struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, struct ParticleCacheKey *cache, float mat[][4], float *scale); +void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ChildParticle *cpa, struct ParticleCacheKey *cache, float mat[][4], float *scale); -ParticleThread *psys_threads_create(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); -int psys_threads_init_distribution(ParticleThread *threads, struct Scene *scene, struct DerivedMesh *dm, int from); -int psys_threads_init_path(ParticleThread *threads, struct Scene *scene, float cfra, int editupdate); +ParticleThread *psys_threads_create(struct ParticleSimulationData *sim); void psys_threads_free(ParticleThread *threads); -void psys_thread_distribute_particle(ParticleThread *thread, struct ParticleData *pa, struct ChildParticle *cpa, int p); -void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i); - void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); /* particle_system.c */ struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt); -void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys); -void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys); +void psys_count_keyed_targets(struct ParticleSimulationData *sim); +//void psys_get_reactor_target(struct ParticleSimulationData *sim, struct Object **target_ob, struct ParticleSystem **target_psys); -void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys); -void psys_end_effectors(struct ParticleSystem *psys); +int psys_update_effectors(ParticleSimulationData *sim, float cfra, int precalc); void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys); -void psys_end_temp_pointcache(struct ParticleSystem *psys); -void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra); +void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, int *sfra, int *efra); void psys_check_boid_data(struct ParticleSystem *psys); @@ -280,39 +286,45 @@ void particle_system_update(struct Scene *scene, struct Object *ob, struct Parti /* ----------- functions needed only inside particlesystem ------------ */ /* particle.c */ +void psys_disable_all(struct Object *ob); +void psys_enable_all(struct Object *ob); + +void free_hair(struct Object *ob, struct ParticleSystem *psys, int dynamics); +void free_keyed_keys(struct ParticleSystem *psys); +void psys_free_particles(struct ParticleSystem *psys); +void psys_free_children(struct ParticleSystem *psys); + void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, int velocity); -void psys_key_to_object(struct Object *ob, struct ParticleKey *key, float imat[][4]); -//void psys_key_to_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key); -//void psys_key_from_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key); -//void psys_face_mat(struct DerivedMesh *dm, struct ParticleData *pa, float mat[][4]); void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec); -//void psys_vec_rot_from_face(struct DerivedMesh *dm, struct ParticleData *pa, float *vec); void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[][4]); +void psys_free_pdd(struct ParticleSystem *psys); + float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup); -void psys_get_texture(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys, struct ParticleData *pa, struct ParticleTexture *ptex, int event); +void psys_get_texture(struct ParticleSimulationData *sim, struct Material *ma, struct ParticleData *pa, struct ParticleTexture *ptex, int event); void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface, float (*orcodata)[3], float *uv, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor); float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values); -float psys_interpolate_value_from_verts(struct DerivedMesh *dm, short from, int index, float *fw, float *values); void psys_get_from_key(struct ParticleKey *key, float *loc, float *vel, float *rot, float *time); +/* only in edisparticle.c*/ int psys_intersect_dm(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_uv, float *face_minmax, float *pa_minmax, float radius, float *ipoint); +/* BLI_bvhtree_ray_cast callback */ void particle_intersect_face(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit); void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor); /* particle_system.c */ -void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd); +void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, int p); int effector_find_co(struct Scene *scene, float *pco, struct SurfaceModifierData *sur, struct Object *ob, struct PartDeflect *pd, float *co, float *nor, float *vel, int *index); -void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float *texco, float *force_field, float *vel,float framestep, float cfra); +void do_effectors(struct ParticleSimulationData *sim, int pa_no, struct ParticleData *pa, struct ParticleKey *state, float *texco, float *force_field, float *vel,float framestep, float cfra); +void psys_end_effectors(struct ParticleSystem *psys); void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys); int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node); -void reset_particle(struct Scene *scene, struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, - float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot); +void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra); /* psys_reset */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 8cb88cdb786..e943d92a0b5 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -766,12 +766,12 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p GroupObject *go; Object *ob=0, **oblist=0, obcopy, *obcopylist=0; DupliObject *dob; + ParticleSimulationData sim = {scene, par, psys, psys_get_modifier(par, psys)}; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa=0; ParticleKey state; ParticleCacheKey *cache; - ParticleSystemModifierData *psmd; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], size=0.0; float (*obmat)[4], (*oldobmat)[4]; @@ -784,7 +784,6 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if(level>MAX_DUPLI_RECUR) return; part=psys->part; - psmd= psys_get_modifier(par, psys); if(part==0) return; @@ -816,7 +815,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p totpart = psys->totcached; } - psys->lattice = psys_get_lattice(scene, par, psys); + psys->lattice = psys_get_lattice(&sim); /* gather list of objects or single object */ if(part->ren_as==PART_DRAW_GR) { @@ -887,11 +886,11 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p /* hair we handle separate and compute transform based on hair keys */ if(a < totpart) { cache = psys->pathcache[a]; - psys_get_dupli_path_transform(par, psys, psmd, pa, 0, cache, pamat, &scale); + psys_get_dupli_path_transform(&sim, pa, 0, cache, pamat, &scale); } else { cache = psys->childcache[a-totpart]; - psys_get_dupli_path_transform(par, psys, psmd, 0, cpa, cache, pamat, &scale); + psys_get_dupli_path_transform(&sim, 0, cpa, cache, pamat, &scale); } VECCOPY(pamat[3], cache->co); @@ -901,7 +900,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else { /* first key */ state.time = ctime; - if(psys_get_particle_state(scene, par, psys, a, &state, 0) == 0) + if(psys_get_particle_state(&sim, a, &state, 0) == 0) continue; QuatToMat4(state.rot, pamat); @@ -921,7 +920,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); Mat4CpyMat4(dob->omat, obcopylist[b].obmat); if(G.rendering) - psys_get_dupli_texture(par, part, psmd, pa, cpa, dob->uv, dob->orco); + psys_get_dupli_texture(par, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { @@ -940,7 +939,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p dob= new_dupli_object(lb, ob, mat, ob->lay, counter, OB_DUPLIPARTS, animated); Mat4CpyMat4(dob->omat, oldobmat); if(G.rendering) - psys_get_dupli_texture(par, part, psmd, pa, cpa, dob->uv, dob->orco); + psys_get_dupli_texture(par, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 18f065b59d9..7c3f3a7876f 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -87,7 +87,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, float vec_to_part[3]; if(pd && pd->forcefield == PFIELD_BOID) { - effector_find_co(bbd->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL); + effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL); VecSubf(vec_to_part, pa->prev_state.co, loc); @@ -99,7 +99,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, priority = 1.0; priority_ob = gabr->ob; } - else for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + else for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { if(ec->type & PSYS_EC_EFFECTOR) { Object *eob = ec->ob; PartDeflect *pd = eob->pd; @@ -111,7 +111,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) { float vec_to_part[3], temp; - effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL); + effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL); VecSubf(vec_to_part, pa->prev_state.co, loc); @@ -147,7 +147,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, if(gabr->options & BRULE_GOAL_AVOID_PREDICT) { /* estimate future location of target */ - surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL); + surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL); VecSubf(vec_to_part, pa->prev_state.co, loc); len = Normalize(vec_to_part); @@ -157,7 +157,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, VecSubf(vec_to_part, pa->prev_state.co, loc); } else { - surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL); + surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL); VecSubf(vec_to_part, pa->prev_state.co, loc); len = VecLength(vec_to_part); @@ -228,7 +228,7 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * hit.dist = col.ray_len = VecLength(ray_dir); /* find out closest deflector object */ - for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { if(ec->type & PSYS_EC_DEFLECT) { Object *eob = ec->ob; @@ -261,12 +261,12 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * //check boids in own system if(acbr->options & BRULE_ACOLL_WITH_BOIDS) { - neighbors = BLI_kdtree_range_search(bbd->psys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); + neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); if(neighbors > 1) for(n=1; nprev_state.co); VECCOPY(vel1, pa->prev_state.vel); - VECCOPY(co2, (bbd->psys->particles + ptn[n].index)->prev_state.co); - VECCOPY(vel2, (bbd->psys->particles + ptn[n].index)->prev_state.vel); + VECCOPY(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co); + VECCOPY(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel); VecSubf(loc, co1, co2); @@ -303,8 +303,8 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * if(ptn){ MEM_freeN(ptn); ptn=NULL; } /* check boids in other systems */ - for(pt=bbd->psys->targets.first; pt; pt=pt->next) { - ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if(epsys) { neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); @@ -362,11 +362,11 @@ static int rule_separate(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Pa ParticleTarget *pt; float len = 2.0f * val->personal_space * pa->size + 1.0f; float vec[3] = {0.0f, 0.0f, 0.0f}; - int neighbors = BLI_kdtree_range_search(bbd->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); + int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); int ret = 0; if(neighbors > 1 && ptn[1].dist!=0.0f) { - VecSubf(vec, pa->prev_state.co, bbd->psys->particles[ptn[1].index].state.co); + VecSubf(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co); VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist); VecAddf(bbd->wanted_co, bbd->wanted_co, vec); bbd->wanted_speed = val->max_speed; @@ -376,8 +376,8 @@ static int rule_separate(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Pa if(ptn){ MEM_freeN(ptn); ptn=NULL; } /* check other boid systems */ - for(pt=bbd->psys->targets.first; pt; pt=pt->next) { - ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if(epsys) { neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); @@ -400,14 +400,14 @@ static int rule_flock(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti { KDTreeNearest ptn[11]; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; - int neighbors = BLI_kdtree_find_n_nearest(bbd->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn); + int neighbors = BLI_kdtree_find_n_nearest(bbd->sim->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn); int n; int ret = 0; if(neighbors > 1) { for(n=1; npsys->particles[ptn[n].index].prev_state.co); - VecAddf(vec, vec, bbd->psys->particles[ptn[n].index].prev_state.vel); + VecAddf(loc, loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co); + VecAddf(vec, vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel); } VecMulf(loc, 1.0f/((float)neighbors - 1.0f)); @@ -429,8 +429,8 @@ static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *va BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; float mul, len; - int n = (flbr->queue_size <= 1) ? bbd->psys->totpart : flbr->queue_size; - int i, ret = 0, p = pa - bbd->psys->particles; + int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size; + int i, ret = 0, p = pa - bbd->sim->psys->particles; if(flbr->ob) { float vec2[3], t; @@ -475,8 +475,8 @@ static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *va /* not blocking so try to follow leader */ if(p && flbr->options & BRULE_LEADER_IN_LINE) { - VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel); - VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co); + VECCOPY(vec, bbd->sim->psys->particles[p-1].prev_state.vel); + VECCOPY(loc, bbd->sim->psys->particles[p-1].prev_state.co); } else { VECCOPY(loc, flbr->oloc); @@ -496,10 +496,10 @@ static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *va float vec2[3], t, t_min = 3.0f; /* first check we're not blocking any leaders */ - for(i = 0; i< bbd->psys->totpart; i+=n){ - VECCOPY(vec, bbd->psys->particles[i].prev_state.vel); + for(i = 0; i< bbd->sim->psys->totpart; i+=n){ + VECCOPY(vec, bbd->sim->psys->particles[i].prev_state.vel); - VecSubf(loc, pa->prev_state.co, bbd->psys->particles[i].prev_state.co); + VecSubf(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co); mul = Inpf(vec, vec); @@ -539,12 +539,12 @@ static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *va /* not blocking so try to follow leader */ if(flbr->options & BRULE_LEADER_IN_LINE) { - VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel); - VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co); + VECCOPY(vec, bbd->sim->psys->particles[p-1].prev_state.vel); + VECCOPY(loc, bbd->sim->psys->particles[p-1].prev_state.co); } else { - VECCOPY(vec, bbd->psys->particles[p - p%n].prev_state.vel); - VECCOPY(loc, bbd->psys->particles[p - p%n].prev_state.co); + VECCOPY(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel); + VECCOPY(loc, bbd->sim->psys->particles[p - p%n].prev_state.co); } /* fac is seconds behind leader */ @@ -584,7 +584,7 @@ static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *va /* leveling */ if(asbr->level > 0.0f) { - Projf(vec, bbd->wanted_co, bbd->psys->part->acc); + Projf(vec, bbd->wanted_co, bbd->sim->psys->part->acc); VecMulf(vec, asbr->level); VecSubf(bbd->wanted_co, bbd->wanted_co, vec); } @@ -601,7 +601,7 @@ static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *va /* leveling */ if(asbr->level > 0.0f) { - Projf(vec, bbd->wanted_co, bbd->psys->part->acc); + Projf(vec, bbd->wanted_co, bbd->sim->psys->part->acc); VecMulf(vec, asbr->level); VecSubf(bbd->wanted_co, bbd->wanted_co, vec); } @@ -627,9 +627,9 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti int n, ret = 0; /* calculate own group strength */ - int neighbors = BLI_kdtree_range_search(bbd->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); + int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); for(n=0; npsys->particles[ptn[n].index].boid; + bpa = bbd->sim->psys->particles[ptn[n].index].boid; health += bpa->data.health; } @@ -638,8 +638,8 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti if(ptn){ MEM_freeN(ptn); ptn=NULL; } /* add other friendlies and calculate enemy strength and find closest enemy */ - for(pt=bbd->psys->targets.first; pt; pt=pt->next) { - ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if(epsys) { epars = epsys->particles; @@ -760,11 +760,11 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface ); /* take surface velocity into account */ - effector_find_co(bbd->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL); + effector_find_co(bbd->sim->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL); VecAddf(x, x, v); /* get actual position on surface */ - effector_find_co(bbd->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL); + effector_find_co(bbd->sim->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL); return bpa->ground; } @@ -785,7 +785,7 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro hit.dist = col.ray_len = VecLength(ray_dir); /* find out upmost deflector object */ - for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) { if(ec->type & PSYS_EC_DEFLECT) { Object *eob = ec->ob; @@ -941,7 +941,7 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; /* create random seed for every particle & frame */ - BLI_srandom(bbd->psys->seed + p); + BLI_srandom(bbd->sim->psys->seed + p); rand = BLI_rand(); BLI_srandom((int)bbd->cfra + rand); @@ -1077,7 +1077,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; float force[3] = {0.0f, 0.0f, 0.0f}, tvel[3] = {0.0f, 0.0f, 1.0f}; float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; - int p = pa - bbd->psys->particles; + int p = pa - bbd->sim->psys->particles; set_boid_values(&val, boids, pa); @@ -1208,7 +1208,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) } /* account for effectors */ - do_effectors(p, pa, &pa->state, bbd->scene, bbd->ob, bbd->psys, pa->state.co, force, tvel, bbd->dfra, bbd->cfra); + do_effectors(bbd->sim, p, pa, &pa->state, pa->state.co, force, tvel, bbd->dfra, bbd->cfra); if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { float length = Normalize(force); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 9ee6be903fa..5cfbd5c18dc 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1160,25 +1160,66 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) BLI_linklist_prepend ( &cloth->springs, spring ); } - // bending springs - search2 = cloth->springs; - for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) - { - if ( !search2 ) - break; + if(numfaces) { + // bending springs + search2 = cloth->springs; + for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) + { + if ( !search2 ) + break; + + tspring2 = search2->link; + search = edgelist[tspring2->kl]; + while ( search ) + { + tspring = search->link; + index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); + + // check for existing spring + // check also if startpoint is equal to endpoint + if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) + && ( index2!=tspring2->ij ) ) + { + spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if(!spring) + { + cloth_free_errorsprings(cloth, edgehash, edgelist); + return 0; + } - tspring2 = search2->link; - search = edgelist[tspring2->kl]; - while ( search ) + spring->ij = MIN2(tspring2->ij, index2); + spring->kl = MAX2(tspring2->ij, index2); + VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); + spring->restlen = sqrt ( INPR ( temp, temp ) ); + spring->type = CLOTH_SPRING_TYPE_BENDING; + spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; + BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); + bend_springs++; + + BLI_linklist_prepend ( &cloth->springs, spring ); + } + search = search->next; + } + search2 = search2->next; + } + } + else if(struct_springs > 2) { + /* bending springs for hair strands */ + /* The current algorightm only goes through the edges in order of the mesh edges list */ + /* and makes springs between the outer vert of edges sharing a vertice. This works just */ + /* fine for hair, but not for user generated string meshes. This could/should be later */ + /* extended to work with non-ordered edges so that it can be used for general "rope */ + /* dynamics" without the need for the vertices or edges to be ordered through the length*/ + /* of the strands. -jahka */ + search = cloth->springs; + search2 = search->next; + while(search && search2) { tspring = search->link; - index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); - - // check for existing spring - // check also if startpoint is equal to endpoint - if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) - && ( index2!=tspring2->ij ) ) - { + tspring2 = search2->link; + + if(tspring->ij == tspring2->kl) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if(!spring) @@ -1187,20 +1228,20 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) return 0; } - spring->ij = MIN2(tspring2->ij, index2); - spring->kl = MAX2(tspring2->ij, index2); + spring->ij = tspring2->ij; + spring->kl = tspring->kl; VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; - BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); } + search = search->next; + search2 = search2->next; } - search2 = search2->next; } /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 58f3db50d0f..4c2b2f3ec12 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -560,6 +560,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O for(; psys; psys=psys->next) { BoidRule *rule = NULL; BoidState *state = NULL; + ParticleSimulationData sim = {scene, ob, psys, NULL}; ParticleSettings *part= psys->part; dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); @@ -592,8 +593,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O } } - psys_end_effectors(psys); - psys_init_effectors(scene, ob, psys->part->eff_group, psys); + psys_update_effectors(&sim, 0.0, 0); for(nec= psys->effectors.first; nec; nec= nec->next) { Object *ob1= nec->ob; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c64c48b9ce7..b9b9ea6b4f3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -6601,6 +6601,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md; + ParticleSimulationData sim; ParticleSystem * psys=0; ParticleData *pa=0, *pars=0; MFace *mface, *orig_mface; @@ -6635,6 +6636,11 @@ static DerivedMesh * particleInstanceModifier_applyModifier( if(totpart==0) return derivedData; + sim.scene = md->scene; + sim.ob = pimd->ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(pimd->ob, psys); + if(pimd->flag & eParticleInstanceFlag_UseSize) { int p; float *si; @@ -6662,7 +6668,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( maxvert=totvert*totpart; maxface=totface*totpart; - psys->lattice=psys_get_lattice(md->scene, ob, psys); + psys->lattice=psys_get_lattice(&sim); if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){ @@ -6712,7 +6718,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( mv->co[axis] = 0.0; } - psys_get_particle_on_path(md->scene, pimd->ob, psys,first_particle + i/totvert, &state,1); + psys_get_particle_on_path(&sim, first_particle + i/totvert, &state,1); Normalize(state.vel); @@ -6734,7 +6740,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( } else{ state.time=-1.0; - psys_get_particle_state(md->scene, pimd->ob, psys, first_particle + i/totvert, &state,1); + psys_get_particle_state(&sim, first_particle + i/totvert, &state,1); } QuatMulVecf(state.rot,mv->co); @@ -7416,6 +7422,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, DerivedMesh *explode, *dm=to_explode; MFace *mf=0; ParticleSettings *part=psmd->psys->part; + ParticleSimulationData sim = {scene, ob, psmd->psys, psmd}; ParticleData *pa=NULL, *pars=psmd->psys->particles; ParticleKey state; EdgeHash *vertpahash; @@ -7431,7 +7438,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, totvert= dm->getNumVerts(dm); totpart= psmd->psys->totpart; - timestep= psys_get_timestep(part); + timestep= psys_get_timestep(&sim); //if(part->flag & PART_GLOB_TIME) cfra=bsystem_time(scene, 0,(float)scene->r.cfra,0.0); @@ -7474,7 +7481,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, /* getting back to object space */ Mat4Invert(imat,ob->obmat); - psmd->psys->lattice = psys_get_lattice(scene, ob, psmd->psys); + psmd->psys->lattice = psys_get_lattice(&sim); /* duplicate & displace vertices */ ehi= BLI_edgehashIterator_new(vertpahash); @@ -7502,7 +7509,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, Mat4MulVecfl(ob->obmat,loc0); state.time=cfra; - psys_get_particle_state(scene, ob, psmd->psys, i, &state,1); + psys_get_particle_state(&sim, i, &state, 1); vertco=CDDM_get_vert(explode,v)->co; @@ -7591,7 +7598,7 @@ static DerivedMesh * explodeModifier_applyModifier( { DerivedMesh *dm = derivedData; ExplodeModifierData *emd= (ExplodeModifierData*) md; - ParticleSystemModifierData *psmd=explodeModifier_findPrecedingParticlesystem(ob,md);; + ParticleSystemModifierData *psmd=explodeModifier_findPrecedingParticlesystem(ob,md); if(psmd){ ParticleSystem * psys=psmd->psys; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index cce18e99157..0dc041bfc6a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -69,7 +69,7 @@ #include "BKE_particle.h" #include "BKE_DerivedMesh.h" #include "BKE_object.h" -#include "BKE_softbody.h" +#include "BKE_cloth.h" #include "BKE_material.h" #include "BKE_key.h" #include "BKE_library.h" @@ -85,7 +85,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fuv, float *orco, ParticleTexture *ptex, int event); static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); -static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, +static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t); @@ -95,11 +95,10 @@ int count_particles(ParticleSystem *psys){ PARTICLE_P; int tot=0; - LOOP_PARTICLES { + LOOP_SHOWN_PARTICLES { if(pa->alive == PARS_KILLED); else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0); else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0); - else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)); else tot++; } return tot; @@ -109,55 +108,14 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur){ PARTICLE_P; int tot=0; - LOOP_PARTICLES { + LOOP_SHOWN_PARTICLES { if(pa->alive == PARS_KILLED); else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0); else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0); - else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)); else if(p%totgr==cur) tot++; } return tot; } -int psys_count_keys(ParticleSystem *psys) -{ - PARTICLE_P; - int totkey=0; - - LOOP_PARTICLES - totkey += pa->totkey; - - return totkey; -} -/* remember to free the pointer returned from this! */ -char *psys_menu_string(Object *ob, int for_sb) -{ - ParticleSystem *psys; - DynStr *ds; - char *str, num[6]; - int i; - - ds = BLI_dynstr_new(); - - if(for_sb) - BLI_dynstr_append(ds, "|Object%x-1"); - - for(i=0,psys=ob->particlesystem.first; psys; i++,psys=psys->next){ - - BLI_dynstr_append(ds, "|"); - sprintf(num,"%i. ",i+1); - BLI_dynstr_append(ds, num); - BLI_dynstr_append(ds, psys->part->id.name+2); - sprintf(num,"%%x%i",i+1); - BLI_dynstr_append(ds, num); - } - - str = BLI_dynstr_get_cstring(ds); - - BLI_dynstr_free(ds); - - return str; -} - /* we allocate path cache memory in chunks instead of a big continguous * chunk, windows' memory allocater fails to find big blocks of memory often */ @@ -257,30 +215,13 @@ Object *psys_find_object(Scene *scene, ParticleSystem *psys) return NULL; } -/* change object's active particle system */ -void psys_change_act(void *ob_v, void *act_v) -{ - Object *ob = ob_v; - ParticleSystem *npsys, *psys; - short act = *((short*)act_v)-1; - - if(act>=0){ - npsys=BLI_findlink(&ob->particlesystem,act); - psys=psys_get_current(ob); - - if(psys) - psys->flag &= ~PSYS_CURRENT; - if(npsys) - npsys->flag |= PSYS_CURRENT; - } -} -Object *psys_get_lattice(Scene *scene, Object *ob, ParticleSystem *psys) +Object *psys_get_lattice(ParticleSimulationData *sim) { Object *lattice=0; - if(psys_in_edit_mode(scene, psys)==0){ + if(psys_in_edit_mode(sim->scene, sim->psys)==0){ - ModifierData *md = (ModifierData*)psys_get_modifier(ob,psys); + ModifierData *md = (ModifierData*)psys_get_modifier(sim->ob, sim->psys); for(; md; md=md->next){ if(md->type==eModifierType_Lattice){ @@ -309,20 +250,20 @@ void psys_enable_all(Object *ob) for(; psys; psys=psys->next) psys->flag &= ~PSYS_DISABLED; } -int psys_ob_has_hair(Object *ob) -{ - ParticleSystem *psys = ob->particlesystem.first; - - for(; psys; psys=psys->next) - if(psys->part->type == PART_HAIR) - return 1; - - return 0; -} int psys_in_edit_mode(Scene *scene, ParticleSystem *psys) { return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys==psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit)); } +static void psys_create_frand(ParticleSystem *psys) +{ + int i; + float *rand = psys->frand = MEM_callocN(PSYS_FRAND_COUNT * sizeof(float), "particle randoms"); + + BLI_srandom(psys->seed); + + for(i=0; i<1024; i++, rand++) + *rand = BLI_frand(); +} int psys_check_enabled(Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; @@ -344,6 +285,14 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys) } else if(!(psmd->modifier.mode & eModifierMode_Realtime)) return 0; + + /* perhaps not the perfect place, but we have to be sure the rands are there before usage */ + if(!psys->frand) + psys_create_frand(psys); + else if(psys->recalc & PSYS_RECALC_RESET) { + MEM_freeN(psys->frand); + psys_create_frand(psys); + } return 1; } @@ -423,7 +372,7 @@ void free_keyed_keys(ParticleSystem *psys) } } } -void free_child_path_cache(ParticleSystem *psys) +static void free_child_path_cache(ParticleSystem *psys) { psys_free_path_cache_buffers(psys->childcache, &psys->childcachebufs); psys->childcache = NULL; @@ -477,6 +426,24 @@ void psys_free_particles(ParticleSystem *psys) psys->totpart= 0; } } +void psys_free_pdd(ParticleSystem *psys) +{ + if(psys->pdd->cdata) + MEM_freeN(psys->pdd->cdata); + psys->pdd->cdata = NULL; + + if(psys->pdd->vdata) + MEM_freeN(psys->pdd->vdata); + psys->pdd->vdata = NULL; + + if(psys->pdd->ndata) + MEM_freeN(psys->pdd->ndata); + psys->pdd->ndata = NULL; + + if(psys->pdd->vedata) + MEM_freeN(psys->pdd->vedata); + psys->pdd->vedata = NULL; +} /* free everything */ void psys_free(Object *ob, ParticleSystem * psys) { @@ -530,6 +497,14 @@ void psys_free(Object *ob, ParticleSystem * psys) BLI_kdtree_free(psys->tree); + if(psys->frand) + MEM_freeN(psys->frand); + + if(psys->pdd) { + psys_free_pdd(psys); + MEM_freeN(psys->pdd); + } + MEM_freeN(psys); } } @@ -721,12 +696,12 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) { DerivedMesh *dm= ctx->dm; - Mesh *me= (Mesh*)(ctx->ob->data); + Mesh *me= (Mesh*)(ctx->sim.ob->data); MFace *mf, *mface; MVert *mvert; ParticleRenderData *data; ParticleRenderElem *elems, *elem; - ParticleSettings *part= ctx->psys->part; + ParticleSettings *part= ctx->sim.psys->part; float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp; float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport; double vprate; @@ -735,10 +710,10 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) if(part->ren_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) return tot; - if(!ctx->psys->renderdata) + if(!ctx->sim.psys->renderdata) return tot; - data= ctx->psys->renderdata; + data= ctx->sim.psys->renderdata; if(data->timeoffset) return 0; if(!(part->simplify_flag & PART_SIMPLIFY_ENABLE)) @@ -815,7 +790,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) /* set simplification parameters per original face */ for(a=0, elem=elems; apsys, facecenter[a], facearea[a], vprate, &viewport); + area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport); arearatio= fac*area/facearea[a]; if((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) { @@ -1437,7 +1412,7 @@ void psys_interpolate_mcol(MCol *mcol, int quad, float *w, MCol *mc) } } -float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, float *fw, float *values) +static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, float *fw, float *values) { if(values==0 || index==-1) return 0.0; @@ -2074,7 +2049,7 @@ static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float VECADDFAC(state->co,state->co,mat[0],rough[0]); VECADDFAC(state->co,state->co,mat[1],rough[1]); } -static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) +static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) { float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}; ParticleKey eff_key; @@ -2084,10 +2059,10 @@ static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, in VECCOPY(eff_key.vel,(ca-1)->vel); QUATCOPY(eff_key.rot,(ca-1)->rot); - pa= psys->particles+i; - do_effectors(i, pa, &eff_key, scene, ob, psys, rootco, force, vel, dfra, cfra); + pa= sim->psys->particles+i; + do_effectors(sim, i, pa, &eff_key, rootco, force, vel, dfra, cfra); - VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) / (float)steps); + VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps); VecAddf(force, force, vec); @@ -2154,12 +2129,12 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) } return vg; } -void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys) +void psys_find_parents(ParticleSimulationData *sim) { - ParticleSettings *part=psys->part; + ParticleSettings *part=sim->psys->part; KDTree *tree; ChildParticle *cpa; - int p, totparent,totchild=psys->totchild; + int p, totparent,totchild=sim->psys->totchild; float co[3], orco[3]; int from=PART_FROM_FACE; totparent=(int)(totchild*part->parents*0.3); @@ -2169,15 +2144,15 @@ void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSys tree=BLI_kdtree_new(totparent); - for(p=0,cpa=psys->child; pnum,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); + for(p=0,cpa=sim->psys->child; ppsmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); BLI_kdtree_insert(tree, p, orco, NULL); } BLI_kdtree_balance(tree); for(; pnum,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(sim->psmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); cpa->parent=BLI_kdtree_find_nearest(tree, orco, NULL, NULL); } @@ -2215,11 +2190,11 @@ static void get_strand_normal(Material *ma, float *surfnor, float surfdist, floa VECCOPY(nor, vnor); } -int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate) +static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate) { ParticleThreadContext *ctx= threads[0].ctx; - Object *ob= ctx->ob; - ParticleSystem *psys= ctx->psys; + Object *ob= ctx->sim.ob; + ParticleSystem *psys= ctx->sim.psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &scene->toolsettings->particle; int totparent=0, between=0; @@ -2252,10 +2227,10 @@ int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, in if(totchild==0) return 0; /* init random number generator */ - if(ctx->psys->part->flag & PART_ANIM_BRANCHING) - seed= 31415926 + ctx->psys->seed + (int)cfra; + if(ctx->sim.psys->part->flag & PART_ANIM_BRANCHING) + seed= 31415926 + ctx->sim.psys->seed + (int)cfra; else - seed= 31415926 + ctx->psys->seed; + seed= 31415926 + ctx->sim.psys->seed; if(part->flag & PART_BRANCHING || ctx->editupdate || totchild < 10000) totthread= 1; @@ -2273,7 +2248,7 @@ int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, in ctx->parent_pass= 0; ctx->cfra= cfra; - psys->lattice = psys_get_lattice(scene, ob, psys); + psys->lattice = psys_get_lattice(&ctx->sim); /* cache all relevant vertex groups if they exist */ if(part->from!=PART_FROM_PARTICLE){ @@ -2299,11 +2274,11 @@ int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, in } /* note: this function must be thread safe, except for branching! */ -void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i) +static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *keys, int i) { ParticleThreadContext *ctx= thread->ctx; - Object *ob= ctx->ob; - ParticleSystem *psys = ctx->psys; + Object *ob= ctx->sim.ob; + ParticleSystem *psys = ctx->sim.psys; ParticleSettings *part = psys->part; ParticleCacheKey **cache= psys->childcache; ParticleCacheKey **pcache= psys->pathcache; @@ -2372,7 +2347,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0); + psys_particle_on_emitter(ctx->sim.psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0); if(part->path_start==0.0f) { /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ @@ -2382,7 +2357,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, pa = psys->particles + cpa->parent; - psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat); pa=0; } @@ -2404,9 +2379,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_num=pa->num; cpa_fuv=pa->fuv; - psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); + psys_particle_on_emitter(ctx->sim.psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); - psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat); } keys->steps = ctx->steps; @@ -2423,7 +2398,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, /* get different child parameters from textures & vgroups */ get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); - if(ptex.exist < cpa->rand[1]) { + if(ptex.exist < PSYS_FRAND(i + 24)) { keys->steps = -1; return; } @@ -2472,7 +2447,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, if(part->flag & PART_CHILD_EFFECT) { for(k=0,state=keys; k<=ctx->steps; k++,state++) { if(k) { - do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec); + do_path_effectors(&ctx->sim, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec); } else { VecSubf(eff_vec,(state+1)->co,state->co); @@ -2498,7 +2473,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t); + do_child_modifiers(&ctx->sim, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t); /* TODO: better branching */ //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) @@ -2575,7 +2550,7 @@ static void *exec_child_path_cache(void *data) { ParticleThread *thread= (ParticleThread*)data; ParticleThreadContext *ctx= thread->ctx; - ParticleSystem *psys= ctx->psys; + ParticleSystem *psys= ctx->sim.psys; ParticleCacheKey **cache= psys->childcache; ChildParticle *cpa; int i, totchild= ctx->totchild, first= 0; @@ -2592,21 +2567,21 @@ static void *exec_child_path_cache(void *data) return 0; } -void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int editupdate) +void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate) { - ParticleSettings *part = psys->part; + ParticleSettings *part = sim->psys->part; ParticleThread *pthreads; ParticleThreadContext *ctx; ParticleCacheKey **cache; ListBase threads; int i, totchild, totparent, totthread; - if(psys->flag & PSYS_GLOBAL_HAIR) + if(sim->psys->flag & PSYS_GLOBAL_HAIR) return; - pthreads= psys_threads_create(scene, ob, psys); + pthreads= psys_threads_create(sim); - if(!psys_threads_init_path(pthreads, scene, cfra, editupdate)) { + if(!psys_threads_init_path(pthreads, sim->scene, cfra, editupdate)) { psys_threads_free(pthreads); return; } @@ -2615,14 +2590,14 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa totchild= ctx->totchild; totparent= ctx->totparent; - if(editupdate && psys->childcache && !(part->flag & PART_BRANCHING) && totchild == psys->totchildcache) { - cache = psys->childcache; + if(editupdate && sim->psys->childcache && !(part->flag & PART_BRANCHING) && totchild == sim->psys->totchildcache) { + cache = sim->psys->childcache; } else { /* clear out old and create new empty path cache */ - free_child_path_cache(psys); - psys->childcache= psys_alloc_path_cache_buffers(&psys->childcachebufs, totchild, ctx->steps+1); - psys->totchildcache = totchild; + free_child_path_cache(sim->psys); + sim->psys->childcache= psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx->steps+1); + sim->psys->totchildcache = totchild; } totthread= pthreads[0].tot; @@ -2660,27 +2635,29 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa /* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */ /* -Makes child strands possible and creates them too into the cache. */ /* -Cached path data is also used to determine cut position for the editmode tool. */ -void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra) +void psys_cache_paths(ParticleSimulationData *sim, float cfra) { - ParticleCacheKey *ca, **cache= psys->pathcache; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + PARTICLE_PSMD; + ParticleEditSettings *pset = &sim->scene->toolsettings->particle; + ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - ParticleEditSettings *pset = &scene->toolsettings->particle; + ParticleCacheKey *ca, **cache= psys->pathcache; DerivedMesh *hair_dm = psys->hair_out_dm; - ParticleData *pa = psys->particles; ParticleKey result; Material *ma; ParticleInterpolationData pind; + + PARTICLE_P; float birthtime = 0.0, dietime = 0.0; - float t, time = 0.0, dfra = 1.0, frs_sec = scene->r.frs_sec; + float t, time = 0.0, dfra = 1.0, frs_sec = sim->scene->r.frs_sec; float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}; float prev_tangent[3], hairmat[4][4]; float rotmat[3][3]; - int k,i; + int k; int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; @@ -2692,7 +2669,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra if((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0) return; - if(psys_in_edit_mode(scene, psys)) + if(psys_in_edit_mode(sim->scene, psys)) if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0) return; @@ -2705,8 +2682,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra psys_free_path_cache(psys, psys->edit); cache= psys->pathcache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1); - psys->lattice = psys_get_lattice(scene, ob, psys); - ma= give_current_material(ob, psys->part->omat); + psys->lattice = psys_get_lattice(sim); + ma= give_current_material(sim->ob, psys->part->omat); if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) @@ -2719,12 +2696,9 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra } /*---first main loop: create all actual particles' paths---*/ - for(i=0; iflag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) - continue; - + LOOP_SHOWN_PARTICLES { if(!psys->totchild) { - BLI_srandom(psys->seed + i); + BLI_srandom(psys->seed + p); pa_length = 1.0f - part->randlength * BLI_frand(); if(vg_length) pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length); @@ -2736,15 +2710,15 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); pind.dm = hair_dm; - memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); + memset(cache[p], 0, sizeof(*cache[p])*(steps+1)); - cache[i]->steps = steps; + cache[p]->steps = steps; /*--get the first data points--*/ - init_particle_interpolation(ob, psys, pa, &pind); + init_particle_interpolation(sim->ob, sim->psys, pa, &pind); /* hairmat is needed for for non-hair particle too so we get proper rotations */ - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, psmd->dm, psys->part->from, pa, hairmat); VECCOPY(rotmat[0], hairmat[2]); VECCOPY(rotmat[1], hairmat[1]); VECCOPY(rotmat[2], hairmat[0]); @@ -2760,26 +2734,26 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra } if(birthtime >= dietime) { - cache[i]->steps = -1; + cache[p]->steps = -1; continue; } dietime = birthtime + pa_length * (dietime - birthtime); /*--interpolate actual path from data points--*/ - for(k=0, ca=cache[i]; k<=steps; k++, ca++){ + for(k=0, ca=cache[p]; k<=steps; k++, ca++){ time = (float)k / (float)steps; t = birthtime + time * (dietime - birthtime); result.time = -t; - do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); + do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, &result); /* dynamic hair is in object space */ /* keyed and baked are allready in global space */ if(hair_dm) - Mat4MulVecfl(ob->obmat, result.co); + Mat4MulVecfl(sim->ob->obmat, result.co); else if(!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) Mat4MulVecfl(hairmat, result.co); @@ -2789,23 +2763,23 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra /*--modify paths and calculate rotation & velocity--*/ - VecSubf(vec,(cache[i]+1)->co,cache[i]->co); + VecSubf(vec,(cache[p]+1)->co,cache[p]->co); length = VecLength(vec); effector= 1.0f; if(vg_effector) effector*= psys_particle_value_from_verts(psmd->dm,psys->part->from,pa,vg_effector); - for(k=0, ca=cache[i]; k<=steps; k++, ca++) { + for(k=0, ca=cache[p]; k<=steps; k++, ca++) { if(!(psys->flag & PSYS_GLOBAL_HAIR)) { /* apply effectors */ if(!(psys->part->flag & PART_CHILD_EFFECT) && k) - do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); + do_path_effectors(sim, p, ca, k, steps, cache[p]->co, effector, dfra, cfra, &length, vec); /* apply guide curves to path data */ if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) /* ca is safe to cast, since only co and vel are used */ - do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); + do_guide(sim->scene, (ParticleKey*)ca, p, (float)k/(float)steps, &psys->effectors); /* apply lattice */ if(psys->lattice) @@ -3021,23 +2995,6 @@ void psys_get_from_key(ParticleKey *key, float *loc, float *vel, float *rot, flo if(time) *time=key->time; } /*-------changing particle keys from space to another-------*/ -void psys_key_to_object(Object *ob, ParticleKey *key, float imat[][4]){ - float q[4], imat2[4][4]; - - if(imat==0){ - Mat4Invert(imat2,ob->obmat); - imat=imat2; - } - - VECADD(key->vel,key->vel,key->co); - - Mat4MulVecfl(imat,key->co); - Mat4MulVecfl(imat,key->vel); - Mat4ToQuat(imat,q); - - VECSUB(key->vel,key->vel,key->co); - QuatMul(key->rot,q,key->rot); -} #if 0 static void key_from_object(Object *ob, ParticleKey *key){ float q[4]; @@ -3410,41 +3367,6 @@ void psys_flush_particle_settings(Scene *scene, ParticleSettings *part, int reca } } -LinkNode *psys_using_settings(struct Scene *scene, ParticleSettings *part, int flush_update) -{ - Object *ob, *tob; - ParticleSystem *psys, *tpsys; - LinkNode *node= NULL; - int found; - - /* update all that have same particle settings */ - for(ob=G.main->object.first; ob; ob=ob->id.next) { - found= 0; - - for(psys=ob->particlesystem.first; psys; psys=psys->next) { - if(psys->part == part) { - BLI_linklist_append(&node, psys); - found++; - } - else if(psys->part->type == PART_REACTOR){ - tob= (psys->target_ob)? psys->target_ob: ob; - tpsys= BLI_findlink(&tob->particlesystem, psys->target_psys-1); - - if(tpsys && tpsys->part==part) { - BLI_linklist_append(&node, tpsys); - found++; - } - } - } - - if(flush_update && found) - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - } - - return node; -} - - /************************************************/ /* Textures */ /************************************************/ @@ -3541,7 +3463,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float } if(event & MAP_PA_DENS) { CLAMP(ptex->exist,0.0,1.0); } } -void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleData *pa, ParticleTexture *ptex, int event) +void psys_get_texture(ParticleSimulationData *sim, Material *ma, ParticleData *pa, ParticleTexture *ptex, int event) { MTex *mtex; int m; @@ -3556,14 +3478,14 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd short blend=mtex->blendtype; short neg=mtex->pmaptoneg; - if((mtex->texco & TEXCO_UV) && ELEM(psys->part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if(!get_particle_uv(psmd->dm, pa, 0, pa->fuv, mtex->uvname, texco)) { + if((mtex->texco & TEXCO_UV) && ELEM(sim->psys->part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if(!get_particle_uv(sim->psmd->dm, pa, 0, pa->fuv, mtex->uvname, texco)) { /* failed to get uv's, let's try orco's */ - psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); + psys_particle_on_emitter(sim->psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); } } else { - psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); + psys_particle_on_emitter(sim->psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); } externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3); @@ -3608,38 +3530,9 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd /************************************************/ /* Particle State */ /************************************************/ -float psys_get_timestep(ParticleSettings *part) +float psys_get_timestep(ParticleSimulationData *sim) { - return 0.04f*part->timetweak; -} -/* part->size should be updated with possible ipo effection before this is called */ -float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, IpoCurve *icu_size, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, float *vg_size) -{ - ParticleTexture ptex; - float size=1.0f; - - BLI_srandom(psys->seed + (pa - psys->particles) + 100); - - if(ma && part->from!=PART_FROM_PARTICLE){ - ptex.size=size; - psys_get_texture(ob,ma,psmd,psys,pa,&ptex,MAP_PA_SIZE); - size=ptex.size; - } - -#if 0 // XXX old animation system - if(icu_size){ - calc_icu(icu_size,pa->time); - size*=icu_size->curval; - } -#endif // XXX old animation system - - if(vg_size) - size*=psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_size); - - if(part->randsize!=0.0) - size*= 1.0f - part->randsize * BLI_frand(); - - return size*part->size; + return 0.04f * sim->psys->part->timetweak; } float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime) { @@ -3654,7 +3547,7 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, w++; } - life = part->lifetime*(1.0f-part->randlife*cpa->rand[1]); + life = part->lifetime * (1.0f - part->randlife * PSYS_FRAND(cpa - psys->child + 25)); } else{ ParticleData *pa = psys->particles + cpa->parent; @@ -3703,13 +3596,16 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, size*=part->childsize; if(part->childrandsize!=0.0) - size *= 1.0f - part->childrandsize*cpa->rand[2]; + size *= 1.0f - part->childrandsize * PSYS_FRAND(cpa - psys->child + 26); return size; } static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex) { - ptex->length= 1.0f - part->randlength*cpa->rand[0]; + ParticleSystem *psys = ctx->sim.psys; + int i = cpa - psys->child; + + ptex->length= 1.0f - part->randlength * PSYS_FRAND(i + 26); ptex->clump=1.0; ptex->kink=1.0; ptex->rough1= 1.0; @@ -3718,13 +3614,13 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread ptex->exist= 1.0; ptex->effector= 1.0; - ptex->length*= part->clength_thres < cpa->rand[1] ? part->clength : 1.0f; + ptex->length*= part->clength_thres < PSYS_FRAND(i + 27) ? part->clength : 1.0f; get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,ptex, MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH); - if(ptex->exist < cpa->rand[1]) + if(ptex->exist < PSYS_FRAND(i + 24)) return; if(ctx->vg_length) @@ -3742,18 +3638,20 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread if(ctx->vg_effector) ptex->effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); } -static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t) +static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t) { + ParticleSettings *part = sim->psys->part; + int i = cpa - sim->psys->child; int guided = 0; if(part->flag & PART_CHILD_EFFECT) /* state is safe to cast, since only co and vel are used */ - guided = do_guide(scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors)); + guided = do_guide(sim->scene, (ParticleKey*)state, cpa->parent, t, &(sim->psys->effectors)); if(guided==0){ if(part->kink) do_prekink(state, par, par_rot, t, part->kink_freq * ptex->kink, part->kink_shape, - part->kink_amp, part->kink, part->kink_axis, ob->obmat); + part->kink_amp, part->kink, part->kink_axis, sim->ob->obmat); do_clump(state, par, t, part->clumpfac, part->clumppow, ptex->clump); } @@ -3762,17 +3660,18 @@ static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, P do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state); if(part->rough2 != 0.0 && ptex->rough2 != 0.0) - do_rough(cpa->rand, mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state); + do_rough(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state); if(part->rough_end != 0.0 && ptex->roughe != 0.0) - do_rough_end(cpa->rand, mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state); + do_rough_end(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state); } /* get's hair (or keyed) particles state at the "path time" specified in state->time */ -void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel) +void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, int vel) { - ParticleSettings *part = psys->part; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - Material *ma = give_current_material(ob, part->omat); + PARTICLE_PSMD; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = sim->psys->part; + Material *ma = give_current_material(sim->ob, part->omat); ParticleData *pa; ChildParticle *cpa; ParticleTexture ptex; @@ -3780,7 +3679,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i ParticleThreadContext ctx; /* fake thread context for child modifiers */ ParticleInterpolationData pind; - float t, frs_sec = scene->r.frs_sec; + float t, frs_sec = sim->scene->r.frs_sec; float co[3], orco[3]; float hairmat[4][4]; int totparent = 0; @@ -3808,17 +3707,17 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i pind.cache = cached ? psys->pointcache : NULL; pind.epoint = NULL; pind.dm = psys->hair_out_dm; - init_particle_interpolation(ob, psys, pa, &pind); + init_particle_interpolation(sim->ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state); if(!keyed && !cached) { if((pa->flag & PARS_REKEY)==0) { - psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, sim->psmd->dm, part->from, pa, hairmat); Mat4MulVecfl(hairmat, state->co); Mat4Mul3Vecfl(hairmat, state->vel); if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { - do_guide(scene, state, p, state->time, &psys->effectors); + do_guide(sim->scene, state, p, state->time, &psys->effectors); /* TODO: proper velocity handling */ } @@ -3851,7 +3750,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i /* get parent states */ while(w<4 && cpa->pa[w]>=0){ keys[w].time = state->time; - psys_get_particle_on_path(scene, ob, psys, cpa->pa[w], keys+w, 1); + psys_get_particle_on_path(sim, cpa->pa[w], keys+w, 1); w++; } @@ -3871,14 +3770,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i pa = psys->particles + cpa->parent; - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); pa=0; } else{ /* get the parent state */ keys->time = state->time; - psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1); + psys_get_particle_on_path(sim, cpa->parent, keys,1); /* get the original coordinates (orco) for texture usage */ pa=psys->particles+cpa->parent; @@ -3889,7 +3788,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0); - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); } /* correct child ipo timing */ @@ -3938,7 +3837,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i copy_particle_key(&tstate, state, 1); /* apply different deformations to the child path */ - do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, hairmat, state, t); + do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t); /* try to estimate correct velocity */ if(vel){ @@ -3947,13 +3846,13 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i if(t>=0.001f){ tstate.time=t-0.001f; - psys_get_particle_on_path(scene,ob,psys,p,&tstate,0); + psys_get_particle_on_path(sim,p,&tstate,0); VECSUB(state->vel,state->co,tstate.co); Normalize(state->vel); } else{ tstate.time=t+0.001f; - psys_get_particle_on_path(scene, ob,psys,p,&tstate,0); + psys_get_particle_on_path(sim,p,&tstate,0); VECSUB(state->vel,tstate.co,state->co); Normalize(state->vel); } @@ -3963,39 +3862,52 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i } } /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */ -int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int always){ - ParticleSettings *part=psys->part; - ParticleData *pa=0; +int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, int always){ + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + ParticleData *pa = NULL; + ChildParticle *cpa = NULL; float cfra; - int totpart=psys->totpart, between=0; + int totpart = psys->totpart, between = 0; /* negative time means "use current time" */ - if(state->time>0) - cfra=state->time; - else - cfra= bsystem_time(scene, 0, (float)scene->r.cfra,0.0); + cfra = state->time > 0 ? state->time : bsystem_time(sim->scene, 0, (float)sim->scene->r.cfra, 0.0); - if(psys->totchild && p>=totpart){ - if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ - between=1; + if(p>=totpart){ + if(!psys->totchild) + return 0; + + if(part->from != PART_FROM_PARTICLE && part->childtype == PART_CHILD_FACES){ + if(!(psys->flag & PSYS_KEYED)) + return 0; + + cpa = psys->child + p - totpart; + + state->time = psys_get_child_time(psys, cpa, cfra, NULL, NULL); + + if(!always) + if((state->time < 0.0 && !(part->flag & PART_UNBORN)) + || (state->time > 1.0 && !(part->flag & PART_DIED))) + return 0; + + state->time= (cfra - (part->sta + (part->end - part->sta) * PSYS_FRAND(p + 23))) / (part->lifetime * PSYS_FRAND(p + 24)); + + psys_get_particle_on_path(sim, p, state,1); + return 1; + } + else { + cpa = sim->psys->child + p - totpart; + pa = sim->psys->particles + cpa->parent; } - else - pa=psys->particles+(psys->child+p-totpart)->parent; } - else - pa=psys->particles+p; + else { + pa = sim->psys->particles + p; + } - if(between){ - state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra,NULL,NULL); + if(pa) { + if(pa->alive == PARS_KILLED) return 0; - if(always==0) - if((state->time<0.0 && (part->flag & PART_UNBORN)==0) - || (state->time>1.0 && (part->flag & PART_DIED)==0)) - return 0; - } - else{ - if(pa->alive==PARS_KILLED) return 0; - if(always==0) + if(!always) if((pa->alive==PARS_UNBORN && (part->flag & PART_UNBORN)==0) || (pa->alive==PARS_DEAD && (part->flag & PART_DIED)==0)) return 0; @@ -4003,38 +3915,28 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy state->time = MIN2(state->time, pa->dietime); } - if(psys->flag & PSYS_KEYED){ - if(between){ - ChildParticle *cpa=psys->child+p-totpart; - state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); - } - else - state->time= -cfra; - - psys_get_particle_on_path(scene, ob, psys, p, state,1); + if(sim->psys->flag & PSYS_KEYED){ + state->time= -cfra; + psys_get_particle_on_path(sim, p, state,1); return 1; } else{ - if(between) - return 0; /* currently not supported */ - else if(psys->totchild && p>=psys->totpart){ - ChildParticle *cpa=psys->child+p-psys->totpart; + if(cpa){ ParticleKey *key1; float t = (cfra - pa->time + pa->loop * pa->lifetime) / pa->lifetime; - pa = psys->particles + cpa->parent; key1=&pa->state; offset_child(cpa, key1, state, part->childflat, part->childrad); CLAMP(t,0.0,1.0); if(part->kink) /* TODO: part->kink_freq*pa_kink */ - do_prekink(state,key1,key1->rot,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); + do_prekink(state,key1,key1->rot,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,sim->ob->obmat); /* TODO: pa_clump vgroup */ do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0); if(psys->lattice) - calc_latt_deform(psys->lattice, state->co,1.0f); + calc_latt_deform(sim->psys->lattice, state->co,1.0f); } else{ if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) @@ -4045,7 +3947,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy /* let's interpolate to try to be as accurate as possible */ if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { ParticleKey keys[4]; - float dfra, keytime, frs_sec = scene->r.frs_sec; + float dfra, keytime, frs_sec = sim->scene->r.frs_sec; if(pa->prev_state.time >= pa->state.time) { /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ @@ -4080,8 +3982,8 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy } } - if(psys->lattice) - calc_latt_deform(psys->lattice, state->co,1.0f); + if(sim->psys->lattice) + calc_latt_deform(sim->psys->lattice, state->co,1.0f); } return 1; @@ -4137,8 +4039,11 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo } } -void psys_get_dupli_path_transform(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) +void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) { + Object *ob = sim->ob; + ParticleSystem *psys = sim->psys; + ParticleSystemModifierData *psmd = sim->psmd; float loc[3], nor[3], vec[3], side[3], len, obrotmat[4][4], qmat[4][4]; float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; @@ -4146,7 +4051,7 @@ void psys_get_dupli_path_transform(Object *ob, ParticleSystem *psys, ParticleSys len= Normalize(vec); if(pa) - psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); + psys_particle_on_emitter(psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); else psys_particle_on_emitter(psmd, (psys->part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 26d23399316..9cd897e4bcd 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -164,20 +164,22 @@ void psys_reset(ParticleSystem *psys, int mode) psys->pointcache->simframe= 0; } -static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) +static void realloc_particles(ParticleSimulationData *sim, int new_totpart) { + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; ParticleData *newpars = NULL; BoidParticle *newboids = NULL; PARTICLE_P; int totpart, totsaved = 0; if(new_totpart<0) { - if(psys->part->distr==PART_DISTR_GRID && psys->part->from != PART_FROM_VERT) { - totpart= psys->part->grid_res; + if(part->distr==PART_DISTR_GRID && part->from != PART_FROM_VERT) { + totpart= part->grid_res; totpart*=totpart*totpart; } else - totpart=psys->part->totpart; + totpart=part->totpart; } else totpart=new_totpart; @@ -212,6 +214,7 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) if(pa->hair) MEM_freeN(pa->hair); MEM_freeN(psys->particles); + psys_free_pdd(psys); } psys->particles=newpars; @@ -605,13 +608,13 @@ static int binary_search_distribution(float *sum, int n, float value) /* note: this function must be thread safe, for from == PART_FROM_CHILD */ #define ONLY_WORKING_WITH_PA_VERTS 0 -void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa, int p) +static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa, int p) { ParticleThreadContext *ctx= thread->ctx; - Object *ob= ctx->ob; + Object *ob= ctx->sim.ob; DerivedMesh *dm= ctx->dm; ParticleData *tpa; - ParticleSettings *part= ctx->psys->part; + ParticleSettings *part= ctx->sim.psys->part; float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3], ornor1[3]; float cur_d, min_d, randu, randv; int from= ctx->from; @@ -624,7 +627,6 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C pa->num= ctx->index[p]; pa->fuv[0] = 1.0f; pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0; - //pa->verts[0] = pa->verts[1] = pa->verts[2] = 0; #if ONLY_WORKING_WITH_PA_VERTS if(ctx->tree){ @@ -652,7 +654,6 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel); psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv); ctx->jitoff[i]++; - //ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel); break; case PART_DISTR_RAND: randu= rng_getFloat(thread->rng); @@ -662,12 +663,6 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C } pa->foffset= 0.0f; - /* - pa->verts[0] = mface->v1; - pa->verts[1] = mface->v2; - pa->verts[2] = mface->v3; - */ - /* experimental */ if(from==PART_FROM_VOLUME){ MVert *mvert=dm->getVertDataArray(dm,CD_MVERT); @@ -723,10 +718,6 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C } } else if(from == PART_FROM_PARTICLE) { - //pa->verts[0]=0; /* not applicable */ - //pa->verts[1]=0; - //pa->verts[2]=0; - tpa=ctx->tpars+ctx->index[p]; pa->num=ctx->index[p]; pa->fuv[0]=tpa->fuv[0]; @@ -742,42 +733,30 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C cpa->num=0; cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f; cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0; - cpa->rand[0]=cpa->rand[1]=cpa->rand[2]=0.0f; return; } mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE); - //switch(distr){ - // case PART_DISTR_JIT: - // i=index[p]; - // psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mf->v4, cpa->fuv); - // ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel); - // break; - // case PART_DISTR_RAND: - randu= rng_getFloat(thread->rng); - randv= rng_getFloat(thread->rng); - psys_uv_to_w(randu, randv, mf->v4, cpa->fuv); - // break; - //} + randu= rng_getFloat(thread->rng); + randv= rng_getFloat(thread->rng); + psys_uv_to_w(randu, randv, mf->v4, cpa->fuv); - cpa->rand[0] = rng_getFloat(thread->rng); - cpa->rand[1] = rng_getFloat(thread->rng); - cpa->rand[2] = rng_getFloat(thread->rng); cpa->num = ctx->index[p]; if(ctx->tree){ KDTreeNearest ptn[10]; - int w,maxw, do_seams; + int w,maxw;//, do_seams; float maxd,mind,dd,totw=0.0; int parent[10]; float pweight[10]; - do_seams= (part->flag&PART_CHILD_SEAMS && ctx->seams); + /*do_seams= (part->flag&PART_CHILD_SEAMS && ctx->seams);*/ psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,0,0,orco1,ornor1); transform_mesh_orco_verts((Mesh*)ob->data, &orco1, 1, 1); - maxw = BLI_kdtree_find_n_nearest(ctx->tree,(do_seams)?10:4,orco1,ornor1,ptn); + //maxw = BLI_kdtree_find_n_nearest(ctx->tree,(do_seams)?10:4,orco1,ornor1,ptn); + maxw = BLI_kdtree_find_n_nearest(ctx->tree,4,orco1,ornor1,ptn); maxd=ptn[maxw-1].dist; mind=ptn[0].dist; @@ -787,70 +766,68 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C for(w=0; wseams; - float temp[3],temp2[3],tan[3]; - float inp,cur_len,min_len=10000.0f; - int min_seam=0, near_vert=0; - /* find closest seam */ - for(i=0; itotseam; i++, seam++){ - VecSubf(temp,co1,seam->v0); - inp=Inpf(temp,seam->dir)/seam->length2; - if(inp<0.0f){ - cur_len=VecLenf(co1,seam->v0); - } - else if(inp>1.0f){ - cur_len=VecLenf(co1,seam->v1); - } - else{ - VecCopyf(temp2,seam->dir); - VecMulf(temp2,inp); - cur_len=VecLenf(temp,temp2); - } - if(cur_len1.0f) near_vert=1; - else near_vert=0; - } - } - seam=ctx->seams+min_seam; - - VecCopyf(temp,seam->v0); - - if(near_vert){ - if(near_vert==-1) - VecSubf(tan,co1,seam->v0); - else{ - VecSubf(tan,co1,seam->v1); - VecCopyf(temp,seam->v1); - } + //if(do_seams){ + // ParticleSeam *seam=ctx->seams; + // float temp[3],temp2[3],tan[3]; + // float inp,cur_len,min_len=10000.0f; + // int min_seam=0, near_vert=0; + // /* find closest seam */ + // for(i=0; itotseam; i++, seam++){ + // VecSubf(temp,co1,seam->v0); + // inp=Inpf(temp,seam->dir)/seam->length2; + // if(inp<0.0f){ + // cur_len=VecLenf(co1,seam->v0); + // } + // else if(inp>1.0f){ + // cur_len=VecLenf(co1,seam->v1); + // } + // else{ + // VecCopyf(temp2,seam->dir); + // VecMulf(temp2,inp); + // cur_len=VecLenf(temp,temp2); + // } + // if(cur_len1.0f) near_vert=1; + // else near_vert=0; + // } + // } + // seam=ctx->seams+min_seam; + // + // VecCopyf(temp,seam->v0); + // + // if(near_vert){ + // if(near_vert==-1) + // VecSubf(tan,co1,seam->v0); + // else{ + // VecSubf(tan,co1,seam->v1); + // VecCopyf(temp,seam->v1); + // } + + // Normalize(tan); + // } + // else{ + // VecCopyf(tan,seam->tan); + // VecSubf(temp2,co1,temp); + // if(Inpf(tan,temp2)<0.0f) + // VecNegf(tan); + // } + // for(w=0; wtan); - VecSubf(temp2,co1,temp); - if(Inpf(tan,temp2)<0.0f) - VecNegf(tan); - } - for(w=0; w=0){ @@ -876,7 +853,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C static void *exec_distribution(void *data) { ParticleThread *thread= (ParticleThread*)data; - ParticleSystem *psys= thread->ctx->psys; + ParticleSystem *psys= thread->ctx->sim.psys; ParticleData *pa; ChildParticle *cpa; int p, totpart; @@ -943,11 +920,11 @@ static int compare_orig_index(const void *p1, const void *p2) /* 6. and we're done! */ /* This is to denote functionality that does not yet work with mesh - only derived mesh */ -int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, DerivedMesh *finaldm, int from) +static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, DerivedMesh *finaldm, int from) { ParticleThreadContext *ctx= threads[0].ctx; - Object *ob= ctx->ob; - ParticleSystem *psys= ctx->psys; + Object *ob= ctx->sim.ob; + ParticleSystem *psys= ctx->sim.psys; Object *tob; ParticleData *pa=0, *tpars= 0; ParticleSettings *part; @@ -999,49 +976,49 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive totpart=get_psys_tot_child(scene, psys); cfrom=from=PART_FROM_FACE; - if(part->flag&PART_CHILD_SEAMS){ - MEdge *ed, *medge=dm->getEdgeDataArray(dm,CD_MEDGE); - MVert *mvert=dm->getVertDataArray(dm,CD_MVERT); - int totedge=dm->getNumEdges(dm); + //if(part->flag&PART_CHILD_SEAMS){ + // MEdge *ed, *medge=dm->getEdgeDataArray(dm,CD_MEDGE); + // MVert *mvert=dm->getVertDataArray(dm,CD_MVERT); + // int totedge=dm->getNumEdges(dm); - for(p=0, ed=medge; pflag&ME_SEAM) - totseam++; + // for(p=0, ed=medge; pflag&ME_SEAM) + // totseam++; - if(totseam){ - ParticleSeam *cur_seam=seams=MEM_callocN(totseam*sizeof(ParticleSeam),"Child Distribution Seams"); - float temp[3],temp2[3]; + // if(totseam){ + // ParticleSeam *cur_seam=seams=MEM_callocN(totseam*sizeof(ParticleSeam),"Child Distribution Seams"); + // float temp[3],temp2[3]; - for(p=0, ed=medge; pflag&ME_SEAM){ - VecCopyf(cur_seam->v0,(mvert+ed->v1)->co); - VecCopyf(cur_seam->v1,(mvert+ed->v2)->co); + // for(p=0, ed=medge; pflag&ME_SEAM){ + // VecCopyf(cur_seam->v0,(mvert+ed->v1)->co); + // VecCopyf(cur_seam->v1,(mvert+ed->v2)->co); - VecSubf(cur_seam->dir,cur_seam->v1,cur_seam->v0); + // VecSubf(cur_seam->dir,cur_seam->v1,cur_seam->v0); - cur_seam->length2=VecLength(cur_seam->dir); - cur_seam->length2*=cur_seam->length2; + // cur_seam->length2=VecLength(cur_seam->dir); + // cur_seam->length2*=cur_seam->length2; - temp[0]=(float)((mvert+ed->v1)->no[0]); - temp[1]=(float)((mvert+ed->v1)->no[1]); - temp[2]=(float)((mvert+ed->v1)->no[2]); - temp2[0]=(float)((mvert+ed->v2)->no[0]); - temp2[1]=(float)((mvert+ed->v2)->no[1]); - temp2[2]=(float)((mvert+ed->v2)->no[2]); + // temp[0]=(float)((mvert+ed->v1)->no[0]); + // temp[1]=(float)((mvert+ed->v1)->no[1]); + // temp[2]=(float)((mvert+ed->v1)->no[2]); + // temp2[0]=(float)((mvert+ed->v2)->no[0]); + // temp2[1]=(float)((mvert+ed->v2)->no[1]); + // temp2[2]=(float)((mvert+ed->v2)->no[2]); - VecAddf(cur_seam->nor,temp,temp2); - Normalize(cur_seam->nor); + // VecAddf(cur_seam->nor,temp,temp2); + // Normalize(cur_seam->nor); - Crossf(cur_seam->tan,cur_seam->dir,cur_seam->nor); + // Crossf(cur_seam->tan,cur_seam->dir,cur_seam->nor); - Normalize(cur_seam->tan); + // Normalize(cur_seam->tan); - cur_seam++; - } - } - } - - } + // cur_seam++; + // } + // } + // } + // + //} } else{ /* no need to figure out distribution */ @@ -1063,10 +1040,6 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive length=VecLength(cpa->fuv); } - cpa->rand[0]=BLI_frand(); - cpa->rand[1]=BLI_frand(); - cpa->rand[2]=BLI_frand(); - cpa->num=-1; } } @@ -1345,7 +1318,6 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive jitlevel= totpart/tot; if(part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ if(jitlevel<3) jitlevel= 3; - //if(jitlevel>100) jitlevel= 100; } jit= MEM_callocN((2+ jitlevel*2)*sizeof(float), "jit"); @@ -1364,7 +1336,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive ctx->tree= tree; ctx->seams= seams; ctx->totseam= totseam; - ctx->psys= psys; + ctx->sim.psys= psys; ctx->index= index; ctx->jit= jit; ctx->jitlevel= jitlevel; @@ -1385,7 +1357,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive if(!children || psys->totchild < 10000) totthread= 1; - seed= 31415926 + ctx->psys->seed; + seed= 31415926 + ctx->sim.psys->seed; for(i=0; ipsmd->dm; ListBase threads; ParticleThread *pthreads; ParticleThreadContext *ctx; int i, totthread; - pthreads= psys_threads_create(scene, ob, psys); + pthreads= psys_threads_create(sim); - if(!psys_threads_init_distribution(pthreads, scene, finaldm, from)) { + if(!psys_threads_init_distribution(pthreads, sim->scene, finaldm, from)) { psys_threads_free(pthreads); return; } @@ -1420,7 +1393,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Scene *scene, Objec else exec_distribution(&pthreads[0]); - psys_calc_dmcache(ob, finaldm, psys); + psys_calc_dmcache(sim->ob, finaldm, sim->psys); ctx= pthreads[0].ctx; if(ctx->dm != finaldm) @@ -1430,8 +1403,9 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Scene *scene, Objec } /* ready for future use, to emit particles without geometry */ -static void distribute_particles_on_shape(Object *ob, ParticleSystem *psys, int from) +static void distribute_particles_on_shape(ParticleSimulationData *sim, int from) { + ParticleSystem *psys = sim->psys; PARTICLE_P; fprintf(stderr,"Shape emission not yet possible!\n"); @@ -1442,22 +1416,22 @@ static void distribute_particles_on_shape(Object *ob, ParticleSystem *psys, int pa->num= -1; } } -static void distribute_particles(Scene *scene, Object *ob, ParticleSystem *psys, int from) +static void distribute_particles(ParticleSimulationData *sim, int from) { - ParticleSystemModifierData *psmd=0; + PARTICLE_PSMD; int distr_error=0; - psmd=psys_get_modifier(ob,psys); if(psmd){ if(psmd->dm) - distribute_particles_on_dm(psmd->dm, scene, ob, psys, from); + distribute_particles_on_dm(sim, from); else distr_error=1; } else - distribute_particles_on_shape(ob,psys,from); + distribute_particles_on_shape(sim, from); if(distr_error){ + ParticleSystem *psys = sim->psys; PARTICLE_P; fprintf(stderr,"Particle distribution error!\n"); @@ -1471,26 +1445,23 @@ static void distribute_particles(Scene *scene, Object *ob, ParticleSystem *psys, } /* threaded child particle distribution and path caching */ -ParticleThread *psys_threads_create(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys) +ParticleThread *psys_threads_create(ParticleSimulationData *sim) { ParticleThread *threads; ParticleThreadContext *ctx; int i, totthread; - if(scene->r.mode & R_FIXED_THREADS) - totthread= scene->r.threads; + if(sim->scene->r.mode & R_FIXED_THREADS) + totthread= sim->scene->r.threads; else totthread= BLI_system_thread_count(); threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread"); ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext"); - ctx->scene= scene; - ctx->ob= ob; - ctx->psys= psys; - ctx->psmd= psys_get_modifier(ob, psys); - ctx->dm= ctx->psmd->dm; - ctx->ma= give_current_material(ob, psys->part->omat); + ctx->sim = *sim; + ctx->dm= ctx->sim.psmd->dm; + ctx->ma= give_current_material(sim->ob, sim->psys->part->omat); memset(threads, 0, sizeof(ParticleThread)*totthread); @@ -1522,9 +1493,9 @@ void psys_threads_free(ParticleThread *threads) if(ctx->vg_roughe) MEM_freeN(ctx->vg_roughe); - if(ctx->psys->lattice){ - end_latt_deform(ctx->psys->lattice); - ctx->psys->lattice= NULL; + if(ctx->sim.psys->lattice){ + end_latt_deform(ctx->sim.psys->lattice); + ctx->sim.psys->lattice= NULL; } /* distribution */ @@ -1550,37 +1521,34 @@ void psys_threads_free(ParticleThread *threads) } /* set particle parameters that don't change during particle's life */ -void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd) +void initialize_particle(ParticleSimulationData *sim, ParticleData *pa, int p) { - ParticleSettings *part; + ParticleSettings *part = sim->psys->part; ParticleTexture ptex; Material *ma=0; //IpoCurve *icu=0; // XXX old animation system int totpart; - float rand; - - part=psys->part; - totpart=psys->totpart; + totpart=sim->psys->totpart; ptex.life=ptex.size=ptex.exist=ptex.length=1.0; ptex.time=(float)p/(float)totpart; - BLI_srandom(psys->seed+p); + BLI_srandom(sim->psys->seed + p + 125); if(part->from!=PART_FROM_PARTICLE && part->type!=PART_FLUID){ - ma=give_current_material(ob,part->omat); + ma=give_current_material(sim->ob,part->omat); /* TODO: needs some work to make most blendtypes generally usefull */ - psys_get_texture(ob,ma,psmd,psys,pa,&ptex,MAP_PA_INIT); + psys_get_texture(sim,ma,pa,&ptex,MAP_PA_INIT); } pa->lifetime= part->lifetime*ptex.life; if(part->type==PART_HAIR) pa->time= 0.0f; - else if(part->type==PART_REACTOR && (part->flag&PART_REACT_STA_END)==0) - pa->time= 300000.0f; /* max frame */ + //else if(part->type==PART_REACTOR && (part->flag&PART_REACT_STA_END)==0) + // pa->time= 300000.0f; /* max frame */ else{ //icu=find_ipocurve(psys->part->ipo,PART_EMIT_TIME); //if(icu){ @@ -1604,10 +1572,8 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps } #endif // XXX old animation system - /* need to get every rand even if we don't use them so that randoms don't affect each other */ - rand= BLI_frand(); if(part->randlife!=0.0) - pa->lifetime*= 1.0f - part->randlife*rand; + pa->lifetime*= 1.0f - part->randlife * BLI_frand(); } pa->dietime= pa->time+pa->lifetime; @@ -1624,13 +1590,14 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps /* usage other than straight after distribute has to handle this index by itself - jahka*/ //pa->num_dmcache = DMCACHE_NOTFOUND; /* assume we dont have a derived mesh face */ } -static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd) +static void initialize_all_particles(ParticleSimulationData *sim) { //IpoCurve *icu=0; // XXX old animation system + ParticleSystem *psys = sim->psys; PARTICLE_P; LOOP_PARTICLES - initialize_particle(pa,p,ob,psys,psmd); + initialize_particle(sim, pa, p); if(psys->part->type != PART_FLUID) { #if 0 // XXX old animation system @@ -1687,66 +1654,51 @@ static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleS } } /* sets particle to the emitter surface with initial velocity & rotation */ -void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, ParticleSystemModifierData *psmd, Object *ob, - float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot) +void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra) { + Object *ob = sim->ob; + ParticleSystem *psys = sim->psys; ParticleSettings *part; ParticleTexture ptex; ParticleKey state; //IpoCurve *icu=0; // XXX old animation system - float fac, phasefac, nor[3]={0,0,0},loc[3],tloc[3],vel[3]={0.0,0.0,0.0},rot[4],q2[4]; + float fac, phasefac, nor[3]={0,0,0},loc[3],vel[3]={0.0,0.0,0.0},rot[4],q2[4]; float r_vel[3],r_ave[3],r_rot[4],p_vel[3]={0.0,0.0,0.0}; float x_vec[3]={1.0,0.0,0.0}, utan[3]={0.0,1.0,0.0}, vtan[3]={0.0,0.0,1.0}, rot_vec[3]={0.0,0.0,0.0}; - float q_phase[4], length, r_phase; + float q_phase[4], r_phase; + int p = pa - psys->particles; part=psys->part; ptex.ivel=1.0; - BLI_srandom(psys->seed + (pa - psys->particles)); - /* we need to get every random even if they're not used so that they don't effect eachother */ - /* while loops are to have a spherical distribution (avoid cubic distribution) */ - length=2.0f; - while(length>1.0){ - r_vel[0]=2.0f*(BLI_frand()-0.5f); - r_vel[1]=2.0f*(BLI_frand()-0.5f); - r_vel[2]=2.0f*(BLI_frand()-0.5f); - length=VecLength(r_vel); - } - - length=2.0f; - while(length>1.0){ - r_ave[0]=2.0f*(BLI_frand()-0.5f); - r_ave[1]=2.0f*(BLI_frand()-0.5f); - r_ave[2]=2.0f*(BLI_frand()-0.5f); - length=VecLength(r_ave); - } - - r_rot[0]=2.0f*(BLI_frand()-0.5f); - r_rot[1]=2.0f*(BLI_frand()-0.5f); - r_rot[2]=2.0f*(BLI_frand()-0.5f); - r_rot[3]=2.0f*(BLI_frand()-0.5f); - + r_vel[0] = 2.0f * (PSYS_FRAND(p + 10) - 0.5f); + r_vel[1] = 2.0f * (PSYS_FRAND(p + 11) - 0.5f); + r_vel[2] = 2.0f * (PSYS_FRAND(p + 12) - 0.5f); + + r_ave[0] = 2.0f * (PSYS_FRAND(p + 13) - 0.5f); + r_ave[1] = 2.0f * (PSYS_FRAND(p + 14) - 0.5f); + r_ave[2] = 2.0f * (PSYS_FRAND(p + 15) - 0.5f); + + r_rot[0] = 2.0f * (PSYS_FRAND(p + 16) - 0.5f); + r_rot[1] = 2.0f * (PSYS_FRAND(p + 17) - 0.5f); + r_rot[2] = 2.0f * (PSYS_FRAND(p + 18) - 0.5f); + r_rot[3] = 2.0f * (PSYS_FRAND(p + 19) - 0.5f); NormalQuat(r_rot); - r_phase = BLI_frand(); + r_phase = PSYS_FRAND(p + 20); if(part->from==PART_FROM_PARTICLE){ - Object *tob; - ParticleSystem *tpsys=0; + ParticleSimulationData tsim = {sim->scene, psys->target_ob ? psys->target_ob : ob, NULL, NULL}; float speed; - tob=psys->target_ob; - if(tob==0) - tob=ob; - - tpsys=BLI_findlink(&tob->particlesystem, psys->target_psys-1); + tsim.psys = BLI_findlink(&tsim.ob->particlesystem, sim->psys->target_psys-1); state.time = pa->time; if(pa->num == -1) memset(&state, 0, sizeof(state)); else - psys_get_particle_state(scene, tob,tpsys,pa->num,&state,1); + psys_get_particle_state(&tsim, pa->num, &state, 1); psys_get_from_key(&state, loc, nor, rot, 0); QuatMulVecf(rot, vtan); @@ -1763,23 +1715,20 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic } else{ /* get precise emitter matrix if particle is born */ - if(part->type!=PART_HAIR && pa->time < cfra && pa->time >= psys->cfra) - where_is_object_time(scene, ob,pa->time); + if(part->type!=PART_HAIR && pa->time < cfra && pa->time >= sim->psys->cfra) + where_is_object_time(sim->scene, sim->ob, pa->time); /* get birth location from object */ if(part->tanfac!=0.0) - psys_particle_on_emitter(psmd,part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0); + psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0); else - psys_particle_on_emitter(psmd,part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0); - - /* save local coordinates for later */ - VECCOPY(tloc,loc); + psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0); /* get possible textural influence */ - psys_get_texture(ob,give_current_material(ob,part->omat),psmd,psys,pa,&ptex,MAP_PA_IVEL); + psys_get_texture(sim, give_current_material(sim->ob,part->omat), pa, &ptex, MAP_PA_IVEL); - if(vg_vel && pa->num != -1) - ptex.ivel*=psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_vel); + //if(vg_vel && pa->num != -1) + // ptex.ivel*=psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_vel); /* particles live in global space so */ /* let's convert: */ @@ -1787,21 +1736,18 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic Mat4MulVecfl(ob->obmat,loc); /* -normal */ - VECADD(nor,tloc,nor); - Mat4MulVecfl(ob->obmat,nor); - VECSUB(nor,nor,loc); + Mat4Mul3Vecfl(ob->obmat,nor); Normalize(nor); /* -tangent */ if(part->tanfac!=0.0){ - float phase=vg_rot?2.0f*(psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_rot)-0.5f):0.0f; + //float phase=vg_rot?2.0f*(psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_rot)-0.5f):0.0f; + float phase=0.0f; VecMulf(vtan,-(float)cos(M_PI*(part->tanphase+phase))); fac=-(float)sin(M_PI*(part->tanphase+phase)); VECADDFAC(vtan,vtan,utan,fac); - VECADD(vtan,tloc,vtan); - Mat4MulVecfl(ob->obmat,vtan); - VECSUB(vtan,vtan,loc); + Mat4Mul3Vecfl(ob->obmat,vtan); VECCOPY(utan,nor); VecMulf(utan,Inpf(vtan,nor)); @@ -1853,11 +1799,6 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic if(part->acc[2]!=0.0f) bpa->gravity[2] = part->acc[2]; - //pa->r_ve[0] = pa->r_ve[1] = 0.0f; - //pa->r_ve[2] = -1.0f; - //if(part->acc[2]!=0.0f) - // pa->r_ve[2] = part->acc[2]; - /* calculate rotation matrix */ Projf(dvec, r_vel, pa->state.ave); VecSubf(mat[0], pa->state.ave, dvec); @@ -1896,8 +1837,9 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic VECADDFAC(vel,vel,nor,part->normfac); /* *emitter tangent */ - if(psmd && part->tanfac!=0.0) - VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f)); + if(sim->psmd && part->tanfac!=0.0) + VECADDFAC(vel,vel,vtan,part->tanfac); + //VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_tan):1.0f)); /* *texture */ /* TODO */ @@ -1917,9 +1859,6 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic //} VecMulf(vel,ptex.ivel); - - //if(ELEM(part->phystype, PART_PHYS_GRADU_EX, PART_PHYS_GRADU_SIM)) - // VecAddf(vel,vel,part->acc); VECCOPY(pa->state.vel,vel); @@ -2001,22 +1940,20 @@ void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, Partic pa->alive = PARS_UNBORN; pa->state.time = cfra; - -// pa->flag &= ~PARS_STICKY; } -static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float dtime, float cfra, int from) +static void reset_all_particles(ParticleSimulationData *sim, float dtime, float cfra, int from) { ParticleData *pa; - int p, totpart=psys->totpart; - float *vg_vel=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); - float *vg_tan=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); - float *vg_rot=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); + int p, totpart=sim->psys->totpart; + //float *vg_vel=psys_cache_vgroup(sim->psmd->dm,sim->psys,PSYS_VG_VEL); + //float *vg_tan=psys_cache_vgroup(sim->psmd->dm,sim->psys,PSYS_VG_TAN); + //float *vg_rot=psys_cache_vgroup(sim->psmd->dm,sim->psys,PSYS_VG_ROT); - for(p=from, pa=psys->particles+from; ppsys->particles+from; ppsys, *kpsys; ParticleTarget *pt = psys->targets.first; int keys_valid = 1; psys->totkeyed = 0; for(; pt; pt=pt->next) { - kpsys = psys_get_target_system(ob, pt); + kpsys = psys_get_target_system(sim->ob, pt); if(kpsys && kpsys->totpart) { psys->totkeyed += keys_valid; @@ -2064,9 +2001,10 @@ void psys_count_keyed_targets(Object *ob, ParticleSystem *psys) psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops; } -static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) +static void set_keyed_keys(ParticleSimulationData *sim) { - ParticleSystem *kpsys = psys; + ParticleSystem *psys = sim->psys; + ParticleSimulationData ksim = {sim->scene, NULL, NULL, NULL}; ParticleTarget *pt; PARTICLE_P; ParticleKey *key; @@ -2096,16 +2034,14 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) pt = psys->targets.first; for(k=0; kob) - kpsys = BLI_findlink(&pt->ob->particlesystem, pt->psys - 1); - else - kpsys = BLI_findlink(&ob->particlesystem, pt->psys - 1); + ksim.ob = pt->ob ? pt->ob : sim->ob; + ksim.psys = BLI_findlink(&ksim.ob->particlesystem, pt->psys - 1); LOOP_PARTICLES { key = pa->keys + k; key->time = -1.0; /* use current time */ - psys_get_particle_state(scene, pt->ob, kpsys, p%kpsys->totpart, key, 1); + psys_get_particle_state(&ksim, p%ksim.psys->totpart, key, 1); if(psys->flag & PSYS_KEYED_TIMING){ key->time = pa->time + pt->time; @@ -2131,111 +2067,109 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) /************************************************/ /* Reactors */ /************************************************/ -static void push_reaction(Object* ob, ParticleSystem *psys, int pa_num, int event, ParticleKey *state) -{ - Object *rob; - ParticleSystem *rpsys; - ParticleSettings *rpart; - ParticleData *pa; - ListBase *lb=&psys->effectors; - ParticleEffectorCache *ec; - ParticleReactEvent *re; - - if(lb->first) for(ec = lb->first; ec; ec= ec->next){ - if(ec->type & PSYS_EC_REACTOR){ - /* all validity checks already done in add_to_effectors */ - rob=ec->ob; - rpsys=BLI_findlink(&rob->particlesystem,ec->psys_nbr); - rpart=rpsys->part; - if(rpsys->part->reactevent==event){ - pa=psys->particles+pa_num; - re= MEM_callocN(sizeof(ParticleReactEvent), "react event"); - re->event=event; - re->pa_num = pa_num; - re->ob = ob; - re->psys = psys; - re->size = pa->size; - copy_particle_key(&re->state,state,1); - - switch(event){ - case PART_EVENT_DEATH: - re->time=pa->dietime; - break; - case PART_EVENT_COLLIDE: - re->time=state->time; - break; - case PART_EVENT_NEAR: - re->time=state->time; - break; - } - - BLI_addtail(&rpsys->reactevents, re); - } - } - } -} -static void react_to_events(ParticleSystem *psys, int pa_num) -{ - ParticleSettings *part=psys->part; - ParticleData *pa=psys->particles+pa_num; - ParticleReactEvent *re=psys->reactevents.first; - int birth=0; - float dist=0.0f; - - for(re=psys->reactevents.first; re; re=re->next){ - birth=0; - if(part->from==PART_FROM_PARTICLE){ - if(pa->num==re->pa_num && pa->alive==PARS_UNBORN){ - if(re->event==PART_EVENT_NEAR){ - ParticleData *tpa = re->psys->particles+re->pa_num; - float pa_time=tpa->time + pa->foffset*tpa->lifetime; - if(re->time >= pa_time){ - pa->time=pa_time; - pa->dietime=pa->time+pa->lifetime; - } - } - else{ - pa->time=re->time; - pa->dietime=pa->time+pa->lifetime; - } - } - } - else{ - dist=VecLenf(pa->state.co, re->state.co); - if(dist <= re->size){ - if(pa->alive==PARS_UNBORN){ - pa->time=re->time; - pa->dietime=pa->time+pa->lifetime; - birth=1; - } - if(birth || part->flag&PART_REACT_MULTIPLE){ - float vec[3]; - VECSUB(vec,pa->state.co, re->state.co); - if(birth==0) - VecMulf(vec,(float)pow(1.0f-dist/re->size,part->reactshape)); - VECADDFAC(pa->state.vel,pa->state.vel,vec,part->reactfac); - VECADDFAC(pa->state.vel,pa->state.vel,re->state.vel,part->partfac); - } - if(birth) - VecMulf(pa->state.vel,(float)pow(1.0f-dist/re->size,part->reactshape)); - } - } - } -} -void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_ob, ParticleSystem **target_psys) -{ - Object *tob; - - tob=psys->target_ob; - if(tob==0) - tob=ob; - - *target_psys=BLI_findlink(&tob->particlesystem,psys->target_psys-1); - if(*target_psys) - *target_ob=tob; - else - *target_ob=0; -} +//static void push_reaction(ParticleSimulationData *sim, int pa_num, int event, ParticleKey *state) +//{ +// Object *rob; +// ParticleSystem *rpsys; +// ParticleSettings *rpart; +// ParticleData *pa; +// ListBase *lb=&sim->psys->effectors; +// ParticleEffectorCache *ec; +// ParticleReactEvent *re; +// +// if(lb->first) for(ec = lb->first; ec; ec= ec->next){ +// if(ec->type & PSYS_EC_REACTOR){ +// /* all validity checks already done in add_to_effectors */ +// rob=ec->ob; +// rpsys=BLI_findlink(&rob->particlesystem,ec->psys_nbr); +// rpart=rpsys->part; +// if(rpsys->part->reactevent==event){ +// pa=sim->psys->particles+pa_num; +// re= MEM_callocN(sizeof(ParticleReactEvent), "react event"); +// re->event=event; +// re->pa_num = pa_num; +// re->ob = sim->ob; +// re->psys = sim->psys; +// re->size = pa->size; +// copy_particle_key(&re->state,state,1); +// +// switch(event){ +// case PART_EVENT_DEATH: +// re->time=pa->dietime; +// break; +// case PART_EVENT_COLLIDE: +// re->time=state->time; +// break; +// case PART_EVENT_NEAR: +// re->time=state->time; +// break; +// } +// +// BLI_addtail(&rpsys->reactevents, re); +// } +// } +// } +//} +//static void react_to_events(ParticleSystem *psys, int pa_num) +//{ +// ParticleSettings *part=psys->part; +// ParticleData *pa=psys->particles+pa_num; +// ParticleReactEvent *re=psys->reactevents.first; +// int birth=0; +// float dist=0.0f; +// +// for(re=psys->reactevents.first; re; re=re->next){ +// birth=0; +// if(part->from==PART_FROM_PARTICLE){ +// if(pa->num==re->pa_num && pa->alive==PARS_UNBORN){ +// if(re->event==PART_EVENT_NEAR){ +// ParticleData *tpa = re->psys->particles+re->pa_num; +// float pa_time=tpa->time + pa->foffset*tpa->lifetime; +// if(re->time >= pa_time){ +// pa->time=pa_time; +// pa->dietime=pa->time+pa->lifetime; +// } +// } +// else{ +// pa->time=re->time; +// pa->dietime=pa->time+pa->lifetime; +// } +// } +// } +// else{ +// dist=VecLenf(pa->state.co, re->state.co); +// if(dist <= re->size){ +// if(pa->alive==PARS_UNBORN){ +// pa->time=re->time; +// pa->dietime=pa->time+pa->lifetime; +// birth=1; +// } +// if(birth || part->flag&PART_REACT_MULTIPLE){ +// float vec[3]; +// VECSUB(vec,pa->state.co, re->state.co); +// if(birth==0) +// VecMulf(vec,(float)pow(1.0f-dist/re->size,part->reactshape)); +// VECADDFAC(pa->state.vel,pa->state.vel,vec,part->reactfac); +// VECADDFAC(pa->state.vel,pa->state.vel,re->state.vel,part->partfac); +// } +// if(birth) +// VecMulf(pa->state.vel,(float)pow(1.0f-dist/re->size,part->reactshape)); +// } +// } +// } +//} +//void psys_get_reactor_target(ParticleSimulationData *sim, Object **target_ob, ParticleSystem **target_psys) +//{ +// Object *tob; +// +// tob = sim->psys->target_ob ? sim->psys->target_ob : sim->ob; +// +// *target_psys = BLI_findlink(&tob->particlesystem, sim->psys->target_psys-1); +// if(*target_psys) +// *target_ob=tob; +// else +// *target_ob=0; +//} /************************************************/ /* Point Cache */ /************************************************/ @@ -2280,11 +2214,9 @@ static void update_particle_tree(ParticleSystem *psys) psys->tree = BLI_kdtree_new(psys->totpart); - LOOP_PARTICLES { - if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive != PARS_ALIVE) - continue; - - BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL); + LOOP_SHOWN_PARTICLES { + if(pa->alive == PARS_ALIVE) + BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL); } BLI_kdtree_balance(psys->tree); @@ -2301,7 +2233,7 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, result[0].nor = result[1].nor = result[2].nor = result[3].nor = 0; - strength= force_val*falloff;///(float)pow((double)distance,(double)power); + strength= force_val*falloff; VECCOPY(tex_co,pa_co); @@ -2364,19 +2296,19 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, VecAddf(field,field,mag_vec); } -static void add_to_effectors(ListBase *lb, Scene *scene, Object *ob, Object *obsrc, ParticleSystem *psys) +static void add_to_effectors(ParticleSimulationData *sim, ListBase *lb, Object *ob) { ParticleEffectorCache *ec; PartDeflect *pd= ob->pd; short type=0,i; - if(pd && ob != obsrc){ + if(pd && ob != sim->ob){ if(pd->forcefield == PFIELD_GUIDE) { if(ob->type==OB_CURVE) { Curve *cu= ob->data; if(cu->flag & CU_PATH) { if(cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(scene, ob, 0); + makeDispListCurveTypes(sim->scene, ob, 0); if(cu->path && cu->path->data) { type |= PSYS_EC_EFFECTOR; } @@ -2410,13 +2342,13 @@ static void add_to_effectors(ListBase *lb, Scene *scene, Object *ob, Object *obs if(ob->particlesystem.first){ ParticleSystem *epsys=ob->particlesystem.first; ParticleSettings *epart=0; - Object *tob; + //Object *tob; for(i=0; epsys; epsys=epsys->next,i++){ if(!psys_check_enabled(ob, epsys)) continue; type=0; - if(epsys!=psys || (psys->part->flag & PART_SELF_EFFECT)){ + if(epsys!=sim->psys || (sim->psys->part->flag & PART_SELF_EFFECT)){ epart=epsys->part; if((epsys->part->pd && epsys->part->pd->forcefield) @@ -2425,13 +2357,13 @@ static void add_to_effectors(ListBase *lb, Scene *scene, Object *ob, Object *obs type=PSYS_EC_PARTICLE; } - if(epart->type==PART_REACTOR) { - tob=epsys->target_ob; - if(tob==0) - tob=ob; - if(BLI_findlink(&tob->particlesystem,epsys->target_psys-1)==psys) - type|=PSYS_EC_REACTOR; - } + //if(epart->type==PART_REACTOR) { + // tob=epsys->target_ob; + // if(tob==0) + // tob=ob; + // if(BLI_findlink(&tob->particlesystem,epsys->target_psys-1)==sim->psys) + // type|=PSYS_EC_REACTOR; + //} if(type){ ec= MEM_callocN(sizeof(ParticleEffectorCache), "effector cache"); @@ -2449,29 +2381,29 @@ static void add_to_effectors(ListBase *lb, Scene *scene, Object *ob, Object *obs } } -static void psys_init_effectors_recurs(Scene *scene, Object *ob, Object *obsrc, ParticleSystem *psys, ListBase *listb, int level) +static void psys_init_effectors_recurs(ParticleSimulationData *sim, Object *ob, ListBase *listb, int level) { Group *group; GroupObject *go; - unsigned int layer= obsrc->lay; + unsigned int layer= sim->ob->lay; if(level>MAX_DUPLI_RECUR) return; if(ob->lay & layer) { if(ob->pd || ob->particlesystem.first) - add_to_effectors(listb, scene, ob, obsrc, psys); + add_to_effectors(sim, listb, ob); if(ob->dup_group) { group= ob->dup_group; for(go= group->gobject.first; go; go= go->next) - psys_init_effectors_recurs(scene, go->ob, obsrc, psys, listb, level+1); + psys_init_effectors_recurs(sim, go->ob, listb, level+1); } } } -void psys_init_effectors(Scene *scene, Object *obsrc, Group *group, ParticleSystem *psys) +static void psys_init_effectors(ParticleSimulationData *sim, Group *group) { - ListBase *listb= &psys->effectors; + ListBase *listb= &sim->psys->effectors; Base *base; listb->first=listb->last=0; @@ -2480,11 +2412,11 @@ void psys_init_effectors(Scene *scene, Object *obsrc, Group *group, ParticleSyst GroupObject *go; for(go= group->gobject.first; go; go= go->next) - psys_init_effectors_recurs(scene, go->ob, obsrc, psys, listb, 0); + psys_init_effectors_recurs(sim, go->ob, listb, 0); } else { - for(base = scene->base.first; base; base= base->next) - psys_init_effectors_recurs(scene, base->object, obsrc, psys, listb, 0); + for(base = sim->scene->base.first; base; base= base->next) + psys_init_effectors_recurs(sim, base->object, listb, 0); } } @@ -2518,13 +2450,16 @@ void psys_end_effectors(ParticleSystem *psys) BLI_freelistN(&psys->effectors); } -static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) +/* precalcs effectors and returns 1 if there were any collision object +/* so collision checks can be avoided as quickly as possible */ +static int precalc_effectors(ParticleSimulationData *sim, float cfra) { + ParticleSystem *psys = sim->psys; ListBase *lb=&psys->effectors; ParticleEffectorCache *ec; ParticleSettings *part=psys->part; PARTICLE_P; - int totpart; + int totpart, collision = 0; float vec2[3],loc[3],radius,*co=0; for(ec= lb->first; ec; ec= ec->next) { @@ -2556,9 +2491,9 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa VECCOPY(loc, pa->fuv); } else - psys_particle_on_emitter(psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,0,0); + psys_particle_on_emitter(sim->psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,0,0); - Mat4MulVecfl(ob->obmat,loc); + Mat4MulVecfl(sim->ob->obmat,loc); ec->distances[p]=VecLenf(loc,vec); VECSUB(loc,loc,vec); VECCOPY(ec->locations+3*p,loc); @@ -2566,11 +2501,10 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa } } else if(ec->type==PSYS_EC_PARTICLE){ - Object *eob = ec->ob; - ParticleSystem *epsys = BLI_findlink(&eob->particlesystem,ec->psys_nbr); - ParticleSettings *epart = epsys->part; + ParticleSimulationData esim = {sim->scene, ec->ob, BLI_findlink(&ec->ob->particlesystem, ec->psys_nbr), NULL}; + ParticleSettings *epart = esim.psys->part; ParticleData *epa; - int p, totepart = epsys->totpart; + int p, totepart = esim.psys->totpart; if(psys->part->phystype==PART_PHYS_BOIDS){ ParticleKey state; @@ -2583,8 +2517,8 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa tree=BLI_kdtree_new(totepart); ec->tree=tree; - for(p=0, epa=epsys->particles; palive==PARS_ALIVE && psys_get_particle_state(scene, eob,epsys,p,&state,0)) + for(p=0, epa=esim.psys->particles; palive==PARS_ALIVE && psys_get_particle_state(&esim,p,&state,0)) BLI_kdtree_insert(tree, p, state.co, NULL); BLI_kdtree_balance(tree); @@ -2594,12 +2528,23 @@ static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, Pa } else if(ec->type==PSYS_EC_DEFLECT) { CollisionModifierData *collmd = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) ); - if(collmd) + if(collmd) { collision_move_object(collmd, 1.0, 0.0); + collision = 1; + } } } + + return collision; } +/* updates particle effectors and returns if any collision objects were found */ +int psys_update_effectors(ParticleSimulationData *sim, float cfra, int precalc) +{ + psys_end_effectors(sim->psys); + psys_init_effectors(sim, sim->psys->part->eff_group); + return (precalc ? precalc_effectors(sim, cfra) : 0); +} int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index) { SurfaceModifierData *surmd = NULL; @@ -2679,10 +2624,10 @@ int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object return ret; } /* calculate forces that all effectors apply to a particle*/ -void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra) +void do_effectors(ParticleSimulationData *sim, int pa_no, ParticleData *pa, ParticleKey *state, float *rootco, float *force_field, float *vel,float framestep, float cfra) { Object *eob; - ParticleSystem *epsys; + ParticleSystem *psys = sim->psys; ParticleSettings *epart; ParticleData *epa; ParticleKey estate; @@ -2712,19 +2657,19 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, if(ec->type & PSYS_EC_EFFECTOR){ pd=eob->pd; if(psys->part->type!=PART_HAIR && psys->part->integrator) - where_is_object_time(scene, eob,cfra); + where_is_object_time(sim->scene, eob, cfra); if(pd && pd->flag&PFIELD_SURFACE) { float velocity[3]; /* using velocity corrected location allows for easier sliding over effector surface */ VecCopyf(velocity, state->vel); - VecMulf(velocity, psys_get_timestep(psys->part)); + VecMulf(velocity, psys_get_timestep(sim)); VecAddf(pco, state->co, velocity); } else VECCOPY(pco, state->co); - effector_find_co(scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index); + effector_find_co(sim->scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index); VecSubf(vec_to_part, state->co, co); @@ -2741,68 +2686,69 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat, strength, falloff, force_field); } else { - do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance, + do_physical_effector(sim->scene, eob, state->co, pd->forcefield,strength,distance, falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part, state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size); } } if(ec->type & PSYS_EC_PARTICLE){ + ParticleSimulationData esim = {sim->scene, eob, BLI_findlink(&eob->particlesystem,ec->psys_nbr), NULL}; int totepart, i; - epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr); - epart= epsys->part; - pd=epart->pd; - totepart= epsys->totpart; + + epart = esim.psys->part; + pd = epart->pd; + totepart = esim.psys->totpart; if(totepart <= 0) continue; if(pd && pd->forcefield==PFIELD_HARMONIC){ /* every particle is mapped to only one harmonic effector particle */ - p= pa_no%epsys->totpart; + p= pa_no%esim.psys->totpart; totepart= p+1; } else{ p=0; } - epsys->lattice= psys_get_lattice(scene, ob, psys); + esim.psys->lattice= psys_get_lattice(sim); for(; pparticles + p; - estate.time=cfra; - if(psys_get_particle_state(scene, eob,epsys,p,&estate,0)){ + epa = esim.psys->particles + p; + estate.time = cfra; + if(psys_get_particle_state(&esim, p, &estate, 0)){ VECSUB(vec_to_part, state->co, estate.co); distance = VecLength(vec_to_part); for(i=0, pd = epart->pd; i<2; i++,pd = epart->pd2) { if(pd==NULL || pd->forcefield==0) continue; - falloff=effector_falloff(pd,estate.vel,vec_to_part); + falloff = effector_falloff(pd, estate.vel, vec_to_part); strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield]; if(falloff<=0.0f) ; /* don't do anything */ else - do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance, + do_physical_effector(sim->scene, eob, state->co, pd->forcefield,strength,distance, falloff,epart->size,pd->f_damp,estate.vel,vec_to_part, state->vel,force_field,0, ec->rng, pd->f_noise,charge,pa->size); } } else if(pd && pd->forcefield==PFIELD_HARMONIC && cfra-framestep <= epa->dietime && cfra>epa->dietime){ /* first step after key release */ - psys_get_particle_state(scene, eob,epsys,p,&estate,1); - VECADD(vel,vel,estate.vel); + psys_get_particle_state(&esim, p, &estate, 1); + VECADD(vel, vel, estate.vel); /* TODO: add rotation handling here too */ } } - if(epsys->lattice){ - end_latt_deform(epsys->lattice); - epsys->lattice= NULL; + if(esim.psys->lattice){ + end_latt_deform(esim.psys->lattice); + esim.psys->lattice= NULL; } } } @@ -2813,11 +2759,14 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, /* Newtonian physics */ /************************************************/ /* gathers all forces that effect particles and calculates a new state for the particle */ -static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Object *ob, ParticleSystem *psys, ParticleSettings *part, float timestep, float dfra, float cfra) +static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra, float cfra) { + ParticleSettings *part = sim->psys->part; + ParticleData *pa = sim->psys->particles + p; ParticleKey states[5], tkey; + float timestep = psys_get_timestep(sim); float force[3],tvel[3],dx[4][3],dv[4][3]; - float dtime=dfra*timestep, time, pa_mass=part->mass, fac, fra=psys->cfra; + float dtime=dfra*timestep, time, pa_mass=part->mass, fac, fra=sim->psys->cfra; int i, steps=1; /* maintain angular velocity */ @@ -2845,7 +2794,7 @@ static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Obj tvel[0]=tvel[1]=tvel[2]=0.0; /* add effectors */ if(part->type != PART_HAIR) - do_effectors(pa_no,pa,states+i,scene, ob, psys,states->co,force,tvel,dfra,fra); + do_effectors(sim, p, pa, states+i, states->co, force, tvel, dfra, fra); /* calculate air-particle interaction */ if(part->dragfac!=0.0f){ @@ -2878,7 +2827,7 @@ static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Obj if(i==0){ VECADDFAC(states[1].co,states->co,states->vel,dtime*0.5f); VECADDFAC(states[1].vel,states->vel,force,dtime*0.5f); - fra=psys->cfra+0.5f*dfra; + fra=sim->psys->cfra+0.5f*dfra; } else{ VECADDFAC(pa->state.co,states->co,states[1].vel,dtime); @@ -2895,7 +2844,7 @@ static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Obj VECADDFAC(states[1].co,states->co,dx[0],0.5f); VECADDFAC(states[1].vel,states->vel,dv[0],0.5f); - fra=psys->cfra+0.5f*dfra; + fra=sim->psys->cfra+0.5f*dfra; break; case 1: VECADDFAC(dx[1],states->vel,dv[0],0.5f); @@ -2949,7 +2898,7 @@ static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Obj tkey.time=pa->state.time; if(part->type != PART_HAIR) { - if(do_guide(scene, &tkey, pa_no, time, &psys->effectors)) { + if(do_guide(sim->scene, &tkey, p, time, &sim->psys->effectors)) { VECCOPY(pa->state.co,tkey.co); /* guides don't produce valid velocity */ VECSUB(pa->state.vel,tkey.co,pa->prev_state.co); @@ -3213,15 +3162,18 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B /* angular momentum <-> linear momentum and swept sphere - mesh collisions */ /* 1. check for all possible deflectors for closest intersection on particle path */ /* 2. if deflection was found kill the particle or calculate new coordinates */ -static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float timestep, float dfra, float cfra){ +static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, float cfra){ Object *ob = NULL, *skip_ob = NULL; - ListBase *lb=&psys->effectors; + ParticleSettings *part = sim->psys->part; + ListBase *lb=&sim->psys->effectors; ParticleEffectorCache *ec; ParticleKey reaction_state; ParticleCollision col; + ParticleData *pa = sim->psys->particles + p; BVHTreeRayHit hit; float ray_dir[3], zerovec[3]={0.0,0.0,0.0}; float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f), boid_z = 0.0f; + float timestep = psys_get_timestep(sim); int deflections=0, max_deflections=10; VECCOPY(col.co1, pa->prev_state.co); @@ -3258,11 +3210,11 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa continue; /* particles should not collide with emitter at birth */ - if(ob==pob && pa->time < cfra && pa->time >= psys->cfra) + if(ob==sim->ob && pa->time < cfra && pa->time >= sim->psys->cfra) continue; if(part->type!=PART_HAIR) - where_is_object_time(scene,ob,cfra); + where_is_object_time(sim->scene, sim->ob, cfra); col.md = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) ); col.ob_t = ob; @@ -3399,9 +3351,9 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa } /* store state for reactors */ - VECCOPY(reaction_state.co, co); - VecLerpf(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt); - QuatInterpol(reaction_state.rot, pa->prev_state.rot, pa->state.rot, dt); + //VECCOPY(reaction_state.co, co); + //VecLerpf(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt); + //QuatInterpol(reaction_state.rot, pa->prev_state.rot, pa->state.rot, dt); /* set coordinates for next iteration */ VECCOPY(col.co1, co); @@ -3423,8 +3375,8 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa } deflections++; - reaction_state.time = cfra - (1.0f - dt) * dfra; - push_reaction(col.ob, psys, p, PART_EVENT_COLLIDE, &reaction_state); + //reaction_state.time = cfra - (1.0f - dt) * dfra; + //push_reaction(col.ob, psys, p, PART_EVENT_COLLIDE, &reaction_state); } else return; @@ -3434,29 +3386,30 @@ static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierDa /* Hair */ /************************************************/ /* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) { - ParticleSettings *part=psys->part; - ParticleEditSettings *pset=&scene->toolsettings->particle; - int distr=0,alloc=0,skip=0; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + ParticleEditSettings *pset = &sim->scene->toolsettings->particle; + int distr=0, alloc=0, skip=0; - if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET) + if((psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) alloc=1; - if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))) + if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT))) distr=1; if(distr){ if(alloc) - realloc_particles(ob,psys,psys->totpart); + realloc_particles(sim, sim->psys->totpart); - if(get_psys_tot_child(scene, psys)) { + if(get_psys_tot_child(sim->scene, psys)) { /* don't generate children while computing the hair keys */ if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { - distribute_particles(scene, ob, psys, PART_FROM_CHILD); + distribute_particles(sim, PART_FROM_CHILD); if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0) - psys_find_parents(ob,psmd,psys); + psys_find_parents(sim); } } } @@ -3470,7 +3423,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif skip = 1; /* draw visualization */ else if(psys->pointcache->flag & PTCACHE_BAKING) skip = 1; /* no need to cache paths while baking dynamics */ - else if(psys_in_edit_mode(scene, psys)) { + else if(psys_in_edit_mode(sim->scene, psys)) { if((pset->flag & PE_DRAW_PART)==0) skip = 1; else if(part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0) @@ -3479,7 +3432,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif } if(!skip) { - psys_cache_paths(scene, ob, psys, cfra); + psys_cache_paths(sim, cfra); /* for render, child particle paths are computed on the fly */ if(part->childtype) { @@ -3489,15 +3442,16 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif skip = 1; if(!skip) - psys_cache_child_paths(scene, ob, psys, cfra, 0); + psys_cache_child_paths(sim, cfra, 0); } } else if(psys->pathcache) psys_free_path_cache(psys, NULL); } -static void do_hair_dynamics(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd) +static void do_hair_dynamics(ParticleSimulationData *sim) { + ParticleSystem *psys = sim->psys; DerivedMesh *dm = psys->hair_in_dm; MVert *mvert = NULL; MEdge *medge = NULL; @@ -3520,7 +3474,8 @@ static void do_hair_dynamics(Scene *scene, Object *ob, ParticleSystem *psys, Par LOOP_PARTICLES totpoint += pa->totkey; - totedge = totpoint - psys->totpart; + totedge = totpoint; + totpoint += psys->totpart; if(dm && (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm))) { dm->release(dm); @@ -3539,14 +3494,39 @@ static void do_hair_dynamics(Scene *scene, Object *ob, ParticleSystem *psys, Par psys->clmd->sim_parms->vgroup_mass = 1; /* make vgroup for pin roots etc.. */ - psys->particles->hair_index = 0; + psys->particles->hair_index = 1; LOOP_PARTICLES { if(p) - pa->hair_index = (pa-1)->hair_index + (pa-1)->totkey; + pa->hair_index = (pa-1)->hair_index + (pa-1)->totkey + 1; - psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat); + psys_mat_hair_to_object(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat); for(k=0, key=pa->hair; ktotkey; k++,key++) { + + /* create fake root before actual root to resist bending */ + if(k==0) { + float temp[3]; + VECSUB(temp, key->co, (key+1)->co); + VECCOPY(mvert->co, key->co); + VECADD(mvert->co, mvert->co, temp); + Mat4MulVecfl(hairmat, mvert->co); + mvert++; + + medge->v1 = pa->hair_index - 1; + medge->v2 = pa->hair_index; + medge++; + + if(dvert) { + if(!dvert->totweight) { + dvert->dw = MEM_callocN (sizeof(MDeformWeight), "deformWeight"); + dvert->totweight = 1; + } + + dvert->dw->weight = 1.0f; + dvert++; + } + } + VECCOPY(mvert->co, key->co); Mat4MulVecfl(hairmat, mvert->co); mvert++; @@ -3576,10 +3556,11 @@ static void do_hair_dynamics(Scene *scene, Object *ob, ParticleSystem *psys, Par psys->clmd->point_cache = psys->pointcache; - psys->hair_out_dm = clothModifier_do(psys->clmd, scene, ob, dm, 0, 0); + psys->hair_out_dm = clothModifier_do(psys->clmd, sim->scene, sim->ob, dm, 0, 0); } -static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +static void hair_step(ParticleSimulationData *sim, float cfra) { + ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; PARTICLE_P; float disp = (float)get_current_display_percentage(psys)/100.0f; @@ -3587,7 +3568,7 @@ static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd BLI_srandom(psys->seed); LOOP_PARTICLES { - if(BLI_frand() > disp) + if(PSYS_FRAND(p) > disp) pa->flag |= PARS_NO_DISP; else pa->flag &= ~PARS_NO_DISP; @@ -3595,36 +3576,33 @@ static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd if(psys->recalc & PSYS_RECALC_RESET) { /* need this for changing subsurf levels */ - psys_calc_dmcache(ob, psmd->dm, psys); + psys_calc_dmcache(sim->ob, sim->psmd->dm, psys); if(psys->clmd) - cloth_free_modifier(ob, psys->clmd); + cloth_free_modifier(sim->ob, psys->clmd); } - if(psys->effectors.first) - psys_end_effectors(psys); - /* dynamics with cloth simulation */ if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) - do_hair_dynamics(scene, ob, psys, psmd); + do_hair_dynamics(sim); - psys_init_effectors(scene, ob, part->eff_group, psys); - if(psys->effectors.first) - precalc_effectors(scene, ob,psys,psmd,cfra); + psys_update_effectors(sim, cfra, 1); - psys_update_path_cache(scene, ob,psmd,psys,cfra); + psys_update_path_cache(sim, cfra); psys->flag |= PSYS_HAIR_UPDATED; } -static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){ +static void save_hair(ParticleSimulationData *sim, float cfra){ + Object *ob = sim->ob; + ParticleSystem *psys = sim->psys; HairKey *key, *root; PARTICLE_P; int totpart; - Mat4Invert(ob->imat,ob->obmat); + Mat4Invert(ob->imat, ob->obmat); - psys->lattice= psys_get_lattice(scene, ob, psys); + psys->lattice= psys_get_lattice(sim); if(psys->totpart==0) return; @@ -3647,7 +3625,7 @@ static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSy if(pa->totkey) { VECSUB(key->co, key->co, root->co); - psys_vec_rot_to_face(psmd->dm, pa, key->co); + psys_vec_rot_to_face(sim->psmd->dm, pa, key->co); } key->time = pa->state.time; @@ -3665,17 +3643,17 @@ static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSy /* System Core */ /************************************************/ /* unbaked particles are calculated dynamically */ -static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra, - float *vg_vel, float *vg_tan, float *vg_rot, float *vg_size) +static void dynamics_step(ParticleSimulationData *sim, float cfra) { + ParticleSystem *psys = sim->psys; ParticleSettings *part=psys->part; KDTree *tree=0; IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system - Material *ma=give_current_material(ob,part->omat); + Material *ma=give_current_material(sim->ob, part->omat); BoidBrainData bbd; PARTICLE_P; float timestep; - int totpart; + int totpart, check_collisions = 0; /* current time */ float ctime, ipotime; // XXX old animation system /* frame & time changes */ @@ -3687,7 +3665,7 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic totpart=psys->totpart; - timestep=psys_get_timestep(part); + timestep=psys_get_timestep(sim); dtime= dfra*timestep; ctime= cfra*timestep; ipotime= cfra; // XXX old animation system @@ -3701,12 +3679,10 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic if(dfra<0.0){ float *vg_size=0; - if(part->type==PART_REACTOR) - vg_size=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); - - LOOP_PARTICLES { - if(pa->flag & PARS_UNEXIST) continue; + //if(part->type==PART_REACTOR) + // vg_size=psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); + LOOP_EXISTING_PARTICLES { /* set correct ipo timing */ #if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ @@ -3715,13 +3691,15 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic execute_ipo((ID *)part, part->ipo); } #endif // XXX old animation system - pa->size=psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); + pa->size = part->size; + if(part->randsize > 0.0) + pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); - reset_particle(scene, pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); + reset_particle(sim, pa, dtime, cfra); - if(cfra>pa->time && part->flag & PART_LOOP && part->type!=PART_HAIR){ - pa->loop=(short)((cfra-pa->time)/pa->lifetime); - pa->alive=PARS_UNBORN; + if(cfra > pa->time && part->flag & PART_LOOP && part->type!=PART_HAIR){ + pa->loop = (short)((cfra-pa->time)/pa->lifetime); + pa->alive = PARS_UNBORN; } else{ pa->loop = 0; @@ -3742,21 +3720,12 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic } else{ BLI_srandom(31415926 + (int)cfra + psys->seed); - - /* update effectors */ - if(psys->effectors.first) - psys_end_effectors(psys); - psys_init_effectors(scene, ob, part->eff_group, psys); - - if(psys->effectors.first) - precalc_effectors(scene, ob,psys,psmd,cfra); + psys_update_effectors(sim, cfra, 1); if(part->phystype==PART_PHYS_BOIDS){ ParticleTarget *pt = psys->targets.first; - bbd.scene = scene; - bbd.ob = ob; - bbd.psys = psys; + bbd.sim = sim; bbd.part = part; bbd.cfra = cfra; bbd.dfra = dfra; @@ -3773,9 +3742,7 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic } /* main loop: calculate physics for all particles */ - LOOP_PARTICLES { - if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; - + LOOP_SHOWN_PARTICLES { copy_particle_key(&pa->prev_state,&pa->state,1); /* set correct ipo timing */ @@ -3786,23 +3753,19 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic execute_ipo((ID *)part, part->ipo); } #endif // XXX old animation system - pa->size=psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); + //update_particle_settings(psys, part, &tpart, pa); + + pa->size = part->size; + if(part->randsize > 0.0) + pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); - /* reactions can change birth time so they need to be checked first */ - if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) - react_to_events(psys,p); + ///* reactions can change birth time so they need to be checked first */ + //if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) + // react_to_events(psys,p); birthtime = pa->time + pa->loop * pa->lifetime; dietime = birthtime + pa->lifetime; - /* allways reset particles to emitter before birth */ - if(pa->alive==PARS_UNBORN - || pa->alive==PARS_KILLED - || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED) - || birthtime >= psys->cfra){ - reset_particle(scene, pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); - } - pa_dfra = dfra; pa_dtime = dtime; @@ -3815,6 +3778,7 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic } else if(birthtime <= cfra && birthtime >= psys->cfra){ /* particle is born some time between this and last step*/ + reset_particle(sim, pa, dtime, cfra); pa->alive = PARS_ALIVE; pa_dfra = cfra - birthtime; pa_dtime = pa_dfra*timestep; @@ -3823,18 +3787,22 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic /* nothing to be done when particle is dead */ } + /* only reset unborn particles if they're shown */ + if(pa->alive==PARS_UNBORN && part->flag & PART_UNBORN) + reset_particle(sim, pa, dtime, cfra); if(dfra>0.0 && ELEM(pa->alive,PARS_ALIVE,PARS_DYING)){ switch(part->phystype){ case PART_PHYS_NEWTON: /* do global forces & effectors */ - apply_particle_forces(scene, p, pa, ob, psys, part, timestep,pa_dfra,cfra); + apply_particle_forces(sim, p, pa_dfra, cfra); /* deflection */ - deflect_particle(scene, ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra); + if(check_collisions) + deflect_particle(sim, p, pa_dfra, cfra); /* rotations */ - rotate_particle(part,pa,pa_dfra,timestep); + rotate_particle(part, pa, pa_dfra, timestep); break; case PART_PHYS_BOIDS: { @@ -3844,18 +3812,18 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic boid_body(&bbd, pa); /* deflection */ - deflect_particle(scene,ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra); + deflect_particle(sim, p, pa_dfra, cfra); } break; } } if(pa->alive == PARS_DYING){ - push_reaction(ob,psys,p,PART_EVENT_DEATH,&pa->state); + //push_reaction(ob,psys,p,PART_EVENT_DEATH,&pa->state); if(part->flag & PART_LOOP && part->type!=PART_HAIR){ pa->loop++; - reset_particle(scene, pa,psys,psmd,ob,0.0,cfra,vg_vel,vg_tan,vg_rot); + reset_particle(sim, pa, 0.0, cfra); pa->alive=PARS_ALIVE; } else{ @@ -3866,7 +3834,7 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic else pa->state.time=cfra; - push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state); + //push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state); } } } @@ -3878,28 +3846,21 @@ static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, Partic } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +static void cached_step(ParticleSimulationData *sim, float cfra) { - ParticleSettings *part=psys->part; - ParticleKey state; - IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system - Material *ma=give_current_material(ob,part->omat); + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + IpoCurve *icu_esize = NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system + Material *ma = give_current_material(sim->ob,part->omat); PARTICLE_P; float disp, birthtime, dietime, *vg_size= NULL; // XXX ipotime=cfra BLI_srandom(psys->seed); if(part->from!=PART_FROM_PARTICLE) - vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); + vg_size= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); - if(psys->effectors.first) - psys_end_effectors(psys); - - //if(part->flag & (PART_BAKED_GUIDES+PART_BAKED_DEATHS)){ - psys_init_effectors(scene, ob, part->eff_group, psys); - if(psys->effectors.first) - precalc_effectors(scene, ob,psys,psmd,cfra); - //} + psys_update_effectors(sim, cfra, 1); disp= (float)get_current_display_percentage(psys)/100.0f; @@ -3911,9 +3872,13 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps execute_ipo((ID *)part, part->ipo); } #endif // XXX old animation system - pa->size= psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); + //update_settings_with_particle(psys, part, pa); + + pa->size = part->size; + if(part->randsize > 0.0) + pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); - psys->lattice= psys_get_lattice(scene, ob, psys); + psys->lattice= psys_get_lattice(sim); if(part->flag & PART_LOOP && part->type!=PART_HAIR) pa->loop = (short)((cfra - pa->time) / pa->lifetime); @@ -3924,25 +3889,16 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time); /* update alive status and push events */ - if(pa->time >= cfra) { - pa->alive = pa->time==cfra ? PARS_ALIVE : PARS_UNBORN; - if((psys->pointcache->flag & PTCACHE_EXTERNAL) == 0) - reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL); + if(pa->time > cfra) { + pa->alive = PARS_UNBORN; + if(part->flag & PART_UNBORN && (psys->pointcache->flag & PTCACHE_EXTERNAL) == 0) + reset_particle(sim, pa, 0.0f, cfra); } else if(dietime <= cfra){ - if(dietime > psys->cfra){ - state.time = dietime; - psys_get_particle_state(scene, ob,psys,p,&state,1); - push_reaction(ob,psys,p,PART_EVENT_DEATH,&state); - } pa->alive = PARS_DEAD; } else{ pa->alive = PARS_ALIVE; - state.time = cfra; - psys_get_particle_state(scene, ob,psys,p,&state,1); - state.time = cfra; - push_reaction(ob,psys,p,PART_EVENT_NEAR,&state); } if(psys->lattice){ @@ -3950,43 +3906,41 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps psys->lattice= NULL; } - if(BLI_frand() > disp) + if(PSYS_FRAND(p) > disp) pa->flag |= PARS_NO_DISP; else pa->flag &= ~PARS_NO_DISP; } /* make sure that children are up to date */ - if(psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) { - realloc_particles(ob, psys, psys->totpart); - distribute_particles(scene, ob, psys, PART_FROM_CHILD); + if(psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) { + realloc_particles(sim, psys->totpart); + distribute_particles(sim, PART_FROM_CHILD); } - psys_update_path_cache(scene, ob,psmd,psys,cfra); + psys_update_path_cache(sim, cfra); if(vg_size) MEM_freeN(vg_size); } -static void psys_changed_type(Object *ob, ParticleSystem *psys) +static void psys_changed_type(ParticleSimulationData *sim) { - ParticleSettings *part; + ParticleSettings *part = sim->psys->part; PTCacheID pid; - part= psys->part; - - BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); /* system type has changed so set sensible defaults and clear non applicable flags */ if(part->from == PART_FROM_PARTICLE) { - if(part->type != PART_REACTOR) - part->from = PART_FROM_FACE; + //if(part->type != PART_REACTOR) + part->from = PART_FROM_FACE; if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) part->distr = PART_DISTR_JIT; } if(part->phystype != PART_PHYS_KEYED) - psys->flag &= ~PSYS_KEYED; + sim->psys->flag &= ~PSYS_KEYED; if(part->type == PART_HAIR) { if(ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) @@ -4001,13 +3955,13 @@ static void psys_changed_type(Object *ob, ParticleSystem *psys) BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { - free_hair(ob, psys, 1); + free_hair(sim->ob, sim->psys, 1); CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime)); CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime)); } - psys_reset(psys, PSYS_RESET_ALL); + psys_reset(sim->psys, PSYS_RESET_ALL); } void psys_check_boid_data(ParticleSystem *psys) { @@ -4033,24 +3987,24 @@ void psys_check_boid_data(ParticleSystem *psys) pa->boid = NULL; } } -static void psys_changed_physics(Object *ob, ParticleSystem *psys) +static void psys_changed_physics(ParticleSimulationData *sim) { - ParticleSettings *part = psys->part; + ParticleSettings *part = sim->psys->part; if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) { PTCacheID pid; - BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys); BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { - free_keyed_keys(psys); - psys->flag &= ~PSYS_KEYED; + free_keyed_keys(sim->psys); + sim->psys->flag &= ~PSYS_KEYED; } if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) { BoidState *state; - psys_check_boid_data(psys); + psys_check_boid_data(sim->psys); part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings"); boid_default_settings(part->boids); @@ -4065,8 +4019,9 @@ static void psys_changed_physics(Object *ob, ParticleSystem *psys) BLI_addtail(&part->boids->states, state); } } -static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra) +static void particles_fluid_step(ParticleSimulationData *sim, int cfra) { + ParticleSystem *psys = sim->psys; if(psys->particles){ MEM_freeN(psys->particles); psys->particles = 0; @@ -4076,7 +4031,7 @@ static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, /* fluid sim particle import handling, actual loading of particles from file */ #ifndef DISABLE_ELBEEM { - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(sim->ob, eModifierType_Fluidsim); if( fluidmd && fluidmd->fss) { FluidsimSettings *fss= fluidmd->fss; @@ -4086,7 +4041,7 @@ static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, char *suffix2 = ".gz"; char filename[256]; char debugStrBuffer[256]; - int curFrame = scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading + int curFrame = sim->scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading int p, j, numFileParts, totpart; int readMask, activeParts = 0, fileParts = 0; gzFile gzf; @@ -4114,11 +4069,11 @@ static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, part->totpart= totpart; part->sta=part->end = 1.0f; - part->lifetime = scene->r.efra + 1; + part->lifetime = sim->scene->r.efra + 1; /* initialize particles */ - realloc_particles(ob, psys, part->totpart); - initialize_all_particles(ob, psys, 0); + realloc_particles(sim, part->totpart); + initialize_all_particles(sim); // set up reading mask readMask = fss->typeFlags; @@ -4174,10 +4129,11 @@ static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, /* Calculates the next state for all particles of the system */ /* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ -static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) +static void system_step(ParticleSimulationData *sim, float cfra) { - ParticleSettings *part; - PointCache *cache; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + PointCache *cache = psys->pointcache; PTCacheID pid; PARTICLE_P; int totpart, oldtotpart, totchild, oldtotchild; @@ -4185,20 +4141,17 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle int init= 0, distr= 0, alloc= 0, usecache= 0, only_children_changed= 0; int framenr, framedelta, startframe, endframe; - part= psys->part; - cache= psys->pointcache; - - framenr= (int)scene->r.cfra; + framenr= (int)sim->scene->r.cfra; framedelta= framenr - cache->simframe; /* set suitable cache range automatically */ if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0 && !(psys->flag & PSYS_HAIR_DYNAMICS)) - psys_get_pointcache_start_end(scene, psys, &cache->startframe, &cache->endframe); + psys_get_pointcache_start_end(sim->scene, sim->psys, &cache->startframe, &cache->endframe); - BKE_ptcache_id_from_particles(&pid, ob, psys); - BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL); + BKE_ptcache_id_from_particles(&pid, sim->ob, psys); + BKE_ptcache_id_time(&pid, sim->scene, 0.0f, &startframe, &endframe, NULL); - psys_clear_temp_pointcache(psys); + psys_clear_temp_pointcache(sim->psys); /* update ipo's */ #if 0 // XXX old animation system @@ -4210,14 +4163,14 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle /* hair if it's already done is handled separate */ if(part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)) { - hair_step(scene, ob, psmd, psys, cfra); + hair_step(sim, cfra); psys->cfra = cfra; psys->recalc = 0; return; } /* fluid is also handled separate */ else if(part->type == PART_FLUID) { - particles_fluid_step(scene, ob, psys, framenr); + particles_fluid_step(sim, framenr); psys->cfra = cfra; psys->recalc = 0; return; @@ -4254,7 +4207,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle totpart = part->grid_res*part->grid_res*part->grid_res; else totpart = psys->part->totpart; - totchild = get_psys_tot_child(scene, psys); + totchild = get_psys_tot_child(sim->scene, psys); if(oldtotpart != totpart || oldtotchild != totchild) { only_children_changed = (oldtotpart == totpart); @@ -4271,45 +4224,45 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle if(init) { if(distr) { if(alloc) { - realloc_particles(ob, psys, totpart); + realloc_particles(sim, totpart); if(usecache && !only_children_changed) { BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); - BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_from_particles(&pid, sim->ob, psys); } } if(!only_children_changed) - distribute_particles(scene, ob, psys, part->from); + distribute_particles(sim, part->from); if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) /* don't generate children while growing hair - waste of time */ psys_free_children(psys); - else if(get_psys_tot_child(scene, psys)) - distribute_particles(scene, ob, psys, PART_FROM_CHILD); + else if(get_psys_tot_child(sim->scene, psys)) + distribute_particles(sim, PART_FROM_CHILD); } if(!only_children_changed) { free_keyed_keys(psys); - initialize_all_particles(ob, psys, psmd); + initialize_all_particles(sim); if(alloc) { - reset_all_particles(scene, ob, psys, psmd, 0.0, cfra, oldtotpart); + reset_all_particles(sim, 0.0, cfra, oldtotpart); } } /* flag for possible explode modifiers after this system */ - psmd->flag |= eParticleSystemFlag_Pars; + sim->psmd->flag |= eParticleSystemFlag_Pars; } /* try to read from the cache */ if(usecache) { - int result = BKE_ptcache_read_cache(&pid, cfra, scene->r.frs_sec); + int result = BKE_ptcache_read_cache(&pid, cfra, sim->scene->r.frs_sec); if(result == PTCACHE_READ_EXACT || result == PTCACHE_READ_INTERPOLATED) { - cached_step(scene, ob, psmd, psys, cfra); + cached_step(sim, cfra); psys->cfra=cfra; psys->recalc = 0; @@ -4333,7 +4286,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle pa->alive = PARS_ALIVE; } } - else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + else if(sim->ob->id.lib || (cache->flag & PTCACHE_BAKED)) { psys_reset(psys, PSYS_RESET_CACHE_MISS); psys->cfra=cfra; psys->recalc = 0; @@ -4351,14 +4304,14 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle BKE_ptcache_write_cache(&pid, startframe); if(part->phystype==PART_PHYS_KEYED) - psys_count_keyed_targets(ob,psys); + psys_count_keyed_targets(sim); /* initialize vertex groups */ if(part->from!=PART_FROM_PARTICLE) { - vg_vel= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); - vg_tan= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); - vg_rot= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); - vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); + vg_vel= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_VEL); + vg_tan= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_TAN); + vg_rot= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_ROT); + vg_size= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE); } /* set particles to be not calculated TODO: can't work with pointcache */ @@ -4366,7 +4319,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle BLI_srandom(psys->seed); LOOP_PARTICLES { - if(BLI_frand() > disp) + if(PSYS_FRAND(p) > disp) pa->flag |= PARS_NO_DISP; else pa->flag &= ~PARS_NO_DISP; @@ -4382,7 +4335,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle for(dframe=-totframesback; dframe<=0; dframe++) { /* ok now we're all set so let's go */ - dynamics_step(scene, ob, psys, psmd, cfra+dframe, vg_vel, vg_tan, vg_rot, vg_size); + dynamics_step(sim, cfra+dframe); psys->cfra = cfra+dframe; } } @@ -4399,8 +4352,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle /* for keyed particles the path is allways known so it can be drawn */ if(part->phystype==PART_PHYS_KEYED) { - set_keyed_keys(scene, ob, psys); - psys_update_path_cache(scene, ob, psmd, psys,(int)cfra); + set_keyed_keys(sim); + psys_update_path_cache(sim,(int)cfra); } else if(psys->pathcache) psys_free_path_cache(psys, NULL); @@ -4430,30 +4383,33 @@ static int hair_needs_recalc(ParticleSystem *psys) /* main particle update call, checks that things are ok on the large scale before actual particle calculations */ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) { - ParticleSystemModifierData *psmd; + ParticleSimulationData sim = {scene, ob, psys, NULL}; float cfra; + /* drawdata is outdated after ANY change */ + if(psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; + if(!psys_check_enabled(ob, psys)) return; cfra= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0f); - psmd= psys_get_modifier(ob, psys); + sim.psmd= psys_get_modifier(ob, psys); /* system was already updated from modifier stack */ - if(psmd->flag & eParticleSystemFlag_psys_updated) { - psmd->flag &= ~eParticleSystemFlag_psys_updated; + if(sim.psmd->flag & eParticleSystemFlag_psys_updated) { + sim.psmd->flag &= ~eParticleSystemFlag_psys_updated; /* make sure it really was updated to cfra */ if(psys->cfra == cfra) return; } - if(!psmd->dm) + if(!sim.psmd->dm) return; if(psys->recalc & PSYS_RECALC_TYPE) - psys_changed_type(ob, psys); + psys_changed_type(&sim); else if(psys->recalc & PSYS_RECALC_PHYS) - psys_changed_physics(ob, psys); + psys_changed_physics(&sim); /* (re-)create hair */ if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { @@ -4467,15 +4423,15 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) for(i=0; i<=psys->part->hair_step; i++){ hcfra=100.0f*(float)i/(float)psys->part->hair_step; - system_step(scene, ob, psys, psmd, hcfra); - save_hair(scene, ob, psys, psmd, hcfra); + system_step(&sim, hcfra); + save_hair(&sim, hcfra); } psys->flag |= PSYS_HAIR_DONE; } /* the main particle system step */ - system_step(scene, ob, psys, psmd, cfra); + system_step(&sim, cfra); /* save matrix for duplicators */ Mat4Invert(psys->imat, ob->obmat); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index d685bc29568..dfc5b4cd770 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -79,6 +79,20 @@ static void ptcache_data_to(void **data, int type, int index, void *to); static void ptcache_data_from(void **data, int type, void *from); +#define PTCACHE_DATA_FROM(data, type, from) if(data[type]) { memcpy(data[type], from, ptcache_data_size[type]); } +#define PTCACHE_DATA_TO(data, type, index, to) if(data[type]) { memcpy(to, (char*)data[type] + (index ? index * ptcache_data_size[type] : 0), ptcache_data_size[type]); } + +int ptcache_data_size[] = { + sizeof(int), // BPHYS_DATA_INDEX + 3 * sizeof(float), // BPHYS_DATA_LOCATION: + 3 * sizeof(float), // BPHYS_DATA_VELOCITY: + 4 * sizeof(float), // BPHYS_DATA_ROTATION: + 3 * sizeof(float), // BPHYS_DATA_AVELOCITY: /* also BPHYS_DATA_XCONST */ + sizeof(float), // BPHYS_DATA_SIZE: + 3 * sizeof(float), // BPHYS_DATA_TIMES: + sizeof(BoidData) // case BPHYS_DATA_BOIDS: +}; + /* Common functions */ static int ptcache_read_basic_header(PTCacheFile *pf) { @@ -110,8 +124,8 @@ static int ptcache_write_softbody(int index, void *soft_v, void **data) SoftBody *soft= soft_v; BodyPoint *bp = soft->bpoint + index; - ptcache_data_from(data, BPHYS_DATA_LOCATION, bp->pos); - ptcache_data_from(data, BPHYS_DATA_VELOCITY, bp->vec); + PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, bp->pos); + PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, bp->vec); return 1; } @@ -125,8 +139,8 @@ static void ptcache_read_softbody(int index, void *soft_v, void **data, float fr memcpy(bp->vec, data + 3, 3 * sizeof(float)); } else { - ptcache_data_to(data, BPHYS_DATA_LOCATION, 0, bp->pos); - ptcache_data_to(data, BPHYS_DATA_VELOCITY, 0, bp->vec); + PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, bp->pos); + PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, bp->vec); } } static void ptcache_interpolate_softbody(int index, void *soft_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) @@ -181,25 +195,25 @@ static int ptcache_write_particle(int index, void *psys_v, void **data) return 0; } - ptcache_data_from(data, BPHYS_DATA_INDEX, &index); - ptcache_data_from(data, BPHYS_DATA_LOCATION, pa->state.co); - ptcache_data_from(data, BPHYS_DATA_VELOCITY, pa->state.vel); - ptcache_data_from(data, BPHYS_DATA_ROTATION, pa->state.rot); - ptcache_data_from(data, BPHYS_DATA_AVELOCITY, pa->state.ave); - ptcache_data_from(data, BPHYS_DATA_SIZE, &pa->size); - ptcache_data_from(data, BPHYS_DATA_TIMES, times); + PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index); + PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co); + PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, pa->state.vel); + PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, pa->state.rot); + PTCACHE_DATA_FROM(data, BPHYS_DATA_AVELOCITY, pa->state.ave); + PTCACHE_DATA_FROM(data, BPHYS_DATA_SIZE, &pa->size); + PTCACHE_DATA_FROM(data, BPHYS_DATA_TIMES, times); if(boid) - ptcache_data_from(data, BPHYS_DATA_BOIDS, &boid->data); + PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data); return 1; } void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time) { - ptcache_data_to(data, BPHYS_DATA_LOCATION, index, key->co); - ptcache_data_to(data, BPHYS_DATA_VELOCITY, index, key->vel); - ptcache_data_to(data, BPHYS_DATA_ROTATION, index, key->rot); - ptcache_data_to(data, BPHYS_DATA_AVELOCITY, index, key->ave); + PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co); + PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, index, key->vel); + PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, key->rot); + PTCACHE_DATA_TO(data, BPHYS_DATA_AVELOCITY, index, key->ave); key->time = time; } static void ptcache_read_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float *old_data) @@ -220,18 +234,18 @@ static void ptcache_read_particle(int index, void *psys_v, void **data, float fr BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra); if(data[BPHYS_DATA_SIZE]) - ptcache_data_to(data, BPHYS_DATA_SIZE, 0, &pa->size); + PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size); if(data[BPHYS_DATA_TIMES]) { float times[3]; - ptcache_data_to(data, BPHYS_DATA_TIMES, 0, ×); + PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, ×); pa->time = times[0]; pa->dietime = times[1]; pa->lifetime = times[2]; } if(boid) - ptcache_data_to(data, BPHYS_DATA_BOIDS, 0, &boid->data); + PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data); /* determine velocity from previous location */ if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) { @@ -307,6 +321,132 @@ static int ptcache_totwrite_particle(void *psys_v) return totwrite; } +//static int ptcache_write_particle_stream(PTCacheFile *pf, PTCacheMem *pm, void *psys_v) +//{ +// ParticleSystem *psys= psys_v; +// ParticleData *pa = psys->particles; +// BoidParticle *boid = NULL; +// float times[3]; +// int i = 0; +// +// if(!pf && !pm) +// return 0; +// +// for(i=0; itotpart; i++, pa++) { +// +// if(data[BPHYS_DATA_INDEX]) { +// int step = psys->pointcache->step; +// /* No need to store unborn or died particles */ +// if(pa->time - step > pa->state.time || pa->dietime + step < pa->state.time) +// continue; +// } +// +// times[0] = pa->time; +// times[1] = pa->dietime; +// times[2] = pa->lifetime; +// +// PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, pa->state.vel); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, pa->state.rot); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_AVELOCITY, pa->state.ave); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_SIZE, &pa->size); +// PTCACHE_DATA_FROM(data, BPHYS_DATA_TIMES, times); +// +// boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL; +// if(boid) +// PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data); +// +// if(pf && !ptcache_file_write_data(pf)) +// return 0; +// +// if(pm) +// BKE_ptcache_mem_incr_pointers(pm); +// } +// +// return 1; +//} +//static void ptcache_read_particle_stream(PTCacheFile *pf, PTCacheMem *pm, void *psys_v, void **data, float frs_sec, float cfra, float *old_data) +//{ +// ParticleSystem *psys= psys_v; +// ParticleData *pa = psys->particles + index; +// BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL; +// +// if(cfra > pa->state.time) +// memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey)); +// +// if(old_data){ +// /* old format cache */ +// memcpy(&pa->state, old_data, sizeof(ParticleKey)); +// return; +// } +// +// BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra); +// +// if(data[BPHYS_DATA_SIZE]) +// PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size); +// +// if(data[BPHYS_DATA_TIMES]) { +// float times[3]; +// PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, ×); +// pa->time = times[0]; +// pa->dietime = times[1]; +// pa->lifetime = times[2]; +// } +// +// if(boid) +// PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data); +// +// /* determine velocity from previous location */ +// if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) { +// if(cfra > pa->prev_state.time) { +// VecSubf(pa->state.vel, pa->state.co, pa->prev_state.co); +// VecMulf(pa->state.vel, (cfra - pa->prev_state.time) / frs_sec); +// } +// else { +// VecSubf(pa->state.vel, pa->prev_state.co, pa->state.co); +// VecMulf(pa->state.vel, (pa->prev_state.time - cfra) / frs_sec); +// } +// } +// +// /* determine rotation from velocity */ +// if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) { +// vectoquat(pa->state.vel, OB_POSX, OB_POSZ, pa->state.rot); +// } +//} +//static void ptcache_interpolate_particle_stream(int index, void *psys_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) +//{ +// ParticleSystem *psys= psys_v; +// ParticleData *pa = psys->particles + index; +// ParticleKey keys[4]; +// float dfra; +// +// cfra = MIN2(cfra, pa->dietime); +// cfra1 = MIN2(cfra1, pa->dietime); +// cfra2 = MIN2(cfra2, pa->dietime); +// +// if(cfra1 == cfra2) +// return; +// +// memcpy(keys+1, &pa->state, sizeof(ParticleKey)); +// if(old_data) +// memcpy(keys+2, old_data, sizeof(ParticleKey)); +// else +// BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2); +// +// dfra = cfra2 - cfra1; +// +// VecMulf(keys[1].vel, dfra / frs_sec); +// VecMulf(keys[2].vel, dfra / frs_sec); +// +// psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1); +// QuatInterpol(pa->state.rot, keys[1].rot,keys[2].rot, (cfra - cfra1) / dfra); +// +// VecMulf(pa->state.vel, frs_sec / dfra); +// +// pa->state.time = cfra; +//} +// /* Cloth functions */ static int ptcache_write_cloth(int index, void *cloth_v, void **data) { @@ -314,9 +454,9 @@ static int ptcache_write_cloth(int index, void *cloth_v, void **data) Cloth *cloth= clmd->clothObject; ClothVertex *vert = cloth->verts + index; - ptcache_data_from(data, BPHYS_DATA_LOCATION, vert->x); - ptcache_data_from(data, BPHYS_DATA_VELOCITY, vert->v); - ptcache_data_from(data, BPHYS_DATA_XCONST, vert->xconst); + PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, vert->x); + PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, vert->v); + PTCACHE_DATA_FROM(data, BPHYS_DATA_XCONST, vert->xconst); return 1; } @@ -332,9 +472,9 @@ static void ptcache_read_cloth(int index, void *cloth_v, void **data, float frs_ memcpy(vert->v, data + 6, 3 * sizeof(float)); } else { - ptcache_data_to(data, BPHYS_DATA_LOCATION, 0, vert->x); - ptcache_data_to(data, BPHYS_DATA_VELOCITY, 0, vert->v); - ptcache_data_to(data, BPHYS_DATA_XCONST, 0, vert->xconst); + PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, vert->x); + PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, vert->v); + PTCACHE_DATA_TO(data, BPHYS_DATA_XCONST, 0, vert->xconst); } } static void ptcache_interpolate_cloth(int index, void *cloth_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) @@ -987,7 +1127,7 @@ static int ptcache_file_read_data(PTCacheFile *pf) int i; for(i=0; idata_types & (1<cur[i], 1, BKE_ptcache_data_size(i))) + if(pf->data_types & (1<cur[i], 1, ptcache_data_size[i])) return 0; } @@ -998,7 +1138,7 @@ static int ptcache_file_write_data(PTCacheFile *pf) int i; for(i=0; idata_types & (1<cur[i], 1, BKE_ptcache_data_size(i))) + if(pf->data_types & (1<cur[i], 1, ptcache_data_size[i])) return 0; } @@ -1045,38 +1185,7 @@ static int ptcache_file_write_header_begin(PTCacheFile *pf) /* Data pointer handling */ int BKE_ptcache_data_size(int data_type) { - switch(data_type) { - case BPHYS_DATA_INDEX: - return sizeof(int); - case BPHYS_DATA_LOCATION: - case BPHYS_DATA_VELOCITY: - case BPHYS_DATA_AVELOCITY: /* also BPHYS_DATA_XCONST */ - case BPHYS_DATA_TIMES: - return 3 * sizeof(float); - case BPHYS_DATA_ROTATION: - return 4 * sizeof(float); - case BPHYS_DATA_SIZE: - return sizeof(float); - case BPHYS_DATA_BOIDS: - return sizeof(BoidData); - default: - return 0; - } -} -static void ptcache_data_to(void **data, int type, int index, void *to) -{ - if(data[type]) { - if(index) - memcpy(to, (char*)data[type] + index * BKE_ptcache_data_size(type), BKE_ptcache_data_size(type)); - else - memcpy(to, data[type], BKE_ptcache_data_size(type)); - } -} - -static void ptcache_data_from(void **data, int type, void *from) -{ - if(data[type]) - memcpy(data[type], from, BKE_ptcache_data_size(type)); + return ptcache_data_size[data_type]; } static void ptcache_file_init_pointers(PTCacheFile *pf) @@ -1108,7 +1217,7 @@ void BKE_ptcache_mem_incr_pointers(PTCacheMem *pm) for(i=0; icur[i]) - pm->cur[i] = (char*)pm->cur[i] + BKE_ptcache_data_size(i); + pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i]; } } static void ptcache_alloc_data(PTCacheMem *pm) @@ -1119,7 +1228,7 @@ static void ptcache_alloc_data(PTCacheMem *pm) for(i=0; idata[i] = MEM_callocN(totpoint * BKE_ptcache_data_size(i), "PTCache Data"); + pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data"); } } static void ptcache_free_data(void *data[]) @@ -1136,7 +1245,7 @@ static void ptcache_copy_data(void *from[], void *to[]) int i; for(i=0; ipathcachebufs.first = psys->pathcachebufs.last = 0; psys->childcachebufs.first = psys->childcachebufs.last = 0; psys->reactevents.first = psys->reactevents.last = 0; + psys->frand = NULL; + psys->pdd = NULL; direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache); diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index 6d1f2e5057b..cbfcf1508c7 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -1184,6 +1184,9 @@ void PE_update_object(Scene *scene, Object *ob, int useflag) point->flag &= ~PEP_EDIT_RECALC; } + if(edit->psys) + edit->psys->flag &= ~PSYS_HAIR_UPDATED; + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); } @@ -1761,6 +1764,7 @@ static void rekey_particle(PEData *data, int pa_index) { PTCacheEdit *edit= data->edit; ParticleSystem *psys= edit->psys; + ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL}; ParticleData *pa= psys->particles + pa_index; PTCacheEditPoint *point = edit->points + pa_index; ParticleKey state; @@ -1785,7 +1789,7 @@ static void rekey_particle(PEData *data, int pa_index) /* interpolate new keys from old ones */ for(k=1,key++; ktotrekey-1; k++,key++) { state.time= (float)k / (float)(data->totrekey-1); - psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0); + psys_get_particle_on_path(&sim, pa_index, &state, 0); VECCOPY(key->co, state.co); key->time= sta + k * dval; } @@ -1853,6 +1857,7 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float { PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys; + ParticleSimulationData sim = {scene, ob, edit ? edit->psys : NULL, NULL}; ParticleData *pa; ParticleKey state; HairKey *new_keys, *key; @@ -1872,7 +1877,7 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float /* interpolate new keys from old ones (roots stay the same) */ for(k=1, key++; k < pa->totkey; k++, key++) { state.time= path_time * (float)k / (float)(pa->totkey-1); - psys_get_particle_on_path(scene, ob, psys, pa_index, &state, 0); + psys_get_particle_on_path(&sim, pa_index, &state, 0); VECCOPY(key->co, state.co); } @@ -2044,6 +2049,7 @@ static void subdivide_particle(PEData *data, int pa_index) { PTCacheEdit *edit= data->edit; ParticleSystem *psys= edit->psys; + ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL}; ParticleData *pa= psys->particles + pa_index; PTCacheEditPoint *point = edit->points + pa_index; ParticleKey state; @@ -2083,7 +2089,7 @@ static void subdivide_particle(PEData *data, int pa_index) if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) { nkey->time= (key->time + (key+1)->time)*0.5f; state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f; - psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0); + psys_get_particle_on_path(&sim, pa_index, &state, 0); VECCOPY(nkey->co, state.co); nekey->co= nkey->co; @@ -2875,12 +2881,13 @@ static void brush_add(PEData *data, short number) ParticleSystem *psys= edit->psys; ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add"); ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys); + ParticleSimulationData sim = {scene, ob, psys, psmd}; ParticleEditSettings *pset= PE_settings(scene); int i, k, n= 0, totpart= psys->totpart; short mco[2]; short dmx= 0, dmy= 0; float co1[3], co2[3], min_d, imat[4][4]; - float framestep, timestep= psys_get_timestep(psys->part); + float framestep, timestep= psys_get_timestep(&sim); short size= pset->brush[PE_BRUSH_ADD].size; short size2= size*size; DerivedMesh *dm=0; @@ -2975,8 +2982,8 @@ static void brush_add(PEData *data, short number) } pa->size= 1.0f; - initialize_particle(pa,i,ob,psys,psmd); - reset_particle(scene, pa,psys,psmd,ob,0.0,1.0,0,0,0); + initialize_particle(&sim, pa,i); + reset_particle(&sim, pa, 0.0, 1.0); point->flag |= PEP_EDIT_RECALC; if(pset->flag & PE_X_MIRROR) point->flag |= PEP_TAG; /* signal for duplicate */ @@ -3013,18 +3020,18 @@ static void brush_add(PEData *data, short number) hkey->time= pa->time + k * framestep; key[0].time= hkey->time/ 100.0f; - psys_get_particle_on_path(scene, ob, psys, ptn[0].index, key, 0); + psys_get_particle_on_path(&sim, ptn[0].index, key, 0); VecMulf(key[0].co, weight[0]); if(maxw>1) { key[1].time= key[0].time; - psys_get_particle_on_path(scene, ob, psys, ptn[1].index, key + 1, 0); + psys_get_particle_on_path(&sim, ptn[1].index, key + 1, 0); VecMulf(key[1].co, weight[1]); VECADD(key[0].co, key[0].co, key[1].co); if(maxw>2) { key[2].time= key[0].time; - psys_get_particle_on_path(scene, ob, psys, ptn[2].index, key + 2, 0); + psys_get_particle_on_path(&sim, ptn[2].index, key + 2, 0); VecMulf(key[2].co, weight[2]); VECADD(key[0].co, key[0].co, key[2].co); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 40eb74e8062..3212d5cee89 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2974,13 +2974,6 @@ static void view3d_particle_text_draw(View3D *v3d, ARegion *ar) if(pstrings.first) BLI_freelistN(&pstrings); } -typedef struct ParticleDrawData { - float *vdata, *vd; - float *ndata, *nd; - float *cdata, *cd; - float *vedata, *ved; - float *ma_r, *ma_g, *ma_b; -} ParticleDrawData; static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd) { float vec[3], vec2[3]; @@ -3145,7 +3138,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv ParticleData *pars, *pa; ParticleKey state, *states=0; ParticleBillboardData bb; - ParticleDrawData pdd; + ParticleSimulationData sim = {scene, ob, psys, NULL}; + ParticleDrawData *pdd = psys->pdd; Material *ma; float vel[3], imat[4][4]; float timestep, pixsize=1.0, pa_size, r_tilt, r_length; @@ -3176,9 +3170,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(part->draw_as==PART_DRAW_NOT) return; /* 2. */ + sim.psmd = psmd = psys_get_modifier(ob,psys); + if(part->phystype==PART_PHYS_KEYED){ if(psys->flag&PSYS_KEYED){ - psys_count_keyed_targets(ob,psys); + psys_count_keyed_targets(&sim); if(psys->totkeyed==0) return; } @@ -3196,8 +3192,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv totchild=0; else totchild=psys->totchild*part->disp/100; - - memset(&pdd, 0, sizeof(ParticleDrawData)); ma= give_current_material(ob,part->omat); @@ -3212,18 +3206,16 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv ma_g = ma->g; ma_b = ma->b; - pdd.ma_r = &ma_r; - pdd.ma_g = &ma_g; - pdd.ma_b = &ma_b; + pdd->ma_r = &ma_r; + pdd->ma_g = &ma_g; + pdd->ma_b = &ma_b; create_cdata = 1; } else cpack(0); - psmd= psys_get_modifier(ob,psys); - - timestep= psys_get_timestep(part); + timestep= psys_get_timestep(&sim); if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) { float mat[4][4]; @@ -3317,54 +3309,65 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv /* 4. */ if(draw_as && draw_as!=PART_DRAW_PATH) { int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); - + + if(!pdd) + pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData"); + if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) { tot_vec_size *= part->trail_count; psys_make_temp_pointcache(ob, psys); } + if(pdd->tot_vec_size != tot_vec_size) + psys_free_pdd(psys); + if(draw_as!=PART_DRAW_CIRC) { switch(draw_as) { case PART_DRAW_AXIS: case PART_DRAW_CROSS: if(draw_as != PART_DRAW_CROSS || create_cdata) - pdd.cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata"); - pdd.vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata"); + if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata"); + if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata"); break; case PART_DRAW_LINE: if(create_cdata) - pdd.cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata"); - pdd.vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata"); + if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata"); + if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata"); break; case PART_DRAW_BB: if(create_cdata) - pdd.cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata"); - pdd.vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); - pdd.ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); + if(!pdd->cdata) pdd->cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata"); + if(!pdd->vdata) pdd->vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); + if(!pdd->ndata) pdd->ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); break; default: if(create_cdata) - pdd.cdata=MEM_callocN(tot_vec_size, "particle_cdata"); - pdd.vdata=MEM_callocN(tot_vec_size, "particle_vdata"); + if(!pdd->cdata) pdd->cdata=MEM_callocN(tot_vec_size, "particle_cdata"); + if(!pdd->vdata) pdd->vdata=MEM_callocN(tot_vec_size, "particle_vdata"); } } if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { - pdd.vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata"); + if(!pdd->vedata) pdd->vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata"); need_v = 1; } - pdd.vd= pdd.vdata; - pdd.ved= pdd.vedata; - pdd.cd= pdd.cdata; - pdd.nd= pdd.ndata; + pdd->vd= pdd->vdata; + pdd->ved= pdd->vedata; + pdd->cd= pdd->cdata; + pdd->nd= pdd->ndata; + pdd->tot_vec_size= tot_vec_size; - psys->lattice= psys_get_lattice(scene, ob, psys); + psys->lattice= psys_get_lattice(&sim); } if(draw_as){ /* 5. */ - for(a=0,pa=pars; aflag & PARTICLE_DRAW_DATA_UPDATED) + && (pdd->vedata || part->draw & (PART_DRAW_SIZE|PART_DRAW_NUM|PART_DRAW_HEALTH))==0) { + totpoint = pdd->totpoint; /* draw data is up to date */ + } + else for(a=0,pa=pars; adraw&PART_DRAW_PARENT)==0) continue; @@ -3374,9 +3377,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_birthtime=pa->time; pa_dietime = pa->dietime; pa_size=pa->size; - if(part->phystype==PART_PHYS_BOIDS) { + if(part->phystype==PART_PHYS_BOIDS) pa_health = pa->boid->data.health; - } else pa_health = -1.0; @@ -3411,10 +3413,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv } #endif // XXX old animation system - BLI_srandom(psys->seed+a); - - r_tilt = 2.0f*(BLI_frand() - 0.5f); - r_length = BLI_frand(); + r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f); + r_length = PSYS_FRAND(a + 22); } else{ ChildParticle *cpa= &psys->child[a-totpart]; @@ -3445,8 +3445,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_health = -1.0; - r_tilt = 2.0f * cpa->rand[2]; - r_length = cpa->rand[1]; + r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f); + r_length = PSYS_FRAND(a + 22); } if(draw_as!=PART_DRAW_PATH){ @@ -3468,7 +3468,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv continue; state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime)); - psys_get_particle_on_path(scene,ob,psys,a,&state,need_v); + psys_get_particle_on_path(&sim,a,&state,need_v); if(psys->parent) Mat4MulVecfl(psys->parent->obmat, state.co); @@ -3480,7 +3480,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv bb.time = ct; } - draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); + draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, psys->pdd); totpoint++; drawn = 1; @@ -3489,7 +3489,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv else { state.time=cfra; - if(psys_get_particle_state(scene,ob,psys,a,&state,0)){ + if(psys_get_particle_state(&sim,a,&state,0)){ if(psys->parent) Mat4MulVecfl(psys->parent->obmat, state.co); @@ -3500,7 +3500,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv bb.time = pa_time; } - draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); + draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, pdd); totpoint++; drawn = 1; @@ -3510,13 +3510,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(drawn) { /* additional things to draw for each particle */ /* (velocity, size and number) */ - if(pdd.vedata){ - VECCOPY(pdd.ved,state.co); - pdd.ved+=3; + if(pdd->vedata){ + VECCOPY(pdd->ved,state.co); + pdd->ved+=3; VECCOPY(vel,state.vel); VecMulf(vel,timestep); - VECADD(pdd.ved,state.co,vel); - pdd.ved+=3; + VECADD(pdd->ved,state.co,vel); + pdd->ved+=3; totve++; } @@ -3628,17 +3628,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDisableClientState(GL_COLOR_ARRAY); /* setup created data arrays */ - if(pdd.vdata){ + if(pdd->vdata){ glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pdd.vdata); + glVertexPointer(3, GL_FLOAT, 0, pdd->vdata); } else glDisableClientState(GL_VERTEX_ARRAY); /* billboards are drawn this way */ - if(pdd.ndata && ob_dt>OB_WIRE){ + if(pdd->ndata && ob_dt>OB_WIRE){ glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, pdd.ndata); + glNormalPointer(GL_FLOAT, 0, pdd->ndata); glEnable(GL_LIGHTING); } else{ @@ -3646,9 +3646,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDisable(GL_LIGHTING); } - if(pdd.cdata){ + if(pdd->cdata){ glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_FLOAT, 0, pdd.cdata); + glColorPointer(3, GL_FLOAT, 0, pdd->cdata); } /* draw created data arrays */ @@ -3670,14 +3670,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDrawArrays(GL_POINTS, 0, totpoint); break; } + + pdd->flag |= PARTICLE_DRAW_DATA_UPDATED; + pdd->totpoint = totpoint; } - if(pdd.vedata){ + if(pdd->vedata){ glDisableClientState(GL_COLOR_ARRAY); cpack(0xC0C0C0); glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pdd.vedata); + glVertexPointer(3, GL_FLOAT, 0, pdd->vedata); glDrawArrays(GL_LINES, 0, 2*totve); } @@ -3694,14 +3697,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(states) MEM_freeN(states); - if(pdd.vdata) - MEM_freeN(pdd.vdata); - if(pdd.vedata) - MEM_freeN(pdd.vedata); - if(pdd.cdata) - MEM_freeN(pdd.cdata); - if(pdd.ndata) - MEM_freeN(pdd.ndata); psys->flag &= ~PSYS_DRAWING; @@ -3728,10 +3723,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj float *pathcol = NULL, *pcol; - if(edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) { + if(edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) PE_update_object(scene, ob, 0); - edit->psys->flag &= ~PSYS_HAIR_UPDATED; - } /* create path and child path cache if it doesn't exist already */ if(edit->pathcache==0) diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 6a0a0e1d912..089c1c76bcf 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -67,7 +67,7 @@ typedef struct ChildParticle { int pa[4]; /* nearest particles to the child, used for the interpolation */ float w[4]; /* interpolation weights for the above particles */ float fuv[4], foffset; /* face vertex weights and offset */ - float rand[3]; + float rt; } ChildParticle; typedef struct ParticleTarget { @@ -234,13 +234,17 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in struct ListBase ptcaches; struct KDTree *tree; /* used for interactions with self and other systems */ + + struct ParticleDrawData *pdd; + + float *frand; /* array of 1024 random floats for fast lookups */ }ParticleSystem; /* part->type */ /* hair is allways baked static in object/geometry space */ /* other types (normal particles) are in global space and not static baked */ #define PART_EMITTER 0 -#define PART_REACTOR 1 +//#define PART_REACTOR 1 #define PART_HAIR 2 #define PART_FLUID 3 @@ -325,7 +329,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PART_DRAW_EMITTER 8 /* render emitter also */ #define PART_DRAW_HEALTH 16 #define PART_ABS_PATH_TIME 32 -//#define PART_DRAW_TRAIL 64 +//#define PART_DRAW_TRAIL 64 /* deprecated */ #define PART_DRAW_BB_LOCK 128 #define PART_DRAW_PARENT 256 #define PART_DRAW_NUM 512 @@ -422,13 +426,13 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PSYS_HAIR_DONE 512 #define PSYS_KEYED 1024 #define PSYS_EDITED 2048 -//#define PSYS_PROTECT_CACHE 4096 +//#define PSYS_PROTECT_CACHE 4096 /* deprecated */ #define PSYS_DISABLED 8192 /* pars->flag */ #define PARS_UNEXIST 1 #define PARS_NO_DISP 2 -//#define PARS_STICKY 4 +//#define PARS_STICKY 4 /* deprecated */ #define PARS_REKEY 8 /* pars->alive */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 02fa0c25335..5821d30bc3b 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -312,9 +312,10 @@ static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value) if(value > settings->end) value = settings->end; - if(settings->type==PART_REACTOR && value < 1.0) - value = 1.0; - else if (value < MINAFRAMEF) + //if(settings->type==PART_REACTOR && value < 1.0) + // value = 1.0; + //else + if (value < MINAFRAMEF) value = MINAFRAMEF; settings->sta = value; @@ -522,9 +523,9 @@ static EnumPropertyItem *rna_Particle_from_itemf(bContext *C, PointerRNA *ptr, i return item; } - if(part->type==PART_REACTOR) - return part_reactor_from_items; - else + //if(part->type==PART_REACTOR) + // return part_reactor_from_items; + //else return part_from_items; } @@ -767,7 +768,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) static EnumPropertyItem type_items[] = { {PART_EMITTER, "EMITTER", 0, "Emitter", ""}, - {PART_REACTOR, "REACTOR", 0, "Reactor", ""}, + //{PART_REACTOR, "REACTOR", 0, "Reactor", ""}, {PART_HAIR, "HAIR", 0, "Hair", ""}, {0, NULL, 0, NULL, NULL} }; @@ -986,10 +987,10 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Children", "Apply effectors to children."); RNA_def_property_update(prop, 0, "rna_Particle_redo"); - prop= RNA_def_property(srna, "child_seams", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_CHILD_SEAMS); - RNA_def_property_ui_text(prop, "Use seams", "Use seams to determine parents"); - RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); + //prop= RNA_def_property(srna, "child_seams", PROP_BOOLEAN, PROP_NONE); + //RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_CHILD_SEAMS); + //RNA_def_property_ui_text(prop, "Use seams", "Use seams to determine parents"); + //RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); /* TODO: used somewhere? */ prop= RNA_def_property(srna, "child_render", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 99825c0c2ff..0c56841b70d 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1484,6 +1484,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem ParticleKey state; ParticleCacheKey *cache=0; ParticleBillboardData bb; + ParticleSimulationData sim = {re->scene, ob, psys, NULL}; ParticleStrandData sd; StrandBuffer *strandbuf=0; StrandVert *svert=0; @@ -1517,14 +1518,16 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem return 1; /* 2. start initialising things */ - if(part->phystype==PART_PHYS_KEYED) - psys_count_keyed_targets(ob,psys); /* last possibility to bail out! */ - psmd= psys_get_modifier(ob,psys); + sim.psmd = psmd = psys_get_modifier(ob,psys); if(!(psmd->modifier.mode & eModifierMode_Render)) return 0; + if(part->phystype==PART_PHYS_KEYED) + psys_count_keyed_targets(&sim); + + if(G.rendering == 0) { /* preview render */ totchild = (int)((float)totchild * (float)part->disp / 100.0f); } @@ -1611,14 +1614,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem #endif // XXX old animation system cfra = bsystem_time(re->scene, 0, (float)re->scene->r.cfra, 0.0); -/* 2.4 setup reactors */ - if(part->type == PART_REACTOR){ - psys_get_reactor_target(ob, psys, &tob, &tpsys); - if(tpsys && (part->from==PART_FROM_PARTICLE || part->phystype==PART_PHYS_NO)){ - psmd = psys_get_modifier(tob,tpsys); - tpart = tpsys->part; - } - } +///* 2.4 setup reactors */ +// if(part->type == PART_REACTOR){ +// psys_get_reactor_target(ob, psys, &tob, &tpsys); +// if(tpsys && (part->from==PART_FROM_PARTICLE || part->phystype==PART_PHYS_NO)){ +// psmd = psys_get_modifier(tob,tpsys); +// tpart = tpsys->part; +// } +// } /* 2.5 setup matrices */ Mat4MulMat4(mat, ob->obmat, re->viewmat); @@ -1695,7 +1698,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } if(path_nbr == 0) - psys->lattice = psys_get_lattice(re->scene, ob, psys); + psys->lattice = psys_get_lattice(&sim); /* 3. start creating renderable things */ for(a=0,pa=pars; arand[2]; - r_length = cpa->rand[1]; + r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f); + r_length = PSYS_FRAND(a + 22); num = cpa->num; @@ -1952,7 +1955,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem continue; state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct; - psys_get_particle_on_path(re->scene,ob,psys,a,&state,1); + psys_get_particle_on_path(&sim,a,&state,1); if(psys->parent) Mat4MulVecfl(psys->parent->obmat, state.co); @@ -1971,7 +1974,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem else { time=0.0f; state.time=cfra; - if(psys_get_particle_state(re->scene,ob,psys,a,&state,0)==0) + if(psys_get_particle_state(&sim,a,&state,0)==0) continue; if(psys->parent) diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 5f8cf5504fa..b7832e74cd1 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -92,6 +92,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa { DerivedMesh* dm; ParticleKey state; + ParticleSimulationData sim = {re->scene, ob, psys, NULL}; ParticleData *pa=NULL; float cfra = bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0); int i, childexists; @@ -120,7 +121,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa Mat4Invert(ob->imat, ob->obmat); total_particles = psys->totpart+psys->totchild; - psys->lattice=psys_get_lattice(re->scene,ob,psys); + psys->lattice=psys_get_lattice(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); @@ -133,7 +134,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { state.time = cfra; - if(psys_get_particle_state(re->scene, ob, psys, i, &state, 0)) { + if(psys_get_particle_state(&sim, i, &state, 0)) { VECCOPY(partco, state.co); -- cgit v1.2.3 From b75d2c56c86ec030dbdf1031361952cccfb89878 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 18 Sep 2009 02:19:27 +0000 Subject: * Made image editor paint use predefined left/right mouse buttons rather than action/select, consistent with 3d view painting (and better for tablets!) * Fixed a small bug in project paint tool ui --- release/ui/space_view3d_toolbar.py | 2 +- source/blender/editors/space_image/space_image.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index cbea6466a85..09e85bf5131 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -599,7 +599,7 @@ class VIEW3D_PT_tools_vertexpaint(View3DPanel): # ********** default tools for texturepaint **************** class VIEW3D_PT_tools_projectpaint(View3DPanel): - __context__ = "projectpaint" + __context__ = "texturepaint" __label__ = "Project Paint" def poll(self, context): diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index e57a059265f..75e7461df95 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -232,9 +232,9 @@ void image_keymap(struct wmWindowManager *wm) RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD4, KM_PRESS, 0, 0)->ptr, "ratio", 0.25f); RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, 0, 0)->ptr, "ratio", 0.125f); - WM_keymap_add_item(keymap, "PAINT_OT_image_paint", ACTIONMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", SELECTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SELECTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); -- cgit v1.2.3 From a393a9c6f05b66692fbbb7ae2a3f101744e550f0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 02:38:38 +0000 Subject: same as r23322 in 2.4x --- 2.4x log use functions to detect stylus and eraser from the wine project, supposed to work with non-wacom tablets too (searches for wizardpen & acecad as well as 'stylus'). 2.4x did an exact check on the name, 2.5 does a case insensitive search on the type. This does a case insensitive check on both the name and type. close the devices on exit too. --- intern/ghost/intern/GHOST_WindowX11.cpp | 128 ++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 14 deletions(-) diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 708256f75f5..ab46c050fa3 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -414,6 +414,100 @@ static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) { return 0 ; } +/* These C functions are copied from Wine 1.1.13's wintab.c */ +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +static bool match_token(const char *haystack, const char *needle) +{ + const char *p, *q; + for (p = haystack; *p; ) + { + while (*p && isspace(*p)) + p++; + if (! *p) + break; + + for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++) + p++; + if (! *q && (isspace(*p) || !*p)) + return TRUE; + + while (*p && ! isspace(*p)) + p++; + } + return FALSE; +} + +/* Determining if an X device is a Tablet style device is an imperfect science. +** We rely on common conventions around device names as well as the type reported +** by Wacom tablets. This code will likely need to be expanded for alternate tablet types +** +** Wintab refers to any device that interacts with the tablet as a cursor, +** (stylus, eraser, tablet mouse, airbrush, etc) +** this is not to be confused with wacom x11 configuration "cursor" device. +** Wacoms x11 config "cursor" refers to its device slot (which we mirror with +** our gSysCursors) for puck like devices (tablet mice essentially). +*/ + +static BOOL is_tablet_cursor(const char *name, const char *type) +{ + int i; + static const char *tablet_cursor_whitelist[] = { + "wacom", + "wizardpen", + "acecad", + "tablet", + "cursor", + "stylus", + "eraser", + "pad", + NULL + }; + + for (i=0; tablet_cursor_whitelist[i] != NULL; i++) { + if (name && match_token(name, tablet_cursor_whitelist[i])) + return TRUE; + if (type && match_token(type, tablet_cursor_whitelist[i])) + return TRUE; + } + return FALSE; +} + +static BOOL is_stylus(const char *name, const char *type) +{ + int i; + static const char* tablet_stylus_whitelist[] = { + "stylus", + "wizardpen", + "acecad", + NULL + }; + + for (i=0; tablet_stylus_whitelist[i] != NULL; i++) { + if (name && match_token(name, tablet_stylus_whitelist[i])) + return TRUE; + if (type && match_token(type, tablet_stylus_whitelist[i])) + return TRUE; + } + + return FALSE; +} + +static BOOL is_eraser(const char *name, const char *type) +{ + if (name && match_token(name, "eraser")) + return TRUE; + if (type && match_token(type, "eraser")) + return TRUE; + return FALSE; +} +#undef BOOL +#undef TRUE +#undef FALSE +/* end code copied from wine */ + void GHOST_WindowX11::initXInputDevices() { static XErrorHandler old_handler = (XErrorHandler) 0 ; @@ -423,28 +517,21 @@ void GHOST_WindowX11::initXInputDevices() if(version->present) { int device_count; XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); - m_xtablet.StylusDevice = 0; - m_xtablet.EraserDevice = 0; + m_xtablet.StylusDevice = NULL; + m_xtablet.EraserDevice = NULL; m_xtablet.CommonData.Active= GHOST_kTabletModeNone; /* Install our error handler to override Xlib's termination behavior */ old_handler = XSetErrorHandler(ApplicationErrorHandler) ; for(int i=0; inum_classes; ++j) { if(ici->c_class==ValuatorClass) { +// printf("\t\tfound ValuatorClass\n"); XValuatorInfo* xvi = (XValuatorInfo*)ici; m_xtablet.PressureLevels = xvi->axes[2].max_value; @@ -469,11 +557,16 @@ void GHOST_WindowX11::initXInputDevices() m_xtablet.StylusID= 0; } } - if(type.find("eraser") != std::string::npos) { + else if(m_xtablet.EraserDevice==NULL && is_eraser(device_info[i].name, device_type)) { +// printf("\tfound eraser\n"); m_xtablet.EraserID= device_info[i].id; m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID= 0; } + + if(device_type) { + XFree((void*)device_type); + } } /* Restore handler */ @@ -1125,6 +1218,13 @@ GHOST_WindowX11:: XFreeCursor(m_display, m_custom_cursor); } + /* close tablet devices */ + if(m_xtablet.StylusDevice) + XCloseDevice(m_display, m_xtablet.StylusDevice); + + if(m_xtablet.EraserDevice) + XCloseDevice(m_display, m_xtablet.EraserDevice); + if (m_context) { if (m_context == s_firstContext) { s_firstContext = NULL; -- cgit v1.2.3 From bf6f23ff5f8af6ae28b5efa113b5b628ad2edb6b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 18 Sep 2009 03:11:17 +0000 Subject: * Added notifiers/redraws for brush edits in 3d view and image editor (so using radial control updates tool properties) * Changed the non-projection paint code to use the brush falloff curve, rather than a predefined falloff. This makes non-projection painting in the 3d view, and image editor painting much more consistent with other brush usage. --- source/blender/blenkernel/intern/brush.c | 9 +++++---- source/blender/editors/sculpt_paint/paint_image.c | 10 ++++++++-- source/blender/editors/sculpt_paint/paint_vertex.c | 12 ++++++++++-- source/blender/editors/sculpt_paint/sculpt.c | 5 ++++- source/blender/editors/space_image/space_image.c | 5 ++++- source/blender/editors/space_view3d/space_view3d.c | 4 ++++ 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 76a26762abe..9ae0863a78a 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -446,6 +446,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o ImBuf *ibuf; float xy[2], dist, rgba[4], *dstf; int x, y, rowbytes, xoff, yoff, imbflag; + int maxsize = brush->size >> 1; char *dst, crgb[3]; imbflag= (flt)? IB_rectfloat: IB_rect; @@ -470,7 +471,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); VECCOPY(dstf, brush->rgb); - dstf[3]= brush_sample_falloff(brush, dist); + dstf[3]= brush_curve_strength(brush, dist, maxsize); } else if (texfall == 1) { brush_sample_tex(brush, xy, dstf); @@ -483,7 +484,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dstf[0] = rgba[0]*brush->rgb[0]; dstf[1] = rgba[1]*brush->rgb[1]; dstf[2] = rgba[2]*brush->rgb[2]; - dstf[3] = rgba[3]*brush_sample_falloff(brush, dist); + dstf[3] = rgba[3]*brush_curve_strength(brush, dist, maxsize); } } } @@ -506,7 +507,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0]= crgb[0]; dst[1]= crgb[1]; dst[2]= crgb[2]; - dst[3]= FTOCHAR(brush_sample_falloff(brush, dist)); + dst[3]= FTOCHAR(brush_curve_strength(brush, dist, maxsize)); } else if (texfall == 1) { brush_sample_tex(brush, xy, rgba); @@ -522,7 +523,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); - dst[3] = FTOCHAR(rgba[3]*brush_sample_falloff(brush, dist)); + dst[3] = FTOCHAR(rgba[3]*brush_curve_strength(brush, dist, maxsize)); } } } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 870b66cdbbd..e8dd27f1bd2 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -4897,12 +4897,15 @@ static int paint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *even static int paint_radial_control_exec(bContext *C, wmOperator *op) { + Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint); float zoom; int ret; char str[256]; get_imapaint_zoom(C, &zoom, &zoom); - ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2.0 / zoom); + ret = brush_radial_control_exec(op, brush, 2.0 / zoom); WM_radial_control_string(op, str, 256); + + WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); return ret; } @@ -5216,10 +5219,13 @@ static int texture_paint_radial_control_invoke(bContext *C, wmOperator *op, wmEv static int texture_paint_radial_control_exec(bContext *C, wmOperator *op) { - int ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2); + Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint); + int ret = brush_radial_control_exec(op, brush, 2); char str[256]; WM_radial_control_string(op, str, 256); + WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); + return ret; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 2375e4e70ec..c43d903d4a6 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1136,7 +1136,11 @@ static int vpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve static int vpaint_radial_control_exec(bContext *C, wmOperator *op) { Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->vpaint->paint); - return brush_radial_control_exec(op, brush, 1); + int ret = brush_radial_control_exec(op, brush, 1); + + WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); + + return ret; } static int wpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -1161,7 +1165,11 @@ static int wpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve static int wpaint_radial_control_exec(bContext *C, wmOperator *op) { Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->wpaint->paint); - return brush_radial_control_exec(op, brush, 1); + int ret = brush_radial_control_exec(op, brush, 1); + + WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); + + return ret; } void PAINT_OT_weight_paint_radial_control(wmOperatorType *ot) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b08e8ab5c2b..822e79bea1e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1091,8 +1091,11 @@ static int sculpt_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve static int sculpt_radial_control_exec(bContext *C, wmOperator *op) { Brush *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint); + int ret = brush_radial_control_exec(op, brush, 1); - return brush_radial_control_exec(op, brush, 1); + WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); + + return ret; } static void SCULPT_OT_radial_control(wmOperatorType *ot) diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 75e7461df95..e325a820e92 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -486,7 +486,10 @@ static void image_buttons_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ switch(wmn->category) { - + case NC_BRUSH: + if(wmn->action==NA_EDITED) + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 15e12e73b49..12c2b272258 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -566,6 +566,10 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) break; } break; + case NC_BRUSH: + if(wmn->action==NA_EDITED) + ED_region_tag_redraw(ar); + break; case NC_SPACE: if(wmn->data == ND_SPACE_VIEW3D) ED_region_tag_redraw(ar); -- cgit v1.2.3 From 985031c23553fb851f3e351d3f3ac2bdafb7c157 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Fri, 18 Sep 2009 03:29:50 +0000 Subject: netrender: only one log file for each chunk --- release/io/netrender/master.py | 61 +++++++++++++++++++++++++++++++++--------- release/io/netrender/model.py | 22 +++++++++++++++ release/io/netrender/slave.py | 25 ++++++++++------- 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 8f59ef37069..58af47d6240 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -82,6 +82,15 @@ class MRenderJob(netrender.model.RenderJob): self.credits += (time.time() - self.last_dispatched) / 60 self.last_dispatched = time.time() + def addLog(self, frames): + log_name = "_".join(("%04d" % f for f in frames)) + ".log" + log_path = self.save_path + log_name + + for number in frames: + frame = self[number] + if frame: + frame.log_path = log_path + def addFrame(self, frame_number): frame = MRenderFrame(frame_number) self.frames.append(frame) @@ -117,6 +126,7 @@ class MRenderFrame(netrender.model.RenderFrame): self.slave = None self.time = 0 self.status = QUEUED + self.log_path = None def reset(self, all): if all or self.status == ERROR: @@ -222,11 +232,11 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): frame = job[job_frame] if frame: - if frame.status in (QUEUED, DISPATCHED): + if not frame.log_path or frame.status in (QUEUED, DISPATCHED): self.send_head(http.client.PROCESSING) else: self.server.stats("", "Sending log back to client") - f = open(job.save_path + "%04d" % job_frame + ".log", 'rb') + f = open(frame.log_path, 'rb') self.send_head() @@ -420,7 +430,27 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): slave_id = self.server.addSlave(slave_info.name, self.client_address, slave_info.stats) self.send_head(headers = {"slave-id": slave_id}) - + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "log": + slave_id = self.headers['slave-id'] + + slave = self.server.updateSlave(slave_id) + + if slave: # only if slave id is valid + length = int(self.headers['content-length']) + + log_info = netrender.model.LogFile.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) + + job = self.server.getJobByID(log_info.job_id) + + if job: + job.addLog(log_info.frames) + self.send_head(http.client.OK) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + else: # invalid slave id + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -526,19 +556,24 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job = self.server.getJobByID(job_id) if job: - length = int(self.headers['content-length']) job_frame = int(self.headers['job-frame']) - buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".log", 'ab') - f.write(buf) - f.close() - - del buf - - self.server.updateSlave(self.headers['slave-id']) + frame = job[job_frame] - self.send_head() + if frame and frame.log_path: + length = int(self.headers['content-length']) + buf = self.rfile.read(length) + f = open(frame.log_path, 'ab') + f.write(buf) + f.close() + + del buf + + self.server.updateSlave(self.headers['slave-id']) + + self.send_head() + else: # frame not found + self.send_head(http.client.NO_CONTENT) else: # job not found self.send_head(http.client.NO_CONTENT) diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 7803ad034a7..924493fd34a 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -4,6 +4,28 @@ import subprocess, shutil, time, hashlib from netrender.utils import * +class LogFile: + def __init__(self, job_id = 0, frames = []): + self.job_id = job_id + self.frames = frames + + def serialize(self): + return { + "job_id": self.job_id, + "frames": self.frames + } + + @staticmethod + def materialize(data): + if not data: + return None + + logfile = LogFile() + logfile.job_id = data["job_id"] + logfile.frames = data["frames"] + + return logfile + class RenderSlave: _slave_map = {} diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index 1f4ef3a3616..ecdbf69591a 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -117,8 +117,14 @@ def render_slave(engine, scene): print("frame", frame.number) frame_args += ["-f", str(frame.number)] + # announce log to master + logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames]) + conn.request("POST", "log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) + response = conn.getresponse() + first_frame = job.frames[0].number + # start render start_t = time.time() val = SetErrorMode() @@ -136,13 +142,14 @@ def render_slave(engine, scene): cancelled = engine.test_break() if current_t - run_t > CANCEL_POLL_SPEED: - # update logs. Eventually, it should support one log file for many frames - for frame in job.frames: - headers["job-frame"] = str(frame.number) + # update logs if needed + if stdout: + # (only need to update on one frame, they are linked + headers["job-frame"] = str(first_frame) conn.request("PUT", "log", stdout, headers=headers) response = conn.getresponse() - - stdout = bytes() + + stdout = bytes() run_t = current_t if testCancel(conn, job.id): @@ -164,10 +171,10 @@ def render_slave(engine, scene): # flush the rest of the logs if stdout: - for frame in job.frames: - headers["job-frame"] = str(frame.number) - conn.request("PUT", "log", stdout, headers=headers) - response = conn.getresponse() + # (only need to update on one frame, they are linked + headers["job-frame"] = str(first_frame) + conn.request("PUT", "log", stdout, headers=headers) + response = conn.getresponse() headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} -- cgit v1.2.3 From fd6654d4ef4be21447e45a983b15c7024de33711 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 03:41:37 +0000 Subject: remove brush_sample_falloff, #if 0, unused function is_tablet_cursor --- intern/ghost/intern/GHOST_WindowX11.cpp | 4 ++-- source/blender/blenkernel/BKE_brush.h | 1 - source/blender/blenkernel/intern/brush.c | 30 ------------------------------ 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index ab46c050fa3..060e9ca6f6c 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -450,7 +450,7 @@ static bool match_token(const char *haystack, const char *needle) ** Wacoms x11 config "cursor" refers to its device slot (which we mirror with ** our gSysCursors) for puck like devices (tablet mice essentially). */ - +#if 0 // unused static BOOL is_tablet_cursor(const char *name, const char *type) { int i; @@ -474,7 +474,7 @@ static BOOL is_tablet_cursor(const char *name, const char *type) } return FALSE; } - +#endif static BOOL is_stylus(const char *name, const char *type) { int i; diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 4d24a2433b3..01566648557 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -63,7 +63,6 @@ void brush_curve_preset(struct Brush *b, BrushCurvePreset preset); float brush_curve_strength(struct Brush *br, float p, const float len); /* sampling */ -float brush_sample_falloff(struct Brush *brush, float dist); void brush_sample_tex(struct Brush *brush, float *xy, float *rgba); void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size, struct ImBuf **imbuf); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 9ae0863a78a..6c23d4260ae 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -379,36 +379,6 @@ void brush_check_exists(Brush **brush, const char *name) } /* Brush Sampling */ - -/*static float taylor_approx_cos(float f) -{ - f = f*f; - f = 1.0f - f/2.0f + f*f/24.0f; - return f; -}*/ - -float brush_sample_falloff(Brush *brush, float dist) -{ - float a, outer, inner; - - outer = brush->size >> 1; - inner = outer*brush->innerradius; - - if (dist <= inner) { - return brush->alpha; - } - else if ((dist < outer) && (inner < outer)) { - a = sqrt((dist - inner)/(outer - inner)); - return (1 - a)*brush->alpha; - - /* formula used by sculpt, with taylor approx - a = 0.5f*(taylor_approx_cos(3.0f*(dist - inner)/(outer - inner)) + 1.0f); - return a*brush->alpha; */ - } - else - return 0.0f; -} - void brush_sample_tex(Brush *brush, float *xy, float *rgba) { MTex *mtex= brush->mtex[brush->texact]; -- cgit v1.2.3 From 292e695a35155d9e97897ac9e708c2fadd6ff2a8 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 18 Sep 2009 03:47:17 +0000 Subject: * fix for previous commit, didn't take brush strength into account --- source/blender/blenkernel/intern/brush.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 6c23d4260ae..2a0256da34c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -441,7 +441,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); VECCOPY(dstf, brush->rgb); - dstf[3]= brush_curve_strength(brush, dist, maxsize); + dstf[3]= brush->alpha*brush_curve_strength(brush, dist, maxsize); } else if (texfall == 1) { brush_sample_tex(brush, xy, dstf); @@ -454,7 +454,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dstf[0] = rgba[0]*brush->rgb[0]; dstf[1] = rgba[1]*brush->rgb[1]; dstf[2] = rgba[2]*brush->rgb[2]; - dstf[3] = rgba[3]*brush_curve_strength(brush, dist, maxsize); + dstf[3] = rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize); } } } @@ -477,7 +477,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0]= crgb[0]; dst[1]= crgb[1]; dst[2]= crgb[2]; - dst[3]= FTOCHAR(brush_curve_strength(brush, dist, maxsize)); + dst[3]= FTOCHAR(brush->alpha*brush_curve_strength(brush, dist, maxsize)); } else if (texfall == 1) { brush_sample_tex(brush, xy, rgba); @@ -493,7 +493,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); - dst[3] = FTOCHAR(rgba[3]*brush_curve_strength(brush, dist, maxsize)); + dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize)); } } } -- cgit v1.2.3 From 2a21669e6522c5a2a0f24b36524f274e5d0a699b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 04:07:41 +0000 Subject: curve could return values lower then zero, making a brush add and subtract the color in different parts. (cool but not useful!) --- source/blender/blenkernel/intern/brush.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2a0256da34c..2e88dc2158c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -933,8 +933,10 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl /* Uses the brush curve control to find a strength value between 0 and 1 */ float brush_curve_strength(Brush *br, float p, const float len) { + float f; if(p > len) p= len; - return curvemapping_evaluateF(br->curve, 0, p/len); + f= curvemapping_evaluateF(br->curve, 0, p/len); + return (f > 0.0f) ? f:0.0f; } /* TODO: should probably be unified with BrushPainter stuff? */ -- cgit v1.2.3 From d56e23afc08f931c6c5ef59e9822f9604b9db0c8 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Fri, 18 Sep 2009 07:44:52 +0000 Subject: Changed a few mutually exclusive options in preferences to radio buttons (enums) --- release/ui/space_userpref.py | 18 +++++++++------ source/blender/makesrna/intern/rna_userdef.c | 34 ++++++++++++++++------------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/release/ui/space_userpref.py b/release/ui/space_userpref.py index c148506214a..9798e0ccab6 100644 --- a/release/ui/space_userpref.py +++ b/release/ui/space_userpref.py @@ -97,14 +97,18 @@ class USERPREF_PT_view(bpy.types.Panel): sub1 = sub.column() sub1.itemL(text="Mouse Buttons:") - sub1.itemR(view, "left_mouse_button_select") - sub1.itemR(view, "right_mouse_button_select") - sub1.itemR(view, "emulate_3_button_mouse") + + sub2 = sub1.column() + sub2.enabled = (view.select_mouse == 'RIGHT') + sub2.itemR(view, "emulate_3_button_mouse") + sub1.itemL(text="Select With:") + sub1.row().itemR(view, "select_mouse", expand=True) + sub1.itemL(text="Middle Mouse:") + sub1.row().itemR(view, "middle_mouse", expand=True) sub1.itemR(view, "use_middle_mouse_paste") - sub1.itemR(view, "middle_mouse_rotate") - sub1.itemR(view, "middle_mouse_pan") - sub1.itemR(view, "wheel_invert_zoom") - sub1.itemR(view, "wheel_scroll_lines") + sub1.itemL(text="Mouse Wheel:") + sub1.itemR(view, "wheel_invert_zoom", text="Invert Zoom") + sub1.itemR(view, "wheel_scroll_lines", text="Scroll Lines") sub1.itemS() sub1.itemS() sub1.itemS() diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index d9ce215f899..b9c5739e7eb 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1563,6 +1563,16 @@ static void rna_def_userdef_view(BlenderRNA *brna) {USER_ZOOM_DOLLY, "DOLLY", 0, "Dolly", "Zooms in and out based on vertical mouse movement."}, {USER_ZOOM_SCALE, "SCALE", 0, "Scale", "Zooms in and out like scaling the view, mouse movements relative to center."}, {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem select_mouse_items[] = { + {USER_LMOUSESELECT, "LEFT", 0, "Left", "Use left Mouse Button for selection."}, + {0, "RIGHT", 0, "Right", "Use Right Mouse Button for selection."}, + {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem middle_mouse_mouse_items[] = { + {0, "PAN", 0, "Pan", "Use the middle mouse button for panning the viewport."}, + {USER_VIEWMOVE, "ROTATE", 0, "Rotate", "Use the middle mouse button for rotation the viewport."}, + {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem view_rotation_items[] = { {0, "TURNTABLE", 0, "Turntable", "Use turntable style rotation in the viewport."}, @@ -1678,15 +1688,11 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Rotate Around Selection", "Use selection as the orbiting center."); /* select with */ - prop= RNA_def_property(srna, "left_mouse_button_select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_LMOUSESELECT); - RNA_def_property_boolean_funcs(prop, NULL, "rna_userdef_lmb_select_set"); - RNA_def_property_ui_text(prop, "Left Mouse Button Select", "Use left Mouse Button for selection."); - prop= RNA_def_property(srna, "right_mouse_button_select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_LMOUSESELECT); - RNA_def_property_boolean_funcs(prop, NULL, "rna_userdef_rmb_select_set"); - RNA_def_property_ui_text(prop, "Right Mouse Button Select", "Use Right Mouse Button for selection."); + prop= RNA_def_property(srna, "select_mouse", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, select_mouse_items); + RNA_def_property_ui_text(prop, "Select Mouse", "The mouse button used for selection."); prop= RNA_def_property(srna, "emulate_3_button_mouse", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TWOBUTTONMOUSE); @@ -1715,13 +1721,11 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_update"); /* middle mouse button */ - prop= RNA_def_property(srna, "middle_mouse_rotate", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_VIEWMOVE); - RNA_def_property_ui_text(prop, "Middle Mouse Rotate", "Use the middle mouse button for rotation the viewport."); - - prop= RNA_def_property(srna, "middle_mouse_pan", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_VIEWMOVE); - RNA_def_property_ui_text(prop, "Middle Mouse Pan", "Use the middle mouse button for panning the viewport."); + + prop= RNA_def_property(srna, "middle_mouse", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, middle_mouse_mouse_items); + RNA_def_property_ui_text(prop, "Middle Mouse", "Use the middle mouse button to pan or zoom the view."); prop= RNA_def_property(srna, "wheel_invert_zoom", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_WHEELZOOMDIR); -- cgit v1.2.3 From ab518939b55810a6bf0be7a23d5f66a547299cd8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 11:25:52 +0000 Subject: - jitter for painting (image and projection painting, others can be added) - remove falloff setting now the curve is used. - bugfix for airbrush & tablet, with no movement it would assume 1.0 pressure. - rna, use the use_* prefix for brush options. --- release/ui/space_image.py | 22 +++++---- release/ui/space_view3d.py | 6 +-- release/ui/space_view3d_toolbar.py | 55 ++++++++++++++------- source/blender/blenkernel/intern/brush.c | 57 +++++++++++++++------- source/blender/editors/sculpt_paint/paint_image.c | 10 ++-- source/blender/editors/space_image/image_buttons.c | 4 +- source/blender/makesdna/DNA_brush_types.h | 4 +- source/blender/makesrna/intern/rna_brush.c | 38 +++++++-------- 8 files changed, 121 insertions(+), 75 deletions(-) diff --git a/release/ui/space_image.py b/release/ui/space_image.py index 161e29194ed..50ccda34c6a 100644 --- a/release/ui/space_image.py +++ b/release/ui/space_image.py @@ -412,7 +412,7 @@ class IMAGE_PT_paint(bpy.types.Panel): row.template_list(settings, "brushes", settings, "active_brush_index", rows=2) col.template_ID(settings, "brush", new="brush.add") - + row = layout.row(align=True) row.item_enumR(settings, "tool", 'DRAW') row.item_enumR(settings, "tool", 'SOFTEN') @@ -424,12 +424,16 @@ class IMAGE_PT_paint(bpy.types.Panel): row = col.row(align=True) row.itemR(brush, "size", slider=True) - row.itemR(brush, "size_pressure", toggle=True, text="") + row.itemR(brush, "use_size_pressure", toggle=True, text="") row = col.row(align=True) row.itemR(brush, "strength", slider=True) - row.itemR(brush, "strength_pressure", toggle=True, text="") - + row.itemR(brush, "use_strength_pressure", toggle=True, text="") + + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") + col.itemR(brush, "blend", text="Blend") class IMAGE_PT_paint_stroke(bpy.types.Panel): @@ -448,16 +452,16 @@ class IMAGE_PT_paint_stroke(bpy.types.Panel): settings = context.tool_settings.image_paint brush = settings.brush - layout.itemR(brush, "airbrush") + layout.itemR(brush, "use_airbrush") col = layout.column() - col.active = brush.airbrush + col.active = brush.use_airbrush col.itemR(brush, "rate", slider=True) - layout.itemR(brush, "space") + layout.itemR(brush, "use_space") row = layout.row(align=True) - row.active = brush.space + row.active = brush.use_space row.itemR(brush, "spacing", text="Distance", slider=True) - row.itemR(brush, "spacing_pressure", toggle=True, text="") + row.itemR(brush, "use_spacing_pressure", toggle=True, text="") class IMAGE_PT_paint_curve(bpy.types.Panel): __space_type__ = 'IMAGE_EDITOR' diff --git a/release/ui/space_view3d.py b/release/ui/space_view3d.py index 62b7fa0d91f..fd06853625e 100644 --- a/release/ui/space_view3d.py +++ b/release/ui/space_view3d.py @@ -539,16 +539,16 @@ class VIEW3D_MT_sculpt(bpy.types.Menu): layout.itemS() if brush.sculpt_tool != 'GRAB': - layout.itemR(brush, "airbrush") + layout.itemR(brush, "use_airbrush") if brush.sculpt_tool != 'LAYER': - layout.itemR(brush, "anchored") + layout.itemR(brush, "use_anchor") if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'): layout.itemR(brush, "flip_direction") if brush.sculpt_tool == 'LAYER': - layout.itemR(brush, "persistent") + layout.itemR(brush, "use_persistent") layout.itemO("sculpt.set_persistent_base") # ********** Particle menu ********** diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 09e85bf5131..6f17ad925cf 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -387,13 +387,18 @@ class VIEW3D_PT_tools_brush(PaintPanel): row = col.row(align=True) row.itemR(brush, "size", slider=True) - row.itemR(brush, "size_pressure", toggle=True, text="") + row.itemR(brush, "use_size_pressure", toggle=True, text="") if brush.sculpt_tool != 'GRAB': row = col.row(align=True) row.itemR(brush, "strength", slider=True) - row.itemR(brush, "strength_pressure", text="") - + row.itemR(brush, "use_strength_pressure", text="") + + ''' # XXX - TODO + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") + ''' col = layout.column() if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'): @@ -419,11 +424,15 @@ class VIEW3D_PT_tools_brush(PaintPanel): row = col.row(align=True) row.itemR(brush, "size", slider=True) - row.itemR(brush, "size_pressure", toggle=True, text="") + row.itemR(brush, "use_size_pressure", toggle=True, text="") row = col.row(align=True) row.itemR(brush, "strength", slider=True) - row.itemR(brush, "strength_pressure", toggle=True, text="") + row.itemR(brush, "use_strength_pressure", toggle=True, text="") + + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") col.itemR(brush, "blend", text="Blend") @@ -435,11 +444,15 @@ class VIEW3D_PT_tools_brush(PaintPanel): col = layout.column() row = col.row(align=True) row.itemR(brush, "size", slider=True) - row.itemR(brush, "size_pressure", toggle=True, text="") + row.itemR(brush, "use_size_pressure", toggle=True, text="") row = col.row(align=True) row.itemR(brush, "strength", slider=True) - row.itemR(brush, "strength_pressure", toggle=True, text="") + row.itemR(brush, "use_strength_pressure", toggle=True, text="") + + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") # Vertex Paint Mode # @@ -449,11 +462,17 @@ class VIEW3D_PT_tools_brush(PaintPanel): row = col.row(align=True) row.itemR(brush, "size", slider=True) - row.itemR(brush, "size_pressure", toggle=True, text="") + row.itemR(brush, "use_size_pressure", toggle=True, text="") row = col.row(align=True) row.itemR(brush, "strength", slider=True) - row.itemR(brush, "strength_pressure", toggle=True, text="") + row.itemR(brush, "use_strength_pressure", toggle=True, text="") + + ''' # XXX - TODO + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") + ''' class VIEW3D_PT_tools_brush_stroke(PaintPanel): __label__ = "Stroke" @@ -475,27 +494,27 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel): if context.sculpt_object: if brush.sculpt_tool != 'LAYER': - layout.itemR(brush, "anchored") - layout.itemR(brush, "rake") + layout.itemR(brush, "use_anchor") + layout.itemR(brush, "use_rake") - layout.itemR(brush, "airbrush") + layout.itemR(brush, "use_airbrush") col = layout.column() - col.active = brush.airbrush + col.active = brush.use_airbrush col.itemR(brush, "rate", slider=True) if not texture_paint: - layout.itemR(brush, "smooth_stroke") + layout.itemR(brush, "use_smooth_stroke") col = layout.column() - col.active = brush.smooth_stroke + col.active = brush.use_smooth_stroke col.itemR(brush, "smooth_stroke_radius", text="Radius", slider=True) col.itemR(brush, "smooth_stroke_factor", text="Factor", slider=True) - layout.itemR(brush, "space") + layout.itemR(brush, "use_space") row = layout.row(align=True) - row.active = brush.space + row.active = brush.use_space row.itemR(brush, "spacing", text="Distance", slider=True) if texture_paint: - row.itemR(brush, "spacing_pressure", toggle=True, text="") + row.itemR(brush, "use_spacing_pressure", toggle=True, text="") class VIEW3D_PT_tools_brush_curve(PaintPanel): __label__ = "Curve" diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2e88dc2158c..6c3c97399e4 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -44,6 +44,7 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" +#include "BLI_rand.h" #include "BKE_brush.h" #include "BKE_colortools.h" @@ -78,7 +79,7 @@ Brush *add_brush(const char *name) brush->smooth_stroke_radius= 75; brush->smooth_stroke_factor= 0.9; brush->rate= 0.1f; - brush->innerradius= 0.5f; + brush->jitter= 0.0f; brush->clone.alpha= 0.5; brush->sculpt_tool = SCULPT_TOOL_DRAW; @@ -513,7 +514,7 @@ typedef struct BrushPainterCache { int lastsize; float lastalpha; - float lastinnerradius; + float lastjitter; ImBuf *ibuf; ImBuf *texibuf; @@ -538,7 +539,7 @@ struct BrushPainter { float startsize; float startalpha; - float startinnerradius; + float startjitter; float startspacing; BrushPainterCache cache; @@ -554,7 +555,7 @@ BrushPainter *brush_painter_new(Brush *brush) painter->startsize = brush->size; painter->startalpha = brush->alpha; - painter->startinnerradius = brush->innerradius; + painter->startjitter = brush->jitter; painter->startspacing = brush->spacing; return painter; @@ -588,7 +589,7 @@ void brush_painter_free(BrushPainter *painter) brush->size = painter->startsize; brush->alpha = painter->startalpha; - brush->innerradius = painter->startinnerradius; + brush->jitter = painter->startjitter; brush->spacing = painter->startspacing; if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); @@ -744,7 +745,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos) short flt; if ((brush->size != cache->lastsize) || (brush->alpha != cache->lastalpha) - || (brush->innerradius != cache->lastinnerradius)) { + || (brush->jitter != cache->lastjitter)) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); cache->ibuf= NULL; @@ -769,7 +770,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos) cache->lastsize= brush->size; cache->lastalpha= brush->alpha; - cache->lastinnerradius= brush->innerradius; + cache->lastjitter= brush->jitter; } else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; @@ -791,20 +792,34 @@ static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pres brush->alpha = MAX2(0.0, painter->startalpha*pressure); if (brush->flag & BRUSH_SIZE_PRESSURE) brush->size = MAX2(1.0, painter->startsize*pressure); - if (brush->flag & BRUSH_RAD_PRESSURE) - brush->innerradius = MAX2(0.0, painter->startinnerradius*pressure); + if (brush->flag & BRUSH_JITTER_PRESSURE) + brush->jitter = MAX2(0.0, painter->startjitter*pressure); if (brush->flag & BRUSH_SPACING_PRESSURE) brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure)); } +static void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos) +{ + if(brush->jitter){ + jitterpos[0] = pos[0] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2); + jitterpos[1] = pos[1] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2); + } + else { + VECCOPY2D(jitterpos, pos); + } +} + int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) { Brush *brush= painter->brush; int totpaintops= 0; - if (pressure == 0.0f) - pressure = 1.0f; /* zero pressure == not using tablet */ - + if (pressure == 0.0f) { + if(painter->lastpressure) // XXX - hack, operator misses + pressure= painter->lastpressure; + else + pressure = 1.0f; /* zero pressure == not using tablet */ + } if (painter->firsttouch) { /* paint exactly once on first touch */ painter->startpaintpos[0]= pos[0]; @@ -855,7 +870,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl } #endif else { - float startdistance, spacing, step, paintpos[2], dmousepos[2]; + float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; float t, len, press; /* compute brush spacing adapted to brush size, spacing may depend @@ -880,11 +895,13 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush_apply_pressure(painter, brush, press); spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f; + brush_jitter_pos(brush, paintpos, finalpos); + if (painter->cache.enabled) - brush_painter_refresh_cache(painter, paintpos); + brush_painter_refresh_cache(painter, finalpos); totpaintops += - func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos); + func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); painter->lastpaintpos[0]= paintpos[0]; painter->lastpaintpos[1]= paintpos[1]; @@ -907,10 +924,14 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl while (painter->accumtime >= brush->rate) { brush_apply_pressure(painter, brush, pressure); + + brush_jitter_pos(brush, pos, finalpos); + if (painter->cache.enabled) - brush_painter_refresh_cache(painter, paintpos); + brush_painter_refresh_cache(painter, finalpos); + totpaintops += - func(user, painter->cache.ibuf, painter->lastmousepos, pos); + func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); painter->accumtime -= brush->rate; } @@ -924,7 +945,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush->alpha = painter->startalpha; brush->size = painter->startsize; - brush->innerradius = painter->startinnerradius; + brush->jitter = painter->startjitter; brush->spacing = painter->startspacing; return totpaintops; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index e8dd27f1bd2..0d83cef3e95 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -4443,6 +4443,7 @@ typedef struct PaintOperation { int first; int prevmouse[2]; + float prev_pressure; /* need this since we dont get tablet events for pressure change */ int brush_size_orig; double starttime; @@ -4722,8 +4723,8 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) if(wmtab->Active == EVT_TABLET_ERASER) pop->s.blend= IMB_BLEND_ERASE_ALPHA; } - else - pressure= 1.0f; + else /* otherwise airbrush becomes 1.0 pressure instantly */ + pressure= pop->prev_pressure ? pop->prev_pressure : 1.0f; if(pop->first) { pop->prevmouse[0]= mouse[0]; @@ -4732,8 +4733,7 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) /* special exception here for too high pressure values on first touch in windows for some tablets, then we just skip first touch .. */ - if ((pop->s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE| - BRUSH_SPACING_PRESSURE|BRUSH_RAD_PRESSURE)) && tablet && (pressure >= 0.99f)) + if ((pop->s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE|BRUSH_SPACING_PRESSURE)) && tablet && (pressure >= 0.99f)) return; } @@ -4748,6 +4748,8 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) /* apply */ paint_apply(C, op, &itemptr); + + pop->prev_pressure= pressure; } static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 78687958c60..bdf3e9416b9 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -453,8 +453,8 @@ void brush_buttons(const bContext *C, uiBlock *block, short fromsima, uiDefIconButBitS(block, TOG|BIT, BRUSH_ALPHA_PRESSURE, evt_nop, ICON_STYLUS_PRESSURE, 180,yco-20,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets"); uiDefButI(block, NUMSLI, evt_nop, "Size ", 0,yco-40,180,19, &brush->size, 1, 200, 0, 0, "The size of the brush"); uiDefIconButBitS(block, TOG|BIT, BRUSH_SIZE_PRESSURE, evt_nop, ICON_STYLUS_PRESSURE, 180,yco-40,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets"); - uiDefButF(block, NUMSLI, evt_nop, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush"); - uiDefIconButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, evt_nop, ICON_STYLUS_PRESSURE, 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets"); +// uiDefButF(block, NUMSLI, evt_nop, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush"); +// uiDefIconButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, evt_nop, ICON_STYLUS_PRESSURE, 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets"); uiDefButF(block, NUMSLI, evt_nop, "Spacing ",0,yco-80,180,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter"); uiDefIconButBitS(block, TOG|BIT, BRUSH_SPACING_PRESSURE, evt_nop, ICON_STYLUS_PRESSURE, 180,yco-80,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets"); uiBlockEndAlign(block); diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index a3a1a342584..1bbccd20486 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -56,7 +56,7 @@ typedef struct Brush { short flag, blend; /* general purpose flag, blend mode */ int size; /* brush diameter */ - float innerradius; /* inner radius after which the falloff starts */ + float jitter; /* jitter the position of the brush */ float spacing; /* spacing of paint operations */ int smooth_stroke_radius; /* turning radius (in pixels) for smooth stroke */ float smooth_stroke_factor; /* higher values limit fast changes in the stroke direction */ @@ -76,7 +76,7 @@ typedef struct Brush { #define BRUSH_TORUS 2 #define BRUSH_ALPHA_PRESSURE 4 #define BRUSH_SIZE_PRESSURE 8 -#define BRUSH_RAD_PRESSURE 16 +#define BRUSH_JITTER_PRESSURE 16 /* was BRUSH_RAD_PRESSURE */ #define BRUSH_SPACING_PRESSURE 32 #define BRUSH_FIXED_TEX 64 #define BRUSH_RAKE 128 diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index eea29381b92..15125795e01 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Contributor(s): Blender Foundation (2008), Juho Vepsäläinen + * Contributor(s): Blender Foundation (2008), Juho Veps�l�inen * * ***** END GPL LICENSE BLOCK ***** */ @@ -133,11 +133,11 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_range(prop, 1, 200); RNA_def_property_ui_text(prop, "Size", "Diameter of the brush."); - prop= RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "innerradius"); + prop= RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "jitter"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Falloff", "Falloff radius of the brush."); - + RNA_def_property_ui_text(prop, "Jitter", "Jitter the position of the brush while painting."); + prop= RNA_def_property(srna, "spacing", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "spacing"); RNA_def_property_range(prop, 1.0f, 100.0f); @@ -166,51 +166,51 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Strength", "The amount of pressure on the brush."); /* flag */ - prop= RNA_def_property(srna, "airbrush", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH); RNA_def_property_ui_text(prop, "Airbrush", "Keep applying paint effect while holding mouse (spray)."); - prop= RNA_def_property(srna, "wrap", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_wrap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TORUS); RNA_def_property_ui_text(prop, "Wrap", "Enable torus wrapping while painting."); - prop= RNA_def_property(srna, "strength_pressure", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength."); - prop= RNA_def_property(srna, "size_pressure", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_size_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SIZE_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Size Pressure", "Enable tablet pressure sensitivity for size."); - prop= RNA_def_property(srna, "falloff_pressure", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RAD_PRESSURE); + prop= RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_JITTER_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); - RNA_def_property_ui_text(prop, "Falloff Pressure", "Enable tablet pressure sensitivity for falloff."); - - prop= RNA_def_property(srna, "spacing_pressure", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, "Jitter Pressure", "Enable tablet pressure sensitivity for jitter."); + + prop= RNA_def_property(srna, "use_spacing_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACING_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing."); - prop= RNA_def_property(srna, "rake", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RAKE); RNA_def_property_ui_text(prop, "Rake", "Rotate the brush texture to match the stroke direction."); - prop= RNA_def_property(srna, "anchored", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_anchor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ANCHORED); RNA_def_property_ui_text(prop, "Anchored", "Keep the brush anchored to the initial location."); - prop= RNA_def_property(srna, "space", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_space", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE); RNA_def_property_ui_text(prop, "Space", "Limit brush application to the distance specified by spacing."); - prop= RNA_def_property(srna, "smooth_stroke", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_smooth_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SMOOTH_STROKE); RNA_def_property_ui_text(prop, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path."); - prop= RNA_def_property(srna, "persistent", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "use_persistent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PERSISTENT); RNA_def_property_ui_text(prop, "Persistent", "Sculpts on a persistent layer of the mesh."); -- cgit v1.2.3 From 854ea35a2498cb35e7cce26e396fab775692196e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 12:43:36 +0000 Subject: 2.5: Handlers are now evaluated in a different order, fixing some issues like Shift+R (repeat last) not giving capital R in the text editor. There is also new modal handler list at the window level, and the API call will always add it to that one now, since modal handlers were not used in other levels. The order used to be: * window modal + keymap * area modal + keymap * region modal + keymap Now it is: * window modal * region keymap * area keymap * window keymap --- source/blender/blenloader/intern/readfile.c | 1 + source/blender/editors/animation/anim_markers.c | 2 +- source/blender/editors/animation/anim_ops.c | 2 +- .../blender/editors/armature/editarmature_sketch.c | 4 +- source/blender/editors/armature/poselib.c | 2 +- source/blender/editors/gpencil/gpencil_paint.c | 2 +- .../blender/editors/interface/interface_handlers.c | 6 +- source/blender/editors/interface/interface_panel.c | 4 +- .../blender/editors/interface/interface_regions.c | 8 +-- source/blender/editors/interface/view2d_ops.c | 6 +- source/blender/editors/mesh/loopcut.c | 4 +- source/blender/editors/physics/editparticle.c | 2 +- source/blender/editors/screen/screen_ops.c | 14 ++-- source/blender/editors/sculpt_paint/paint_image.c | 4 +- source/blender/editors/sculpt_paint/paint_vertex.c | 4 +- source/blender/editors/sculpt_paint/sculpt.c | 2 +- source/blender/editors/space_image/image_ops.c | 8 +-- source/blender/editors/space_node/node_edit.c | 4 +- source/blender/editors/space_text/text_ops.c | 6 +- source/blender/editors/space_view3d/view3d_edit.c | 6 +- source/blender/editors/transform/transform_ops.c | 2 +- source/blender/editors/uvedit/uvedit_unwrap_ops.c | 2 +- source/blender/makesdna/DNA_windowmanager_types.h | 3 +- source/blender/windowmanager/WM_api.h | 2 +- .../blender/windowmanager/intern/wm_event_system.c | 77 ++++++++++++++-------- source/blender/windowmanager/intern/wm_init_exit.c | 1 + source/blender/windowmanager/intern/wm_operators.c | 10 +-- source/blender/windowmanager/intern/wm_window.c | 1 + 28 files changed, 106 insertions(+), 83 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 0cbbc1051e7..c5dcf1ce520 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4371,6 +4371,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) win->timers.first= win->timers.last= NULL; win->queue.first= win->queue.last= NULL; win->handlers.first= win->handlers.last= NULL; + win->modalhandlers.first= win->modalhandlers.last= NULL; win->subwindows.first= win->subwindows.last= NULL; win->gesture.first= win->gesture.last= NULL; diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 06fa3b715e0..bed534ae070 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -458,7 +458,7 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt) mm->event_type= evt->type; /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); /* reset frs delta */ RNA_int_set(op->ptr, "frames", 0); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 186bdc3b762..80077a6d4b3 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -162,7 +162,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event) change_frame_apply(C, op); /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 79d3d7b1366..1e416d9c31d 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -2618,7 +2618,7 @@ static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event) sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -2644,7 +2644,7 @@ static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event) sk_start_draw_gesture(sketch); sk_draw_stroke(C, sketch, sketch->gesture, dd, snap); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index c332a297e57..f072f2e980e 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -1411,7 +1411,7 @@ static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *event) poselib_preview_apply(C, op); /* add temp handler if we're running as a modal operator */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 99b85d62026..92ae2400666 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1341,7 +1341,7 @@ static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event) } /* add a modal handler for this operator, so that we can then draw continuous strokes */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 246058ceacc..e8d813d8ff9 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3660,11 +3660,11 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if(!(but->block->handle && but->block->handle->popup)) { if(button_modal_state(state)) { if(!button_modal_state(data->state)) - WM_event_add_ui_handler(C, &data->window->handlers, ui_handler_region_menu, NULL, data); + WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data); } else { if(button_modal_state(data->state)) - WM_event_remove_ui_handler(&data->window->handlers, ui_handler_region_menu, NULL, data); + WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data); } } @@ -4600,7 +4600,7 @@ static int ui_handler_popup(bContext *C, wmEvent *event, void *userdata) uiPopupBlockHandle temp= *menu; ui_popup_block_free(C, menu); - WM_event_remove_ui_handler(&CTX_wm_window(C)->handlers, ui_handler_popup, ui_handler_remove_popup, menu); + WM_event_remove_ui_handler(&CTX_wm_window(C)->modalhandlers, ui_handler_popup, ui_handler_remove_popup, menu); if(temp.menuretval == UI_RETURN_OK) { if(temp.popup_func) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 776122380bf..cf29a1ddb58 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1400,14 +1400,14 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat MEM_freeN(data); pa->activedata= NULL; - WM_event_remove_ui_handler(&win->handlers, ui_handler_panel, ui_handler_remove_panel, pa); + WM_event_remove_ui_handler(&win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa); } else { if(!data) { data= MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData"); pa->activedata= data; - WM_event_add_ui_handler(C, &win->handlers, ui_handler_panel, ui_handler_remove_panel, pa); + WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa); } if(ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 95305819e2b..065d391e6d6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2275,7 +2275,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut if(!but) { handle->popup= 1; - UI_add_popup_handlers(C, &window->handlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle); WM_event_add_mousemove(C); } @@ -2332,7 +2332,7 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup) menu= ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup); menu->popup= 1; - UI_add_popup_handlers(C, &window->handlers, menu); + UI_add_popup_handlers(C, &window->modalhandlers, menu); WM_event_add_mousemove(C); MEM_freeN(pup); @@ -2493,7 +2493,7 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, char *opname, i handle->optype= (opname)? WM_operatortype_find(opname, 0): NULL; handle->opcontext= opcontext; - UI_add_popup_handlers(C, &window->handlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle); WM_event_add_mousemove(C); } @@ -2516,7 +2516,7 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int handle->cancel_func= confirm_cancel_operator; handle->opcontext= opcontext; - UI_add_popup_handlers(C, &window->handlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle); WM_event_add_mousemove(C); } diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 33838418842..ae4fe4eed1b 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -210,7 +210,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); /* add temp handler */ - WM_event_add_modal_handler(C, &window->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -764,7 +764,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); /* add temp handler */ - WM_event_add_modal_handler(C, &window->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1292,7 +1292,7 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) v2d->scroll_ui |= V2D_SCROLL_V_ACTIVE; /* still ok, so can add */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } else { diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index f83ab04d785..c322a169679 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -328,7 +328,7 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_CANCELLED; /* add a modal handler for this operator - handles loop selection */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); lcd = op->customdata; lcd->vc.mval[0] = evt->mval[0]; @@ -356,7 +356,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_CANCELLED; /* add a modal handler for this operator - handles loop selection */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); lcd = op->customdata; lcd->vc.mval[0] = evt->mval[0]; diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index cbfcf1508c7..a5e169eba06 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -3352,7 +3352,7 @@ static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event) brush_edit_apply_event(C, op, event); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 605bd8682f5..6107d412323 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -456,7 +456,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event) } else { /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -588,7 +588,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event) /* add modal handler */ WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -870,7 +870,7 @@ static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_PASS_THROUGH; /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1160,7 +1160,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event) area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller); /* add temp handler for edge move or cancel */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1296,7 +1296,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event) rmd->origval= rmd->ar->type->minsizey; /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1749,7 +1749,7 @@ static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_PASS_THROUGH; /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -2944,7 +2944,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event) WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); /* add modal handler for ESC */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 0d83cef3e95..d3cd49a2658 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -4764,7 +4764,7 @@ static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) paint_apply_event(C, op, event); pop= op->customdata; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); if(pop->s.brush->flag & BRUSH_AIRBRUSH) pop->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f); @@ -4966,7 +4966,7 @@ static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event) cmv->starty= event->y; op->customdata= cmv; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index c43d903d4a6..17fd1d4fa4a 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1502,7 +1502,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) wpaint_stroke_done); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); op->type->modal(C, op, event); @@ -1775,7 +1775,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) vpaint_stroke_done); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); op->type->modal(C, op, event); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 822e79bea1e..a466c87746b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1440,7 +1440,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even sculpt_stroke_done); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); op->type->modal(C, op, event); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index d54dd56d1e8..3491ccd9d20 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -161,7 +161,7 @@ static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event) vpd->xof= sima->xof; vpd->yof= sima->yof; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); } static void view_pan_exit(bContext *C, wmOperator *op, int cancel) @@ -280,7 +280,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event) vpd->y= event->y; vpd->zoom= sima->zoom; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); } static void view_zoom_exit(bContext *C, wmOperator *op, int cancel) @@ -1453,7 +1453,7 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) sample_apply(C, op, event); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1621,7 +1621,7 @@ static int record_composite_invoke(bContext *C, wmOperator *op, wmEvent *event) rcd= op->customdata; rcd->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.0f); - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); if(!record_composite_apply(C, op)) return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 4fd6995b8fd..5fc09408229 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1216,7 +1216,7 @@ static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event) nsw->oldwidth= node->width; /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -2033,7 +2033,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) nldrag->link= nodeAddLink(snode->edittree, NULL, NULL, nldrag->node, nldrag->sock); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 3568f50dfe1..8e81336912b 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -1731,7 +1731,7 @@ static int scroll_invoke(bContext *C, wmOperator *op, wmEvent *event) st->flags|= ST_SCROLL_SELECT; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1860,7 +1860,7 @@ static int scroll_bar_invoke(bContext *C, wmOperator *op, wmEvent *event) st->flags|= ST_SCROLL_SELECT; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -2115,7 +2115,7 @@ static int set_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) scu->sell= txt_get_span(st->text->lines.first, st->text->sell); scu->selc= st->text->selc; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); set_cursor_apply(C, op, event); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index bbcee0415f8..d28789491dd 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -541,7 +541,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -625,7 +625,7 @@ static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) viewops_data(C, op, event); /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -823,7 +823,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event) viewops_data(C, op, event); /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7dfae33bc39..f9597b81114 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -270,7 +270,7 @@ static int transform_invoke(bContext *C, wmOperator *op, wmEvent *event) TransInfo *t = op->customdata; /* add temp handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); t->flag |= T_MODAL; // XXX meh maybe somewhere else diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index ccdc51430bc..b848bd4fb09 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -342,7 +342,7 @@ static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *event) minimize_stretch_iteration(C, op, 1); ms= op->customdata; - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); ms->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f); return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 00fbc04844c..67a6b3153e4 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -162,7 +162,8 @@ typedef struct wmWindow { ListBase timers; ListBase queue; /* all events (ghost level events were handled) */ - ListBase handlers; /* window+screen handlers, overriding all queues */ + ListBase handlers; /* window+screen handlers, handled last */ + ListBase modalhandlers; /* modal handlers, overriding all queues */ ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */ ListBase gesture; /* gesture stuff */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index b2edbc324ea..a757deb4a8a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -119,7 +119,7 @@ void WM_event_remove_ui_handler(ListBase *handlers, int (*func)(struct bContext *C, struct wmEvent *event, void *userdata), void (*remove)(struct bContext *C, void *userdata), void *userdata); -struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, ListBase *handlers, struct wmOperator *op); +struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); void WM_event_add_mousemove(struct bContext *C); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 22c5788b0ae..2a2e0141381 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1024,7 +1024,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ action= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); - if(action==WM_HANDLER_BREAK) /* not wm_event_always_pass(event) here, it denotes removed handler */ + if(action==WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */ break; } } @@ -1042,8 +1042,12 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) action= wm_handler_operator_call(C, handlers, handler, event, NULL); } - if(!always_pass && action==WM_HANDLER_BREAK) - break; + if(action==WM_HANDLER_BREAK) { + if(always_pass) + action= WM_HANDLER_CONTINUE; + else + break; + } } /* fileread case */ @@ -1055,6 +1059,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) static int wm_event_inside_i(wmEvent *event, rcti *rect) { + if(wm_event_always_pass(event)) + return 1; if(BLI_in_rcti(rect, event->x, event->y)) return 1; if(event->type==MOUSEMOVE) { @@ -1156,58 +1162,70 @@ void wm_event_do_handlers(bContext *C) /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */ wm_window_make_drawable(C, win); - action= wm_handlers_do(C, event, &win->handlers); + /* first we do modal handlers */ + action= wm_handlers_do(C, event, &win->modalhandlers); /* fileread case */ - if(CTX_wm_window(C)==NULL) { + if(CTX_wm_window(C)==NULL) return; - } /* builtin tweak, if action is break it removes tweak */ - if(!wm_event_always_pass(event)) - wm_tweakevent_test(C, event, action); + wm_tweakevent_test(C, event, action); - if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { + if(action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; int doit= 0; /* XXX to solve, here screen handlers? */ - if(!wm_event_always_pass(event)) { - if(event->type==MOUSEMOVE) { - /* state variables in screen, cursors */ - ED_screen_set_subwinactive(win, event); - /* for regions having custom cursors */ - wm_paintcursor_test(C, event); - } + if(event->type==MOUSEMOVE) { + /* state variables in screen, cursors */ + ED_screen_set_subwinactive(win, event); + /* for regions having custom cursors */ + wm_paintcursor_test(C, event); } for(sa= win->screen->areabase.first; sa; sa= sa->next) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &sa->totrct)) { - + if(wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, NULL); - action= wm_handlers_do(C, event, &sa->handlers); - if(wm_event_always_pass(event) || action==WM_HANDLER_CONTINUE) { + if(action==WM_HANDLER_CONTINUE) { for(ar=sa->regionbase.first; ar; ar= ar->next) { - if(wm_event_always_pass(event) || wm_event_inside_i(event, &ar->winrct)) { + if(wm_event_inside_i(event, &ar->winrct)) { CTX_wm_region_set(C, ar); action= wm_handlers_do(C, event, &ar->handlers); doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y)); - if(!wm_event_always_pass(event)) { - if(action==WM_HANDLER_BREAK) - break; - } + if(action==WM_HANDLER_BREAK) + break; } } } + + CTX_wm_region_set(C, NULL); + + if(action==WM_HANDLER_CONTINUE) + action= wm_handlers_do(C, event, &sa->handlers); + + CTX_wm_area_set(C, NULL); + /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */ } } + if(action==WM_HANDLER_CONTINUE) { + /* also some non-modal handlers need active area/region */ + CTX_wm_area_set(C, area_event_inside(C, event->x, event->y)); + CTX_wm_region_set(C, region_event_inside(C, event->x, event->y)); + + action= wm_handlers_do(C, event, &win->handlers); + + /* fileread case */ + if(CTX_wm_window(C)==NULL) + return; + } + /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? doing it on ghost queue gives errors when mousemoves go over area borders */ if(doit && win->screen->subwinactive != win->screen->mainwin) { @@ -1274,7 +1292,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->op_region= CTX_wm_region(C); handler->filescreen= CTX_wm_screen(C); - BLI_addhead(&win->handlers, handler); + BLI_addhead(&win->modalhandlers, handler); WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN); } @@ -1285,9 +1303,10 @@ void WM_event_set_handler_flag(wmEventHandler *handler, int flag) handler->flag= flag; } -wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op) +wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) { wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler"); + wmWindow *win= CTX_wm_window(C); /* operator was part of macro */ if(op->opm) { @@ -1302,7 +1321,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOp handler->op_area= CTX_wm_area(C); /* means frozen screen context for modal handlers! */ handler->op_region= CTX_wm_region(C); - BLI_addhead(handlers, handler); + BLI_addhead(&win->modalhandlers, handler); return handler; } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 9a268f8be17..5c78b32f3f8 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -186,6 +186,7 @@ void WM_exit(bContext *C) CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); + WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, win->screen); } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 2e2d463bbd9..f31d62967ae 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1366,7 +1366,7 @@ int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); wm_gesture_tag_redraw(C); @@ -1430,7 +1430,7 @@ int WM_gesture_circle_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= WM_gesture_new(C, event, WM_GESTURE_CIRCLE); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); wm_gesture_tag_redraw(C); @@ -1607,7 +1607,7 @@ int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= WM_gesture_new(C, event, WM_GESTURE_LASSO); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); wm_gesture_tag_redraw(C); @@ -1622,7 +1622,7 @@ int WM_gesture_lines_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= WM_gesture_new(C, event, WM_GESTURE_LINES); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); wm_gesture_tag_redraw(C); @@ -1929,7 +1929,7 @@ int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) wm_radial_control_paint, op->customdata); /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + WM_event_add_modal_handler(C, op); WM_radial_control_modal(C, op, event); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index cbb5bed4c00..2eee11c6820 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -146,6 +146,7 @@ void wm_window_free(bContext *C, wmWindow *win) CTX_wm_window_set(C, NULL); WM_event_remove_handlers(C, &win->handlers); + WM_event_remove_handlers(C, &win->modalhandlers); /* end running jobs, a job end also removes its timer */ for(wt= win->timers.first; wt; wt= wtnext) { -- cgit v1.2.3 From 26836bf44f39d4c83d7b4de94dd742c84cf82eda Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 13:02:20 +0000 Subject: 2.5: Python operators now have a working poll() function, solved by wrapping all polling in WM_operator_poll and adding a special callback for python. --- release/io/export_ply.py | 1 - source/blender/editors/interface/interface.c | 2 +- .../editors/interface/interface_templates.c | 2 +- .../blender/editors/space_view3d/view3d_toolbar.c | 4 +-- source/blender/makesdna/DNA_windowmanager_types.h | 1 + source/blender/python/intern/bpy_operator.c | 2 +- source/blender/python/intern/bpy_operator_wrap.c | 42 +++++++++++----------- source/blender/windowmanager/WM_api.h | 1 + .../blender/windowmanager/intern/wm_event_system.c | 15 ++++---- source/blender/windowmanager/intern/wm_operators.c | 2 +- 10 files changed, 39 insertions(+), 33 deletions(-) diff --git a/release/io/export_ply.py b/release/io/export_ply.py index 491ffe6b9df..b8fbe56f01c 100644 --- a/release/io/export_ply.py +++ b/release/io/export_ply.py @@ -250,7 +250,6 @@ class EXPORT_OT_ply(bpy.types.Operator): ] def poll(self, context): - print("Poll") return context.active_object != None def execute(self, context): diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 2d4b2caa845..fbc3c859f20 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -597,7 +597,7 @@ void uiEndBlock(const bContext *C, uiBlock *block) if(but->context) CTX_store_set((bContext*)C, but->context); - if(ot==NULL || (ot->poll && ot->poll((bContext *)C)==0)) { + if(ot == NULL || WM_operator_poll((bContext*)C, ot)==0) { but->flag |= UI_BUT_DISABLED; but->lock = 1; } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b27425f958d..b15ddcfae17 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2064,7 +2064,7 @@ static void operator_search_cb(const bContext *C, void *arg, char *str, uiSearch for(; ot; ot= ot->next) { if(BLI_strcasestr(ot->name, str)) { - if(ot->poll==NULL || ot->poll((bContext *)C)) { + if(WM_operator_poll((bContext*)C, ot)) { char name[256]; int len= strlen(ot->name); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 46341f53c26..e1c6f70bde0 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -163,7 +163,7 @@ static void view3d_panel_operator_redo(const bContext *C, Panel *pa) if(op==NULL) return; - if(op->type->poll && op->type->poll((bContext *)C)==0) + if(WM_operator_poll((bContext*)C, op->type) == 0) return; block= uiLayoutGetBlock(pa->layout); @@ -208,7 +208,7 @@ static void operator_search_cb(const struct bContext *C, void *arg, char *str, u for(; ot; ot= ot->next) { if(BLI_strcasestr(ot->name, str)) { - if(ot->poll==NULL || ot->poll((bContext *)C)) { + if(WM_operator_poll((bContext*)C, ot)) { if(0==uiSearchItemAdd(items, ot->name, ot, 0)) break; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 67a6b3153e4..ee2b0ab848f 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -228,6 +228,7 @@ typedef struct wmOperatorType { /* only used for operators defined with python * use to store pointers to python functions */ void *pyop_data; + int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot); } wmOperatorType; diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 69a7e554452..f2e2dd77e6d 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -65,7 +65,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) return NULL; } - if(ot->poll && (ot->poll(C) == FALSE)) { + if(WM_operator_poll((bContext*)C, ot) == FALSE) { PyErr_SetString( PyExc_SystemError, "bpy.__ops__.call: operator poll() function failed, context is incorrect"); return NULL; } diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 0a487a8dbe8..bbf657d8ce0 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -81,9 +81,9 @@ static struct BPY_flag_def pyop_ret_flags[] = { extern void BPY_update_modules( void ); //XXX temp solution -static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event) +static int PYTHON_OT_generic(int mode, bContext *C, wmOperatorType *ot, wmOperator *op, wmEvent *event) { - PyObject *py_class = op->type->pyop_data; + PyObject *py_class = ot->pyop_data; PyObject *args; PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); @@ -105,7 +105,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve /* Assign instance attributes from operator properties */ - { + if(op) { const char *arg_name; RNA_STRUCT_BEGIN(op->ptr, prop) { @@ -121,10 +121,12 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } /* set operator pointer RNA as instance "__operator__" attribute */ - RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); - py_operator= pyrna_struct_CreatePyObject(&ptr_operator); - PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); - Py_DECREF(py_operator); + if(op) { + RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); + py_operator= pyrna_struct_CreatePyObject(&ptr_operator); + PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); + Py_DECREF(py_operator); + } RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); @@ -148,8 +150,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); args = PyTuple_New(2); - //XXX Todo - wrap context in a useful way, None for now. - PyTuple_SET_ITEM(args, 1, Py_None); + PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); } PyTuple_SET_ITEM(args, 0, py_class_instance); @@ -160,21 +161,24 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } if (ret == NULL) { /* covers py_class_instance failing too */ - BPy_errors_to_report(op->reports); + if(op) + BPy_errors_to_report(op->reports); } else { if (mode==PYOP_POLL) { if (PyBool_Check(ret) == 0) { PyErr_SetString(PyExc_ValueError, "Python poll function return value "); - BPy_errors_to_report(op->reports); + if(op) + BPy_errors_to_report(op->reports); } else { ret_flag= ret==Py_True ? 1:0; } } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) { - /* the returned value could not be converted into a flag */ - BPy_errors_to_report(op->reports); + /* the returned value could not be converted into a flag */ + if(op) + BPy_errors_to_report(op->reports); ret_flag = OPERATOR_CANCELLED; } @@ -225,19 +229,17 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event) { - return PYTHON_OT_generic(PYOP_INVOKE, C, op, event); + return PYTHON_OT_generic(PYOP_INVOKE, C, op->type, op, event); } static int PYTHON_OT_execute(bContext *C, wmOperator *op) { - return PYTHON_OT_generic(PYOP_EXEC, C, op, NULL); + return PYTHON_OT_generic(PYOP_EXEC, C, op->type, op, NULL); } -static int PYTHON_OT_poll(bContext *C) +static int PYTHON_OT_poll(bContext *C, wmOperatorType *ot) { - // XXX TODO - no way to get the operator type (and therefor class) from the poll function. - //return PYTHON_OT_generic(PYOP_POLL, C, NULL, NULL); - return 1; + return PYTHON_OT_generic(PYOP_POLL, C, ot, NULL, NULL); } void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) @@ -270,7 +272,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) if (PyObject_HasAttrString(py_class, "execute")) ot->exec= PYTHON_OT_execute; if (PyObject_HasAttrString(py_class, "poll")) - ot->poll= PYTHON_OT_poll; + ot->pyop_poll= PYTHON_OT_poll; ot->pyop_data= userdata; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a757deb4a8a..69c96d0d89d 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -162,6 +162,7 @@ wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag) wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname); +int WM_operator_poll (struct bContext *C, struct wmOperatorType *ot); int WM_operator_call (struct bContext *C, struct wmOperator *op); int WM_operator_repeat (struct bContext *C, struct wmOperator *op); int WM_operator_name_call (struct bContext *C, const char *opstring, int context, struct PointerRNA *properties); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 2a2e0141381..e570a733d89 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -259,20 +259,23 @@ void wm_event_do_notifiers(bContext *C) /* ********************* operators ******************* */ -static int wm_operator_poll(bContext *C, wmOperatorType *ot) +int WM_operator_poll(bContext *C, wmOperatorType *ot) { wmOperatorTypeMacro *otmacro; for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) { wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0); - if(0==wm_operator_poll(C, ot)) + if(0==WM_operator_poll(C, ot)) return 0; } - if(ot->poll) + /* python needs operator type, so we added exception for it */ + if(ot->pyop_poll) + return ot->pyop_poll(C, ot); + else if(ot->poll) return ot->poll(C); - + return 1; } @@ -284,7 +287,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat) if(op==NULL || op->type==NULL) return retval; - if(0==wm_operator_poll(C, op->type)) + if(0==WM_operator_poll(C, op->type)) return retval; if(op->type->exec) @@ -397,7 +400,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P wmWindowManager *wm= CTX_wm_manager(C); int retval= OPERATOR_PASS_THROUGH; - if(wm_operator_poll(C, ot)) { + if(WM_operator_poll(C, ot)) { wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */ if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index f31d62967ae..a6fc575ce70 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -682,7 +682,7 @@ static void operator_search_cb(const struct bContext *C, void *arg, char *str, u for(; ot; ot= ot->next) { if(BLI_strcasestr(ot->name, str)) { - if(ot->poll==NULL || ot->poll((bContext *)C)) { + if(WM_operator_poll((bContext*)C, ot)) { char name[256]; int len= strlen(ot->name); -- cgit v1.2.3 From c67db42e3ee8d6d8a373a76fa62b2e28adf6d24e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 13:13:28 +0000 Subject: Fix #19383: crash pressing image open in texture buttons. --- source/blender/editors/space_image/image_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 3491ccd9d20..483d2fc6043 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -643,7 +643,7 @@ static int open_exec(bContext *C, wmOperator *op) static int open_invoke(bContext *C, wmOperator *op, wmEvent *event) { SpaceImage *sima= CTX_wm_space_image(C); - char *path= (sima->image)? sima->image->name: U.textudir; + char *path= (sima && sima->image)? sima->image->name: U.textudir; if(RNA_property_is_set(op->ptr, "path")) return open_exec(C, op); -- cgit v1.2.3 From 0f25d9bb542d4c78b3b28571e1ed435928f5c336 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 13:17:33 +0000 Subject: Fix #19381: Switching from sculpt to object mode does not update toolbar. --- source/blender/editors/sculpt_paint/sculpt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index a466c87746b..89cd0555ff9 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1569,10 +1569,10 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op) paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); paint_cursor_start(C, sculpt_poll); - - WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C)); } + WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C)); + return OPERATOR_FINISHED; } -- cgit v1.2.3 From 474378a0e80cb89a91d206d77b933f5c5bdd2319 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 15:47:00 +0000 Subject: VecAngle3_2D, VecAngle2 and VecAngle3 returned degrees, in arithb.c degrees are most common. - These now return radians - added macro RAD2DEG(rad) - renamed VecAngle3_2D to Vec2Angle3 since Vec2* is used in arithb.c for 2D vector functions. --- source/blender/blenkernel/intern/curve.c | 2 +- source/blender/blenlib/BLI_arithb.h | 4 +++- source/blender/blenlib/intern/arithb.c | 8 +++---- .../blender/editors/armature/editarmature_sketch.c | 6 ++--- source/blender/editors/armature/meshlaplacian.c | 6 ++--- source/blender/editors/mesh/editmesh_mods.c | 10 ++++---- source/blender/editors/mesh/editmesh_tools.c | 12 +++++----- source/blender/editors/space_view3d/drawobject.c | 10 ++++---- source/blender/editors/uvedit/uvedit_draw.c | 28 +++++++++++----------- 9 files changed, 44 insertions(+), 42 deletions(-) diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index ea3fce9ffaf..2ce877bd847 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1616,7 +1616,7 @@ static void bevel_list_flip_tangents(BevList *bl) nr= bl->nr; while(nr--) { - if(VecAngle2(bevp0->tan, bevp1->tan) > 90) + if(RAD2DEG(VecAngle2(bevp0->tan, bevp1->tan)) > 90) VecNegf(bevp1->tan); bevp0= bevp1; diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index c2d707f60f0..623a9afeb73 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -401,7 +401,7 @@ float VecAngle2(float *v1, float *v2); float VecAngle3(float *v1, float *v2, float *v3); float NormalizedVecAngle2(float *v1, float *v2); -float VecAngle3_2D(float *v1, float *v2, float *v3); +float Vec2Angle3(float *v1, float *v2, float *v3); float NormalizedVecAngle2_2D(float *v1, float *v2); void NormalShortToFloat(float *out, short *in); @@ -454,6 +454,8 @@ void i_window( #define BLI_CS_REC709 1 #define BLI_CS_CIE 2 +#define RAD2DEG(_rad) ((_rad)*(180.0/M_PI)) + void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b); void hex_to_rgb(char *hexcol, float *r, float *g, float *b); void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv); diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index b7f56e6ca1c..b10051b056a 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -3548,10 +3548,10 @@ float VecAngle3(float *v1, float *v2, float *v3) Normalize(vec1); Normalize(vec2); - return NormalizedVecAngle2(vec1, vec2) * (float)(180.0/M_PI); + return NormalizedVecAngle2(vec1, vec2); } -float VecAngle3_2D(float *v1, float *v2, float *v3) +float Vec2Angle3(float *v1, float *v2, float *v3) { float vec1[2], vec2[2]; @@ -3564,7 +3564,7 @@ float VecAngle3_2D(float *v1, float *v2, float *v3) Normalize2(vec1); Normalize2(vec2); - return NormalizedVecAngle2_2D(vec1, vec2) * (float)(180.0/M_PI); + return NormalizedVecAngle2_2D(vec1, vec2); } /* Return the shortest angle in degrees between the 2 vectors */ @@ -3577,7 +3577,7 @@ float VecAngle2(float *v1, float *v2) Normalize(vec1); Normalize(vec2); - return NormalizedVecAngle2(vec1, vec2)* (float)(180.0/M_PI); + return NormalizedVecAngle2(vec1, vec2); } float NormalizedVecAngle2(float *v1, float *v2) diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 1e416d9c31d..7f2f2a3410c 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -1814,7 +1814,7 @@ int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) VecSubf(s1, gest->segments->points[1].p, gest->segments->points[0].p); VecSubf(s2, gest->segments->points[2].p, gest->segments->points[1].p); - angle = VecAngle2(s1, s2); + angle = RAD2DEG(VecAngle2(s1, s2)); if (angle > 60 && angle < 120) { @@ -1932,7 +1932,7 @@ int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) VecSubf(s1, gest->segments->points[1].p, gest->segments->points[0].p); VecSubf(s2, gest->segments->points[2].p, gest->segments->points[1].p); - angle = VecAngle2(s1, s2); + angle = RAD2DEG(VecAngle2(s1, s2)); if (angle > 120) { @@ -2064,7 +2064,7 @@ int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) VecSubf(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p); } - angle = VecAngle2(start_v, end_v); + angle = RAD2DEG(VecAngle2(start_v, end_v)); if (angle > 120) { diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index a6c94bee5b1..81e67c4d46e 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -176,9 +176,9 @@ static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3 t2= cotan_weight(v2, v3, v1); t3= cotan_weight(v3, v1, v2); - if(VecAngle3(v2, v1, v3) > 90) obtuse= 1; - else if(VecAngle3(v1, v2, v3) > 90) obtuse= 2; - else if(VecAngle3(v1, v3, v2) > 90) obtuse= 3; + if(RAD2DEG(VecAngle3(v2, v1, v3)) > 90) obtuse= 1; + else if(RAD2DEG(VecAngle3(v1, v2, v3)) > 90) obtuse= 2; + else if(RAD2DEG(VecAngle3(v1, v3, v2)) > 90) obtuse= 3; if (obtuse > 0) { area= AreaT3Dfl(v1, v2, v3); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 7301901aff5..09ea9088a16 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -761,7 +761,7 @@ static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode) float angle; for(efa= em->faces.first; efa; efa= efa->next) { if (!(efa->f & SELECT) && !efa->h) { - angle= VecAngle2(base_efa->n, efa->n); + angle= RAD2DEG(VecAngle2(base_efa->n, efa->n)); if (angle/180.0<=thresh) { EM_select_face(efa, 1); selcount++; @@ -776,7 +776,7 @@ static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode) base_dot= Inpf(base_efa->cent, base_efa->n); for(efa= em->faces.first; efa; efa= efa->next) { if (!(efa->f & SELECT) && !efa->h) { - angle= VecAngle2(base_efa->n, efa->n); + angle= RAD2DEG(VecAngle2(base_efa->n, efa->n)); if (angle/180.0<=thresh) { dot=Inpf(efa->cent, base_efa->n); if (fabs(base_dot-dot) <= thresh) { @@ -916,7 +916,7 @@ static int similar_edge_select__internal(ToolSettings *ts, EditMesh *em, int mod else if (eed->f2==0) /* first access, assign the face */ eed->tmp.f= efa; else if (eed->f2==1) /* second, we assign the angle*/ - eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180; + eed->tmp.fp= RAD2DEG(VecAngle2(eed->tmp.f->n, efa->n))/180; eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/ } j++; @@ -946,7 +946,7 @@ static int similar_edge_select__internal(ToolSettings *ts, EditMesh *em, int mod for(eed= em->edges.first; eed; eed= eed->next) { if (!(eed->f & SELECT) && !eed->h) { VecSubf(dir, eed->v1->co, eed->v2->co); - angle= VecAngle2(base_dir, dir); + angle= RAD2DEG(VecAngle2(base_dir, dir)); if (angle>90) /* use the smallest angle between the edges */ angle= fabs(angle-180.0f); @@ -1137,7 +1137,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) float angle; for(eve= em->verts.first; eve; eve= eve->next) { if (!(eve->f & SELECT) && !eve->h) { - angle= VecAngle2(base_eve->no, eve->no); + angle= RAD2DEG(VecAngle2(base_eve->no, eve->no)); if (angle/180.0<=thresh) { eve->f |= SELECT; selcount++; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1d2b97b3f29..46b941f70df 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3121,13 +3121,13 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert CalcNormFloat(v1->co, v3->co, v4->co, noA2); if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0; - else normalADiff = VecAngle2(noA1, noA2); + else normalADiff = RAD2DEG(VecAngle2(noA1, noA2)); //if(!normalADiff) normalADiff = 179; CalcNormFloat(v2->co, v3->co, v4->co, noB1); CalcNormFloat(v4->co, v1->co, v2->co, noB2); if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0; - else normalBDiff = VecAngle2(noB1, noB2); + else normalBDiff = RAD2DEG(VecAngle2(noB1, noB2)); //if(!normalBDiff) normalBDiff = 179; measure += (normalADiff/360) + (normalBDiff/360); @@ -3142,10 +3142,10 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert diff = 0.0; diff = ( - fabs(VecAngle2(edgeVec1, edgeVec2) - 90) + - fabs(VecAngle2(edgeVec2, edgeVec3) - 90) + - fabs(VecAngle2(edgeVec3, edgeVec4) - 90) + - fabs(VecAngle2(edgeVec4, edgeVec1) - 90)) / 360; + fabs(RAD2DEG(VecAngle2(edgeVec1, edgeVec2)) - 90) + + fabs(RAD2DEG(VecAngle2(edgeVec2, edgeVec3)) - 90) + + fabs(RAD2DEG(VecAngle2(edgeVec3, edgeVec4)) - 90) + + fabs(RAD2DEG(VecAngle2(edgeVec4, edgeVec1)) - 90)) / 360; if(!diff) return 0.0; measure += diff; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3212d5cee89..b8852486dea 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1991,29 +1991,29 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E if( (e4->f & e1->f & SELECT) || (G.moving && (efa->v1->f & SELECT)) ) { /* Vec 1 */ - sprintf(val,"%.3f", VecAngle3(v4, v1, v2)); + sprintf(val,"%.3f", RAD2DEG(VecAngle3(v4, v1, v2))); VecLerpf(fvec, efa->cent, efa->v1->co, 0.8f); view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) { /* Vec 2 */ - sprintf(val,"%.3f", VecAngle3(v1, v2, v3)); + sprintf(val,"%.3f", RAD2DEG(VecAngle3(v1, v2, v3))); VecLerpf(fvec, efa->cent, efa->v2->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) { /* Vec 3 */ if(efa->v4) - sprintf(val,"%.3f", VecAngle3(v2, v3, v4)); + sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v4))); else - sprintf(val,"%.3f", VecAngle3(v2, v3, v1)); + sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v1))); VecLerpf(fvec, efa->cent, efa->v3->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } /* Vec 4 */ if(efa->v4) { if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) { - sprintf(val,"%.3f", VecAngle3(v3, v4, v1)); + sprintf(val,"%.3f", RAD2DEG(VecAngle3(v3, v4, v1))); VecLerpf(fvec, efa->cent, efa->v4->co, 0.8f); view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a58ee9772e9..fbd12007c16 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -251,17 +251,17 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac if(efa->v4) { #if 0 /* Simple but slow, better reuse normalized vectors */ - uvang1 = VecAngle3_2D(tf_uv[3], tf_uv[0], tf_uv[1]); - ang1 = VecAngle3(efa->v4->co, efa->v1->co, efa->v2->co); + uvang1 = RAD2DEG(Vec2Angle3(tf_uv[3], tf_uv[0], tf_uv[1])); + ang1 = RAD2DEG(VecAngle3(efa->v4->co, efa->v1->co, efa->v2->co)); - uvang2 = VecAngle3_2D(tf_uv[0], tf_uv[1], tf_uv[2]); - ang2 = VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co); + uvang2 = RAD2DEG(Vec2Angle3(tf_uv[0], tf_uv[1], tf_uv[2])); + ang2 = RAD2DEG(VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co)); - uvang3 = VecAngle3_2D(tf_uv[1], tf_uv[2], tf_uv[3]); - ang3 = VecAngle3(efa->v2->co, efa->v3->co, efa->v4->co); + uvang3 = RAD2DEG(Vec2Angle3(tf_uv[1], tf_uv[2], tf_uv[3])); + ang3 = RAD2DEG(VecAngle3(efa->v2->co, efa->v3->co, efa->v4->co)); - uvang4 = VecAngle3_2D(tf_uv[2], tf_uv[3], tf_uv[0]); - ang4 = VecAngle3(efa->v3->co, efa->v4->co, efa->v1->co); + uvang4 = RAD2DEG(Vec2Angle3(tf_uv[2], tf_uv[3], tf_uv[0])); + ang4 = RAD2DEG(VecAngle3(efa->v3->co, efa->v4->co, efa->v1->co)); #endif /* uv angles */ @@ -315,14 +315,14 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac } else { #if 0 /* Simple but slow, better reuse normalized vectors */ - uvang1 = VecAngle3_2D(tf_uv[2], tf_uv[0], tf_uv[1]); - ang1 = VecAngle3(efa->v3->co, efa->v1->co, efa->v2->co); + uvang1 = RAD2DEG(Vec2Angle3(tf_uv[2], tf_uv[0], tf_uv[1])); + ang1 = RAD2DEG(VecAngle3(efa->v3->co, efa->v1->co, efa->v2->co)); - uvang2 = VecAngle3_2D(tf_uv[0], tf_uv[1], tf_uv[2]); - ang2 = VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co); + uvang2 = RAD2DEG(Vec2Angle3(tf_uv[0], tf_uv[1], tf_uv[2])); + ang2 = RAD2DEG(VecAngle3(efa->v1->co, efa->v2->co, efa->v3->co)); - uvang3 = 180-(uvang1+uvang2); - ang3 = 180-(ang1+ang2); + uvang3 = M_PI-(uvang1+uvang2); + ang3 = M_PI-(ang1+ang2); #endif /* uv angles */ -- cgit v1.2.3 From 9435727712e39d728b83de9c4709679c32006405 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 15:48:49 +0000 Subject: Handlers/keymaps, some tweaks for previous commits: * Screen keymap is now split up in two, some of the area/region manipulation operators here need to be handled before others. * Moved paint/sculpt/sketch out of the 3d view keymap, these were there as a workaround, now with keymap poll no longer needed. * Also fixes #19297, 3d cursor moves when combing in particle mode. --- source/blender/editors/armature/armature_ops.c | 9 +++++ source/blender/editors/include/ED_sculpt.h | 2 +- source/blender/editors/screen/screen_ops.c | 18 +++++---- source/blender/editors/sculpt_paint/paint_image.c | 5 +++ source/blender/editors/sculpt_paint/paint_intern.h | 7 +++- source/blender/editors/sculpt_paint/paint_ops.c | 46 ++++++++++++++++++++++ source/blender/editors/sculpt_paint/paint_vertex.c | 20 +++++----- source/blender/editors/sculpt_paint/sculpt.c | 2 +- .../blender/editors/sculpt_paint/sculpt_intern.h | 3 ++ source/blender/editors/space_api/spacetypes.c | 1 + source/blender/editors/space_image/space_image.c | 2 +- source/blender/editors/space_view3d/space_view3d.c | 28 ++++++++----- source/blender/editors/space_view3d/view3d_edit.c | 3 +- source/blender/editors/space_view3d/view3d_ops.c | 32 --------------- source/blender/makesdna/DNA_windowmanager_types.h | 2 +- .../blender/windowmanager/intern/wm_event_system.c | 2 +- source/blender/windowmanager/intern/wm_window.c | 3 ++ 17 files changed, 118 insertions(+), 67 deletions(-) diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 4a61c8ddaf8..9076b533974 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -279,6 +279,15 @@ void ED_keymap_armature(wmWindowManager *wm) WM_keymap_add_item(keymap, "SKETCH_OT_cancel_stroke", ESCKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "SKETCH_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + /* sketch poll checks mode */ + WM_keymap_add_item(keymap, "SKETCH_OT_gesture", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", ACTIONMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "snap", 1); + WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, 0, 0); + kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "snap", 1); + /* Pose ------------------------ */ /* only set in posemode, by space_view3d listener */ keymap= WM_keymap_find(wm, "Pose", 0, 0); diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index c6a8881a0c6..a08f0576f42 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -33,10 +33,10 @@ struct wmWindowManager; /* sculpt.c */ void ED_operatortypes_sculpt(void); -void ED_keymap_sculpt(struct wmWindowManager *wm); /* paint_ops.c */ void ED_operatortypes_paint(void); +void ED_keymap_paint(struct wmWindowManager *wm); /* paint_image.c */ void undo_imagepaint_step(int step); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 6107d412323..b7e7fd18547 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3293,17 +3293,13 @@ void ED_keymap_screen(wmWindowManager *wm) { wmKeyMap *keymap; - /* Screen General ------------------------------------------------ */ - keymap= WM_keymap_find(wm, "Screen", 0, 0); - - - /* standard timers */ - WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0); + /* Screen Editing ------------------------------------------------ */ + keymap= WM_keymap_find(wm, "Screen Editing", 0, 0); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2); - + /* screen tools */ WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0); WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0); @@ -3312,6 +3308,14 @@ void ED_keymap_screen(wmWindowManager *wm) WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0); /* area move after action zones */ WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0); + + + /* Screen General ------------------------------------------------ */ + keymap= WM_keymap_find(wm, "Screen", 0, 0); + + /* standard timers */ + WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0); + RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index d3cd49a2658..b42566732ec 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -5240,6 +5240,11 @@ static int texture_paint_poll(bContext *C) return 0; } +int image_texture_paint_poll(bContext *C) +{ + return (texture_paint_poll(C) || image_paint_poll(C)); +} + void PAINT_OT_texture_paint_radial_control(wmOperatorType *ot) { WM_OT_radial_control_partial(ot); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index ba1b57a1bef..8251d1a5a1a 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -57,7 +57,10 @@ int paint_poll(bContext *C); void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C)); /* paint_vertex.c */ -int vertex_paint_mode_poll(bContext *C); +int weight_paint_poll(struct bContext *C); +int vertex_paint_poll(struct bContext *C); +int vertex_paint_mode_poll(struct bContext *C); + void clear_vpaint(Scene *scene, int selected); void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); @@ -69,6 +72,8 @@ void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_vertex_paint(struct wmOperatorType *ot); /* paint_image.c */ +int image_texture_paint_poll(struct bContext *C); + void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_image_paint_radial_control(struct wmOperatorType *ot); void PAINT_OT_grab_clone(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 19b46f5a941..514c80d929d 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -38,6 +38,7 @@ #include "RNA_enum_types.h" #include "paint_intern.h" +#include "sculpt_intern.h" #include @@ -133,3 +134,48 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_set); } +void ED_keymap_paint(wmWindowManager *wm) +{ + wmKeyMap *keymap; + + /* Sculpt mode */ + keymap= WM_keymap_find(wm, "Sculpt", 0, 0); + keymap->poll= sculpt_poll; + + RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); + RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); + RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE); + + WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + + /* Vertex Paint mode */ + keymap= WM_keymap_find(wm, "Vertex Paint", 0, 0); + keymap->poll= vertex_paint_poll; + + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); + WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); + + /* Weight Paint mode */ + keymap= WM_keymap_find(wm, "Weight Paint", 0, 0); + keymap->poll= weight_paint_poll; + + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); + + WM_keymap_verify_item(keymap, "PAINT_OT_weight_paint", LEFTMOUSE, KM_PRESS, 0, 0); + + /* Image/Texture Paint mode */ + keymap= WM_keymap_find(wm, "Image Paint", 0, 0); + keymap->poll= image_texture_paint_poll; + + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_texture_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_texture_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); + + WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINT_OT_clone_cursor_set", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); +} + diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 17fd1d4fa4a..5afc4954c9c 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -119,7 +119,7 @@ int vertex_paint_mode_poll(bContext *C) return ob && ob->mode == OB_MODE_VERTEX_PAINT; } -static int vp_poll(bContext *C) +int vertex_paint_poll(bContext *C) { if(vertex_paint_mode_poll(C) && paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { @@ -133,7 +133,7 @@ static int vp_poll(bContext *C) return 0; } -static int wp_poll(bContext *C) +int weight_paint_poll(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -1060,7 +1060,7 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ wp= scene->toolsettings->wpaint= new_vpaint(1); paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); - paint_cursor_start(C, wp_poll); + paint_cursor_start(C, weight_paint_poll); mesh_octree_table(ob, NULL, NULL, 's'); @@ -1129,7 +1129,7 @@ static int vpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve { int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - paint_cursor_start(C, vp_poll); + paint_cursor_start(C, vertex_paint_poll); return ret; } @@ -1158,7 +1158,7 @@ static int wpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve { int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - paint_cursor_start(C, wp_poll); + paint_cursor_start(C, weight_paint_poll); return ret; } @@ -1182,7 +1182,7 @@ void PAINT_OT_weight_paint_radial_control(wmOperatorType *ot) ot->invoke= wpaint_radial_control_invoke; ot->modal= wpaint_radial_control_modal; ot->exec= wpaint_radial_control_exec; - ot->poll= wp_poll; + ot->poll= weight_paint_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; @@ -1198,7 +1198,7 @@ void PAINT_OT_vertex_paint_radial_control(wmOperatorType *ot) ot->invoke= vpaint_radial_control_invoke; ot->modal= vpaint_radial_control_modal; ot->exec= vpaint_radial_control_exec; - ot->poll= vp_poll; + ot->poll= vertex_paint_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; @@ -1520,7 +1520,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) ot->invoke= wpaint_invoke; ot->modal= paint_stroke_modal; /* ot->exec= vpaint_exec; <-- needs stroke property */ - ot->poll= wp_poll; + ot->poll= weight_paint_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; @@ -1567,7 +1567,7 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ if(vp==NULL) vp= scene->toolsettings->vpaint= new_vpaint(0); - paint_cursor_start(C, vp_poll); + paint_cursor_start(C, vertex_paint_poll); paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); } @@ -1792,7 +1792,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) ot->invoke= vpaint_invoke; ot->modal= paint_stroke_modal; /* ot->exec= vpaint_exec; <-- needs stroke property */ - ot->poll= vp_poll; + ot->poll= vertex_paint_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 89cd0555ff9..64af39ea497 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1039,7 +1039,7 @@ static int sculpt_mode_poll(bContext *C) return ob && ob->mode & OB_MODE_SCULPT; } -static int sculpt_poll(bContext *C) +int sculpt_poll(bContext *C) { return sculpt_mode_poll(C) && paint_poll(C); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 25f97b862e6..15ccacc294a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -33,6 +33,7 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +struct bContext; struct Brush; struct Mesh; struct Object; @@ -53,6 +54,8 @@ struct Brush *sculptmode_brush(void); char sculpt_modifiers_active(struct Object *ob); void sculpt(Sculpt *sd); +int sculpt_poll(struct bContext *C); + /* Stroke */ struct SculptStroke *sculpt_stroke_new(const int max); void sculpt_stroke_free(struct SculptStroke *); diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index edd5da44526..18bc7ec9555 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -129,6 +129,7 @@ void ED_spacetypes_keymap(wmWindowManager *wm) ED_keymap_armature(wm); ED_keymap_particle(wm); ED_keymap_metaball(wm); + ED_keymap_paint(wm); ED_marker_keymap(wm); UI_view2d_keymap(wm); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index e325a820e92..f222499ba86 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -404,7 +404,7 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) // UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* image paint polls for mode */ - keymap= WM_keymap_find(wm, "ImagePaint", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm, "Image Paint", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); keymap= WM_keymap_find(wm, "UVEdit", 0, 0); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 12c2b272258..5ea633a47f7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -279,14 +279,7 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; - - /* own keymap */ - keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); - /* object ops. */ keymap= WM_keymap_find(wm, "Object Non-modal", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); @@ -295,11 +288,19 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) keymap= WM_keymap_find(wm, "Pose", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - /* operator poll checks for modes */ - keymap= WM_keymap_find(wm, "ImagePaint", 0, 0); + keymap= WM_keymap_find(wm, "Object Mode", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Object Mode", 0, 0); + keymap= WM_keymap_find(wm, "Image Paint", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Vertex Paint", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Weight Paint", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "Sculpt", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); keymap= WM_keymap_find(wm, "EditMesh", 0, 0); @@ -330,6 +331,13 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) /* editfont keymap swallows all... */ keymap= WM_keymap_find(wm, "Font", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); + + /* own keymap, last so modes can override it */ + keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); } /* type callback, not region itself */ diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d28789491dd..0faa1f8c16d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1850,8 +1850,7 @@ static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event) // XXX notifier for scene */ ED_area_tag_redraw(CTX_wm_area(C)); - /* prevent other mouse ops to fail */ - return OPERATOR_PASS_THROUGH; + return OPERATOR_FINISHED; } void VIEW3D_OT_cursor3d(wmOperatorType *ot) diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 9ffdef478b3..3569e2a79e3 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -114,26 +114,6 @@ void view3d_keymap(wmWindowManager *wm) /* only for region 3D window */ keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); - /* paint poll checks mode */ - WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "PAINT_OT_weight_paint", LEFTMOUSE, KM_PRESS, 0, 0); - - WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "PAINT_OT_clone_cursor_set", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); - - /* sketch poll checks mode */ - WM_keymap_add_item(keymap, "SKETCH_OT_gesture", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", ACTIONMOUSE, KM_PRESS, 0, 0); - km = WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(km->ptr, "snap", 1); - WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, 0, 0); - km = WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, KM_CTRL, 0); - RNA_boolean_set(km->ptr, "snap", 1); - WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, 0, 0); /* manipulator always on left mouse, not on action mouse*/ WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0); @@ -234,18 +214,6 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW3D_OT_camera_to_view", PAD0, KM_PRESS, KM_ALT|KM_CTRL, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_snap_menu", SKEY, KM_PRESS, KM_SHIFT, 0); - - /* radial control */ - RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); - RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); - RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE); - - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_texture_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); - RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_texture_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); transform_keymap_for_space(wm, keymap, SPACE_VIEW3D); diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index ee2b0ab848f..f1ce3491d0a 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -163,7 +163,7 @@ typedef struct wmWindow { ListBase queue; /* all events (ghost level events were handled) */ ListBase handlers; /* window+screen handlers, handled last */ - ListBase modalhandlers; /* modal handlers, overriding all queues */ + ListBase modalhandlers; /* priority handlers, handled first */ ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */ ListBase gesture; /* gesture stuff */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index e570a733d89..40026d27bac 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1165,7 +1165,7 @@ void wm_event_do_handlers(bContext *C) /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */ wm_window_make_drawable(C, win); - /* first we do modal handlers */ + /* first we do priority handlers, modal + some limited keymaps */ action= wm_handlers_do(C, event, &win->modalhandlers); /* fileread case */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2eee11c6820..9d3d0a9535e 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -373,6 +373,9 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) keymap= WM_keymap_find(wm, "Screen", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); + + keymap= WM_keymap_find(wm, "Screen Editing", 0, 0); + WM_event_add_keymap_handler(&win->modalhandlers, keymap); wm_window_title(wm, win); } -- cgit v1.2.3 From 9787a2e55aecef7cad850b7e3bccf62af7220a21 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Sep 2009 15:52:28 +0000 Subject: UI: fix some python errors in sculpt/paint modes when there is no brush. --- release/ui/space_image.py | 33 ++++++++++++++++++--------------- release/ui/space_view3d_toolbar.py | 8 ++++---- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/release/ui/space_image.py b/release/ui/space_image.py index 50ccda34c6a..b14bec0e40e 100644 --- a/release/ui/space_image.py +++ b/release/ui/space_image.py @@ -419,22 +419,23 @@ class IMAGE_PT_paint(bpy.types.Panel): row.item_enumR(settings, "tool", 'CLONE') row.item_enumR(settings, "tool", 'SMEAR') - col = layout.column() - col.itemR(brush, "color", text="") + if brush: + col = layout.column() + col.itemR(brush, "color", text="") - row = col.row(align=True) - row.itemR(brush, "size", slider=True) - row.itemR(brush, "use_size_pressure", toggle=True, text="") - - row = col.row(align=True) - row.itemR(brush, "strength", slider=True) - row.itemR(brush, "use_strength_pressure", toggle=True, text="") + row = col.row(align=True) + row.itemR(brush, "size", slider=True) + row.itemR(brush, "use_size_pressure", toggle=True, text="") + + row = col.row(align=True) + row.itemR(brush, "strength", slider=True) + row.itemR(brush, "use_strength_pressure", toggle=True, text="") - row = col.row(align=True) - row.itemR(brush, "jitter", slider=True) - row.itemR(brush, "use_jitter_pressure", toggle=True, text="") + row = col.row(align=True) + row.itemR(brush, "jitter", slider=True) + row.itemR(brush, "use_jitter_pressure", toggle=True, text="") - col.itemR(brush, "blend", text="Blend") + col.itemR(brush, "blend", text="Blend") class IMAGE_PT_paint_stroke(bpy.types.Panel): __space_type__ = 'IMAGE_EDITOR' @@ -444,7 +445,8 @@ class IMAGE_PT_paint_stroke(bpy.types.Panel): def poll(self, context): sima = context.space_data - return sima.show_paint + settings = context.tool_settings.image_paint + return sima.show_paint and settings.brush def draw(self, context): layout = self.layout @@ -471,7 +473,8 @@ class IMAGE_PT_paint_curve(bpy.types.Panel): def poll(self, context): sima = context.space_data - return sima.show_paint + settings = context.tool_settings.image_paint + return sima.show_paint and settings.brush def draw(self, context): layout = self.layout diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 6f17ad925cf..9492437b863 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -379,7 +379,7 @@ class VIEW3D_PT_tools_brush(PaintPanel): # Sculpt Mode # - elif context.sculpt_object and settings.brush: + elif context.sculpt_object and brush: col = layout.column() col.itemS() col.itemR(brush, "sculpt_tool", expand=True) @@ -412,7 +412,7 @@ class VIEW3D_PT_tools_brush(PaintPanel): # Texture Paint Mode # - elif context.texture_paint_object: + elif context.texture_paint_object and brush: col = layout.column(align=True) col.item_enumR(settings, "tool", 'DRAW') col.item_enumR(settings, "tool", 'SOFTEN') @@ -438,7 +438,7 @@ class VIEW3D_PT_tools_brush(PaintPanel): # Weight Paint Mode # - elif context.weight_paint_object: + elif context.weight_paint_object and brush: layout.itemR(context.tool_settings, "vertex_group_weight", text="Weight", slider=True) col = layout.column() @@ -456,7 +456,7 @@ class VIEW3D_PT_tools_brush(PaintPanel): # Vertex Paint Mode # - elif context.vertex_paint_object: + elif context.vertex_paint_object and brush: col = layout.column() col.itemR(brush, "color", text="") -- cgit v1.2.3 From c388244be4eac3535e785516d0a8c4b5b5d22643 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2009 16:39:45 +0000 Subject: Move some static math functions out of paint_image.c into arithb.c * VecLerp3f and Vec2Lerp3f - interpolate 3 2d/3d vectors from 3 weights * AngleToLength(angle) - useful for making even width shell/walls based on the angles of the surrounding geometry from each point. (same method used in 2.4x python solidify script). also quiet some warnings. --- source/blender/blenkernel/intern/particle.c | 4 +- source/blender/blenkernel/intern/particle_system.c | 10 +-- source/blender/blenlib/BLI_arithb.h | 8 ++- source/blender/blenlib/intern/arithb.c | 34 +++++++-- source/blender/editors/sculpt_paint/paint_image.c | 80 ++++++++-------------- source/blender/makesrna/intern/rna_particle.c | 2 +- .../blender/render/intern/source/convertblender.c | 2 +- 7 files changed, 72 insertions(+), 68 deletions(-) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0dc041bfc6a..e18e7f54e49 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2193,7 +2193,7 @@ static void get_strand_normal(Material *ma, float *surfnor, float surfdist, floa static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate) { ParticleThreadContext *ctx= threads[0].ctx; - Object *ob= ctx->sim.ob; +/* Object *ob= ctx->sim.ob; */ ParticleSystem *psys= ctx->sim.psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &scene->toolsettings->particle; @@ -3868,7 +3868,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta ParticleData *pa = NULL; ChildParticle *cpa = NULL; float cfra; - int totpart = psys->totpart, between = 0; + int totpart = psys->totpart; /* negative time means "use current time" */ cfra = state->time > 0 ? state->time : bsystem_time(sim->scene, 0, (float)sim->scene->r.cfra, 0.0); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 9cd897e4bcd..1b6d56e6459 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -614,7 +614,7 @@ static void psys_thread_distribute_particle(ParticleThread *thread, ParticleData Object *ob= ctx->sim.ob; DerivedMesh *dm= ctx->dm; ParticleData *tpa; - ParticleSettings *part= ctx->sim.psys->part; +/* ParticleSettings *part= ctx->sim.psys->part; */ float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3], ornor1[3]; float cur_d, min_d, randu, randv; int from= ctx->from; @@ -2451,7 +2451,7 @@ void psys_end_effectors(ParticleSystem *psys) } /* precalcs effectors and returns 1 if there were any collision object -/* so collision checks can be avoided as quickly as possible */ + * so collision checks can be avoided as quickly as possible */ static int precalc_effectors(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; @@ -3561,7 +3561,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) static void hair_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; - ParticleSettings *part = psys->part; +/* ParticleSettings *part = psys->part; */ PARTICLE_P; float disp = (float)get_current_display_percentage(psys)/100.0f; @@ -3649,7 +3649,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) ParticleSettings *part=psys->part; KDTree *tree=0; IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system - Material *ma=give_current_material(sim->ob, part->omat); +/* Material *ma=give_current_material(sim->ob, part->omat); */ BoidBrainData bbd; PARTICLE_P; float timestep; @@ -3851,7 +3851,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; IpoCurve *icu_esize = NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system - Material *ma = give_current_material(sim->ob,part->omat); +/* Material *ma = give_current_material(sim->ob,part->omat); */ PARTICLE_P; float disp, birthtime, dietime, *vg_size= NULL; // XXX ipotime=cfra diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index 623a9afeb73..793dab12b83 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -364,7 +364,8 @@ void printvec4f(char *str, float v[4]); void VecAddf(float *v, float *v1, float *v2); void VecSubf(float *v, float *v1, float *v2); void VecMulVecf(float *v, float *v1, float *v2); -void VecLerpf(float *target, float *a, float *b, float t); +void VecLerpf(float *target, const float *a, const float *b, const float t); +void VecLerp3f(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]); void VecMidf(float *v, float *v1, float *v2); void VecOrthoBasisf(float *v, float *v1, float *v2); @@ -375,7 +376,8 @@ void Vec2Mulf(float *v1, float f); void Vec2Addf(float *v, float *v1, float *v2); void Vec2Subf(float *v, float *v1, float *v2); void Vec2Copyf(float *v1, float *v2); -void Vec2Lerpf(float *target, float *a, float *b, float t); +void Vec2Lerpf(float *target, const float *a, const float *b, const float t); +void Vec2Lerp3f(float p[2], const float v1[2], const float v2[2], const float v3[2], const float w[3]); void AxisAngleToQuat(float q[4], float axis[3], float angle); void QuatToAxisAngle(float q[4], float axis[3], float *angle); @@ -527,6 +529,8 @@ int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3]); float lambda_cp_line_ex(float p[3], float l1[3], float l2[3], float cp[3]); +float AngleToLength(const float angle); + typedef struct DualQuat { float quat[4]; float trans[4]; diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index b10051b056a..ac79894d827 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -2187,23 +2187,40 @@ void VecMulVecf(float *v, float *v1, float *v2) v[2] = v1[2] * v2[2]; } -void VecLerpf(float *target, float *a, float *b, float t) +void VecLerpf(float *target, const float *a, const float *b, const float t) { - float s = 1.0f-t; + const float s = 1.0f-t; target[0]= s*a[0] + t*b[0]; target[1]= s*a[1] + t*b[1]; target[2]= s*a[2] + t*b[2]; } -void Vec2Lerpf(float *target, float *a, float *b, float t) +void Vec2Lerpf(float *target, const float *a, const float *b, const float t) { - float s = 1.0f-t; + const float s = 1.0f-t; target[0]= s*a[0] + t*b[0]; target[1]= s*a[1] + t*b[1]; } +/* weight 3 vectors, (VecWeightf in 2.4x) + * 'w' must be unit length but is not a vector, just 3 weights */ +void VecLerp3f(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]) +{ + p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2]; + p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2]; + p[2] = v1[2]*w[0] + v2[2]*w[1] + v3[2]*w[2]; +} + +/* weight 3 2D vectors, (Vec2Weightf in 2.4x) + * 'w' must be unit length but is not a vector, just 3 weights */ +void Vec2Lerp3f(float p[2], const float v1[2], const float v2[2], const float v3[2], const float w[3]) +{ + p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2]; + p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2]; +} + void VecMidf(float *v, float *v1, float *v2) { v[0]= 0.5f*(v1[0]+ v2[0]); @@ -4823,6 +4840,15 @@ static float lambda_cp_line(float p[3], float l1[3], float l2[3]) } #endif +/* useful to calculate an even width shell, by taking the angle between 2 planes. + * The return value is a scale on the offset. + * no angle between planes is 1.0, as the angle between the 2 planes approches 180d + * the distance gets very hight, 180d would be inf, but this case isnt valid */ +float AngleToLength(const float angle) +{ + return (angle < SMALL_NUMBER) ? 1.0f : fabsf(1.0f / cosf(angle * (M_PI/180.0f))); +} + /* Similar to LineIntersectsTriangleUV, except it operates on a quad and in 2d, assumes point is in quad */ void PointInQuad2DUV(float v0[2], float v1[2], float v2[2], float v3[2], float pt[2], float *uv) { diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index b42566732ec..91ee2fa55d1 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -625,19 +625,6 @@ static void BarycentricWeightsPersp2f(float pt[2], float v1[4], float v2[4], flo w[0] = w[1] = w[2] = 1.0f/3.0f; } -static void VecWeightf(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]) -{ - p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2]; - p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2]; - p[2] = v1[2]*w[0] + v2[2]*w[1] + v3[2]*w[2]; -} - -static void Vec2Weightf(float p[2], const float v1[2], const float v2[2], const float v3[2], const float w[3]) -{ - p[0] = v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2]; - p[1] = v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2]; -} - static float VecZDepthOrtho(float pt[2], float v1[3], float v2[3], float v3[3], float w[3]) { BarycentricWeights2f(pt, v1, v2, v3, w); @@ -746,10 +733,10 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float tf = ps->dm_mtface + face_index; if (side == 0) { - Vec2Weightf(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); + Vec2Lerp3f(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); } else { /* QUAD */ - Vec2Weightf(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); + Vec2Lerp3f(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); } ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */ @@ -870,8 +857,8 @@ static int project_paint_occlude_ptv_clip( } /* Test if we're in the clipped area, */ - if (side) VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); - else VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); + if (side) VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); + else VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); Mat4MulVecfl(ps->ob->obmat, wco); if(!view3d_test_clipping(ps->rv3d, wco)) { @@ -1146,19 +1133,6 @@ static int check_seam(const ProjPaintState *ps, const int orig_face, const int o return 1; } -/* TODO - move to arithb.c */ -/* Converts an angle to a length that can be used for maintaining an even margin around UV's */ -static float angleToLength(float angle) -{ - // already accounted for - if (angle < 0.000001f) { - return 1.0f; - } - else { - return fabsf(1.0f / cosf(angle * (M_PI/180.0f))); - } -} - /* Calculate outset UV's, this is not the same as simply scaling the UVs, * since the outset coords are a margin that keep an even distance from the original UV's, * note that the image aspect is taken into account */ @@ -1204,15 +1178,15 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl } if (is_quad) { - a1 = angleToLength(NormalizedVecAngle2_2D(dir4, dir1)); - a2 = angleToLength(NormalizedVecAngle2_2D(dir1, dir2)); - a3 = angleToLength(NormalizedVecAngle2_2D(dir2, dir3)); - a4 = angleToLength(NormalizedVecAngle2_2D(dir3, dir4)); + a1 = AngleToLength(NormalizedVecAngle2_2D(dir4, dir1)); + a2 = AngleToLength(NormalizedVecAngle2_2D(dir1, dir2)); + a3 = AngleToLength(NormalizedVecAngle2_2D(dir2, dir3)); + a4 = AngleToLength(NormalizedVecAngle2_2D(dir3, dir4)); } else { - a1 = angleToLength(NormalizedVecAngle2_2D(dir3, dir1)); - a2 = angleToLength(NormalizedVecAngle2_2D(dir1, dir2)); - a3 = angleToLength(NormalizedVecAngle2_2D(dir2, dir3)); + a1 = AngleToLength(NormalizedVecAngle2_2D(dir3, dir1)); + a2 = AngleToLength(NormalizedVecAngle2_2D(dir1, dir2)); + a3 = AngleToLength(NormalizedVecAngle2_2D(dir2, dir3)); } if (is_quad) { @@ -1329,7 +1303,7 @@ static void screen_px_from_ortho( float w[3]) { BarycentricWeights2f(uv, uv1co, uv2co, uv3co, w); - VecWeightf(pixelScreenCo, v1co, v2co, v3co, w); + VecLerp3f(pixelScreenCo, v1co, v2co, v3co, w); } /* same as screen_px_from_ortho except we need to take into account @@ -1363,7 +1337,7 @@ static void screen_px_from_persp( } /* done re-weighting */ - VecWeightf(pixelScreenCo, v1co, v2co, v3co, w); + VecLerp3f(pixelScreenCo, v1co, v2co, v3co, w); } static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4]) @@ -1381,7 +1355,7 @@ static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const uvCo3 = (float *)tf_other->uv[2]; } - Vec2Weightf(uv_other, uvCo1, uvCo2, uvCo3, w); + Vec2Lerp3f(uv_other, uvCo1, uvCo2, uvCo3, w); /* use */ uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y); @@ -1916,22 +1890,22 @@ static void rect_to_uvspace_ortho( uv[0] = bucket_bounds->xmax; uv[1] = bucket_bounds->ymin; BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); //uv[0] = bucket_bounds->xmax; // set above uv[1] = bucket_bounds->ymax; BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); uv[0] = bucket_bounds->xmin; //uv[1] = bucket_bounds->ymax; // set above BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); //uv[0] = bucket_bounds->xmin; // set above uv[1] = bucket_bounds->ymin; BarycentricWeights2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); } /* same as above but use BarycentricWeightsPersp2f */ @@ -1950,22 +1924,22 @@ static void rect_to_uvspace_persp( uv[0] = bucket_bounds->xmax; uv[1] = bucket_bounds->ymin; BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?3:0], uv1co, uv2co, uv3co, w); //uv[0] = bucket_bounds->xmax; // set above uv[1] = bucket_bounds->ymax; BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?2:1], uv1co, uv2co, uv3co, w); uv[0] = bucket_bounds->xmin; //uv[1] = bucket_bounds->ymax; // set above BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?1:2], uv1co, uv2co, uv3co, w); //uv[0] = bucket_bounds->xmin; // set above uv[1] = bucket_bounds->ymin; BarycentricWeightsPersp2f(uv, v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[flip?0:3], uv1co, uv2co, uv3co, w); } /* This works as we need it to but we can save a few steps and not use it */ @@ -2209,13 +2183,13 @@ static void project_bucket_clip_face( if (is_ortho) { for(i=0; i<(*tot); i++) { BarycentricWeights2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); } } else { for(i=0; i<(*tot); i++) { BarycentricWeightsPersp2f(isectVCosSS[i], v1coSS, v2coSS, v3coSS, w); - Vec2Weightf(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); + Vec2Lerp3f(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); } } } @@ -2470,7 +2444,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* a pitty we need to get the worldspace pixel location here */ if(ps->rv3d->rflag & RV3D_CLIPPING) { - VecWeightf(wco, ps->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm_mvert[ (*(&mf->v1 + i3)) ].co, w); + VecLerp3f(wco, ps->dm_mvert[ (*(&mf->v1 + i1)) ].co, ps->dm_mvert[ (*(&mf->v1 + i2)) ].co, ps->dm_mvert[ (*(&mf->v1 + i3)) ].co, w); Mat4MulVecfl(ps->ob->obmat, wco); if(view3d_test_clipping(ps->rv3d, wco)) { continue; /* Watch out that no code below this needs to run */ @@ -2686,8 +2660,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* a pitty we need to get the worldspace pixel location here */ if(ps->rv3d->rflag & RV3D_CLIPPING) { - if (side) VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); - else VecWeightf(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); + if (side) VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); + else VecLerp3f(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); Mat4MulVecfl(ps->ob->obmat, wco); if(view3d_test_clipping(ps->rv3d, wco)) { diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 5821d30bc3b..04b4b1142be 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -507,7 +507,7 @@ EnumPropertyItem reactor_from_items[] = { static EnumPropertyItem *rna_Particle_from_itemf(bContext *C, PointerRNA *ptr, int *free) { - ParticleSettings *part = ptr->id.data; + /* ParticleSettings *part = ptr->id.data; */ if(C==NULL) { EnumPropertyItem *item= NULL; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 0c56841b70d..48a7c003c9f 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1474,7 +1474,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset) { Object *ob= obr->ob; - Object *tob=0; +// Object *tob=0; Material *ma=0; ParticleSystemModifierData *psmd; ParticleSystem *tpsys=0; -- cgit v1.2.3 From 6114de09b5b611478758698eab054576496d6b02 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Fri, 18 Sep 2009 21:04:54 +0000 Subject: 2.5 Nodes: More Nodes are wrapped to the layout engine. +a bit code cleanup. Brecht: please check on greying out, it doesn't look correct. :) --- source/blender/editors/space_node/drawnode.c | 364 ++++++++------------------ source/blender/makesrna/intern/rna_nodetree.c | 23 +- 2 files changed, 120 insertions(+), 267 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index a9f53c9efd9..8bd8477fe13 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Bob Holcomb + * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Bob Holcomb, Thomas Dinges * * ***** END GPL LICENSE BLOCK ***** */ @@ -1163,268 +1163,139 @@ static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeDBlurData *ndbd = node->storage; - short dy = butr->ymin + 171; - short dx = butr->xmax - butr->xmin; - short halfdx= (short)dx/2; - - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &ndbd->iter, 1, 32, 10, 0, "Amount of iterations"); - uiDefButC(block, TOG, B_NODE_EXEC, "Wrap", - butr->xmin, dy-= 19, dx, 19, - &ndbd->wrap, 0, 0, 0, 0, "Wrap blur"); - uiBlockEndAlign(block); - - dy-= 9; - - uiDefBut(block, LABEL, B_NOP, "Center", butr->xmin, dy-= 19, dx, 19, NULL, 0.0f, 0.0f, 0, 0, ""); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy-= 19, halfdx, 19, - &ndbd->center_x, 0.0f, 1.0f, 10, 0, "X center in percents"); - uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+halfdx, dy, halfdx, 19, - &ndbd->center_y, 0.0f, 1.0f, 10, 0, "Y center in percents"); - uiBlockEndAlign(block); - - dy-= 9; - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->distance, -1.0f, 1.0f, 10, 0, "Amount of which the image moves"); - uiDefButF(block, NUM, B_NODE_EXEC, "Angle:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->angle, 0.0f, 360.0f, 1000, 0, "Angle in which the image will be moved"); - uiBlockEndAlign(block); - - dy-= 9; - - uiDefButF(block, NUM, B_NODE_EXEC, "Spin:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->spin, -360.0f, 360.0f, 1000, 0, "Angle that is used to spin the image"); - - dy-= 9; - - uiDefButF(block, NUM, B_NODE_EXEC, "Zoom:", - butr->xmin, dy-= 19, dx, 19, - &ndbd->zoom, 0.0f, 100.0f, 100, 0, "Amount of which the image is zoomed"); + uiLayout *row, *col; + + uiItemR(layout, NULL, 0, ptr, "iterations", 0); + uiItemR(layout, NULL, 0, ptr, "wrap", 0); + + col= uiLayoutColumn(layout, 1); + uiItemL(col, "Center:", 0); + + row= uiLayoutRow(col, 1); + uiItemR(row, "X:", 0, ptr, "center_x", 0); + uiItemR(row, "Y", 0, ptr, "center_y", 0); + + uiItemS(layout); + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "distance", 0); + uiItemR(col, NULL, 0, ptr, "angle", 0); + + uiItemS(layout); + + uiItemR(layout, NULL, 0, ptr, "spin", 0); + uiItemR(layout, NULL, 0, ptr, "zoom", 0); } static void node_composit_buts_bilateralblur(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeBilateralBlurData *nbbd= node->storage; - short dy= butr->ymin+38; - short dx= (butr->xmax-butr->xmin); +{ + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy, dx, 19, - &nbbd->iter, 1, 128, 0, 0, "Amount of iterations"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Color Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_color,0.01, 3, 10, 0, "Sigma value used to modify color"); - dy-=19; - uiDefButF(block, NUM, B_NODE_EXEC, "Space Sigma:", - butr->xmin, dy, dx, 19, - &nbbd->sigma_space ,0.01, 30, 10, 0, "Sigma value used to modify space"); + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "iterations", 0); + uiItemR(col, NULL, 0, ptr, "sigma_color", 0); + uiItemR(col, NULL, 0, ptr, "sigma_space", 0); } /* qdn: defocus node */ static void node_composit_buts_defocus(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeDefocus *nqd = node->storage; - short dy = butr->ymin + 209; - short dx = butr->xmax - butr->xmin; - char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0"; - - uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, ""); - uiDefButC(block, MENU, B_NODE_EXEC, mstr1, - butr->xmin, dy-19, dx, 19, - &nqd->bktype, 0, 0, 0, 0, "Bokeh type"); - if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */ - uiDefButC(block, NUM, B_NODE_EXEC, "Rotate:", - butr->xmin, dy-38, dx, 19, - &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees"); - } - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma Correct", - butr->xmin, dy-57, dx, 19, - &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process"); - if (nqd->no_zbuf==0) { - // only needed for zbuffer input - uiDefButF(block, NUM, B_NODE_EXEC, "fStop:", - butr->xmin, dy-76, dx, 19, - &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Maxblur:", - butr->xmin, dy-95, dx, 19, - &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit"); - uiDefButF(block, NUM, B_NODE_EXEC, "BThreshold:", - butr->xmin, dy-114, dx, 19, - &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); - uiDefButC(block, TOG, B_NODE_EXEC, "Preview", - butr->xmin, dy-142, dx, 19, - &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts"); - if (nqd->preview) { - /* only visible when sampling mode enabled */ - uiDefButS(block, NUM, B_NODE_EXEC, "Samples:", - butr->xmin, dy-161, dx, 19, - &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)"); - } - uiDefButS(block, TOG, B_NODE_EXEC, "No zbuffer", - butr->xmin, dy-190, dx, 19, - &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)"); - if (nqd->no_zbuf) { - uiDefButF(block, NUM, B_NODE_EXEC, "Zscale:", - butr->xmin, dy-209, dx, 19, - &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1"); - } -} + uiLayout *sub, *col; + + col= uiLayoutColumn(layout, 1); + uiItemL(col, "Bokeh Type:", 0); + uiItemR(col, "", 0, ptr, "bokeh", 0); + uiItemR(col, NULL, 0, ptr, "angle", 0); + + uiItemR(layout, NULL, 0, ptr, "gamma_correction", 0); + col = uiLayoutColumn(layout, 0); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer")==0); + uiItemR(col, NULL, 0, ptr, "f_stop", 0); + + uiItemR(layout, NULL, 0, ptr, "max_blur", 0); + uiItemR(layout, NULL, 0, ptr, "threshold", 0); + + // Preview + col = uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "preview", 0); + sub = uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "preview")); + uiItemR(sub, NULL, 0, ptr, "samples", 0); + + // Z-Buffer + col = uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "use_zbuffer", 0); + sub = uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer")); + uiItemR(sub, NULL, 0, ptr, "z_scale", 0); +} /* qdn: glare node */ static void node_composit_buts_glare(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeGlare *ndg = node->storage; - short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin; - char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0"; - char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2"; - uiDefButC(block, MENU, B_NODE_EXEC, mn1, - butr->xmin, dy, dx, 19, - &ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type"); - uiDefButC(block, MENU, B_NODE_EXEC, mn2, - butr->xmin, dy-19, dx, 19, - &ndg->quality, 0, 0, 0, 0, - "Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image"); - if (ndg->type != 1) { - uiDefButC(block, NUM, B_NODE_EXEC, "Iterations:", - butr->xmin, dy-38, dx, 19, - &ndg->iter, 2, 5, 1, 0, - "higher values will generate longer/more streaks/ghosts"); - if (ndg->type != 0) - uiDefButF(block, NUM, B_NODE_EXEC, "ColMod:", - butr->xmin, dy-57, dx, 19, - &ndg->colmod, 0, 1, 10, 0, - "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Mix:", - butr->xmin, dy-76, dx, 19, - &ndg->mix, -1, 1, 10, 0, - "Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); - uiDefButF(block, NUM, B_NODE_EXEC, "Threshold:", - butr->xmin, dy-95, dx, 19, - &ndg->threshold, 0, 1000, 10, 0, - "Brightness threshold, the glarefilter will be applied only to pixels brighter than this value"); - if ((ndg->type == 2) || (ndg->type == 0)) - { - if (ndg->type == 2) { - uiDefButC(block, NUM, B_NODE_EXEC, "streaks:", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 2, 16, 1000, 0, - "Total number of streaks"); - uiDefButC(block, NUM, B_NODE_EXEC, "AngOfs:", - butr->xmin, dy-133, dx, 19, - &ndg->angle_ofs, 0, 180, 1000, 0, - "Streak angle rotation offset in degrees"); - } - uiDefButF(block, NUM, B_NODE_EXEC, "Fade:", - butr->xmin, dy-152, dx, 19, - &ndg->fade, 0.75, 1, 5, 0, - "Streak fade out factor"); - } - if (ndg->type == 0) - uiDefButC(block, TOG, B_NODE_EXEC, "Rot45", - butr->xmin, dy-114, dx, 19, - &ndg->angle, 0, 0, 0, 0, - "simple star filter, add 45 degree rotation offset"); - if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow - uiDefButC(block, NUM, B_NODE_EXEC, "Size:", - butr->xmin, dy-114, dx, 19, - &ndg->size, 6, 9, 1000, 0, - "glow/glare size (not actual size, relative to initial size of bright area of pixels)"); +{ + uiItemR(layout, "", 0, ptr, "glare_type", 0); + uiItemR(layout, "", 0, ptr, "quality", 0); + + if (RNA_enum_get(ptr, "glare_type")!= 1) { + uiItemR(layout, NULL, 0, ptr, "iterations", 0); + + if (RNA_enum_get(ptr, "glare_type")!= 0) + uiItemR(layout, NULL, 0, ptr, "color_modulation", 0); + } + + uiItemR(layout, NULL, 0, ptr, "mix", 0); + uiItemR(layout, NULL, 0, ptr, "threshold", 0); + + if (RNA_enum_get(ptr, "glare_type")== 2) { + uiItemR(layout, NULL, 0, ptr, "streaks", 0); + uiItemR(layout, NULL, 0, ptr, "angle_offset", 0); + } + if (RNA_enum_get(ptr, "glare_type")== 0 || RNA_enum_get(ptr, "glare_type")== 2) { + uiItemR(layout, NULL, 0, ptr, "fade", 0); + + if (RNA_enum_get(ptr, "glare_type")== 0) + uiItemR(layout, NULL, 0, ptr, "rotate_45", 0); + } + if (RNA_enum_get(ptr, "glare_type")== 1) { + uiItemR(layout, NULL, 0, ptr, "size", 0); + } } /* qdn: tonemap node */ static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeTonemap *ntm = node->storage; - short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin; - char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0"; - - uiBlockBeginAlign(block); - uiDefButI(block, MENU, B_NODE_EXEC, mn, - butr->xmin, dy, dx, 19, - &ntm->type, 0, 0, 0, 0, - "Tone mapping type"); - if (ntm->type == 0) { - uiDefButF(block, NUM, B_NODE_EXEC, "Key:", - butr->xmin, dy-19, dx, 19, - &ntm->key, 0, 1, 5, 0, - "The value the average luminance is mapped to"); - uiDefButF(block, NUM, B_NODE_EXEC, "Offset:", - butr->xmin, dy-38, dx, 19, - &ntm->offset, 0.001, 10, 5, 0, - "Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve"); - uiDefButF(block, NUM, B_NODE_EXEC, "Gamma:", - butr->xmin, dy-57, dx, 19, - &ntm->gamma, 0.001, 3, 5, 0, - "Gamma factor, if not used, set to 1"); +{ + uiLayout *col; + + col = uiLayoutColumn(layout, 1); + uiItemR(col, "", 0, ptr, "tonemap_type", 0); + if (RNA_enum_get(ptr, "tonemap_type")== 0) { + uiItemR(col, NULL, 0, ptr, "key", 0); + uiItemR(col, NULL, 0, ptr, "offset", 0); + uiItemR(col, NULL, 0, ptr, "gamma", 0); } else { - uiDefButF(block, NUM, B_NODE_EXEC, "Intensity:", - butr->xmin, dy-19, dx, 19, - &ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter"); - uiDefButF(block, NUM, B_NODE_EXEC, "Contrast:", - butr->xmin, dy-38, dx, 19, - &ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image"); - uiDefButF(block, NUM, B_NODE_EXEC, "Adaptation:", - butr->xmin, dy-57, dx, 19, - &ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity"); - uiDefButF(block, NUM, B_NODE_EXEC, "ColCorrect:", - butr->xmin, dy-76, dx, 19, - &ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent"); + uiItemR(col, NULL, 0, ptr, "intensity", 0); + uiItemR(col, NULL, 0, ptr, "contrast", 0); + uiItemR(col, NULL, 0, ptr, "adaptation", 0); + uiItemR(col, NULL, 0, ptr, "correction", 0); } - uiBlockEndAlign(block); } /* qdn: lens distortion node */ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - - bNode *node= ptr->data; - NodeLensDist *nld = node->storage; col= uiLayoutColumn(layout, 0); - uiItemR(col, NULL, 0, ptr, "projector", 0); - if (!nld->proj) { - col = uiLayoutColumn(col, 0); - uiItemR(col, NULL, 0, ptr, "jitter", 0); - uiItemR(col, NULL, 0, ptr, "fit", 0); - } -// uiLayoutSetActive(col, RNA_boolean_get(&imaptr, "projector")); -} + col = uiLayoutColumn(col, 0); + uiLayoutSetActive(col, RNA_boolean_get(ptr, "projector")==0); + uiItemR(col, NULL, 0, ptr, "jitter", 0); + uiItemR(col, NULL, 0, ptr, "fit", 0); + +} static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) { @@ -1438,10 +1309,8 @@ static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) uiItemL(col, "Speed:", 0); uiItemR(col, "Min", 0, ptr, "min_speed", 0); uiItemR(col, "Max", 0, ptr, "max_speed", 0); - - col= uiLayoutColumn(layout, 0); - uiItemR(col, NULL, 0, ptr, "curved", 0); + uiItemR(layout, NULL, 0, ptr, "curved", 0); } static void node_composit_buts_filter(uiLayout *layout, PointerRNA *ptr) @@ -1458,9 +1327,7 @@ static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col= uiLayoutColumn(layout, 1); - - uiItemR(col, NULL, 0, ptr, "crop_size", 0); + uiItemR(layout, NULL, 0, ptr, "crop_size", 0); col= uiLayoutColumn(layout, 1); uiItemR(col, "Left", 0, ptr, "x1", 0); @@ -1471,21 +1338,12 @@ static void node_composit_buts_crop(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiBlockBeginAlign(block); + uiLayout *row, *col; - uiDefButS(block, ROW, B_NODE_EXEC, "X", - butr->xmin, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 0.0, 0, 0, ""); - uiDefButS(block, ROW, B_NODE_EXEC, "Y", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20, - &node->custom2, 0.0, 1.0, 0, 0, ""); - - uiDefButS(block, NUMSLI, B_NODE_EXEC, "Split %: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 100, 10, 0, ""); + col= uiLayoutColumn(layout, 1); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "axis", UI_ITEM_R_EXPAND); + uiItemR(col, NULL, 0, ptr, "factor", 0); } static void node_composit_buts_map_value(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index f2caf1a4d52..73aaf0837db 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1066,11 +1066,10 @@ static void def_cmp_splitviewer(StructRNA *srna) RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Axis", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); - - /* TODO: percentage */ - prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_float_sdna(prop, NULL, "custom1"); - RNA_def_property_range(prop, 0.0f, 100.0f); + + prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PERCENTAGE); + RNA_def_property_int_sdna(prop, NULL, "custom1"); + RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Factor", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -1255,7 +1254,7 @@ static void def_cmp_dblur(StructRNA *srna) prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); - RNA_def_property_range(prop, 1, 128); + RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text(prop, "Iterations", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -1356,12 +1355,12 @@ static void def_cmp_glare(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; - /*static EnumPropertyItem quality_items[] = { + static EnumPropertyItem quality_items[] = { {0, "HIGH", 0, "High", ""}, {1, "MEDIUM", 0, "Medium", ""}, {2, "LOW", 0, "Low", ""}, {0, NULL, 0, NULL, NULL} - };*/ + }; RNA_def_struct_sdna_from(srna, "NodeGlare", "storage"); @@ -1373,7 +1372,7 @@ static void def_cmp_glare(StructRNA *srna) prop = RNA_def_property(srna, "quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "quality"); - RNA_def_property_enum_items(prop, type_items); + RNA_def_property_enum_items(prop, quality_items); RNA_def_property_ui_text(prop, "Quality", "If not set to high quality, the effect will be applied to a low-res copy of the source image"); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -1386,7 +1385,7 @@ static void def_cmp_glare(StructRNA *srna) prop = RNA_def_property(srna, "color_modulation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colmod"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Color Modulation", ""); + RNA_def_property_ui_text(prop, "Color Modulation", "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "mix", PROP_FLOAT, PROP_NONE); @@ -1451,8 +1450,6 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_ui_text(prop, "Tonemap Type", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); - /* TODO: if type==0 { */ - prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "key"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1471,8 +1468,6 @@ static void def_cmp_tonemap(StructRNA *srna) RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1"); RNA_def_property_update(prop, 0, "rna_Node_update"); - /* TODO: } else { */ - prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f"); RNA_def_property_range(prop, -8.0f, 8.0f); -- cgit v1.2.3 From ad07133e531b4f1eb81cdd5086d1f769e971d606 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Fri, 18 Sep 2009 22:12:29 +0000 Subject: Add path to find SYS_System.h (which is only included with gameengine). Reported by Jasper Mine. Fixed comment, it was away from the directive it explained. --- source/blender/editors/space_view3d/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_view3d/Makefile b/source/blender/editors/space_view3d/Makefile index 07102157854..9204f2482c6 100644 --- a/source/blender/editors/space_view3d/Makefile +++ b/source/blender/editors/space_view3d/Makefile @@ -53,6 +53,9 @@ CPPFLAGS += -I../../render/extern/include CPPFLAGS += -I../../blenfont CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I$(NAN_SMOKE)/include -# own include +ifneq ($(NAN_NO_KETSJI),true) + CPPFLAGS += -I../../../kernel/gen_system +endif +# own include CPPFLAGS += -I../include -- cgit v1.2.3 From 8ab24bb2c2f38f3d52c985d83cf691274fa0d6f0 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 19 Sep 2009 00:18:42 +0000 Subject: 2.5 - Pose Enhancement Tools This commit restores the 'Relax Pose' tool, and also introduces two others: 'Push Pose' and 'Pose Breakdowner'. Be aware that this commit is just the initial starting point, with some parts yet to be done. A short description of these tools follows: * Relax Pose (Alt-E) - makes the current pose more like the poses on either side of it * Push Pose (Ctrl-E) - exaggerates the current pose * Breakdowner (Shift-E)[not working yet] - when this works, it will allow for interactive selection of a good in-between pose to act as a breakdown. Todo's: * Connect up the 'percentage' slider in the operator settings to allow these effects to be dialed in/out, exaggerating/relaxing/moveing-between-keyframes by varying degrees until the desired effect is reached. * Allow these effects to be interactively dialed in/out. The idea is to use the mouse to interactively set the percentage slider value initially, then use the percentage slider to tweak later. * Figure out why breakdown breaks down --- source/blender/blenkernel/BKE_fcurve.h | 5 + source/blender/blenkernel/intern/fcurve.c | 79 +++ source/blender/editors/animation/keyframes_draw.c | 24 +- source/blender/editors/animation/keyframing.c | 79 --- source/blender/editors/armature/armature_intern.h | 8 + source/blender/editors/armature/armature_ops.c | 11 + source/blender/editors/armature/poseSlide.c | 722 +++++++++++++++++++++ source/blender/editors/armature/poselib.c | 7 +- source/blender/editors/armature/poseobject.c | 172 +---- source/blender/editors/include/ED_keyframes_draw.h | 4 + source/blender/editors/screen/screen_ops.c | 23 - 11 files changed, 859 insertions(+), 275 deletions(-) create mode 100644 source/blender/editors/armature/poseSlide.c diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index cda64c6b241..e25e32a2010 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -153,6 +153,11 @@ void copy_fcurves(ListBase *dst, ListBase *src); /* find matching F-Curve in the given list of F-Curves */ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); +/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number. + * Returns the index to insert at (data already at that index will be offset if replace is 0) + */ +int binarysearch_bezt_index(struct BezTriple array[], float frame, int arraylen, short *replace); + /* get the time extents for F-Curve */ void calc_fcurve_range(struct FCurve *fcu, float *min, float *max); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index f7f79e9772f..0ecd1fe912b 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -200,6 +200,85 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array return NULL; } +/* threshold for binary-searching keyframes - threshold here should be good enough for now, but should become userpref */ +#define BEZT_BINARYSEARCH_THRESH 0.00001f + +/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve) + * Returns the index to insert at (data already at that index will be offset if replace is 0) + */ +int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace) +{ + int start=0, end=arraylen; + int loopbreaker= 0, maxloop= arraylen * 2; + + /* initialise replace-flag first */ + *replace= 0; + + /* sneaky optimisations (don't go through searching process if...): + * - keyframe to be added is to be added out of current bounds + * - keyframe to be added would replace one of the existing ones on bounds + */ + if ((arraylen <= 0) || (array == NULL)) { + printf("Warning: binarysearch_bezt_index() encountered invalid array \n"); + return 0; + } + else { + /* check whether to add before/after/on */ + float framenum; + + /* 'First' Keyframe (when only one keyframe, this case is used) */ + framenum= array[0].vec[1][0]; + if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) { + *replace = 1; + return 0; + } + else if (frame < framenum) + return 0; + + /* 'Last' Keyframe */ + framenum= array[(arraylen-1)].vec[1][0]; + if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) { + *replace= 1; + return (arraylen - 1); + } + else if (frame > framenum) + return arraylen; + } + + + /* most of the time, this loop is just to find where to put it + * 'loopbreaker' is just here to prevent infinite loops + */ + for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { + /* compute and get midpoint */ + int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ + float midfra= array[mid].vec[1][0]; + + /* check if exactly equal to midpoint */ + if (IS_EQT(frame, midfra, BEZT_BINARYSEARCH_THRESH)) { + *replace = 1; + return mid; + } + + /* repeat in upper/lower half */ + if (frame > midfra) + start= mid + 1; + else if (frame < midfra) + end= mid - 1; + } + + /* print error if loop-limit exceeded */ + if (loopbreaker == (maxloop-1)) { + printf("Error: binarysearch_bezt_index() was taking too long \n"); + + // include debug info + printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen); + } + + /* not found, so return where to place it */ + return start; +} + /* Calculate the extents of F-Curve's data */ void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax) { diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index abea38e129e..8e7789190c3 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -316,7 +316,7 @@ static void set_touched_actkeyblock (ActKeyBlock *ab) /* *************************** Keyframe Drawing *************************** */ /* helper function - find actkeycolumn that occurs on cframe */ -static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) +ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) { /* sanity checks */ if (ak == NULL) @@ -331,6 +331,28 @@ static ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) return ak; /* match */ } +/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ +ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next) +{ + ActKeyColumn *akn= NULL; + + /* sanity checks */ + if (ak == NULL) + return NULL; + + /* check if this is a match, or whether it is in some subtree */ + if (cframe < ak->cfra) + akn= cfra_find_nearest_next_ak(ak->left, cframe, next); + else if (cframe > ak->cfra) + akn= cfra_find_nearest_next_ak(ak->right, cframe, next); + + /* if no match found (or found match), just use the current one */ + if (akn == NULL) + return ak; + else + return akn; +} + /* -------- */ /* coordinates for diamond shape */ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 7135f8802bc..e8451b0f979 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -176,85 +176,6 @@ FCurve *verify_fcurve (bAction *act, const char group[], const char rna_path[], /* -------------- BezTriple Insertion -------------------- */ -/* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */ -#define BEZT_INSERT_THRESH 0.00001f - -/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu) - * Returns the index to insert at (data already at that index will be offset if replace is 0) - */ -static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace) -{ - int start=0, end=arraylen; - int loopbreaker= 0, maxloop= arraylen * 2; - - /* initialise replace-flag first */ - *replace= 0; - - /* sneaky optimisations (don't go through searching process if...): - * - keyframe to be added is to be added out of current bounds - * - keyframe to be added would replace one of the existing ones on bounds - */ - if ((arraylen <= 0) || (array == NULL)) { - printf("Warning: binarysearch_bezt_index() encountered invalid array \n"); - return 0; - } - else { - /* check whether to add before/after/on */ - float framenum; - - /* 'First' Keyframe (when only one keyframe, this case is used) */ - framenum= array[0].vec[1][0]; - if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) { - *replace = 1; - return 0; - } - else if (frame < framenum) - return 0; - - /* 'Last' Keyframe */ - framenum= array[(arraylen-1)].vec[1][0]; - if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) { - *replace= 1; - return (arraylen - 1); - } - else if (frame > framenum) - return arraylen; - } - - - /* most of the time, this loop is just to find where to put it - * 'loopbreaker' is just here to prevent infinite loops - */ - for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { - /* compute and get midpoint */ - int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ - float midfra= array[mid].vec[1][0]; - - /* check if exactly equal to midpoint */ - if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) { - *replace = 1; - return mid; - } - - /* repeat in upper/lower half */ - if (frame > midfra) - start= mid + 1; - else if (frame < midfra) - end= mid - 1; - } - - /* print error if loop-limit exceeded */ - if (loopbreaker == (maxloop-1)) { - printf("Error: binarysearch_bezt_index() was taking too long \n"); - - // include debug info - printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen); - } - - /* not found, so return where to place it */ - return start; -} - /* This function adds a given BezTriple to an F-Curve. It will allocate * memory for the array if needed, and will insert the BezTriple into a * suitable place in chronological order. diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 0c8c0e8e644..6f5a5f44d87 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -118,11 +118,19 @@ void SKETCH_OT_select(struct wmOperatorType *ot); /* ******************************************************* */ /* PoseLib */ + void POSELIB_OT_pose_add(struct wmOperatorType *ot); void POSELIB_OT_pose_remove(struct wmOperatorType *ot); void POSELIB_OT_pose_rename(struct wmOperatorType *ot); void POSELIB_OT_browse_interactive(struct wmOperatorType *ot); +/* ******************************************************* */ +/* Pose Sliding Tools */ + +void POSE_OT_push(struct wmOperatorType *ot); +void POSE_OT_relax(struct wmOperatorType *ot); +void POSE_OT_breakdown(struct wmOperatorType *ot); + /* ******************************************************* */ /* editarmature.c */ struct bArmature; diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 9076b533974..a8b8b8aecc1 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -196,6 +196,11 @@ void ED_operatortypes_armature(void) WM_operatortype_append(POSELIB_OT_pose_remove); WM_operatortype_append(POSELIB_OT_pose_rename); + /* POSE SLIDING */ + WM_operatortype_append(POSE_OT_push); + WM_operatortype_append(POSE_OT_relax); + WM_operatortype_append(POSE_OT_breakdown); + /* TESTS */ WM_operatortype_append(ARMATURE_OT_test); // XXX temp test for context iterators... to be removed } @@ -365,5 +370,11 @@ void ED_keymap_armature(wmWindowManager *wm) WM_keymap_add_item(keymap, "POSELIB_OT_pose_add", LKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSELIB_OT_pose_remove", LKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "POSELIB_OT_pose_rename", LKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + + /* Pose -> Pose Sliding ------------- */ + /* only set in posemode, by space_view3d listener */ + WM_keymap_add_item(keymap, "POSE_OT_push", EKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "POSE_OT_relax", EKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "POSE_OT_breakdown", EKEY, KM_PRESS, KM_SHIFT, 0); } diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c new file mode 100644 index 00000000000..464dbcba54b --- /dev/null +++ b/source/blender/editors/armature/poseSlide.c @@ -0,0 +1,722 @@ +/** + * $Id: poseSlide.c 23179 2009-09-13 12:34:00Z aligorith $ + * + * ***** 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, Joshua Leung + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" +#include "BLI_dlrbTree.h" + +#include "DNA_listBase.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_object.h" + +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "BIF_gl.h" + +#include "ED_anim_api.h" +#include "ED_armature.h" +#include "ED_keyframes_draw.h" +#include "ED_keyframing.h" +#include "ED_keyframes_edit.h" +#include "ED_screen.h" + +#include "armature_intern.h" + +/* **************************************************** */ +/* == POSE 'SLIDING' TOOLS == + * + * A) Push & Relax, Breakdowner + * These tools provide the animator with various capabilities + * for interactively controlling the spacing of poses, but also + * for 'pushing' and/or 'relaxing' extremes as they see fit. + * + * B) Pose Sculpting + * This is yet to be implemented, but the idea here is to use + * sculpting techniques to make it easier to pose rigs by allowing + * rigs to be manipulated using a familiar paint-based interface. + */ +/* **************************************************** */ +/* A) Push & Relax, Breakdowner */ + +/* Temporary data shared between these operators */ +typedef struct tPoseSlideOp { + Scene *scene; /* current scene */ + ARegion *ar; /* region that we're operating in (needed for */ + Object *ob; /* active object that Pose Info comes from */ + + ListBase pfLinks; /* links between posechannels and f-curves */ + DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */ + + KeyingSet *ks_loc; /* builtin KeyingSet for keyframing locations */ + KeyingSet *ks_rot; /* builtin KeyingSet for keyframing rotations */ + KeyingSet *ks_scale;/* builtin KeyingSet for keyframing scale */ + + int cframe; /* current frame number */ + int prevFrame; /* frame before current frame (blend-from) */ + int nextFrame; /* frame after current frame (blend-to) */ + + int mode; /* sliding mode (ePoseSlide_Modes) */ + int flag; // unused for now, but can later get used for storing runtime settings.... + + float percentage; /* 0-1 value for determining the influence of whatever is relevant */ +} tPoseSlideOp; + +/* Pose Sliding Modes */ +typedef enum ePoseSlide_Modes { + POSESLIDE_PUSH = 0, /* exaggerate the pose... */ + POSESLIDE_RELAX, /* soften the pose... */ + POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */ +} ePoseSlide_Modes; + +/* Temporary data linking PoseChannels with the F-Curves they affect */ +typedef struct tPChanFCurveLink { + struct tPChanFCurveLink *next, *prev; + + ListBase fcurves; /* F-Curves for this PoseChannel */ + bPoseChannel *pchan; /* Pose Channel which data is attached to */ + char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */ +} tPChanFCurveLink; + +/* ------------------------------------ */ + +/* operator init */ +static int pose_slide_init (bContext *C, wmOperator *op, short mode) +{ + tPoseSlideOp *pso; + bAction *act= NULL; + + /* init slide-op data */ + pso= op->customdata= MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp"); + + /* get info from context */ + pso->scene= CTX_data_scene(C); + pso->ob= CTX_data_active_object(C); + pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */ + + pso->cframe= pso->scene->r.cfra; + pso->mode= mode; + + /* set range info from property values - these may get overridden for the invoke() */ + pso->percentage= RNA_float_get(op->ptr, "percentage"); + pso->prevFrame= RNA_int_get(op->ptr, "prev_frame"); + pso->nextFrame= RNA_int_get(op->ptr, "next_frame"); + + /* check the settings from the context */ + if (ELEM3(NULL, pso->ob, pso->ob->adt, pso->ob->adt->action)) + return 0; + else + act= pso->ob->adt->action; + + /* for each Pose-Channel which gets affected, get the F-Curves for that channel + * and set the relevant transform flags... + */ + CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) + { + ListBase curves = {NULL, NULL}; + int transFlags = action_get_item_transforms(act, pso->ob, pchan, &curves); + + pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + + /* check if any transforms found... */ + if (transFlags) { + /* make new linkage data */ + tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink"); + PointerRNA ptr; + + pfl->fcurves= curves; + pfl->pchan= pchan; + + /* get the RNA path to this pchan - this needs to be freed! */ + RNA_pointer_create((ID *)pso->ob, &RNA_PoseChannel, pchan, &ptr); + pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr); + + /* add linkage data to operator data */ + BLI_addtail(&pso->pfLinks, pfl); + + /* set pchan's transform flags */ + if (transFlags & ACT_TRANS_LOC) + pchan->flag |= POSE_LOC; + if (transFlags & ACT_TRANS_ROT) + pchan->flag |= POSE_ROT; + if (transFlags & ACT_TRANS_SCALE) + pchan->flag |= POSE_SIZE; + } + } + CTX_DATA_END; + + /* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up + * to the caller of this (usually only invoke() will do it, to make things more efficient). + */ + BLI_dlrbTree_init(&pso->keys); + + /* get builtin KeyingSets */ + pso->ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location"); + pso->ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scale"); + + /* return status is whether we've got all the data we were requested to get */ + return 1; +} + +/* exiting the operator - free data */ +static void pose_slide_exit (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso= op->customdata; + + /* if data exists, clear its data and exit */ + if (pso) { + tPChanFCurveLink *pfl, *pfln=NULL; + + /* free the temp pchan links and their data */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfln) { + pfln= pfl->next; + + /* free list of F-Curve reference links */ + BLI_freelistN(&pfl->fcurves); + + /* free pchan RNA Path */ + MEM_freeN(pfl->pchan_path); + + /* free link itself */ + BLI_freelinkN(&pso->pfLinks, pfl); + } + + /* free RB-BST for keyframes (if it contained data) */ + BLI_dlrbTree_free(&pso->keys); + + /* free data itself */ + MEM_freeN(pso); + } + + /* cleanup */ + op->customdata= NULL; +} + +/* ------------------------------------ */ + +/* helper for apply() callabcks - find the next F-Curve with matching path... */ +static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path) +{ + LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL; + LinkData *ld; + + /* check each link to see if the linked F-Curve has a matching path */ + for (ld= first; ld; ld= ld->next) { + FCurve *fcu= (FCurve *)ld->data; + + /* check if paths match */ + if (strcmp(path, fcu->rna_path) == 0) + return ld; + } + + /* none found */ + return NULL; +} + +/* helper for apply() - perform sliding for some 3-element vector */ +static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], char *propName) +{ + LinkData *ld=NULL; + char *path=NULL; + float cframe; + + /* get the path to use... */ + path= BLI_sprintfN("%s.%s", pfl->pchan_path, propName); + + /* get the current frame number */ + cframe= (float)pso->cframe; + + /* using this path, find each matching F-Curve for the variables we're interested in */ + while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) { + FCurve *fcu= (FCurve *)ld->data; + float w1, w2, wtot, ctrl, ictrl; + float sVal, eVal; + int ch; + + /* get keyframe values for endpoint poses to blend with */ + /* previous/start */ + sVal= evaluate_fcurve(fcu, (float)pso->prevFrame); + /* next/end */ + eVal= evaluate_fcurve(fcu, (float)pso->nextFrame); + + /* get channel index */ + ch= fcu->array_index; + + /* get the influence of the control */ + ctrl= pso->percentage; + ictrl= 1.0f - pso->percentage; + + /* calculate the relative weights of the endpoints + * - these weights are derived from the relative distance of these + * poses from the current frame + * - they then get normalised, with the results of these normalised + */ + w1 = cframe - (float)pso->prevFrame; + w2 = (float)pso->nextFrame - cframe; + + wtot = w1 + w2; + w1 = w1/wtot; + w2 = w2/wtot; + + /* depending on the mode, */ + switch (pso->mode) { + case POSESLIDE_PUSH: /* make the current pose more pronounced */ + // TODO: this is not interactively modifiable! + vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; + break; + + case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ + /* apply the value with a hard coded 6th */ + // TODO: this is not interactively modifiable! + vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f; + break; + + case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ + // NOTE: just linear interpolation for now, but could add small component of our key if necessary... + // TODO: this doesn't work at all + w2= 1.0f - w1; + vec[ch]= ((sVal * w1) + (eVal * w2)); + break; + } + + } + + /* free the temp path we got */ + MEM_freeN(path); +} + +/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */ +static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl) +{ + // TODO: this is quite evil stuff... +#if 0 // XXX port... + /* get 2 quats */ + quat_prev[0] = eval_icu(icu_w, frame_prev); + quat_prev[1] = eval_icu(icu_x, frame_prev); + quat_prev[2] = eval_icu(icu_y, frame_prev); + quat_prev[3] = eval_icu(icu_z, frame_prev); + + quat_next[0] = eval_icu(icu_w, frame_next); + quat_next[1] = eval_icu(icu_x, frame_next); + quat_next[2] = eval_icu(icu_y, frame_next); + quat_next[3] = eval_icu(icu_z, frame_next); + +#if 0 + /* apply the setting, completely smooth */ + QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); +#else + /* tricky interpolation */ + QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); + QUATCOPY(quat_orig, pchan->quat); + QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); + /* done */ +#endif +#endif +} + +/* helper for apply() - perform autokeyframing */ +static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso, bPoseChannel *pchan, KeyingSet *ks) +{ + /* insert keyframes as necessary if autokeyframing */ + if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) { + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; + + /* init common-key-source for use by KeyingSets */ + // TODO: for now, we don't clear it out, since it should be safe to do so... + //memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &pso->ob->id; + + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + /* insert keyframes */ + modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + } +} + +/* apply() - perform the pose sliding based on weighting various poses */ +static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + + /* sanitise the frame ranges */ + if (pso->prevFrame == pso->nextFrame) { + /* move out one step either side */ + pso->prevFrame--; + pso->nextFrame++; + } + + /* for each link, handle each set of transforms */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + /* valid transforms for each PoseChannel should have been noted already + * - sliding the pose should be a straightforward exercise for location+rotation, + * but rotations get more complicated since we may want to use quaternion blending + * for quaternions instead... + */ + bPoseChannel *pchan= pfl->pchan; + + if (pchan->flag & POSE_LOC) { + /* calculate these for the 'location' vector, and use location curves */ + pose_slide_apply_vec3(pso, pfl, pchan->loc, "location"); + /* insert keyframes if needed */ + pose_slide_autoKeyframe(C, pso, pchan, pso->ks_loc); + } + + if (pchan->flag & POSE_SIZE) { + /* calculate these for the 'scale' vector, and use scale curves */ + pose_slide_apply_vec3(pso, pfl, pchan->size, "scale"); + /* insert keyframes if needed */ + pose_slide_autoKeyframe(C, pso, pchan, pso->ks_scale); + } + + if (pchan->flag & POSE_ROT) { + /* everything depends on the rotation mode */ + if (pchan->rotmode > 0) { + /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */ + pose_slide_apply_vec3(pso, pfl, pchan->eul, "euler_rotation"); + } + else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) { + // TODO: need to figure out how to do this! + } + else { + /* quaternions - use quaternion blending */ + pose_slide_apply_quat(pso, pfl); + } + + /* insert keyframes if needed */ + pose_slide_autoKeyframe(C, pso, pchan, pso->ks_rot); + } + } + + /* funky depsgraph flags - are these still needed? */ + pso->ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); + + /* do depsgraph flush */ + DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); + + /* note, notifier might evolve */ + //WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, pso->ob); +} + +/* ------------------------------------ */ + +/* common code for invoke() methods */ +static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + AnimData *adt= pso->ob->adt; + + /* for each link, add all its keyframes to the search tree */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + LinkData *ld; + + /* do this for each F-Curve */ + for (ld= pfl->fcurves.first; ld; ld= ld->next) { + FCurve *fcu= (FCurve *)ld->data; + fcurve_to_keylist(adt, fcu, &pso->keys, NULL); + } + } + + /* consolidate these keyframes, and figure out the nearest ones */ + BLI_dlrbTree_linkedlist_sync(&pso->keys); + + /* cancel if no keyframes found... */ + if (pso->keys.root) { + ActKeyColumn *ak; + + /* firstly, check if the current frame is a keyframe... */ + ak= cfra_find_actkeycolumn(pso->keys.root, pso->cframe); + + if (ak == NULL) { + /* current frame is not a keyframe, so search */ + /* prev frame */ + ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0); + pso->prevFrame= (ak)? (ak->cfra) : (pso->cframe - 1); + RNA_int_set(op->ptr, "prev_frame", pso->prevFrame); + /* next frame */ + ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1); + pso->nextFrame= (ak)? (ak->cfra) : (pso->cframe + 1); + RNA_int_set(op->ptr, "next_frame", pso->prevFrame); + } + else { + /* current frame itself is a keyframe, so just take keyframes on either side */ + /* prev frame */ + pso->prevFrame= (ak->prev)? (ak->prev->cfra) : (pso->cframe - 1); + RNA_int_set(op->ptr, "prev_frame", pso->prevFrame); + /* next frame */ + pso->nextFrame= (ak->next)? (ak->next->cfra) : (pso->cframe + 1); + RNA_int_set(op->ptr, "next_frame", pso->nextFrame); + } + } + else { + BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between."); + return OPERATOR_CANCELLED; + } + + + // TODO ----------------------------------- + // from here on, we should just invoke the modal operator, but for now, just do static... + + /* temp static operator code... */ + pose_slide_apply(C, op, pso); + pose_slide_exit(C, op); + return OPERATOR_FINISHED; +} + +// TODO: common modal + cancel + + +/* common code for exec() methods */ +static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso) +{ + /* settings should have been set up ok for applying, so just apply! */ + pose_slide_apply(C, op, pso); + + /* cleanup and done */ + pose_slide_exit(C, op); + + return OPERATOR_FINISHED; +} + +/* common code for defining RNA properties */ +static void pose_slide_opdef_properties (wmOperatorType *ot) +{ + RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame.", 0, 50); + RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame.", 0, 50); + RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for the sliding operation", 0.3, 0.7); +} + +/* ------------------------------------ */ + +/* invoke() - for 'push' mode */ +static int pose_slide_push_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for push */ +static int pose_slide_push_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_push (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Push Pose"; + ot->idname= "POSE_OT_push"; + ot->description= "Exaggerate the current pose"; + + /* callbacks */ + ot->exec= pose_slide_push_exec; + ot->invoke= pose_slide_push_invoke; + //ot->modal= pose_slide_modal; + //ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'relax' mode */ +static int pose_slide_relax_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for relax */ +static int pose_slide_relax_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_relax (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Relax Pose"; + ot->idname= "POSE_OT_relax"; + ot->description= "Make the current pose more similar to its surrounding ones."; + + /* callbacks */ + ot->exec= pose_slide_relax_exec; + ot->invoke= pose_slide_relax_invoke; + //ot->modal= pose_slide_modal; + //ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'breakdown' mode */ +static int pose_slide_breakdown_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso; + + /* initialise data */ + if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for breakdown */ +static int pose_slide_breakdown_exec (bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialise data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + } + else + pso= op->customdata; + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_breakdown (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Pose Breakdowner"; + ot->idname= "POSE_OT_breakdown"; + ot->description= "Create a suitable breakdown pose on the current frame."; + + /* callbacks */ + ot->exec= pose_slide_breakdown_exec; + ot->invoke= pose_slide_breakdown_invoke; + //ot->modal= pose_slide_modal; + //ot->cancel= pose_slide_cancel; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* **************************************************** */ diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index f072f2e980e..ce07cfb9042 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -44,7 +44,6 @@ #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" -#include "DNA_ipo_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_scene_types.h" @@ -62,8 +61,6 @@ #include "BKE_report.h" #include "BKE_utildefines.h" -#include "PIL_time.h" /* sleep */ - #include "RNA_access.h" #include "RNA_define.h" #include "RNA_types.h" @@ -769,6 +766,10 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData if (poselib_ks_locrotscale == NULL) poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + /* now insert the keyframe */ modify_keyframes(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index bab7111dbd7..e5a7a1e167d 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -1084,6 +1084,9 @@ static int pose_paste_exec (bContext *C, wmOperator *op) if (posePaste_ks_locrotscale == NULL) posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ @@ -1983,175 +1986,6 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot) /* ********************************************** */ -#if 0 -// XXX old sys -/* for use with pose_relax only */ -static int pose_relax_icu(struct IpoCurve *icu, float framef, float *val, float *frame_prev, float *frame_next) -{ - if (!icu) { - return 0; - } - else { - BezTriple *bezt = icu->bezt; - - BezTriple *bezt_prev=NULL, *bezt_next=NULL; - float w1, w2, wtot; - int i; - - for (i=0; i < icu->totvert; i++, bezt++) { - if (bezt->vec[1][0] < framef - 0.5) { - bezt_prev = bezt; - } else { - break; - } - } - - if (bezt_prev==NULL) return 0; - - /* advance to the next, dont need to advance i */ - bezt = bezt_prev+1; - - for (; i < icu->totvert; i++, bezt++) { - if (bezt->vec[1][0] > framef + 0.5) { - bezt_next = bezt; - break; - } - } - - if (bezt_next==NULL) return 0; - - if (val) { - w1 = framef - bezt_prev->vec[1][0]; - w2 = bezt_next->vec[1][0] - framef; - wtot = w1 + w2; - w1=w1/wtot; - w2=w2/wtot; -#if 0 - val = (bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1); -#else - /* apply the value with a hard coded 6th */ - *val = (((bezt_prev->vec[1][1] * w2) + (bezt_next->vec[1][1] * w1)) + (*val * 5.0f)) / 6.0f; -#endif - } - - if (frame_prev) *frame_prev = bezt_prev->vec[1][0]; - if (frame_next) *frame_next = bezt_next->vec[1][0]; - - return 1; - } -} -#endif - -void pose_relax(Scene *scene) -{ - Object *ob = OBACT; - bPose *pose; - bAction *act; - bArmature *arm; - -// IpoCurve *icu_w, *icu_x, *icu_y, *icu_z; - - bPoseChannel *pchan; -// bActionChannel *achan; -// float framef = F_CFRA; -// float frame_prev, frame_next; -// float quat_prev[4], quat_next[4], quat_interp[4], quat_orig[4]; - - int do_scale = 0; - int do_loc = 0; - int do_quat = 0; - int flag = 0; -// int do_x, do_y, do_z; - - if (!ob) return; - - pose = ob->pose; - act = ob->action; - arm = (bArmature *)ob->data; - - if (!pose || !act || !arm) return; - - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) { - - pchan->bone->flag &= ~BONE_TRANSFORM; - - if (pchan->bone->layer & arm->layer) { - if (pchan->bone->flag & BONE_SELECTED) { - /* do we have an ipo curve? */ -#if 0 // XXX old animation system - achan= get_action_channel(act, pchan->name); - - if (achan && achan->ipo) { - /*calc_ipo(achan->ipo, ctime);*/ - - do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_X), framef, &pchan->loc[0], NULL, NULL); - do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Y), framef, &pchan->loc[1], NULL, NULL); - do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Z), framef, &pchan->loc[2], NULL, NULL); - do_loc += do_x + do_y + do_z; - - do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_X), framef, &pchan->size[0], NULL, NULL); - do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Y), framef, &pchan->size[1], NULL, NULL); - do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Z), framef, &pchan->size[2], NULL, NULL); - do_scale += do_x + do_y + do_z; - - if( ((icu_w = find_ipocurve(achan->ipo, AC_QUAT_W))) && - ((icu_x = find_ipocurve(achan->ipo, AC_QUAT_X))) && - ((icu_y = find_ipocurve(achan->ipo, AC_QUAT_Y))) && - ((icu_z = find_ipocurve(achan->ipo, AC_QUAT_Z))) ) - { - /* use the quatw keyframe as a basis for others */ - if (pose_relax_icu(icu_w, framef, NULL, &frame_prev, &frame_next)) { - /* get 2 quats */ - quat_prev[0] = eval_icu(icu_w, frame_prev); - quat_prev[1] = eval_icu(icu_x, frame_prev); - quat_prev[2] = eval_icu(icu_y, frame_prev); - quat_prev[3] = eval_icu(icu_z, frame_prev); - - quat_next[0] = eval_icu(icu_w, frame_next); - quat_next[1] = eval_icu(icu_x, frame_next); - quat_next[2] = eval_icu(icu_y, frame_next); - quat_next[3] = eval_icu(icu_z, frame_next); - -#if 0 - /* apply the setting, completely smooth */ - QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); -#else - /* tricky interpolation */ - QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); - QUATCOPY(quat_orig, pchan->quat); - QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); - /* done */ -#endif - do_quat++; - } - } - - /* apply BONE_TRANSFORM tag so that autokeying will pick it up */ - pchan->bone->flag |= BONE_TRANSFORM; - } - -#endif // XXX old animation system - } - } - } - - ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); - - /* do auto-keying */ - if (do_loc) flag |= TFM_TRANSLATION; - if (do_scale) flag |= TFM_RESIZE; - if (do_quat) flag |= TFM_ROTATION; - autokeyframe_pose_cb_func(ob, flag, 0); - - /* clear BONE_TRANSFORM flags */ - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) - pchan->bone->flag &= ~ BONE_TRANSFORM; - - /* do depsgraph flush */ - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - BIF_undo_push("Relax Pose"); -} - /* for use in insertkey, ensure rotation goes other way around */ void pose_flipquats(Scene *scene) { diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 0969398f1e2..51d7c664fba 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -119,5 +119,9 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); +/* Keyframe Finding */ +ActKeyColumn *cfra_find_actkeycolumn(ActKeyColumn *ak, float cframe); +ActKeyColumn *cfra_find_nearest_next_ak(ActKeyColumn *ak, float cframe, short next); + #endif /* ED_KEYFRAMES_DRAW_H */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index b7e7fd18547..a055041d8ae 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1444,29 +1444,6 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) /* ************** jump to keyframe operator ***************************** */ -/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ -// TODO: make this an API func? -static ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next) -{ - ActKeyColumn *akn= NULL; - - /* sanity checks */ - if (ak == NULL) - return NULL; - - /* check if this is a match, or whether it is in some subtree */ - if (cframe < ak->cfra) - akn= cfra_find_nearest_next_ak(ak->left, cframe, next); - else if (cframe > ak->cfra) - akn= cfra_find_nearest_next_ak(ak->right, cframe, next); - - /* if no match found (or found match), just use the current one */ - if (akn == NULL) - return ak; - else - return akn; -} - /* function to be called outside UI context, or for redo */ static int keyframe_jump_exec(bContext *C, wmOperator *op) { -- cgit v1.2.3 From 1ec44f3bb2f371b4f4c389e5f0d4a0c655672c9a Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Sat, 19 Sep 2009 01:05:16 +0000 Subject: compile fix --- source/blender/blenkernel/BKE_fcurve.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index e25e32a2010..94d0864024b 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -35,6 +35,8 @@ struct DriverTarget; struct BezTriple; +#include "DNA_curve_types.h" + /* ************** Keyframe Tools ***************** */ // XXX this stuff is defined in BKE_ipo.h too, so maybe skip for now? -- cgit v1.2.3 From 9710673192f5ed972343c8e9cc6438fc97eb573e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 19 Sep 2009 11:59:23 +0000 Subject: 2.5 - Animation Bugfixes: * Breakdown tool for Poses (Shift-E in PoseMode) now works. Now this works as a modal operator when invoked, with the horizontal movement of the mouse (left to right) corresponding the placement of the breakdown relative to the endpoint keyframes. * Moving bones between armature layers in Edit Mode didn't work (wrong variable name used) * Fixed several notifier-related bugs regarding editing armature settings and the 3d-view not refreshing * Duplicating bones preserves the rotation mode * Animation Data for Nodes is now show in Datablocks viewer (i.e. AnimData for NodeTrees has now been wrapped) --- source/blender/editors/animation/keyframes_draw.c | 1 + source/blender/editors/armature/editarmature.c | 3 + source/blender/editors/armature/poseSlide.c | 158 +++++++++++++++------ source/blender/editors/armature/poseobject.c | 4 +- source/blender/editors/space_view3d/space_view3d.c | 2 + source/blender/makesrna/intern/rna_nodetree.c | 2 + 6 files changed, 123 insertions(+), 47 deletions(-) diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 8e7789190c3..dcb37f4d2c4 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -332,6 +332,7 @@ ActKeyColumn *cfra_find_actkeycolumn (ActKeyColumn *ak, float cframe) } /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */ +// FIXME: this is buggy... next() is ignored completely... ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next) { ActKeyColumn *akn= NULL; diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 7d196d23c98..394df8111d8 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -2630,6 +2630,9 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) /* copy transform locks */ channew->protectflag = chanold->protectflag; + /* copy rotation mode */ + channew->rotmode = chanold->rotmode; + /* copy bone group */ channew->agrp_index= chanold->agrp_index; diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index 464dbcba54b..bbc9ef4d09c 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -103,6 +103,7 @@ typedef struct tPoseSlideOp { Scene *scene; /* current scene */ ARegion *ar; /* region that we're operating in (needed for */ Object *ob; /* active object that Pose Info comes from */ + bArmature *arm; /* armature for pose */ ListBase pfLinks; /* links between posechannels and f-curves */ DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */ @@ -151,6 +152,7 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) /* get info from context */ pso->scene= CTX_data_scene(C); pso->ob= CTX_data_active_object(C); + pso->arm= (pso->ob)? pso->ob->data : NULL; pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */ pso->cframe= pso->scene->r.cfra; @@ -162,7 +164,7 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) pso->nextFrame= RNA_int_get(op->ptr, "next_frame"); /* check the settings from the context */ - if (ELEM3(NULL, pso->ob, pso->ob->adt, pso->ob->adt->action)) + if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; else act= pso->ob->adt->action; @@ -204,6 +206,11 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) } CTX_DATA_END; + /* set depsgraph flags */ + /* make sure the lock is set OK, unlock can be accidentally saved? */ + pso->ob->pose->flag |= POSE_LOCKED; + pso->ob->pose->flag &= ~POSE_DO_UNLOCK; + /* do basic initialise of RB-BST used for finding keyframes, but leave the filling of it up * to the caller of this (usually only invoke() will do it, to make things more efficient). */ @@ -289,8 +296,8 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo /* using this path, find each matching F-Curve for the variables we're interested in */ while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) { FCurve *fcu= (FCurve *)ld->data; - float w1, w2, wtot, ctrl, ictrl; float sVal, eVal; + float w1, w2; int ch; /* get keyframe values for endpoint poses to blend with */ @@ -302,21 +309,26 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo /* get channel index */ ch= fcu->array_index; - /* get the influence of the control */ - ctrl= pso->percentage; - ictrl= 1.0f - pso->percentage; - - /* calculate the relative weights of the endpoints - * - these weights are derived from the relative distance of these - * poses from the current frame - * - they then get normalised, with the results of these normalised - */ - w1 = cframe - (float)pso->prevFrame; - w2 = (float)pso->nextFrame - cframe; - - wtot = w1 + w2; - w1 = w1/wtot; - w2 = w2/wtot; + /* calculate the relative weights of the endpoints */ + if (pso->mode == POSESLIDE_BREAKDOWN) { + /* get weights from the percentage control */ + w1= pso->percentage; /* this must come second */ + w2= 1.0f - w1; /* this must come first */ + } + else { + /* - these weights are derived from the relative distance of these + * poses from the current frame + * - they then get normalised so that they only sum up to 1 + */ + float wtot; + + w1 = cframe - (float)pso->prevFrame; + w2 = (float)pso->nextFrame - cframe; + + wtot = w1 + w2; + w1 = (w1/wtot); + w2 = (w2/wtot); + } /* depending on the mode, */ switch (pso->mode) { @@ -332,10 +344,8 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo break; case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ - // NOTE: just linear interpolation for now, but could add small component of our key if necessary... - // TODO: this doesn't work at all - w2= 1.0f - w1; - vec[ch]= ((sVal * w1) + (eVal * w2)); + /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */ + vec[ch]= ((sVal * w2) + (eVal * w1)); break; } @@ -449,15 +459,18 @@ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) } } - /* funky depsgraph flags - are these still needed? */ - pso->ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); - - /* do depsgraph flush */ - DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); + /* old optimize trick... this enforces to bypass the depgraph + * - note: code copied from transform_generics.c -> recalcData() + */ + // FIXME: shouldn't this use the builtin stuff? + if ((pso->arm->flag & ARM_DELAYDEFORM)==0) + DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); /* sets recalc flags */ + else + where_is_pose(pso->scene, pso->ob); /* note, notifier might evolve */ - //WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); - WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, pso->ob); + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); } /* ------------------------------------ */ @@ -482,7 +495,7 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * /* consolidate these keyframes, and figure out the nearest ones */ BLI_dlrbTree_linkedlist_sync(&pso->keys); - /* cancel if no keyframes found... */ + /* cancel if no keyframes found... */ if (pso->keys.root) { ActKeyColumn *ak; @@ -491,14 +504,24 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * if (ak == NULL) { /* current frame is not a keyframe, so search */ + ActKeyColumn *pk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0); + ActKeyColumn *nk= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1); + + /* check if we found good keyframes */ + if ((pk == nk) && (pk != NULL)) { + if (pk->cfra < pso->cframe) + nk= nk->next; + else if (nk->cfra > pso->cframe) + pk= pk->prev; + } + + /* new set the frames */ /* prev frame */ - ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 0); - pso->prevFrame= (ak)? (ak->cfra) : (pso->cframe - 1); + pso->prevFrame= (pk)? (pk->cfra) : (pso->cframe - 1); RNA_int_set(op->ptr, "prev_frame", pso->prevFrame); /* next frame */ - ak= cfra_find_nearest_next_ak(pso->keys.root, pso->cframe, 1); - pso->nextFrame= (ak)? (ak->cfra) : (pso->cframe + 1); - RNA_int_set(op->ptr, "next_frame", pso->prevFrame); + pso->nextFrame= (nk)? (nk->cfra) : (pso->cframe + 1); + RNA_int_set(op->ptr, "next_frame", pso->nextFrame); } else { /* current frame itself is a keyframe, so just take keyframes on either side */ @@ -515,18 +538,63 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * return OPERATOR_CANCELLED; } + // FIXME: for now, just do modal for breakdowns... + if (pso->mode == POSESLIDE_BREAKDOWN) { + /* initial apply for operator... */ + pose_slide_apply(C, op, pso); + + /* add a modal handler for this operator */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + else { + /* temp static operator code... until a way to include percentage in the formulation comes up */ + pose_slide_apply(C, op, pso); + pose_slide_exit(C, op); + return OPERATOR_FINISHED; + } +} + +/* common code for modal() */ +static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) +{ + tPoseSlideOp *pso= op->customdata; - // TODO ----------------------------------- - // from here on, we should just invoke the modal operator, but for now, just do static... + switch (evt->type) { + case LEFTMOUSE: /* confirm */ + pose_slide_exit(C, op); + return OPERATOR_FINISHED; + + case ESCKEY: /* cancel */ + case RIGHTMOUSE: + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; + + case MOUSEMOVE: /* calculate new position */ + { + /* calculate percentage based on position of mouse (we only use x-axis for now. + * since this is more conveninent for users to do), and store new percentage value + */ + pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* apply... */ + pose_slide_apply(C, op, pso); + } + break; + } - /* temp static operator code... */ - pose_slide_apply(C, op, pso); - pose_slide_exit(C, op); - return OPERATOR_FINISHED; + /* still running... */ + return OPERATOR_RUNNING_MODAL; } -// TODO: common modal + cancel - +/* common code for cancel() */ +static int pose_slide_cancel (bContext *C, wmOperator *op) +{ + /* cleanup and done */ + pose_slide_exit(C, op); + return OPERATOR_CANCELLED; +} /* common code for exec() methods */ static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *pso) @@ -708,12 +776,12 @@ void POSE_OT_breakdown (wmOperatorType *ot) /* callbacks */ ot->exec= pose_slide_breakdown_exec; ot->invoke= pose_slide_breakdown_invoke; - //ot->modal= pose_slide_modal; - //ot->cancel= pose_slide_cancel; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; ot->poll= ED_operator_posemode; /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; /* Properties */ pose_slide_opdef_properties(ot); diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index e5a7a1e167d..305e153f805 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -1942,7 +1942,7 @@ static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *ev /* Set the visible layers for the active armature (edit and pose modes) */ static int armature_bone_layers_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= CTX_data_edit_object(C); bArmature *arm= (ob)? ob->data : NULL; PointerRNA ptr; int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */ @@ -1955,7 +1955,7 @@ static int armature_bone_layers_exec (bContext *C, wmOperator *op) { /* get pointer for pchan, and write flags this way */ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr); - RNA_boolean_set_array(&ptr, "layers", layers); + RNA_boolean_set_array(&ptr, "layer", layers); } CTX_DATA_END; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 5ea633a47f7..a73a16f38ba 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -420,6 +420,7 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_TRANSFORM: + case ND_POSE: case ND_DRAW: case ND_MODIFIER: case ND_CONSTRAINT: @@ -560,6 +561,7 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_TRANSFORM: + case ND_POSE: case ND_DRAW: case ND_KEYS: ED_region_tag_redraw(ar); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 73aaf0837db..b310ff06b8e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1660,6 +1660,8 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Node Tree", "Node tree consisting of linked nodes used for materials, textures and compositing."); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_NODE); + + rna_def_animdata_common(srna); prop = RNA_def_property(srna, "nodes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "nodes", NULL); -- cgit v1.2.3 From 7eb436a6b85156c56dc842ff4289e5a3e2b7b5e9 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 19 Sep 2009 12:36:22 +0000 Subject: 2.5 - More Animation Bugfixes * Updating Preview Range settings results in correct updates for Animation Editors * Compositing nodes now correctly animate when the values were set by IKEY/RMB on suitable node parameters. Beware that these nodes are not relinkable node-trees, hence the standard code not working. * Ctrl-P to parent objects to bones now works in Pose Mode too. I needed to add a special keymap entry for this, though I thought this would have been better to be automatically inherited/present from Object keymap already? * Ctrl-P -> Parent to Bone option now works correctly again. 1.5 lines of code missing here... * Breakdowns tool now shows custom cursor during 'modal' phase so that it's not that confusing what's going on. --- source/blender/blenkernel/intern/anim_sys.c | 18 +++++++++++++++++- source/blender/editors/armature/armature_ops.c | 4 +++- source/blender/editors/armature/poseSlide.c | 7 +++++++ source/blender/editors/object/object_relations.c | 2 ++ source/blender/editors/space_action/space_action.c | 1 + source/blender/editors/space_graph/space_graph.c | 1 + source/blender/editors/space_nla/space_nla.c | 1 + 7 files changed, 32 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 522297da1d7..8b761a2ee0e 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -40,6 +40,7 @@ #include "BLI_dynstr.h" #include "DNA_anim_types.h" +#include "DNA_scene_types.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -1517,7 +1518,10 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) AnimData *adt= BKE_animdata_from_id(id); Curve *cu= (Curve *)id; + /* set ctime variable for curve */ cu->ctime= ctime; + + /* now execute animation data on top of this as per normal */ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); } @@ -1537,7 +1541,19 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) EVAL_ANIM_IDS(main->world.first, ADT_RECALC_ANIM); /* scenes */ - EVAL_ANIM_IDS(main->scene.first, ADT_RECALC_ANIM); + for (id= main->scene.first; id; id= id->next) { + AnimData *adt= BKE_animdata_from_id(id); + Scene *scene= (Scene *)id; + + /* do compositing nodes first (since these aren't included in main tree) */ + if (scene->nodetree) { + AnimData *adt2= BKE_animdata_from_id((ID *)scene->nodetree); + BKE_animsys_evaluate_animdata((ID *)scene->nodetree, adt2, ctime, ADT_RECALC_ANIM); + } + + /* now execute scene animation data as per normal */ + BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); + } } /* ***************************************** */ diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index a8b8b8aecc1..fae0b093551 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -298,6 +298,9 @@ void ED_keymap_armature(wmWindowManager *wm) keymap= WM_keymap_find(wm, "Pose", 0, 0); keymap->poll= ED_operator_posemode; + // XXX: set parent is object-based operator, but it should also be available here... + WM_keymap_add_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, 0, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "unselected", 1); @@ -310,7 +313,6 @@ void ED_keymap_armature(wmWindowManager *wm) WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "POSE_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); - // for now, we include hotkeys for copy/paste WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0); kmi= WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index bbc9ef4d09c..e55c5608112 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -480,6 +480,7 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * { tPChanFCurveLink *pfl; AnimData *adt= pso->ob->adt; + wmWindow *win= CTX_wm_window(C); /* for each link, add all its keyframes to the search tree */ for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { @@ -543,6 +544,9 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * /* initial apply for operator... */ pose_slide_apply(C, op, pso); + /* set cursor to indicate modal */ + WM_cursor_modal(win, BC_EW_SCROLLCURSOR); + /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -559,14 +563,17 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) { tPoseSlideOp *pso= op->customdata; + wmWindow *win= CTX_wm_window(C); switch (evt->type) { case LEFTMOUSE: /* confirm */ + WM_cursor_restore(win); pose_slide_exit(C, op); return OPERATOR_FINISHED; case ESCKEY: /* cancel */ case RIGHTMOUSE: + WM_cursor_restore(win); pose_slide_exit(C, op); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 12cb2b95e06..65061e8dfb9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -647,6 +647,8 @@ static int parent_set_exec(bContext *C, wmOperator *op) if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm ) ob->partype= PARSKEL; /* note, dna define, not operator property */ + else if (partype == PAR_BONE) + ob->partype= PARBONE; /* note, dna define, not operator property */ else ob->partype= PAROBJECT; /* note, dna define, not operator property */ } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index bceee73d5f0..3b275cab814 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -323,6 +323,7 @@ static void action_main_area_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index e0b961b38f1..a7ea2294ed4 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -374,6 +374,7 @@ static void graph_region_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 06ee34a6573..41435810889 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -409,6 +409,7 @@ static void nla_main_area_listener(ARegion *ar, wmNotifier *wmn) break; case NC_SCENE: switch(wmn->data) { + case ND_RENDER_OPTIONS: case ND_OB_ACTIVE: case ND_FRAME: case ND_MARKERS: -- cgit v1.2.3 From 645ca520a313a9881ee77556fc85820e74f83887 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Sat, 19 Sep 2009 13:50:24 +0000 Subject: Armature UI Added the new pose tools in the toolbar. Changed a few armature values to enums. Brecht: The Heads/Tails enum seems to also enable armature.draw_axis, and the paths_type enum affects armature.draw_names --- release/ui/buttons_data_armature.py | 20 +++++++----- release/ui/space_view3d_toolbar.py | 8 +++-- source/blender/makesrna/intern/rna_armature.c | 45 +++++++++++++++++---------- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/release/ui/buttons_data_armature.py b/release/ui/buttons_data_armature.py index 5924a2eb4ea..49da9c190ff 100644 --- a/release/ui/buttons_data_armature.py +++ b/release/ui/buttons_data_armature.py @@ -121,28 +121,31 @@ class DATA_PT_paths(DataButtonsPanel): layout = self.layout arm = context.armature - + + layout.itemR(arm, "paths_type", expand=True) + split = layout.split() col = split.column() - col.itemR(arm, "paths_show_around_current_frame", text="Around Frame") sub = col.column(align=True) - if (arm.paths_show_around_current_frame): + if (arm.paths_type == 'CURRENT_FRAME'): sub.itemR(arm, "path_before_current", text="Before") sub.itemR(arm, "path_after_current", text="After") - else: + elif (arm.paths_type == 'RANGE'): sub.itemR(arm, "path_start_frame", text="Start") sub.itemR(arm, "path_end_frame", text="End") - sub.itemR(arm, "path_size", text="Step") - col.itemR(arm, "paths_calculate_head_positions", text="Head") + sub.itemR(arm, "path_size", text="Step") + col.row().itemR(arm, "paths_location", expand=True) col = split.column() col.itemL(text="Show:") col.itemR(arm, "paths_show_frame_numbers", text="Frame Numbers") col.itemR(arm, "paths_highlight_keyframes", text="Keyframes") col.itemR(arm, "paths_show_keyframe_numbers", text="Keyframe Numbers") + + layout.itemO("pose.paths_calculate") class DATA_PT_ghost(DataButtonsPanel): __label__ = "Ghost" @@ -151,11 +154,12 @@ class DATA_PT_ghost(DataButtonsPanel): layout = self.layout arm = context.armature - + + layout.itemR(arm, "ghost_type", expand=True) + split = layout.split() col = split.column() - col.itemR(arm, "ghost_type", text="") sub = col.column(align=True) if arm.ghost_type == 'RANGE': diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 9492437b863..415a3e223bb 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -299,11 +299,13 @@ class VIEW3D_PT_tools_posemode(View3DPanel): col.itemL(text="Pose:") col.itemO("pose.copy", text="Copy") col.itemO("pose.paste", text="Paste") + col.itemO("poselib.pose_add", text="Add To library") col = layout.column(align=True) - col.itemL(text="Library:") - col.itemO("poselib.pose_add", text="Add") - col.itemO("poselib.pose_remove", text="Remove") + col.itemL(text="In-Between:") + col.itemO("pose.relax", text="Relax") + col.itemO("pose.push", text="Push") + col.itemO("pose.breakdown", text="Breakdowner") col = layout.column(align=True) col.itemL(text="Repeat:") diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index dcf89b7ac1e..c271b34b6d4 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -526,15 +526,24 @@ static void rna_def_armature(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_drawtype_items[] = { - {ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Draw bones as octahedral shape (default)."}, - {ARM_LINE, "STICK", 0, "Stick", "Draw bones as simple 2D lines with dots."}, - {ARM_B_BONE, "BBONE", 0, "B-Bone", "Draw bones as boxes, showing subdivision and B-Splines"}, - {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Draw bones as extruded spheres, showing defomation influence volume."}, + {ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape (default)."}, + {ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots."}, + {ARM_B_BONE, "BBONE", 0, "B-Bone", "Display bones as boxes, showing subdivision and B-Splines"}, + {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Display bones as extruded spheres, showing defomation influence volume."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_ghost_type_items[] = { - {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Current Frame", "Draw Ghosts of poses within a fixed number of frames around the current frame."}, - {ARM_GHOST_RANGE, "RANGE", 0, "In Range", "Draw Ghosts of poses within specified range."}, - {ARM_GHOST_KEYS, "KEYS", 0, "On Keyframes", "Draw Ghosts of poses on Keyframes."}, + {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Frame", "Display Ghosts of poses within a fixed number of frames around the current frame."}, + {ARM_GHOST_RANGE, "RANGE", 0, "In Range", "Display Ghosts of poses within specified range."}, + {ARM_GHOST_KEYS, "KEYS", 0, "On Keyframes", "Display Ghosts of poses on Keyframes."}, + {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_paths_type_items[]= { + {ARM_PATH_ACFRA, "CURRENT_FRAME", 0, "Around Frame", "Display Paths of poses within a fixed number of frames around the current frame."}, + {0, "RANGE", 0, "In Range", "Display Paths of poses within specified range."}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem prop_paths_location_items[]= { + {ARM_PATH_HEADS, "HEADS", 0, "Heads", "Calculate bone paths from heads"}, + {0, "TIPS", 0, "Tips", "Calculate bone paths from tips"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Armature", "ID"); @@ -564,7 +573,19 @@ static void rna_def_armature(BlenderRNA *brna) prop= RNA_def_property(srna, "ghost_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ghosttype"); RNA_def_property_enum_items(prop, prop_ghost_type_items); - RNA_def_property_ui_text(prop, "Ghost Drawing", "Method of Onion-skinning for active Action"); + RNA_def_property_ui_text(prop, "Ghost Type", "Method of Onion-skinning for active Action"); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + + prop= RNA_def_property(srna, "paths_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_paths_type_items); + RNA_def_property_ui_text(prop, "Paths Type", "Mapping type to use for this image in the game engine."); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + + prop= RNA_def_property(srna, "paths_location", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_paths_location_items); + RNA_def_property_ui_text(prop, "Paths Location", "When calculating Bone Paths, use Head or Tips"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* Boolean values */ @@ -672,15 +693,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Paths Show Keyframe Numbers", "When drawing Armature in Pose Mode, show frame numbers of Keyframes on Bone Paths"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - prop= RNA_def_property(srna, "paths_show_around_current_frame", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "pathflag", ARM_PATH_ACFRA); - RNA_def_property_ui_text(prop, "Paths Around Current Frame", "When drawing Armature in Pose Mode, only show section of Bone Paths that falls around current frame"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - prop= RNA_def_property(srna, "paths_calculate_head_positions", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "pathflag", ARM_PATH_HEADS); - RNA_def_property_ui_text(prop, "Paths Use Heads", "When calculating Bone Paths, use Head locations instead of Tips"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* Number fields */ /* ghost/onionskining settings */ -- cgit v1.2.3 From d25ab89ac08db7598a62614b537ae4679f26a86d Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 19 Sep 2009 14:16:02 +0000 Subject: RNA: for last commit, fix paths_location and paths_type enums, these had wrong DNA variable name already before this change. --- source/blender/makesrna/intern/rna_armature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index c271b34b6d4..aa422f85d7b 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -577,13 +577,13 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop= RNA_def_property(srna, "paths_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "pathflag"); RNA_def_property_enum_items(prop, prop_paths_type_items); RNA_def_property_ui_text(prop, "Paths Type", "Mapping type to use for this image in the game engine."); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop= RNA_def_property(srna, "paths_location", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "pathflag"); RNA_def_property_enum_items(prop, prop_paths_location_items); RNA_def_property_ui_text(prop, "Paths Location", "When calculating Bone Paths, use Head or Tips"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); -- cgit v1.2.3 From fcbfd2979644d1b0eac963d49ee9f0e8f38d9f5b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 19 Sep 2009 15:48:47 +0000 Subject: Fix combined pose + weight paint mode, was using wrong object in a few places, missing some checks. --- source/blender/editors/armature/editarmature.c | 2 +- source/blender/editors/space_view3d/drawarmature.c | 10 +++++++--- source/blender/editors/space_view3d/view3d_select.c | 2 +- source/blender/editors/transform/transform_conversions.c | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 394df8111d8..80f8c2b07aa 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -4333,7 +4333,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor } /* in weightpaint we select the associated vertex group too */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (OBACT && OBACT->mode & OB_MODE_WEIGHT_PAINT) { if (nearBone->flag & BONE_ACTIVE) { ED_vgroup_select_by_name(OBACT, nearBone->name); DAG_id_flush_update(&OBACT->id, OB_RECALC_DATA); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index fa810677fe8..497091f2660 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2513,7 +2513,11 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int /* drawing posemode selection indices or colors only in these cases */ if(!(base->flag & OB_FROMDUPLI)) { if(G.f & G_PICKSEL) { - if(ob->mode & OB_MODE_POSE) + if(OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { + if(ob==modifiers_isDeformedByArmature(OBACT)) + arm->flag |= ARM_POSEMODE; + } + else if(ob->mode & OB_MODE_POSE) arm->flag |= ARM_POSEMODE; } else if(ob->mode & OB_MODE_POSE) { @@ -2530,8 +2534,8 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int if ((flag & DRAW_SCENESET)==0) { if(ob==OBACT) arm->flag |= ARM_POSEMODE; - else if(ob->mode & OB_MODE_WEIGHT_PAINT) { - if(OBACT && ob==modifiers_isDeformedByArmature(OBACT)) + else if(OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { + if(ob==modifiers_isDeformedByArmature(OBACT)) arm->flag |= ARM_POSEMODE; } draw_pose_paths(scene, v3d, rv3d, ob); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index b1fec793b09..a37e916064c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1148,7 +1148,7 @@ static void mouse_select(bContext *C, short *mval, short extend, short obcenter, WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object); /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */ - if(basact->object->mode & OB_MODE_WEIGHT_PAINT) { + if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) { /* prevent activating */ basact= NULL; } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 776f2e47d1e..e59ec3746e3 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5289,7 +5289,7 @@ void createTransData(bContext *C, TransInfo *t) { if(ob_armature->type==OB_ARMATURE) { - if(ob_armature->mode & OB_MODE_POSE) + if((ob_armature->mode & OB_MODE_POSE) && ob_armature == modifiers_isDeformedByArmature(ob)) { createTransPose(C, t, ob_armature); break; -- cgit v1.2.3 From 01ef3301a81b18fb40257161d7d0c5daa9a1f024 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 19 Sep 2009 18:45:31 +0000 Subject: Fix drawing of armature bone axes, these were not showing labels. Also unified drawing code for object & particle text, was almost the same function duplicated, and now also used for bones. --- source/blender/editors/space_view3d/drawarmature.c | 107 +++++++----- source/blender/editors/space_view3d/drawobject.c | 179 ++++++++------------- .../blender/editors/space_view3d/view3d_intern.h | 7 +- 3 files changed, 138 insertions(+), 155 deletions(-) diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 497091f2660..028d666dc71 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -639,7 +639,7 @@ static void draw_sphere_bone_dist(float smat[][4], float imat[][4], int boneflag /* figure out the sizes of spheres */ if (ebone) { - /* this routine doesn't call set_matrix_editbone() that calculates it */ + /* this routine doesn't call get_matrix_editbone() that calculates it */ ebone->length = VecLenf(ebone->head, ebone->tail); length= ebone->length; @@ -749,7 +749,7 @@ static void draw_sphere_bone_wire(float smat[][4], float imat[][4], int armflag, /* figure out the sizes of spheres */ if (ebone) { - /* this routine doesn't call set_matrix_editbone() that calculates it */ + /* this routine doesn't call get_matrix_editbone() that calculates it */ ebone->length = VecLenf(ebone->head, ebone->tail); length= ebone->length; @@ -1516,15 +1516,25 @@ static void draw_pose_dofs(Object *ob) } } +static void bone_matrix_translate_y(float mat[][4], float y) +{ + float trans[3]; + + VECCOPY(trans, mat[1]); + VecMulf(trans, y); + VecAddf(mat[3], mat[3], trans); +} + /* assumes object is Armature with pose */ -static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt) +static void draw_pose_channels(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt) { + RegionView3D *rv3d= ar->regiondata; Object *ob= base->object; bArmature *arm= ob->data; bPoseChannel *pchan; Bone *bone; GLfloat tmp; - float smat[4][4], imat[4][4]; + float smat[4][4], imat[4][4], bmat[4][4]; int index= -1; short do_dashed= 3, draw_wire= 0; short flag, constflag; @@ -1809,15 +1819,21 @@ static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ba /* Draw names of bone */ if (arm->flag & ARM_DRAWNAMES) { VecMidf(vec, pchan->pose_head, pchan->pose_tail); - view3d_object_text_draw_add(vec[0], vec[1], vec[2], pchan->name, 10); + view3d_cached_text_draw_add(vec[0], vec[1], vec[2], pchan->name, 10); } /* Draw additional axes on the bone tail */ if ( (arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE) ) { glPushMatrix(); - glMultMatrixf(pchan->pose_mat); - glTranslatef(0.0f, pchan->bone->length, 0.0f); - drawaxes(0.25f*pchan->bone->length, 0, OB_ARROWS); + Mat4CpyMat4(bmat, pchan->pose_mat); + bone_matrix_translate_y(bmat, pchan->bone->length); + glMultMatrixf(bmat); + + /* do cached text draw immediate to include transform */ + view3d_cached_text_draw_begin(); + drawaxes(pchan->bone->length*0.25f, 0, OB_ARROWS); + view3d_cached_text_draw_end(v3d, ar, 1, bmat); + glPopMatrix(); } } @@ -1830,32 +1846,28 @@ static void draw_pose_channels(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ba } /* in editmode, we don't store the bone matrix... */ -static void set_matrix_editbone(EditBone *eBone) +static void get_matrix_editbone(EditBone *eBone, float bmat[][4]) { - float delta[3],offset[3]; - float mat[3][3], bmat[4][4]; + float delta[3]; + float mat[3][3]; /* Compose the parent transforms (i.e. their translations) */ - VECCOPY(offset, eBone->head); - - glTranslatef(offset[0],offset[1],offset[2]); - VecSubf(delta, eBone->tail, eBone->head); eBone->length = (float)sqrt(delta[0]*delta[0] + delta[1]*delta[1] +delta[2]*delta[2]); vec_roll_to_mat3(delta, eBone->roll, mat); Mat4CpyMat3(bmat, mat); - - glMultMatrixf(bmat); - + + VecAddf(bmat[3], bmat[3], eBone->head); } -static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) +static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) { + RegionView3D *rv3d= ar->regiondata; EditBone *eBone; bArmature *arm= ob->data; - float smat[4][4], imat[4][4]; + float smat[4][4], imat[4][4], bmat[4][4]; unsigned int index; int flag; @@ -1893,7 +1905,8 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A)==0) { glPushMatrix(); - set_matrix_editbone(eBone); + get_matrix_editbone(eBone, bmat); + glMultMatrixf(bmat); /* catch exception for bone with hidden parent */ flag= eBone->flag; @@ -1941,7 +1954,8 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) } else { glPushMatrix(); - set_matrix_editbone(eBone); + get_matrix_editbone(eBone, bmat); + glMultMatrixf(bmat); if (arm->drawtype == ARM_LINE) draw_line_bone(arm->flag, flag, 0, index, NULL, eBone); @@ -1994,14 +2008,20 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) if (arm->flag & ARM_DRAWNAMES) { VecMidf(vec, eBone->head, eBone->tail); glRasterPos3fv(vec); - view3d_object_text_draw_add(vec[0], vec[1], vec[2], eBone->name, 10); + view3d_cached_text_draw_add(vec[0], vec[1], vec[2], eBone->name, 10); } /* Draw additional axes */ if (arm->flag & ARM_DRAWAXES) { glPushMatrix(); - set_matrix_editbone(eBone); - glTranslatef(0.0f, eBone->length, 0.0f); + get_matrix_editbone(eBone, bmat); + bone_matrix_translate_y(bmat, eBone->length); + glMultMatrixf(bmat); + + /* do cached text draw immediate to include transform */ + view3d_cached_text_draw_begin(); drawaxes(eBone->length*0.25f, 0, OB_ARROWS); + view3d_cached_text_draw_end(v3d, ar, 1, bmat); + glPopMatrix(); } @@ -2021,8 +2041,9 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt) /* draw bone paths * - in view space */ -static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) +static void draw_pose_paths(Scene *scene, View3D *v3d, ARegion *ar, Object *ob) { + RegionView3D *rv3d= ar->regiondata; AnimData *adt= BKE_animdata_from_id(&ob->id); bArmature *arm= ob->data; bPoseChannel *pchan; @@ -2155,12 +2176,12 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec /* only draw framenum if several consecutive highlighted points don't occur on same point */ if (a == 0) { sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } else if ((a > stepsize) && (a < len-stepsize)) { if ((VecEqual(fp, fp-(stepsize*3))==0) || (VecEqual(fp, fp+(stepsize*3))==0)) { sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } } } @@ -2202,7 +2223,7 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec char str[32]; sprintf(str, "%d", (a+sfra)); - view3d_object_text_draw_add(fp[0], fp[1], fp[2], str, 0); + view3d_cached_text_draw_add(fp[0], fp[1], fp[2], str, 0); } } } @@ -2253,7 +2274,7 @@ static void ghost_poses_tag_unselected(Object *ob, short unset) /* draw ghosts that occur within a frame range * note: object should be in posemode */ -static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2295,7 +2316,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2315,7 +2336,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d /* draw ghosts on keyframes in action within range * - object should be in posemode */ -static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2374,7 +2395,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } glDisable(GL_BLEND); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); @@ -2394,7 +2415,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* draw ghosts around current frame * - object is supposed to be armature in posemode */ -static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { Object *ob= base->object; AnimData *adt= BKE_animdata_from_id(&ob->id); @@ -2444,7 +2465,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } } @@ -2459,7 +2480,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base if (CFRA != cfrao) { BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL); where_is_pose(scene, ob); - draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE); + draw_pose_channels(scene, v3d, ar, base, OB_WIRE); } } } @@ -2480,7 +2501,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base /* ********************************** Armature Drawing - Main ************************* */ /* called from drawobject.c, return 1 if nothing was drawn */ -int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag) +int draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt, int flag) { Object *ob= base->object; bArmature *arm= ob->data; @@ -2504,7 +2525,7 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int /* editmode? */ if(arm->edbo) { arm->flag |= ARM_EDITMODE; - draw_ebones(v3d, rv3d, ob, dt); + draw_ebones(v3d, ar, ob, dt); arm->flag &= ~ARM_EDITMODE; } else{ @@ -2522,14 +2543,14 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int } else if(ob->mode & OB_MODE_POSE) { if (arm->ghosttype == ARM_GHOST_RANGE) { - draw_ghost_poses_range(scene, v3d, rv3d, base); + draw_ghost_poses_range(scene, v3d, ar, base); } else if (arm->ghosttype == ARM_GHOST_KEYS) { - draw_ghost_poses_keys(scene, v3d, rv3d, base); + draw_ghost_poses_keys(scene, v3d, ar, base); } else if (arm->ghosttype == ARM_GHOST_CUR) { if (arm->ghostep) - draw_ghost_poses(scene, v3d, rv3d, base); + draw_ghost_poses(scene, v3d, ar, base); } if ((flag & DRAW_SCENESET)==0) { if(ob==OBACT) @@ -2538,11 +2559,11 @@ int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int if(ob==modifiers_isDeformedByArmature(OBACT)) arm->flag |= ARM_POSEMODE; } - draw_pose_paths(scene, v3d, rv3d, ob); + draw_pose_paths(scene, v3d, ar, ob); } } } - draw_pose_channels(scene, v3d, rv3d, base, dt); + draw_pose_channels(scene, v3d, ar, base, dt); arm->flag &= ~ARM_POSEMODE; if(ob->mode & OB_MODE_POSE) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index b8852486dea..60ae91e7a89 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -434,11 +434,11 @@ void drawaxes(float size, int flag, char drawtype) // patch for 3d cards crashing on glSelect for text drawing (IBM) if((flag & DRAW_PICKING) == 0) { if (axis==0) - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "x", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "x", 0); else if (axis==1) - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "y", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "y", 0); else - view3d_object_text_draw_add(v2[0], v2[1], v2[2], "z", 0); + view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "z", 0); } } break; @@ -496,23 +496,32 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, float *vec, int se if(v3d->zbuf) glDepthFunc(GL_LEQUAL); } -/* *********** text drawing for object ************* */ -static ListBase strings= {NULL, NULL}; +/* *********** text drawing for object/particles/armature ************* */ -typedef struct ViewObjectString { - struct ViewObjectString *next, *prev; +static ListBase CachedText[3]; +static int CachedTextLevel= 0; + +typedef struct ViewCachedString { + struct ViewCachedString *next, *prev; float vec[3], col[4]; char str[128]; short mval[2]; short xoffs; -} ViewObjectString; +} ViewCachedString; +void view3d_cached_text_draw_begin() +{ + ListBase *strings= &CachedText[CachedTextLevel]; + strings->first= strings->last= NULL; + CachedTextLevel++; +} -void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs) +void view3d_cached_text_draw_add(float x, float y, float z, char *str, short xoffs) { - ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); + ListBase *strings= &CachedText[CachedTextLevel-1]; + ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString), "ViewCachedString"); - BLI_addtail(&strings, vos); + BLI_addtail(strings, vos); BLI_strncpy(vos->str, str, 128); vos->vec[0]= x; vos->vec[1]= y; @@ -521,22 +530,23 @@ void view3d_object_text_draw_add(float x, float y, float z, char *str, short xof vos->xoffs= xoffs; } -static void view3d_object_text_draw(View3D *v3d, ARegion *ar) +void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4]) { - ViewObjectString *vos; - int tot= 0; + RegionView3D *rv3d= ar->regiondata; + ListBase *strings= &CachedText[CachedTextLevel-1]; + ViewCachedString *vos; + int a, tot= 0; /* project first and test */ - for(vos= strings.first; vos; vos= vos->next) { + for(vos= strings->first; vos; vos= vos->next) { + if(mat) + Mat4MulVecfl(mat, vos->vec); view3d_project_short_clip(ar, vos->vec, vos->mval); if(vos->mval[0]!=IS_CLIPPED) tot++; } - + if(tot) { - RegionView3D *rv3d= ar->regiondata; - int a; - if(rv3d->rflag & RV3D_CLIPPING) for(a=0; a<6; a++) glDisable(GL_CLIP_PLANE0+a); @@ -544,16 +554,22 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar) wmPushMatrix(); ED_region_pixelspace(ar); - if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + if(depth_write) { + if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + } + else glDepthMask(0); - for(vos= strings.first; vos; vos= vos->next) { + for(vos= strings->first; vos; vos= vos->next) { if(vos->mval[0]!=IS_CLIPPED) { glColor3fv(vos->col); - BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 0.0, vos->str); + BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], (depth_write)? 0.0f: 2.0f, vos->str); } } - if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + if(depth_write) { + if(v3d->zbuf) glEnable(GL_DEPTH_TEST); + } + else glDepthMask(1); wmPopMatrix(); @@ -562,10 +578,14 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar) glEnable(GL_CLIP_PLANE0+a); } - if(strings.first) - BLI_freelistN(&strings); + if(strings->first) + BLI_freelistN(strings); + + CachedTextLevel--; } +/* ******************** primitive drawing ******************* */ + static void drawcube(void) { @@ -1912,7 +1932,7 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val, conv_float, VecLenf(v1, v2)); - view3d_object_text_draw_add(x, y, z, val, 0); + view3d_cached_text_draw_add(x, y, z, val, 0); } } } @@ -1951,7 +1971,7 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val, conv_float, area); - view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); + view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } } } @@ -1993,13 +2013,13 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E /* Vec 1 */ sprintf(val,"%.3f", RAD2DEG(VecAngle3(v4, v1, v2))); VecLerpf(fvec, efa->cent, efa->v1->co, 0.8f); - view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); + view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0); } if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) { /* Vec 2 */ sprintf(val,"%.3f", RAD2DEG(VecAngle3(v1, v2, v3))); VecLerpf(fvec, efa->cent, efa->v2->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) { /* Vec 3 */ @@ -2008,14 +2028,14 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E else sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v1))); VecLerpf(fvec, efa->cent, efa->v3->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } /* Vec 4 */ if(efa->v4) { if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) { sprintf(val,"%.3f", RAD2DEG(VecAngle3(v3, v4, v1))); VecLerpf(fvec, efa->cent, efa->v4->co, 0.8f); - view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); + view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0); } } } @@ -2905,75 +2925,8 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas return retval; } -/* *********** text drawing for particles ************* */ -static ListBase pstrings= {NULL, NULL}; - -typedef struct ViewParticleString { - struct ViewParticleString *next, *prev; - float vec[3], col[4]; - char str[128]; - short mval[2]; - short xoffs; -} ViewParticleString; - - -void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs) -{ - ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); - - BLI_addtail(&pstrings, vos); - BLI_strncpy(vos->str, str, 128); - vos->vec[0]= x; - vos->vec[1]= y; - vos->vec[2]= z; - glGetFloatv(GL_CURRENT_COLOR, vos->col); - vos->xoffs= xoffs; -} - -static void view3d_particle_text_draw(View3D *v3d, ARegion *ar) -{ - ViewObjectString *vos; - int tot= 0; - - /* project first and test */ - for(vos= pstrings.first; vos; vos= vos->next) { - project_short(ar, vos->vec, vos->mval); - if(vos->mval[0]!=IS_CLIPPED) - tot++; - } - - if(tot) { - RegionView3D *rv3d= ar->regiondata; - int a; - - if(rv3d->rflag & RV3D_CLIPPING) - for(a=0; a<6; a++) - glDisable(GL_CLIP_PLANE0+a); - - wmPushMatrix(); - ED_region_pixelspace(ar); - - if(v3d->zbuf) glDepthMask(0); - - for(vos= pstrings.first; vos; vos= vos->next) { - if(vos->mval[0]!=IS_CLIPPED) { - glColor3fv(vos->col); - BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str); - } - } - - if(v3d->zbuf) glDepthMask(1); - - wmPopMatrix(); +/* *********** drawing for particles ************* */ - if(rv3d->rflag & RV3D_CLIPPING) - for(a=0; a<6; a++) - glEnable(GL_CLIP_PLANE0+a); - } - - if(pstrings.first) - BLI_freelistN(&pstrings); -} static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd) { float vec[3], vec2[3]; @@ -3540,7 +3493,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv sprintf(val, "%s %.2f", val, pa_health); /* in path drawing state.co is the end point */ - view3d_particle_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); + view3d_cached_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); } } } @@ -4755,8 +4708,9 @@ static void drawtexspace(Object *ob) } /* draws wire outline */ -static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) +static void drawSolidSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base) { + RegionView3D *rv3d= ar->regiondata; Object *ob= base->object; glLineWidth(2.0); @@ -4775,7 +4729,7 @@ static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base } else if(ob->type==OB_ARMATURE) { if(!(ob->mode & OB_MODE_POSE)) - draw_armature(scene, v3d, rv3d, base, OB_WIRE, 0); + draw_armature(scene, v3d, ar, base, OB_WIRE, 0); } glLineWidth(1.0); @@ -4885,11 +4839,11 @@ void drawRBpivot(bRigidBodyJointConstraint *data) glVertex3fv(v); glEnd(); if (axis==0) - view3d_object_text_draw_add(v[0], v[1], v[2], "px", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "px", 0); else if (axis==1) - view3d_object_text_draw_add(v[0], v[1], v[2], "py", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "py", 0); else - view3d_object_text_draw_add(v[0], v[1], v[2], "pz", 0); + view3d_cached_text_draw_add(v[0], v[1], v[2], "pz", 0); } glLineWidth (1.0f); setlinestyle(0); @@ -4932,6 +4886,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) } } + /* no return after this point, otherwise leaks */ + view3d_cached_text_draw_begin(); + /* draw keys? */ #if 0 // XXX old animation system if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) { @@ -5116,7 +5073,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) if(dt>OB_WIRE && dtobedit && (flag && DRAW_SCENESET)==0) { if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { - drawSolidSelect(scene, v3d, rv3d, base); + drawSolidSelect(scene, v3d, ar, base); } } } @@ -5262,7 +5219,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) break; case OB_ARMATURE: if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material - empty_object= draw_armature(scene, v3d, rv3d, base, dt, flag); + empty_object= draw_armature(scene, v3d, ar, base, dt, flag); if(dt>OB_WIRE) GPU_disable_material(); break; default: @@ -5282,10 +5239,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) wmLoadMatrix(rv3d->viewmat); + view3d_cached_text_draw_begin(); + for(psys=ob->particlesystem.first; psys; psys=psys->next) draw_new_particle_system(scene, v3d, rv3d, base, psys, dt); - view3d_particle_text_draw(v3d, ar); + view3d_cached_text_draw_end(v3d, ar, 0, NULL); wmMultMatrix(ob->obmat); @@ -5437,7 +5396,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */ /* but, we also dont draw names for sets or duplicators */ if(flag == 0) { - view3d_object_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10); + view3d_cached_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10); } } /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/ @@ -5460,7 +5419,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) } /* return warning, this is cached text draw */ - view3d_object_text_draw(v3d, ar); + view3d_cached_text_draw_end(v3d, ar, 1, NULL); wmLoadMatrix(rv3d->viewmat); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 7dbea44b68b..52505fad521 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -89,10 +89,13 @@ int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt); void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int dt, int outline); void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob); void drawaxes(float size, int flag, char drawtype); -void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs); + +void view3d_cached_text_draw_begin(void); +void view3d_cached_text_draw_add(float x, float y, float z, char *str, short xoffs); +void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4]); /* drawarmature.c */ -int draw_armature(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag); +int draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int dt, int flag); /* drawmesh.c */ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, struct DerivedMesh *dm, int faceselect); -- cgit v1.2.3 From 45089af1b277770ea6eb02f1d92af9f8f1d05125 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 19 Sep 2009 19:40:38 +0000 Subject: Bone constraints are now in a separate tab. It's more consistent since object constraints also have their own tab, and I didn't want to break context going from left to right. --- release/ui/buttons_data_bone.py | 1 + release/ui/buttons_object_constraint.py | 2 +- .../editors/space_buttons/buttons_context.c | 1 + .../blender/editors/space_buttons/buttons_header.c | 6 ++++-- .../blender/editors/space_buttons/space_buttons.c | 2 ++ source/blender/makesdna/DNA_space_types.h | 25 +++++++++++----------- source/blender/makesrna/intern/rna_space.c | 5 +++-- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/release/ui/buttons_data_bone.py b/release/ui/buttons_data_bone.py index a0121821e55..b4048a94f23 100644 --- a/release/ui/buttons_data_bone.py +++ b/release/ui/buttons_data_bone.py @@ -74,6 +74,7 @@ class BONE_PT_transform(BoneButtonsPanel): class BONE_PT_transform_locks(BoneButtonsPanel): __label__ = "Transform Locks" + __default_closed__ = True def poll(self, context): return context.bone diff --git a/release/ui/buttons_object_constraint.py b/release/ui/buttons_object_constraint.py index c8f7e467a18..1d2f9a5cb49 100644 --- a/release/ui/buttons_object_constraint.py +++ b/release/ui/buttons_object_constraint.py @@ -513,7 +513,7 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel): class BONE_PT_constraints(ConstraintButtonsPanel): __label__ = "Constraints" - __context__ = "bone" + __context__ = "bone_constraint" def poll(self, context): ob = context.object diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 635abd429f6..f51cb5d6f8c 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -463,6 +463,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma found= buttons_context_path_texture(C, path); break; case BCONTEXT_BONE: + case BCONTEXT_BONE_CONSTRAINT: found= buttons_context_path_bone(path); if(!found) found= buttons_context_path_data(path, OB_ARMATURE); diff --git a/source/blender/editors/space_buttons/buttons_header.c b/source/blender/editors/space_buttons/buttons_header.c index a1041bc5106..83dd679c543 100644 --- a/source/blender/editors/space_buttons/buttons_header.c +++ b/source/blender/editors/space_buttons/buttons_header.c @@ -114,13 +114,15 @@ void buttons_header_buttons(const bContext *C, ARegion *ar) if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_OBJECT, 0, 0, "Object"); if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_CONSTRAINT, 0, 0, "Constraint"); + uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_CONSTRAINT, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_CONSTRAINT, 0, 0, "Object Constraints"); if(sbuts->pathflag & (1<dataicon, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_DATA, 0, 0, "Object Data"); if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_MODIFIER, 0, 0, "Modifier"); + uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_MODIFIER, xco+=BUTS_UI_UNIT, yco, BUTS_UI_UNIT, BUTS_UI_UNIT, &(sbuts->mainb), 0.0, (float)BCONTEXT_MODIFIER, 0, 0, "Modifiers"); if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_BONE, 0, 0, "Bone"); + if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_BONE_CONSTRAINT, 0, 0, "Bone Constraints"); if(sbuts->pathflag & (1<mainb), 0.0, (float)BCONTEXT_MATERIAL, 0, 0, "Material"); if(sbuts->pathflag & (1<mainb); else if (sbuts->mainb == BCONTEXT_CONSTRAINT) ED_region_panels(C, ar, vertical, "constraint", sbuts->mainb); + else if(sbuts->mainb == BCONTEXT_BONE_CONSTRAINT) + ED_region_panels(C, ar, vertical, "bone_constraint", sbuts->mainb); sbuts->re_align= 0; sbuts->mainbo= sbuts->mainb; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 806d12815b5..1a368877243 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -569,18 +569,19 @@ typedef struct SpaceUserPref { /* buts->mainb new */ -#define BCONTEXT_SCENE 0 -#define BCONTEXT_WORLD 1 -#define BCONTEXT_OBJECT 2 -#define BCONTEXT_DATA 3 -#define BCONTEXT_MATERIAL 4 -#define BCONTEXT_TEXTURE 5 -#define BCONTEXT_PARTICLE 6 -#define BCONTEXT_PHYSICS 7 -#define BCONTEXT_BONE 9 -#define BCONTEXT_MODIFIER 10 -#define BCONTEXT_CONSTRAINT 12 -#define BCONTEXT_TOT 13 +#define BCONTEXT_SCENE 0 +#define BCONTEXT_WORLD 1 +#define BCONTEXT_OBJECT 2 +#define BCONTEXT_DATA 3 +#define BCONTEXT_MATERIAL 4 +#define BCONTEXT_TEXTURE 5 +#define BCONTEXT_PARTICLE 6 +#define BCONTEXT_PHYSICS 7 +#define BCONTEXT_BONE 9 +#define BCONTEXT_MODIFIER 10 +#define BCONTEXT_CONSTRAINT 12 +#define BCONTEXT_BONE_CONSTRAINT 13 +#define BCONTEXT_TOT 14 /* sbuts->flag */ #define SB_PRV_OSA 1 diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 30c5d4988b3..8e783354653 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -747,10 +747,11 @@ static void rna_def_space_buttons(BlenderRNA *brna) {BCONTEXT_SCENE, "SCENE", ICON_SCENE, "Scene", "Scene"}, {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"}, {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"}, - {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraint", "Constraint"}, - {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifier", "Modifier"}, + {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Constraints"}, + {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"}, {BCONTEXT_DATA, "DATA", 0, "Data", "Data"}, {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"}, + {BCONTEXT_BONE_CONSTRAINT, "BONE_CONSTRAINT", ICON_CONSTRAINT, "Bone Constraints", "Bone Constraints"}, {BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material"}, {BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"}, {BCONTEXT_PARTICLE, "PARTICLE", ICON_PARTICLES, "Particle", "Particle"}, -- cgit v1.2.3 From f7d8275ddbca3d5a1eb9c1208561d874818da390 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 19 Sep 2009 19:57:30 +0000 Subject: More Nodes wrapped to Layout Engine: * Map Value, Alpha Over, Hue Saturation, Dilate/Erode * RNA fixes and additions. --- source/blender/editors/space_node/drawnode.c | 77 ++++++++-------------- source/blender/makesrna/intern/rna_nodetree.c | 35 +++++++++- .../blender/makesrna/intern/rna_nodetree_types.h | 2 +- 3 files changed, 61 insertions(+), 53 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 8bd8477fe13..3fa1e43b51b 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1348,72 +1348,49 @@ static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_map_value(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - TexMapping *texmap= node->storage; - short xstart= (short)butr->xmin; - short dy= (short)(butr->ymax-19.0f); - short dx= (short)(butr->xmax-butr->xmin)/2; + uiLayout *sub, *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButF(block, NUM, B_NODE_EXEC, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, ""); - dy-= 23; - uiBlockBeginAlign(block); - uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, ""); - dy-= 19; - uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, ""); - uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, ""); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "offset", 0); + uiItemR(col, NULL, 0, ptr, "size", 0); + + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "use_min", 0); + sub =uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); + uiItemR(sub, "", 0, ptr, "min", 0); + + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "use_max", 0); + sub =uiLayoutColumn(col, 0); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); + uiItemR(sub, "", 0, ptr, "max", 0); } static void node_composit_buts_alphaover(uiLayout *layout, PointerRNA *ptr) -{ - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeTwoFloats *ntf= node->storage; +{ + uiLayout *col; + col =uiLayoutColumn(layout, 1); /* alpha type */ - uiDefButS(block, TOG, B_NODE_EXEC, "ConvertPremul", - butr->xmin, butr->ymin+19, butr->xmax-butr->xmin, 19, - &node->custom1, 0, 0, 0, 0, ""); + uiItemR(col, NULL, 0, ptr, "convert_premul", 0); /* mix factor */ - uiDefButF(block, NUM, B_NODE_EXEC, "Premul: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19, - &ntf->x, 0.0f, 1.0f, 100, 0, ""); + uiItemR(col, NULL, 0, ptr, "premul", 0); } static void node_composit_buts_hue_sat(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeHueSat *nhs= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Hue: ", - butr->xmin, butr->ymin+40.0f, butr->xmax-butr->xmin, 20, - &nhs->hue, 0.0f, 1.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Sat: ", - butr->xmin, butr->ymin+20.0f, butr->xmax-butr->xmin, 20, - &nhs->sat, 0.0f, 2.0f, 100, 0, ""); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Val: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &nhs->val, 0.0f, 2.0f, 100, 0, ""); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "hue", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "sat", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "val", UI_ITEM_R_SLIDER); } static void node_composit_buts_dilateerode(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiDefButS(block, NUM, B_NODE_EXEC, "Distance:", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom2, -100, 100, 0, 0, "Distance to grow/shrink (number of iterations)"); + uiItemR(layout, NULL, 0, ptr, "distance", 0); } static void node_composit_buts_diff_matte(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b310ff06b8e..b89bf0552bd 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -473,10 +473,11 @@ static void def_sh_geometry(StructRNA *srna) static void def_cmp_alpha_over(StructRNA *srna) { PropertyRNA *prop; - + + // XXX: Tooltip prop = RNA_def_property(srna, "convert_premul", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); - RNA_def_property_ui_text(prop, "convert_premul", "TODO: don't know what this is"); + RNA_def_property_ui_text(prop, "Convert Premul", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoFloats", "storage"); @@ -488,6 +489,31 @@ static void def_cmp_alpha_over(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_cmp_hue_saturation(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeHueSat", "storage"); + + prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "hue"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Hue", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); + + prop = RNA_def_property(srna, "sat", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "sat"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_text(prop, "Saturation", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); + + prop = RNA_def_property(srna, "val", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "val"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} + static void def_cmp_blur(StructRNA *srna) { PropertyRNA *prop; @@ -605,12 +631,14 @@ static void def_cmp_map_value(StructRNA *srna) prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "loc"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Offset", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "size"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Size", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -627,12 +655,14 @@ static void def_cmp_map_value(StructRNA *srna) prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Minimum", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); + RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Maximum", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -837,6 +867,7 @@ static void def_cmp_dilate_erode(StructRNA *srna) prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); + RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)"); RNA_def_property_update(prop, 0, "rna_Node_update"); } diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index be4f131a6d6..420f1deae48 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -64,7 +64,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" ) DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" ) DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" ) -DefNode( CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue/Saturation", "" ) +DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue/Saturation", "" ) DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode( CompositorNode, CMP_NODE_COMPOSITE, 0, "COMPOSITE", Composite, "Composite", "" ) -- cgit v1.2.3 From 8b4ad3584cbd66c7fc76dbb9593e56d145b9fc7b Mon Sep 17 00:00:00 2001 From: William Reynish Date: Sat, 19 Sep 2009 21:40:37 +0000 Subject: A few smaller adjustments to armature and bone properties. --- release/ui/buttons_data_armature.py | 14 ++++++++++---- release/ui/buttons_data_bone.py | 8 ++++---- source/blender/makesrna/intern/rna_armature.c | 23 +++++++++++++++++------ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/release/ui/buttons_data_armature.py b/release/ui/buttons_data_armature.py index 49da9c190ff..413deee362b 100644 --- a/release/ui/buttons_data_armature.py +++ b/release/ui/buttons_data_armature.py @@ -37,7 +37,9 @@ class DATA_PT_skeleton(DataButtonsPanel): ob = context.object arm = context.armature space = context.space_data - + + layout.itemR(arm, "pose_position", expand=True) + split = layout.split() col = split.column() @@ -50,7 +52,6 @@ class DATA_PT_skeleton(DataButtonsPanel): col.itemR(arm, "auto_ik") col = split.column() - col.itemR(arm, "rest_position") col.itemL(text="Deform:") col.itemR(arm, "deform_vertexgroups", text="Vertex Groups") col.itemR(arm, "deform_envelope", text="Envelopes") @@ -140,12 +141,16 @@ class DATA_PT_paths(DataButtonsPanel): col.row().itemR(arm, "paths_location", expand=True) col = split.column() - col.itemL(text="Show:") + col.itemL(text="Display:") col.itemR(arm, "paths_show_frame_numbers", text="Frame Numbers") col.itemR(arm, "paths_highlight_keyframes", text="Keyframes") col.itemR(arm, "paths_show_keyframe_numbers", text="Keyframe Numbers") - layout.itemO("pose.paths_calculate") + layout.itemS() + + row = layout.row() + row.itemO("pose.paths_calculate", text="Calculate Paths") + row.itemO("pose.paths_clear", text="Clear Paths") class DATA_PT_ghost(DataButtonsPanel): __label__ = "Ghost" @@ -171,6 +176,7 @@ class DATA_PT_ghost(DataButtonsPanel): sub.itemR(arm, "ghost_size", text="Step") col = split.column() + col.itemL(text="Display:") col.itemR(arm, "ghost_only_selected", text="Selected Only") bpy.types.register(DATA_PT_context_arm) diff --git a/release/ui/buttons_data_bone.py b/release/ui/buttons_data_bone.py index b4048a94f23..510b41de8a7 100644 --- a/release/ui/buttons_data_bone.py +++ b/release/ui/buttons_data_bone.py @@ -177,7 +177,7 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel): split = layout.split(percentage=0.25) split.itemR(pchan, "ik_dof_x", text="X") row = split.row() - row.itemR(pchan, "ik_stiffness_x", text="Stiffness") + row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True) row.active = pchan.ik_dof_x split = layout.split(percentage=0.25) @@ -192,7 +192,7 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel): split = layout.split(percentage=0.25) split.itemR(pchan, "ik_dof_y", text="Y") row = split.row() - row.itemR(pchan, "ik_stiffness_y", text="Stiffness") + row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True) row.active = pchan.ik_dof_y split = layout.split(percentage=0.25) @@ -207,7 +207,7 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel): split = layout.split(percentage=0.25) split.itemR(pchan, "ik_dof_z", text="Z") row = split.row() - row.itemR(pchan, "ik_stiffness_z", text="Stiffness") + row.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True) row.active = pchan.ik_dof_z split = layout.split(percentage=0.25) @@ -220,7 +220,7 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel): row.active = pchan.ik_dof_z and pchan.ik_limit_z split = layout.split() - split.itemR(pchan, "ik_stretch", text="Stretch") + split.itemR(pchan, "ik_stretch", text="Stretch", slider=True) split.itemL() class BONE_PT_deform(BoneButtonsPanel): diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index aa422f85d7b..a1bcbe57bd5 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -540,10 +540,13 @@ static void rna_def_armature(BlenderRNA *brna) {ARM_PATH_ACFRA, "CURRENT_FRAME", 0, "Around Frame", "Display Paths of poses within a fixed number of frames around the current frame."}, {0, "RANGE", 0, "In Range", "Display Paths of poses within specified range."}, {0, NULL, 0, NULL, NULL}}; - static const EnumPropertyItem prop_paths_location_items[]= { {ARM_PATH_HEADS, "HEADS", 0, "Heads", "Calculate bone paths from heads"}, - {0, "TIPS", 0, "Tips", "Calculate bone paths from tips"}, + {0, "TAILS", 0, "Tails", "Calculate bone paths from tails"}, + {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem prop_pose_position_items[]= { + {0, "POSE_POSITION", 0, "Pose Position", "Show armature in posed state."}, + {ARM_RESTPOS, "REST_POSITION", 0, "Rest Position", "Show Armature in binding pose state. No posing possible."}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Armature", "ID"); @@ -565,6 +568,17 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edit Bones", ""); /* Enum values */ +// prop= RNA_def_property(srna, "rest_position", PROP_BOOLEAN, PROP_NONE); +// RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_RESTPOS); +// RNA_def_property_ui_text(prop, "Rest Position", "Show Armature in Rest Position. No posing possible."); +// RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + + prop= RNA_def_property(srna, "pose_position", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_pose_position_items); + RNA_def_property_ui_text(prop, "Pose Position", "Show armature in binding pose or final posed state."); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + prop= RNA_def_property(srna, "drawtype", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_drawtype_items); RNA_def_property_ui_text(prop, "Draw Type", ""); @@ -606,10 +620,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* flag */ - prop= RNA_def_property(srna, "rest_position", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_RESTPOS); - RNA_def_property_ui_text(prop, "Rest Position", "Show Armature in Rest Position. No posing possible."); - RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + prop= RNA_def_property(srna, "draw_axes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWAXES); -- cgit v1.2.3 From b28109b442f5e87edf865c6bcbdb8f53665cdef5 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sat, 19 Sep 2009 22:11:26 +0000 Subject: netrender: first draft for job balancer + some minor fixes --- release/io/netrender/__init__.py | 1 + release/io/netrender/balancing.py | 75 +++++++++++++++++++++++++++++++++++++++ release/io/netrender/client.py | 7 ++-- release/io/netrender/master.py | 60 +++++++++++++------------------ release/io/netrender/model.py | 12 +++++++ release/io/netrender/operators.py | 6 ++-- release/io/netrender/slave.py | 18 +++++----- release/io/netrender/utils.py | 8 ++++- 8 files changed, 135 insertions(+), 52 deletions(-) create mode 100644 release/io/netrender/balancing.py diff --git a/release/io/netrender/__init__.py b/release/io/netrender/__init__.py index 1eb91abb938..b313d64ccbb 100644 --- a/release/io/netrender/__init__.py +++ b/release/io/netrender/__init__.py @@ -6,6 +6,7 @@ import client import slave import master import utils +import balancing import ui # store temp data in bpy module diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py new file mode 100644 index 00000000000..89e1e3f7b06 --- /dev/null +++ b/release/io/netrender/balancing.py @@ -0,0 +1,75 @@ +import time + +from netrender.utils import * +import netrender.model + +class RatingRule: + def rate(self, job): + return 0 + +class ExclusionRule: + def test(self, job): + return False + +class PriorityRule: + def test(self, job): + return False + +class Balancer: + def __init__(self): + self.rules = [] + self.priorities = [] + self.exceptions = [] + + def addRule(self, rule): + self.rules.append(rule) + + def addPriority(self, priority): + self.priorities.append(priority) + + def addException(self, exception): + self.exceptions.append(exception) + + def applyRules(self, job): + return sum((rule.rate(job) for rule in self.rules)) + + def applyPriorities(self, job): + for priority in self.priorities: + if priority.test(job): + return True # priorities are first + + return False + + def applyExceptions(self, job): + for exception in self.exceptions: + if exception.test(job): + return True # exceptions are last + + return False + + def sortKey(self, job): + return (1 if self.applyExceptions(job) else 0, # exceptions after + 0 if self.applyPriorities(job) else 1, # priorities first + self.applyRules(job)) + + def balance(self, jobs): + if jobs: + jobs.sort(key=self.sortKey) + return jobs[0] + else: + return None + +# ========================== + + +class RatingCredit(RatingRule): + def rate(self, job): + return -job.credits # more credit is better (sort at first in list) + +class NewJobPriority(PriorityRule): + def test(self, job): + return job.countFrames(status = DISPATCHED) == 0 + +class ExcludeQueuedEmptyJob(ExclusionRule): + def test(self, job): + return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0 diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py index a6cfb4e020d..f445fe2f608 100644 --- a/release/io/netrender/client.py +++ b/release/io/netrender/client.py @@ -103,7 +103,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5): job.priority = netsettings.priority # try to send path first - conn.request("POST", "job", repr(job.serialize())) + conn.request("POST", "/job", repr(job.serialize())) response = conn.getresponse() job_id = response.getheader("job-id") @@ -112,7 +112,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5): if response.status == http.client.ACCEPTED: for filepath, start, end in job.files: f = open(filepath, "rb") - conn.request("PUT", "file", f, headers={"job-id": job_id, "job-file": filepath}) + conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath}) f.close() response = conn.getresponse() @@ -121,7 +121,7 @@ def clientSendJob(conn, scene, anim = False, chunks = 5): return job_id def requestResult(conn, job_id, frame): - conn.request("GET", "render", headers={"job-id": job_id, "job-frame":str(frame)}) + conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)}) @rnaType class NetworkRenderEngine(bpy.types.RenderEngine): @@ -174,7 +174,6 @@ class NetworkRenderEngine(bpy.types.RenderEngine): requestResult(conn, job_id, scene.current_frame) while response.status == http.client.ACCEPTED and not self.test_break(): - print("waiting") time.sleep(1) requestResult(conn, job_id, scene.current_frame) response = conn.getresponse() diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 58af47d6240..58c6c1b2d00 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -4,10 +4,7 @@ import subprocess, shutil, time, hashlib from netrender.utils import * import netrender.model - -JOB_WAITING = 0 # before all data has been entered -JOB_PAUSED = 1 # paused by user -JOB_QUEUED = 2 # ready to be dispatched +import netrender.balancing class MRenderFile: def __init__(self, filepath, start, end): @@ -38,10 +35,6 @@ class MRenderSlave(netrender.model.RenderSlave): def seen(self): self.last_seen = time.time() -# sorting key for jobs -def groupKey(job): - return (job.status, job.framesLeft() > 0, job.priority, job.credits) - class MRenderJob(netrender.model.RenderJob): def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []): super().__init__() @@ -95,14 +88,6 @@ class MRenderJob(netrender.model.RenderJob): frame = MRenderFrame(frame_number) self.frames.append(frame) return frame - - def framesLeft(self): - total = 0 - for j in self.frames: - if j.status == QUEUED: - total += 1 - - return total def reset(self, all): for f in self.frames: @@ -153,7 +138,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): def do_HEAD(self): print(self.path) - if self.path == "status": + if self.path == "/status": job_id = self.headers.get('job-id', "") job_frame = int(self.headers.get('job-frame', -1)) @@ -185,12 +170,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): def do_GET(self): print(self.path) - if self.path == "version": + if self.path == "/version": self.send_head() self.server.stats("", "New client connection") self.wfile.write(VERSION) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "render": + elif self.path == "/render": job_id = self.headers['job-id'] job_frame = int(self.headers['job-frame']) print("render:", job_id, job_frame) @@ -221,7 +206,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): # no such job id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "log": + elif self.path == "/log": job_id = self.headers['job-id'] job_frame = int(self.headers['job-frame']) print("log:", job_id, job_frame) @@ -250,7 +235,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): # no such job id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "status": + elif self.path == "/status": job_id = self.headers.get('job-id', "") job_frame = int(self.headers.get('job-frame', -1)) @@ -284,7 +269,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.wfile.write(bytes(repr(message), encoding='utf8')) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "job": + elif self.path == "/job": self.server.update() slave_id = self.headers['slave-id'] @@ -315,7 +300,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # invalid slave id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "file": + elif self.path == "/file": slave_id = self.headers['slave-id'] slave = self.server.updateSlave(slave_id) @@ -348,7 +333,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # invalid slave id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "slave": + elif self.path == "/slave": message = [] for slave in self.server.slaves: @@ -368,7 +353,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): print(self.path) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - if self.path == "job": + if self.path == "/job": print("posting job info") self.server.stats("", "Receiving job") @@ -394,7 +379,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: self.send_head(http.client.ACCEPTED, headers=headers) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "cancel": + elif self.path == "/cancel": job_id = self.headers.get('job-id', "") if job_id: print("cancel:", job_id, "\n") @@ -404,7 +389,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head() # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "reset": + elif self.path == "/reset": job_id = self.headers.get('job-id', "") job_frame = int(self.headers.get('job-frame', "-1")) all = bool(self.headers.get('reset-all', "False")) @@ -421,7 +406,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # job not found self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "slave": + elif self.path == "/slave": length = int(self.headers['content-length']) job_frame_string = self.headers['job-frame'] @@ -431,7 +416,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head(headers = {"slave-id": slave_id}) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "log": + elif self.path == "/log": slave_id = self.headers['slave-id'] slave = self.server.updateSlave(slave_id) @@ -460,7 +445,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): print(self.path) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - if self.path == "file": + if self.path == "/file": print("writing blend file") self.server.stats("", "Receiving job") @@ -504,7 +489,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # job not found self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "render": + elif self.path == "/render": print("writing result file") self.server.stats("", "Receiving render result") @@ -547,7 +532,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # invalid slave id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "log": + elif self.path == "/log": print("writing log file") self.server.stats("", "Receiving log file") @@ -587,6 +572,11 @@ class RenderMasterServer(http.server.HTTPServer): self.job_id = 0 self.path = path + "master_" + str(os.getpid()) + os.sep + self.balancer = netrender.balancing.Balancer() + self.balancer.addRule(netrender.balancing.RatingCredit()) + self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) + self.balancer.addPriority(netrender.balancing.NewJobPriority()) + if not os.path.exists(self.path): os.mkdir(self.path) @@ -616,7 +606,7 @@ class RenderMasterServer(http.server.HTTPServer): self.jobs = [] def update(self): - self.jobs.sort(key = groupKey) + self.balancer.balance(self.jobs) def removeJob(self, id): job = self.jobs_map.pop(id) @@ -644,8 +634,8 @@ class RenderMasterServer(http.server.HTTPServer): def getNewJob(self, slave_id): if self.jobs: - for job in reversed(self.jobs): - if job.status == JOB_QUEUED and job.framesLeft() > 0 and slave_id not in job.blacklist: + for job in self.jobs: + if not self.balancer.applyExceptions(job) and slave_id not in job.blacklist: return job, job.getFrames() return None, None diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 924493fd34a..9a6645e79cf 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -95,6 +95,18 @@ class RenderJob: def __len__(self): return len(self.frames) + def countFrames(self, status=QUEUED): + total = 0 + for j in self.frames: + if j.status == status: + total += 1 + + return total + + def countSlaves(self): + return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED))) + + def framesStatus(self): results = { QUEUED: 0, diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index e6888731437..bfc67c25285 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -89,7 +89,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): conn = clientConnection(context.scene) if conn: - conn.request("GET", "status") + conn.request("GET", "/status") response = conn.getresponse() print( response.status, response.reason ) @@ -205,7 +205,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): conn = clientConnection(context.scene) if conn: - conn.request("GET", "slave") + conn.request("GET", "/slave") response = conn.getresponse() print( response.status, response.reason ) @@ -258,7 +258,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): if conn: job = bpy.data.netrender_jobs[netsettings.active_job_index] - conn.request("POST", "cancel", headers={"job-id":job.id}) + conn.request("POST", "/cancel", headers={"job-id":job.id}) response = conn.getresponse() print( response.status, response.reason ) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index ecdbf69591a..406b987c990 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -33,7 +33,7 @@ def slave_Info(): return slave def testCancel(conn, job_id): - conn.request("HEAD", "status", headers={"job-id":job_id}) + conn.request("HEAD", "/status", headers={"job-id":job_id}) response = conn.getresponse() # cancelled if job isn't found anymore @@ -47,7 +47,7 @@ def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None): if not os.path.exists(job_full_path): temp_path = JOB_PREFIX + "slave.temp.blend" - conn.request("GET", "file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) + conn.request("GET", "/file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) response = conn.getresponse() if response.status != http.client.OK: @@ -76,7 +76,7 @@ def render_slave(engine, scene): conn = clientConnection(scene) if conn: - conn.request("POST", "slave", repr(slave_Info().serialize())) + conn.request("POST", "/slave", repr(slave_Info().serialize())) response = conn.getresponse() slave_id = response.getheader("slave-id") @@ -87,7 +87,7 @@ def render_slave(engine, scene): while not engine.test_break(): - conn.request("GET", "job", headers={"slave-id":slave_id}) + conn.request("GET", "/job", headers={"slave-id":slave_id}) response = conn.getresponse() if response.status == http.client.OK: @@ -119,7 +119,7 @@ def render_slave(engine, scene): # announce log to master logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames]) - conn.request("POST", "log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) + conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) response = conn.getresponse() first_frame = job.frames[0].number @@ -146,7 +146,7 @@ def render_slave(engine, scene): if stdout: # (only need to update on one frame, they are linked headers["job-frame"] = str(first_frame) - conn.request("PUT", "log", stdout, headers=headers) + conn.request("PUT", "/log", stdout, headers=headers) response = conn.getresponse() stdout = bytes() @@ -173,7 +173,7 @@ def render_slave(engine, scene): if stdout: # (only need to update on one frame, they are linked headers["job-frame"] = str(first_frame) - conn.request("PUT", "log", stdout, headers=headers) + conn.request("PUT", "/log", stdout, headers=headers) response = conn.getresponse() headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} @@ -184,7 +184,7 @@ def render_slave(engine, scene): headers["job-frame"] = str(frame.number) # send result back to server f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') - conn.request("PUT", "render", f, headers=headers) + conn.request("PUT", "/render", f, headers=headers) f.close() response = conn.getresponse() else: @@ -192,7 +192,7 @@ def render_slave(engine, scene): for frame in job.frames: headers["job-frame"] = str(frame.number) # send error result back to server - conn.request("PUT", "render", headers=headers) + conn.request("PUT", "/render", headers=headers) response = conn.getresponse() else: if timeout < MAX_TIMEOUT: diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index 46c2011b188..50ca08d1723 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -8,6 +8,12 @@ import netrender.model VERSION = b"0.5" +# Jobs status +JOB_WAITING = 0 # before all data has been entered +JOB_PAUSED = 1 # paused by user +JOB_QUEUED = 2 # ready to be dispatched + +# Frames status QUEUED = 0 DISPATCHED = 1 DONE = 2 @@ -36,7 +42,7 @@ def clientConnection(scene): return None def clientVerifyVersion(conn): - conn.request("GET", "version") + conn.request("GET", "/version") response = conn.getresponse() if response.status != http.client.OK: -- cgit v1.2.3 From f4b9ec0e37d636c974f4ea24c90d288015df7d24 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 20 Sep 2009 01:36:11 +0000 Subject: 2.5 - 2 Armature Related Crash Fixes * #19397: Properties panel (transform panel in 3D-View) crashed when there was no active posechannel. * Breakdown/Push/Relax Pose tools crashed when auto-keyframing was enabled. There where 2 main causes here: 1) laziness to try and avoid having to clear some data everytime, 2) a typo for one of the KeyingSet names --- source/blender/editors/armature/poseSlide.c | 5 ++--- source/blender/editors/space_view3d/view3d_buttons.c | 17 ++++------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index e55c5608112..eb290b1f83c 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -219,7 +219,7 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) /* get builtin KeyingSets */ pso->ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location"); pso->ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scale"); + pso->ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scaling"); /* return status is whether we've got all the data we were requested to get */ return 1; @@ -393,8 +393,7 @@ static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso, bPoseChanne ListBase dsources = {&cks, &cks}; /* init common-key-source for use by KeyingSets */ - // TODO: for now, we don't clear it out, since it should be safe to do so... - //memset(&cks, 0, sizeof(bCommonKeySrc)); + memset(&cks, 0, sizeof(bCommonKeySrc)); cks.id= &pso->ob->id; /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 286b0ca0898..89d07fbbfea 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -512,6 +512,10 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if(bone && (bone->flag & BONE_ACTIVE) && (bone->layer & arm->layer)) break; } + if (!pchan) { + uiDefBut(block, LABEL, 0, "No Bone Active", 0, 240, 100, 20, 0, 0, 0, 0, 0, ""); + return; + } if (pchan->rotmode == PCHAN_ROT_AXISANGLE) { float quat[4]; @@ -1447,25 +1451,12 @@ void view3d_buttons_register(ARegionType *art) pt->draw= view3d_panel_transform_spaces; BLI_addtail(&art->paneltypes, pt); - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil"); - strcpy(pt->idname, "VIEW3D_PT_gpencil"); - strcpy(pt->label, "Greas Pencil"); - pt->draw= view3d_panel_gpencil; - BLI_addtail(&art->paneltypes, pt);*/ - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel bonesketch spaces"); strcpy(pt->idname, "VIEW3D_PT_bonesketch_spaces"); strcpy(pt->label, "Bone Sketching"); pt->draw= view3d_panel_bonesketch_spaces; pt->poll= view3d_panel_bonesketch_spaces_poll; BLI_addtail(&art->paneltypes, pt); - - /* - pt= MEM_callocN(sizeof(PanelType), "spacetype view3d panel redo"); - strcpy(pt->idname, "VIEW3D_PT_redo"); - strcpy(pt->label, "Last Operator"); - pt->draw= view3d_panel_operator_redo; - BLI_addtail(&art->paneltypes, pt); */ // XXX view3d_panel_preview(C, ar, 0); } -- cgit v1.2.3 From 22995e9c459ad8dc7acbde15db94b2013def78f8 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 20 Sep 2009 05:05:16 +0000 Subject: 2.5 - Pose Relax/Push improvements * Relax and Push are now interactive. Moving the mouse left<->right decreases/increases (respectively) the number of times the pose is relaxed or pushed. The sensitivity on this could be tweaked as necessary. * Cancelling these 'pose sliding' tools now correctly restores the initial pose * Autokeyframing is now only done when the operator is confirmed. -- Also, made 'View persp/ortho' <-> 'View Persp/Ortho' to be more in line with other operator names, but to also make it easier to read. --- source/blender/editors/armature/poseSlide.c | 220 +++++++++++++++------- source/blender/editors/space_view3d/view3d_edit.c | 2 +- 2 files changed, 153 insertions(+), 69 deletions(-) diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index eb290b1f83c..02c23f01f1e 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -135,7 +135,13 @@ typedef struct tPChanFCurveLink { ListBase fcurves; /* F-Curves for this PoseChannel */ bPoseChannel *pchan; /* Pose Channel which data is attached to */ + char *pchan_path; /* RNA Path to this Pose Channel (needs to be freed when we're done) */ + + float oldloc[3]; /* transform values at start of operator (to be restored before each modal step) */ + float oldrot[3]; + float oldscale[3]; + float oldquat[4]; } tPChanFCurveLink; /* ------------------------------------ */ @@ -202,6 +208,12 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) pchan->flag |= POSE_ROT; if (transFlags & ACT_TRANS_SCALE) pchan->flag |= POSE_SIZE; + + /* store current transforms */ + VECCOPY(pfl->oldloc, pchan->loc); + VECCOPY(pfl->oldrot, pchan->eul); + VECCOPY(pfl->oldscale, pchan->size); + QUATCOPY(pfl->oldquat, pchan->quat); } } CTX_DATA_END; @@ -261,6 +273,23 @@ static void pose_slide_exit (bContext *C, wmOperator *op) /* ------------------------------------ */ +/* helper for apply() / reset() - refresh the data */ +static void pose_slide_refresh (bContext *C, tPoseSlideOp *pso) +{ + /* old optimize trick... this enforces to bypass the depgraph + * - note: code copied from transform_generics.c -> recalcData() + */ + // FIXME: shouldn't this use the builtin stuff? + if ((pso->arm->flag & ARM_DELAYDEFORM)==0) + DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); /* sets recalc flags */ + else + where_is_pose(pso->scene, pso->ob); + + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); +} + /* helper for apply() callabcks - find the next F-Curve with matching path... */ static LinkData *find_next_fcurve_link (ListBase *fcuLinks, LinkData *prev, char *path) { @@ -330,22 +359,45 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo w2 = (w2/wtot); } - /* depending on the mode, */ + /* depending on the mode, calculate the new value + * - in all of these, the start+end values are multiplied by w2 and w1 (respectively), + * since multiplication in another order would decrease the value the current frame is closer to + */ switch (pso->mode) { case POSESLIDE_PUSH: /* make the current pose more pronounced */ - // TODO: this is not interactively modifiable! - vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; + { + /* perform a weighted average here, favouring the middle pose + * - numerator should be larger than denominator to 'expand' the result + * - perform this weighting a number of times given by the percentage... + */ + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + while (iters-- > 0) { + vec[ch]= ( -((sVal * w2) + (eVal * w1)) + (vec[ch] * 6.0f) ) / 5.0f; + } + } break; case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ - /* apply the value with a hard coded 6th */ - // TODO: this is not interactively modifiable! - vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f; + { + /* perform a weighted average here, favouring the middle pose + * - numerator should be smaller than denominator to 'relax' the result + * - perform this weighting a number of times given by the percentage... + */ + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + while (iters-- > 0) { + vec[ch]= ( ((sVal * w2) + (eVal * w1)) + (vec[ch] * 5.0f) ) / 6.0f; + } + } break; case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ + { /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */ + // TODO: make this use some kind of spline interpolation instead? vec[ch]= ((sVal * w2) + (eVal * w1)); + } break; } @@ -384,26 +436,6 @@ static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl) #endif } -/* helper for apply() - perform autokeyframing */ -static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso, bPoseChannel *pchan, KeyingSet *ks) -{ - /* insert keyframes as necessary if autokeyframing */ - if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) { - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &pso->ob->id; - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - - /* insert keyframes */ - modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)pso->cframe); - } -} - /* apply() - perform the pose sliding based on weighting various poses */ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) { @@ -428,15 +460,11 @@ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) if (pchan->flag & POSE_LOC) { /* calculate these for the 'location' vector, and use location curves */ pose_slide_apply_vec3(pso, pfl, pchan->loc, "location"); - /* insert keyframes if needed */ - pose_slide_autoKeyframe(C, pso, pchan, pso->ks_loc); } if (pchan->flag & POSE_SIZE) { /* calculate these for the 'scale' vector, and use scale curves */ pose_slide_apply_vec3(pso, pfl, pchan->size, "scale"); - /* insert keyframes if needed */ - pose_slide_autoKeyframe(C, pso, pchan, pso->ks_scale); } if (pchan->flag & POSE_ROT) { @@ -452,24 +480,58 @@ static void pose_slide_apply (bContext *C, wmOperator *op, tPoseSlideOp *pso) /* quaternions - use quaternion blending */ pose_slide_apply_quat(pso, pfl); } - - /* insert keyframes if needed */ - pose_slide_autoKeyframe(C, pso, pchan, pso->ks_rot); } } - /* old optimize trick... this enforces to bypass the depgraph - * - note: code copied from transform_generics.c -> recalcData() - */ - // FIXME: shouldn't this use the builtin stuff? - if ((pso->arm->flag & ARM_DELAYDEFORM)==0) - DAG_id_flush_update(&pso->ob->id, OB_RECALC_DATA); /* sets recalc flags */ - else - where_is_pose(pso->scene, pso->ob); + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); +} + +/* perform autokeyframing after changes were made + confirmed */ +static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso) +{ + /* insert keyframes as necessary if autokeyframing */ + if (autokeyframe_cfra_can_key(pso->scene, &pso->ob->id)) { + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; + tPChanFCurveLink *pfl; + + /* init common-key-source for use by KeyingSets */ + memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &pso->ob->id; + + /* iterate over each pose-channel affected, applying the changes */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + bPoseChannel *pchan= pfl->pchan; + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + + /* insert keyframes */ + if (pchan->flag & POSE_LOC) + modify_keyframes(C, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + if (pchan->flag & POSE_ROT) + modify_keyframes(C, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + if (pchan->flag & POSE_SIZE) + modify_keyframes(C, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + } + } +} + +/* reset changes made to current pose */ +static void pose_slide_reset (bContext *C, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT|ND_POSE, pso->ob); - WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + /* iterate over each pose-channel affected, restoring all channels to their original values */ + for (pfl= pso->pfLinks.first; pfl; pfl= pfl->next) { + bPoseChannel *pchan= pfl->pchan; + + /* just copy all the values over regardless of whether they changed or not */ + VECCOPY(pchan->loc, pfl->oldloc); + VECCOPY(pchan->eul, pfl->oldrot); + VECCOPY(pchan->size, pfl->oldscale); + QUATCOPY(pchan->quat, pfl->oldquat); + } } /* ------------------------------------ */ @@ -538,24 +600,19 @@ static int pose_slide_invoke_common (bContext *C, wmOperator *op, tPoseSlideOp * return OPERATOR_CANCELLED; } - // FIXME: for now, just do modal for breakdowns... - if (pso->mode == POSESLIDE_BREAKDOWN) { - /* initial apply for operator... */ - pose_slide_apply(C, op, pso); - - /* set cursor to indicate modal */ - WM_cursor_modal(win, BC_EW_SCROLLCURSOR); - - /* add a modal handler for this operator */ - WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; - } - else { - /* temp static operator code... until a way to include percentage in the formulation comes up */ - pose_slide_apply(C, op, pso); - pose_slide_exit(C, op); - return OPERATOR_FINISHED; - } + /* initial apply for operator... */ + // TODO: need to calculate percentage for initial round too... + pose_slide_apply(C, op, pso); + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); + + /* set cursor to indicate modal */ + WM_cursor_modal(win, BC_EW_SCROLLCURSOR); + + /* add a modal handler for this operator */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; } /* common code for modal() */ @@ -566,15 +623,36 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) switch (evt->type) { case LEFTMOUSE: /* confirm */ + { + /* return to normal cursor */ WM_cursor_restore(win); + + /* insert keyframes as required... */ + pose_slide_autoKeyframe(C, pso); pose_slide_exit(C, op); + + /* done! */ return OPERATOR_FINISHED; + } case ESCKEY: /* cancel */ case RIGHTMOUSE: + { + /* return to normal cursor */ WM_cursor_restore(win); + + /* reset transforms back to original state */ + pose_slide_reset(C, pso); + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); + + /* clean up temp data */ pose_slide_exit(C, op); + + /* cancelled! */ return OPERATOR_CANCELLED; + } case MOUSEMOVE: /* calculate new position */ { @@ -584,6 +662,9 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) pso->percentage= (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); RNA_float_set(op->ptr, "percentage", pso->percentage); + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(C, pso); + /* apply... */ pose_slide_apply(C, op, pso); } @@ -608,6 +689,9 @@ static int pose_slide_exec_common (bContext *C, wmOperator *op, tPoseSlideOp *ps /* settings should have been set up ok for applying, so just apply! */ pose_slide_apply(C, op, pso); + /* insert keyframes if needed */ + pose_slide_autoKeyframe(C, pso); + /* cleanup and done */ pose_slide_exit(C, op); @@ -668,12 +752,12 @@ void POSE_OT_push (wmOperatorType *ot) /* callbacks */ ot->exec= pose_slide_push_exec; ot->invoke= pose_slide_push_invoke; - //ot->modal= pose_slide_modal; - //ot->cancel= pose_slide_cancel; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; ot->poll= ED_operator_posemode; /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; /* Properties */ pose_slide_opdef_properties(ot); @@ -725,12 +809,12 @@ void POSE_OT_relax (wmOperatorType *ot) /* callbacks */ ot->exec= pose_slide_relax_exec; ot->invoke= pose_slide_relax_invoke; - //ot->modal= pose_slide_modal; - //ot->cancel= pose_slide_cancel; + ot->modal= pose_slide_modal; + ot->cancel= pose_slide_cancel; ot->poll= ED_operator_posemode; /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;//|OPTYPE_BLOCKING; + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; /* Properties */ pose_slide_opdef_properties(ot); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 0faa1f8c16d..b788dc28311 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1628,7 +1628,7 @@ static int viewpersportho_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_persportho(wmOperatorType *ot) { /* identifiers */ - ot->name= "View persp/ortho"; + ot->name= "View Persp/Ortho"; ot->description = "Switch the current view from perspective/orthographic."; ot->idname= "VIEW3D_OT_view_persportho"; -- cgit v1.2.3 From 2c871f722d3cbc80c9f076d7c23137e19633ba3a Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 11:13:57 +0000 Subject: 2.5 MSVC projectfiles * maintenance (added poseSlide.c) --- projectfiles_vc9/blender/editors/ED_editors.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projectfiles_vc9/blender/editors/ED_editors.vcproj b/projectfiles_vc9/blender/editors/ED_editors.vcproj index 948a26c49b5..e81e1a2e361 100644 --- a/projectfiles_vc9/blender/editors/ED_editors.vcproj +++ b/projectfiles_vc9/blender/editors/ED_editors.vcproj @@ -1286,6 +1286,10 @@ RelativePath="..\..\..\source\blender\editors\armature\poseobject.c" > + + -- cgit v1.2.3 From ad25fc829e736be4bbf2e2a125347eda294fdac9 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 20 Sep 2009 11:21:44 +0000 Subject: 2.5 - More animation/rigging bugfixes * #19419: PoseLib rename/remove tools could crash when an invalid (However, now care is needed when touching that index field, since the warnings can keep piling up) * Added Browse Poses for PoseLib to the toolbar * Removing constraints from bones now properly updates. A DAG rebuild is now forced, and the constraint flags are cleared. * Attempting to improve the situation with Copy Rotation constraint and rotation orders other than xyz. Unforunately, it looks like a different method is required... --- release/ui/space_view3d_toolbar.py | 5 ++--- source/blender/blenkernel/intern/constraint.c | 14 +++++++++++--- source/blender/editors/armature/poselib.c | 2 ++ source/blender/editors/object/object_constraint.c | 15 ++++++++++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 415a3e223bb..239a727d2a2 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -277,8 +277,6 @@ class VIEW3D_PT_tools_posemode(View3DPanel): def draw(self, context): layout = self.layout - - col = layout.column(align=True) col.itemL(text="Transform:") col.itemO("tfm.translate") @@ -299,7 +297,8 @@ class VIEW3D_PT_tools_posemode(View3DPanel): col.itemL(text="Pose:") col.itemO("pose.copy", text="Copy") col.itemO("pose.paste", text="Paste") - col.itemO("poselib.pose_add", text="Add To library") + col.itemO("poselib.pose_add", text="Add To Library") + col.itemO("poselib.browse_interactive", text="Browse Library") col = layout.column(align=True) col.itemL(text="In-Between:") diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index e5c0b3947de..748208d6c0b 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -685,9 +685,17 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain ct->flag= CONSTRAINT_TAR_TEMP; \ \ if (ct->tar) { \ - if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_BONE; \ - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_VERT; \ - else ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) { \ + bPoseChannel *pchan= get_pose_channel(ct->tar->pose, ct->subtarget); \ + ct->type = CONSTRAINT_OBTYPE_BONE; \ + ct->rotOrder= pchan->rotmode; \ + }\ + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { \ + ct->type = CONSTRAINT_OBTYPE_VERT; \ + } \ + else {\ + ct->type = CONSTRAINT_OBTYPE_OBJECT; \ + } \ } \ \ BLI_addtail(list, ct); \ diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index ce07cfb9042..386cb6512a3 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -467,6 +467,7 @@ static int poselib_remove_exec (bContext *C, wmOperator *op) marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "index")); if (marker == NULL) { BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); + return OPERATOR_CANCELLED; } /* remove relevant keyframes */ @@ -533,6 +534,7 @@ static int poselib_rename_exec (bContext *C, wmOperator *op) marker= BLI_findlink(&act->markers, RNA_int_get(op->ptr, "index")); if (marker == NULL) { BKE_report(op->reports, RPT_ERROR, "Invalid index for Pose"); + return OPERATOR_CANCELLED; } /* get new name */ diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 9b073ed5878..eee6659c6b2 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -823,17 +823,22 @@ void CONSTRAINT_OT_move_up (wmOperatorType *ot) static int pose_constraints_clear_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); + Scene *scene= CTX_data_scene(C); /* free constraints for all selected bones */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) { free_constraints(&pchan->constraints); + pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_CONST); } CTX_DATA_END; + /* force depsgraph to get recalculated since relationships removed */ + DAG_scene_sort(scene); /* sort order of objects */ + /* do updates */ - DAG_id_flush_update(&ob->id, OB_RECALC_OB); - WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_CONSTRAINT|NA_REMOVED, ob); + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); return OPERATOR_FINISHED; } @@ -854,14 +859,18 @@ void POSE_OT_constraints_clear(wmOperatorType *ot) static int object_constraints_clear_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); + Scene *scene= CTX_data_scene(C); /* do freeing */ // TODO: we should free constraints for all selected objects instead (to be more consistent with bones) free_constraints(&ob->constraints); + /* force depsgraph to get recalculated since relationships removed */ + DAG_scene_sort(scene); /* sort order of objects */ + /* do updates */ DAG_id_flush_update(&ob->id, OB_RECALC_OB); - WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT|NA_REMOVED, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); return OPERATOR_FINISHED; } -- cgit v1.2.3 From 2f71b49484ee2c45d77784d07a21031d07f699ed Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 20 Sep 2009 12:54:30 +0000 Subject: 2.5 - Yet another round of bugfixes * Copy Rotation constraint "should" work ok for custom rotation orders now. It now converts both rotations to the form used by the owner. So far, this doesn't seem to have broken any of the test rigs in my test-suite, though new specimens for the hall of flakiness are always welcome. * Fixed many RNA wrapping bugs for Armature data. - Fixed a few wrong tooltips - Made proper refreshes for restpose/posed, etc. * Started converting special quaternion interpolation for Pose Sliding tools (push/relax/breakdown), though this doesn't seem to be working correctly yet. -->> Help to get these working right is welcome :) --- source/blender/blenkernel/intern/constraint.c | 3 +- source/blender/editors/armature/poseSlide.c | 100 +++++++++++++++++++------- source/blender/makesrna/intern/rna_armature.c | 12 ++-- 3 files changed, 84 insertions(+), 31 deletions(-) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 748208d6c0b..e49bda0fdd2 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1588,7 +1588,8 @@ static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta VECCOPY(loc, cob->matrix[3]); Mat4ToSize(cob->matrix, size); - Mat4ToEulO(ct->matrix, eul, ct->rotOrder); + /* to allow compatible rotations, must get both rotations in the order of the owner... */ + Mat4ToEulO(ct->matrix, eul, cob->rotOrder); Mat4ToEulO(cob->matrix, obeul, cob->rotOrder); if ((data->flag & ROTLIKE_X)==0) diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index 02c23f01f1e..353503967ec 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -410,30 +410,82 @@ static void pose_slide_apply_vec3 (tPoseSlideOp *pso, tPChanFCurveLink *pfl, flo /* helper for apply() - perform sliding for quaternion rotations (using quat blending) */ static void pose_slide_apply_quat (tPoseSlideOp *pso, tPChanFCurveLink *pfl) { - // TODO: this is quite evil stuff... -#if 0 // XXX port... - /* get 2 quats */ - quat_prev[0] = eval_icu(icu_w, frame_prev); - quat_prev[1] = eval_icu(icu_x, frame_prev); - quat_prev[2] = eval_icu(icu_y, frame_prev); - quat_prev[3] = eval_icu(icu_z, frame_prev); - - quat_next[0] = eval_icu(icu_w, frame_next); - quat_next[1] = eval_icu(icu_x, frame_next); - quat_next[2] = eval_icu(icu_y, frame_next); - quat_next[3] = eval_icu(icu_z, frame_next); - -#if 0 - /* apply the setting, completely smooth */ - QuatInterpol(pchan->quat, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); -#else - /* tricky interpolation */ - QuatInterpol(quat_interp, quat_prev, quat_next, (framef-frame_prev) / (frame_next-frame_prev) ); - QUATCOPY(quat_orig, pchan->quat); - QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); - /* done */ -#endif -#endif + FCurve *fcu_w=NULL, *fcu_x=NULL, *fcu_y=NULL, *fcu_z=NULL; + bPoseChannel *pchan= pfl->pchan; + LinkData *ld=NULL; + char *path=NULL; + float cframe; + + /* get the path to use - this should be quaternion rotations only (needs care) */ + path= BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation"); + + /* get the current frame number */ + cframe= (float)pso->cframe; + + /* using this path, find each matching F-Curve for the variables we're interested in */ + while ( (ld= find_next_fcurve_link(&pfl->fcurves, ld, path)) ) { + FCurve *fcu= (FCurve *)ld->data; + + /* assign this F-Curve to one of the relevant pointers... */ + switch (fcu->array_index) { + case 3: /* z */ + fcu_z= fcu; + break; + case 2: /* y */ + fcu_y= fcu; + break; + case 1: /* x */ + fcu_x= fcu; + break; + case 0: /* w */ + fcu_w= fcu; + break; + } + } + + /* only if all channels exist, proceed */ + if (fcu_w && fcu_x && fcu_y && fcu_z) { + float quat_prev[4], quat_next[4]; + + /* get 2 quats */ + quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame); + quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame); + quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame); + quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame); + + quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame); + quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame); + quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame); + quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame); + + /* perform blending */ + if (pso->mode == POSESLIDE_BREAKDOWN) { + /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */ + QuatInterpol(pchan->quat, quat_prev, quat_next, pso->percentage); + } + else { + float quat_interp[4], quat_orig[4]; + int iters= (int)ceil(10.0f*pso->percentage); // TODO: maybe a sensitivity ctrl on top of this is needed + + /* perform this blending several times until a satisfactory result is reached */ + while (iters-- > 0) { + /* calculate the interpolation between the endpoints */ + QuatInterpol(quat_interp, quat_prev, quat_next, (cframe-pso->prevFrame) / (pso->nextFrame-pso->prevFrame) ); + + /* make a copy of the original rotation */ + QUATCOPY(quat_orig, pchan->quat); + + /* tricky interpolations - mode-dependent blending between original and new */ + if (pso->mode == POSESLIDE_RELAX) // xxx this was the original code, so should work fine + QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f); + else // I'm just guessing here... + QuatInterpol(pchan->quat, quat_orig, quat_interp, 6.0f/5.0f); + } + } + } + + /* free the path now */ + MEM_freeN(path); } /* apply() - perform the pose sliding based on weighting various poses */ diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index a1bcbe57bd5..d06c8ccee03 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -52,6 +52,7 @@ static void rna_Armature_update_data(bContext *C, PointerRNA *ptr) DAG_id_flush_update(id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, id); + //WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); } static void rna_Armature_redraw_data(bContext *C, PointerRNA *ptr) @@ -577,7 +578,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, prop_pose_position_items); RNA_def_property_ui_text(prop, "Pose Position", "Show armature in binding pose or final posed state."); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + RNA_def_property_update(prop, 0, "rna_Armature_update_data"); prop= RNA_def_property(srna, "drawtype", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_drawtype_items); @@ -593,7 +594,7 @@ static void rna_def_armature(BlenderRNA *brna) prop= RNA_def_property(srna, "paths_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "pathflag"); RNA_def_property_enum_items(prop, prop_paths_type_items); - RNA_def_property_ui_text(prop, "Paths Type", "Mapping type to use for this image in the game engine."); + RNA_def_property_ui_text(prop, "Paths Type", "Type of range to show for Bone Paths"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop= RNA_def_property(srna, "paths_location", PROP_ENUM, PROP_NONE); @@ -609,7 +610,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_array(prop, 16); RNA_def_property_ui_text(prop, "Visible Layers", "Armature layer visibility."); RNA_def_property_boolean_funcs(prop, NULL, "rna_Armature_layer_set"); - RNA_def_property_update(prop, NC_OBJECT|ND_POSE, NULL); + RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* layer protection */ @@ -658,8 +659,8 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); prop= RNA_def_property(srna, "ghost_only_selected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ARM_GHOST_ONLYSEL); - RNA_def_property_ui_text(prop, "Draw Ghosts on Selected Keyframes Only", ""); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_GHOST_ONLYSEL); + RNA_def_property_ui_text(prop, "Draw Ghosts on Selected Bones Only", ""); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* deformflag */ @@ -705,7 +706,6 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - /* Number fields */ /* ghost/onionskining settings */ prop= RNA_def_property(srna, "ghost_step", PROP_INT, PROP_NONE); -- cgit v1.2.3 From 7d86e92df9d92fe7c2fe7dc144b113dcc8436578 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 20 Sep 2009 13:34:54 +0000 Subject: 2.5: * Wrapped Invert, PremulKey Levels Node, Distance Key, Difference Key and Color Spill. * Added RNA for Levels Node. * Small RNA fixes. --- source/blender/editors/space_node/drawnode.c | 106 ++++----------------- source/blender/makesrna/intern/rna_nodetree.c | 26 ++++- .../blender/makesrna/intern/rna_nodetree_types.h | 4 +- 3 files changed, 46 insertions(+), 90 deletions(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 3fa1e43b51b..9b73bdbb255 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1294,7 +1294,6 @@ static void node_composit_buts_lensdist(uiLayout *layout, PointerRNA *ptr) uiLayoutSetActive(col, RNA_boolean_get(ptr, "projector")==0); uiItemR(col, NULL, 0, ptr, "jitter", 0); uiItemR(col, NULL, 0, ptr, "fit", 0); - } static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) @@ -1395,60 +1394,30 @@ static void node_composit_buts_dilateerode(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_diff_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color differences below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color differences below this additional threshold are partially keyed."); - uiBlockEndAlign(block); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "tolerance", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "falloff", UI_ITEM_R_SLIDER); } static void node_composit_buts_distance_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; + uiLayout *col; - uiBlockBeginAlign(block); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Tolerance: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 1.0f, 100, 0, "Color distances below this threshold are keyed."); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Color distances below this additional threshold are partially keyed."); - uiBlockEndAlign(block); + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "tolerance", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "falloff", UI_ITEM_R_SLIDER); } static void node_composit_buts_color_spill(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short dx= (butr->xmax-butr->xmin)/3; - - NodeChroma *c=node->storage; - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_NODE_EXEC, "Enhance: ", - butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.5f, 100, 2, "Adjusts how much selected channel is affected by color spill algorithm"); - uiDefButS(block, ROW, B_NODE_EXEC, "R", - butr->xmin,butr->ymin,dx,20, - &node->custom1,1,1, 0, 0, "Red Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "G", - butr->xmin+dx,butr->ymin,dx,20, - &node->custom1,1,2, 0, 0, "Green Spill Suppression"); - uiDefButS(block, ROW, B_NODE_EXEC, "B", - butr->xmin+2*dx,butr->ymin,dx,20, - &node->custom1, 1, 3, 0, 0, "Blue Spill Suppression"); - uiBlockEndAlign(block); + uiLayout *row, *col; + + col =uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "factor", 0); + row= uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "channel", UI_ITEM_R_EXPAND); } static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) @@ -1709,56 +1678,23 @@ static void node_composit_buts_scale(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_invert(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC, "RGB", - butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC, "A", - butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20, - &node->custom1, 0, 0, 0, 0, ""); - uiBlockEndAlign(block); + uiLayout *col; + + col= uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "rgb", 0); + uiItemR(col, NULL, 0, ptr, "alpha", 0); } static void node_composit_buts_premulkey(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - uiBut *bt; - - /* blend type */ - bt=uiDefButS(block, MENU, B_NODE_EXEC, "Key to Premul %x0|Premul to Key %x1", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &node->custom1, 0, 0, 0, 0, "Conversion between premultiplied alpha and key alpha"); + uiItemR(layout, "", 0, ptr, "mapping", 0); } static void node_composit_buts_view_levels(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short sx= (butr->xmax-butr->xmin)/5; - - /*color space selectors*/ - uiBlockBeginAlign(block); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"C", - butr->xmin,butr->ymin,sx,20,&node->custom1,1,1, 0, 0, "Combined RGB"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"R", - butr->xmin+sx,butr->ymin,sx,20,&node->custom1,1,2, 0, 0, "Red Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"G", - butr->xmin+2*sx,butr->ymin,sx,20,&node->custom1,1,3, 0, 0, "Green Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"B", - butr->xmin+3*sx,butr->ymin,sx,20,&node->custom1,1,4, 0, 0, "Blue Channel"); - uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"L", - butr->xmin+4*sx,butr->ymin,sx,20,&node->custom1,1,5, 0, 0, "Luminenc Channel"); - uiBlockEndAlign(block); + uiItemR(layout, NULL, 0, ptr, "color_space", UI_ITEM_R_EXPAND); } - /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b89bf0552bd..239fd894e4f 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -700,6 +700,26 @@ static void def_cmp_vector_blur(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_cmp_levels(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem space_items[] = { + {1, "COMNINED_RGB", 0, "C", "Combined RGB"}, + {2, "RED", 0, "R", "Red Channel"}, + {3, "GREEN", 0, "G", "Green Channel"}, + {4, "BLUE", 0, "B", "Blue Channel"}, + {5, "LUMINANCE", 0, "L", "Luminance Channel"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, space_items); + RNA_def_property_ui_text(prop, "Color Space", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} + static void def_cmp_image(StructRNA *srna) { PropertyRNA *prop; @@ -964,9 +984,9 @@ static void def_cmp_color_spill(StructRNA *srna) PropertyRNA *prop; static EnumPropertyItem channel_items[] = { - {1, "R", 0, "Red", ""}, - {2, "G", 0, "Green", ""}, - {3, "B", 0, "Blue", ""}, + {1, "R", 0, "R", "Red Spill Suppression"}, + {2, "G", 0, "G", "Green Spill Suppression"}, + {3, "B", 0, "B", "Blue Spill Suppression"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index 420f1deae48..69424649b3b 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -64,7 +64,7 @@ DefNode( CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBL DefNode( CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" ) DefNode( CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" ) DefNode( CompositorNode, CMP_NODE_SETALPHA, 0, "SETALPHA", SetAlpha, "Set Alpha", "" ) -DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue/Saturation", "" ) +DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_SAT", HueSat, "Hue/Saturation", "" ) DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode( CompositorNode, CMP_NODE_COMPOSITE, 0, "COMPOSITE", Composite, "Composite", "" ) @@ -104,7 +104,7 @@ DefNode( CompositorNode, CMP_NODE_PREMULKEY, def_cmp_premul_key, "PREMU DefNode( CompositorNode, CMP_NODE_GLARE, def_cmp_glare, "GLARE", Glare, "Glare", "" ) DefNode( CompositorNode, CMP_NODE_TONEMAP, def_cmp_tonemap, "TONEMAP", Tonemap, "Tonemap", "" ) DefNode( CompositorNode, CMP_NODE_LENSDIST, def_cmp_lensdist, "LENSDIST", Lensdist, "Lensdist", "" ) -DefNode( CompositorNode, CMP_NODE_VIEW_LEVELS, 0, "LEVELS", Levels, "Levels", "" ) +DefNode( CompositorNode, CMP_NODE_VIEW_LEVELS, def_cmp_levels, "LEVELS", Levels, "Levels", "" ) DefNode( CompositorNode, CMP_NODE_COLOR_MATTE, def_cmp_color_matte, "COLOR_MATTE", ColorMatte, "Color Matte", "" ) DefNode( CompositorNode, CMP_NODE_DIST_MATTE, def_cmp_distance_matte, "DISTANCE_MATTE", DistanceMatte, "Distance Matte", "" ) -- cgit v1.2.3 From 1185be4355e6f0d812b7a8909ab3677aeec694ed Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 20 Sep 2009 14:00:00 +0000 Subject: Sound: * Moved AudioData back to Scene * Updated RNA stuff * Added mixdown volume --- intern/audaspace/intern/AUD_C-API.cpp | 25 ++++++++++++++++--- intern/audaspace/intern/AUD_C-API.h | 15 ++++++++++-- source/blender/blenkernel/BKE_sound.h | 2 +- source/blender/blenkernel/intern/scene.c | 2 +- source/blender/blenkernel/intern/sound.c | 8 +++--- source/blender/blenkernel/intern/writeffmpeg.c | 9 +++---- source/blender/blenloader/intern/readfile.c | 5 +++- source/blender/editors/screen/screen_ops.c | 2 +- source/blender/makesdna/DNA_scene_types.h | 9 ++++--- source/blender/makesrna/intern/rna_scene.c | 34 ++++++++++++++++++++++---- 10 files changed, 85 insertions(+), 26 deletions(-) diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 45faebc7e97..afa1568d6dc 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -516,21 +516,40 @@ AUD_Device* AUD_openReadDevice(AUD_Specs specs) } } -int AUD_playDevice(AUD_Device* device, AUD_Sound* sound) +AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound) { assert(device); assert(sound); try { - return device->play(sound) != NULL; + return device->play(sound); } catch(AUD_Exception) { - return false; + return NULL; } } +int AUD_setDeviceSoundVolume(AUD_Device* device, AUD_Handle* handle, + float volume) +{ + if(handle) + { + assert(device); + AUD_SourceCaps caps; + caps.handle = handle; + caps.value = volume; + + try + { + return device->setCapability(AUD_CAPS_SOURCE_VOLUME, &caps); + } + catch(AUD_Exception) {} + } + return false; +} + int AUD_readDevice(AUD_Device* device, sample_t* buffer, int length) { assert(device); diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index 6ec5ec87ad5..b02b465bff2 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -303,9 +303,20 @@ extern AUD_Device* AUD_openReadDevice(AUD_Specs specs); * Plays back a sound file through a read device. * \param device The read device. * \param sound The handle of the sound file. - * \return Whether the sound could be played back. + * \return A handle to the played back sound. + */ +extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound); + +/** + * Sets the volume of a played back sound of a read device. + * \param device The read device. + * \param handle The handle to the sound. + * \param volume The new volume, must be between 0.0 and 1.0. + * \return Whether the action succeeded. */ -extern int AUD_playDevice(AUD_Device* device, AUD_Sound* sound); +extern int AUD_setDeviceSoundVolume(AUD_Device* device, + AUD_Handle* handle, + float volume); /** * Reads the next samples into the supplied buffer. diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index e9f6eb21e36..cbce4663d6f 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -71,7 +71,7 @@ void sound_update_playing(struct bContext *C); void sound_scrub(struct bContext *C); #ifdef AUD_CAPI -AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end); +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end, float volume); #endif void sound_stop_all(struct bContext *C); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 6f9ed3e0978..a9d7caaf5e0 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -419,7 +419,7 @@ Scene *add_scene(char *name) pset->brush[PE_BRUSH_CUT].strength= 100; sce->jumpframe = 10; - sce->r.audio.mixrate = 44100; + sce->r.ffcodecdata.audio_mixrate = 44100; strcpy(sce->r.backbuf, "//backbuf"); strcpy(sce->r.pic, U.renderdir); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 2d5d8dad7a8..fdf6283925e 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -421,7 +421,7 @@ void sound_scrub(struct bContext *C) int cfra = CFRA; float fps = FPS; - if(scene->r.audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) + if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) { AUD_lock(); @@ -443,13 +443,14 @@ void sound_scrub(struct bContext *C) } } -AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end) +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end, float volume) { AUD_Device* mixdown = AUD_openReadDevice(specs); SoundHandle *handle; float fps = FPS; AUD_Sound *limiter, *delayer; int frameskip, s, e; + AUD_Handle* h; end++; @@ -470,7 +471,8 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int e limiter = AUD_limitSound(handle->source->handle, frameskip / fps, e / fps); delayer = AUD_delaySound(limiter, s / fps); - AUD_playDevice(mixdown, delayer); + h = AUD_playDevice(mixdown, delayer); + AUD_setDeviceSoundVolume(mixdown, h, volume); AUD_unload(delayer); AUD_unload(limiter); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index a90924055b3..1953058fddf 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -559,7 +559,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex c->codec_id = codec_id; c->codec_type = CODEC_TYPE_AUDIO; - c->sample_rate = rd->audio.mixrate; + c->sample_rate = rd->ffcodecdata.audio_mixrate; c->bit_rate = ffmpeg_audio_bitrate*1000; c->channels = 2; codec = avcodec_find_encoder(c->codec_id); @@ -734,7 +734,7 @@ static void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_multiplex_audio && rd->audio.mixrate != 48000) { + if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) { G.afbreek = 1; //XXX error("FFMPEG only supports 48khz / stereo " // "audio for DV!"); @@ -831,7 +831,6 @@ static void makeffmpegstring(RenderData* rd, char* string) { } } - void start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty) { ffmpeg_autosplit_count = 0; @@ -844,8 +843,8 @@ void start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty) AUD_Specs specs; specs.channels = c->channels; specs.format = AUD_FORMAT_S16; - specs.rate = rd->audio.mixrate; - audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra); + specs.rate = rd->ffcodecdata.audio_mixrate; + audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume); } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c5dcf1ce520..2d612cffc7d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9354,7 +9354,10 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* toolsettings */ for(scene= main->scene.first; scene; scene= scene->id.next) - scene->r.audio = scene->audio; + { + scene->r.ffcodecdata.audio_mixrate = scene->audio.mixrate; + scene->r.ffcodecdata.audio_volume = scene->audio.main; + } /* shader, composit and texture node trees have id.name empty, put something in * to have them show in RNA viewer and accessible otherwise. diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a055041d8ae..ef28ff6dbd1 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2206,7 +2206,7 @@ static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event) /* sync, don't sync, or follow scene setting */ if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1; else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0; - else sync= (scene->r.audio.flag & AUDIO_SYNC); + else sync= (scene->audio.flag & AUDIO_SYNC); if(sync) { /* skip frames */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 73afc3d1a53..b41cd79b6d4 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -93,6 +93,8 @@ typedef struct FFMpegCodecData { int audio_codec; int video_bitrate; int audio_bitrate; + int audio_mixrate; + int audio_volume; int gop_size; int flags; @@ -106,8 +108,8 @@ typedef struct FFMpegCodecData { typedef struct AudioData { - int mixrate; - float main; /* Main mix in dB */ + int mixrate; // 2.5: now in FFMpegCodecData: audio_mixrate + float main; // 2.5: now in FFMpegCodecData: audio_volume short flag; short pad[3]; } AudioData; @@ -170,7 +172,6 @@ typedef struct RenderData { struct AviCodecData *avicodecdata; struct QuicktimeCodecData *qtcodecdata; struct FFMpegCodecData ffcodecdata; - struct AudioData audio; /* new in 2.5 */ int cfra, sfra, efra; /* frames as in 'images' */ int psfra, pefra; /* start+end frames of preview range */ @@ -697,7 +698,7 @@ typedef struct Scene { /* migrate or replace? depends on some internal things... */ /* no, is on the right place (ton) */ struct RenderData r; - struct AudioData audio; /* DEPRECATED 2.5 */ + struct AudioData audio; ListBase markers; ListBase transform_spaces; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 08efa13d8f4..d6991a3a624 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1512,6 +1512,19 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "ffcodecdata.flags", FFMPEG_MULTIPLEX_AUDIO); RNA_def_property_ui_text(prop, "Multiplex Audio", "Interleave audio with the output video"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "ffmpeg_audio_mixrate", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_mixrate"); + RNA_def_property_range(prop, 8000, 192000); + RNA_def_property_ui_text(prop, "Sample", "Audio samplerate(samples/s)"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "ffmpeg_audio_volume", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ffcodecdata.audio_volume"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Volume", "Audio volume"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + #endif prop= RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); @@ -1583,11 +1596,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fields Still", "Disable the time difference between fields."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); - prop= RNA_def_property(srna, "sync_audio", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC); - RNA_def_property_ui_text(prop, "Sync Audio", "Play back and sync with audio from Sequence Editor"); - RNA_def_property_update(prop, NC_SCENE, NULL); - prop= RNA_def_property(srna, "render_shadows", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SHADOW); RNA_def_property_ui_text(prop, "Render Shadows", "Calculate shadows while rendering."); @@ -2063,6 +2071,22 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_struct_type(prop, "TimelineMarker"); RNA_def_property_ui_text(prop, "Timeline Markers", "Markers used in all timelines for the current scene."); + /* Audio Settings */ + prop= RNA_def_property(srna, "mute_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_MUTE); + RNA_def_property_ui_text(prop, "Mute Audio", "Play back of audio from Sequence Editor will be muted."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "sync_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC); + RNA_def_property_ui_text(prop, "Sync Audio", "Play back and sync with audio from Sequence Editor."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "scrub_audio", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SCRUB); + RNA_def_property_ui_text(prop, "Scrub Audio", "Play audio from Sequence Editor while scrubbing."); + RNA_def_property_update(prop, NC_SCENE, NULL); + /* Game Settings */ prop= RNA_def_property(srna, "game_data", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); -- cgit v1.2.3 From ec8c47f0c08bf500bbf5d5fe6a833942c7710d29 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 20 Sep 2009 14:14:40 +0000 Subject: * UI for recent sound commit. --- release/ui/buttons_scene.py | 2 ++ release/ui/space_time.py | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/release/ui/buttons_scene.py b/release/ui/buttons_scene.py index c25e6352aaf..6f283bb5d5b 100644 --- a/release/ui/buttons_scene.py +++ b/release/ui/buttons_scene.py @@ -323,8 +323,10 @@ class SCENE_PT_encoding(RenderButtonsPanel): col = split.column() col.itemR(rd, "ffmpeg_audio_bitrate") + col.itemR(rd, "ffmpeg_audio_mixrate") col = split.column() col.itemR(rd, "ffmpeg_multiplex_audio") + col.itemR(rd, "ffmpeg_audio_volume") class SCENE_PT_antialiasing(RenderButtonsPanel): __label__ = "Anti-Aliasing" diff --git a/release/ui/space_time.py b/release/ui/space_time.py index bb82eea3272..b51b1d8af79 100644 --- a/release/ui/space_time.py +++ b/release/ui/space_time.py @@ -9,7 +9,6 @@ class TIME_HT_header(bpy.types.Header): st = context.space_data scene = context.scene - rd = context.scene.render_data tools = context.tool_settings screen = context.screen @@ -55,7 +54,7 @@ class TIME_HT_header(bpy.types.Header): subsub = row.row() subsub.itemR(tools, "record_with_nla", toggle=True) - layout.itemR(rd, "sync_audio", text="", toggle=True, icon='ICON_SPEAKER') + layout.itemR(scene, "sync_audio", text="", toggle=True, icon='ICON_SPEAKER') layout.itemS() @@ -112,7 +111,7 @@ class TIME_MT_playback(bpy.types.Menu): layout = self.layout st = context.space_data - rd = context.scene.render_data + scene = context.scene layout.itemR(st, "play_top_left") layout.itemR(st, "play_all_3d") @@ -127,10 +126,10 @@ class TIME_MT_playback(bpy.types.Menu): layout.itemS() - layout.itemR(rd, "sync_audio", icon='ICON_SPEAKER') + layout.itemR(scene, "sync_audio", icon='ICON_SPEAKER') + layout.itemR(scene, "mute_audio") + layout.itemR(scene, "scrub_audio") - - class TIME_MT_autokey(bpy.types.Menu): __space_type__ = 'TIMELINE' __label__ = "Auto-Keyframing Mode" -- cgit v1.2.3 From 85e529433b62b27680203221083481db04e867a1 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 15:02:14 +0000 Subject: 2.5 filebrowser * fix selection related bugs: ** selection outside filelist would select first item ** border select would enter directory even if more than one is selected --- source/blender/editors/space_file/file_ops.c | 49 ++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index faca6db75bf..5603c0bb2e4 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -68,7 +68,7 @@ /* ---------- FILE SELECTION ------------ */ -static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y, short clamp) +static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y) { float fx,fy; int active_file = -1; @@ -78,15 +78,6 @@ static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short UI_view2d_region_to_view(v2d, x, y, &fx, &fy); active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy); - - if(active_file < 0) { - if(clamp) active_file= 0; - else active_file= -1; - } - else if(active_file >= numfiles) { - if(clamp) active_file= numfiles-1; - else active_file= -1; - } return active_file; } @@ -109,6 +100,31 @@ typedef enum FileSelect { FILE_SELECT_DIR = 1, FILE_SELECT_FILE = 2 } FileSelect; +static void clamp_to_filelist(int numfiles, int *first_file, int *last_file) +{ + /* border select before the first file */ + if ( (*first_file < 0) && (*last_file >=0 ) ) { + *first_file = 0; + } + /* don't select if everything is outside filelist */ + if ( (*first_file >= numfiles) && ((*last_file < 0) || (*last_file >= numfiles)) ) { + *first_file = -1; + *last_file = -1; + } + + /* fix if last file invalid */ + if ( (*first_file > 0) && (*last_file < 0) ) + *last_file = numfiles-1; + + /* clamp */ + if ( (*first_file >= numfiles) ) { + *first_file = numfiles-1; + } + if ( (*last_file >= numfiles) ) { + *last_file = numfiles-1; + } +} + static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val) { int first_file = -1; @@ -123,9 +139,11 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s int numfiles = filelist_numfiles(sfile->files); params->selstate = NOTACTIVE; - first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax, 1); - last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin, 1); + first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax); + last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin); + clamp_to_filelist(numfiles, &first_file, &last_file); + /* select all valid files between first and last indicated */ if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) { for (act_file = first_file; act_file <= last_file; act_file++) { @@ -137,6 +155,9 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s } } + /* Don't act on multiple selected files */ + if (first_file != last_file) selecting= 0; + /* make the last file active */ if (selecting && (last_file >= 0 && last_file < numfiles)) { struct direntry* file = filelist_file(sfile->files, last_file); @@ -168,7 +189,7 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s } } - } + } return retval; } @@ -449,7 +470,7 @@ int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) my -= ar->winrct.ymin; if(BLI_in_rcti(&ar->v2d.mask, mx, my)) { - actfile = find_file_mouse(sfile, ar, mx , my, 0); + actfile = find_file_mouse(sfile, ar, mx , my); if((actfile >= 0) && (actfile < numfiles)) params->active_file=actfile; -- cgit v1.2.3 From 4b6c61e0a704a713d13090231aa73056ff48c6d4 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 15:30:52 +0000 Subject: 2.5 filebrowser * changed filebrowser operator property "filename" to "path" - fixed two missing operators. * small cleanup in init of filebrowser --- source/blender/editors/curve/editfont.c | 10 +++++----- source/blender/editors/space_buttons/buttons_ops.c | 2 +- source/blender/editors/space_file/filesel.c | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 868c5902670..2be567e1921 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -381,19 +381,19 @@ static int paste_file(bContext *C, ReportList *reports, char *filename) static int paste_file_exec(bContext *C, wmOperator *op) { - char *filename; + char *path; int retval; - filename= RNA_string_get_alloc(op->ptr, "filename", NULL, 0); - retval= paste_file(C, op->reports, filename); - MEM_freeN(filename); + path= RNA_string_get_alloc(op->ptr, "path", NULL, 0); + retval= paste_file(C, op->reports, path); + MEM_freeN(path); return retval; } static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if(RNA_property_is_set(op->ptr, "filename")) + if(RNA_property_is_set(op->ptr, "path")) return paste_file_exec(C, op); WM_event_add_fileselect(C, op); diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 9b335b86163..5466a06550b 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -1107,7 +1107,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event) op->customdata= fbo; str= RNA_property_string_get_alloc(&ptr, prop, 0, 0); - RNA_string_set(op->ptr, "filename", str); + RNA_string_set(op->ptr, "path", str); MEM_freeN(str); WM_event_add_fileselect(C, op); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index a0787ef989d..e9e09d8f60b 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -117,8 +117,6 @@ short ED_fileselect_set_params(SpaceFile *sfile) BLI_strncpy(sfile->params->file, file, sizeof(sfile->params->file)); BLI_make_file_string(G.sce, sfile->params->dir, dir, ""); /* XXX needed ? - also solve G.sce */ } - - ED_fileselect_reset_params(sfile); params = sfile->params; -- cgit v1.2.3 From e4a50e3f47de157b4213062d1dea9ff5c1ab0104 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 17:23:57 +0000 Subject: 2.5 filebrowser * fix crash when filebrowser tried to invoke the file_exec or file_cancel in cases no operator was set. --- source/blender/editors/space_file/file_ops.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 5603c0bb2e4..16c8733cb5b 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -526,6 +526,16 @@ int file_cancel_exec(bContext *C, wmOperator *unused) return OPERATOR_FINISHED; } +int file_operator_poll(bContext *C) +{ + int poll = ED_operator_file_active(C); + SpaceFile *sfile= CTX_wm_space_file(C); + + if (!sfile->op) poll= 0; + + return poll; +} + void FILE_OT_cancel(struct wmOperatorType *ot) { /* identifiers */ @@ -534,7 +544,7 @@ void FILE_OT_cancel(struct wmOperatorType *ot) /* api callbacks */ ot->exec= file_cancel_exec; - ot->poll= ED_operator_file_active; + ot->poll= file_operator_poll; } /* sends events now, so things get handled on windowqueue level */ @@ -612,7 +622,7 @@ void FILE_OT_execute(struct wmOperatorType *ot) /* api callbacks */ ot->exec= file_exec; - ot->poll= ED_operator_file_active; /* <- important, handler is on window level */ + ot->poll= file_operator_poll; } -- cgit v1.2.3 From 4f6ea2b683b81fe12642f92e8f0e0d48904f2c6c Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sun, 20 Sep 2009 17:24:56 +0000 Subject: Ghost/Compiz bug: Sometimes, events for window size or move are sent even when the window hasn't changed. This triggers unneeded refreshes. As a precaution, we now ignore all such events (eventually, it should be done in Ghost X11, but I don't know that code well enough). --- source/blender/windowmanager/intern/wm_window.c | 78 ++++++++++++++++--------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 9d3d0a9535e..c853afe4507 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -627,6 +627,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) if(state!=GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; int l, t, r, b, scr_w, scr_h; + int sizex, sizey, posx, posy; client_rect= GHOST_GetClientBounds(win->ghostwin); GHOST_GetRectangle(client_rect, &l, &t, &r, &b); @@ -634,37 +635,56 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) GHOST_DisposeRectangle(client_rect); wm_get_screensize(&scr_w, &scr_h); - win->sizex= r-l; - win->sizey= b-t; - win->posx= l; - win->posy= scr_h - t - win->sizey; - - /* debug prints */ - if(0) { - state = GHOST_GetWindowState(win->ghostwin); - - if(state==GHOST_kWindowStateNormal) { - if(G.f & G_DEBUG) printf("window state: normal\n"); - } - else if(state==GHOST_kWindowStateMinimized) { - if(G.f & G_DEBUG) printf("window state: minimized\n"); - } - else if(state==GHOST_kWindowStateMaximized) { - if(G.f & G_DEBUG) printf("window state: maximized\n"); + sizex= r-l; + sizey= b-t; + posx= l; + posy= scr_h - t - win->sizey; + + /* + * Ghost sometimes send size or move events when the window hasn't changed. + * One case of this is using compiz on linux. To alleviate the problem + * we ignore all such event here. + * + * It might be good to eventually do that at Ghost level, but that is for + * another time. + */ + if (win->sizex != sizex || + win->sizey != sizey || + win->posx != posx || + win->posy != posy) + { + win->sizex= sizex; + win->sizey= sizey; + win->posx= posx; + win->posy= posy; + + /* debug prints */ + if(0) { + state = GHOST_GetWindowState(win->ghostwin); + + if(state==GHOST_kWindowStateNormal) { + if(G.f & G_DEBUG) printf("window state: normal\n"); + } + else if(state==GHOST_kWindowStateMinimized) { + if(G.f & G_DEBUG) printf("window state: minimized\n"); + } + else if(state==GHOST_kWindowStateMaximized) { + if(G.f & G_DEBUG) printf("window state: maximized\n"); + } + else if(state==GHOST_kWindowStateFullScreen) { + if(G.f & G_DEBUG) printf("window state: fullscreen\n"); + } + + if(type!=GHOST_kEventWindowSize) { + if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); + } + } - else if(state==GHOST_kWindowStateFullScreen) { - if(G.f & G_DEBUG) printf("window state: fullscreen\n"); - } - - if(type!=GHOST_kEventWindowSize) { - if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); - } - + + wm_window_make_drawable(C, win); + wm_draw_window_clear(win); + WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } - - wm_window_make_drawable(C, win); - wm_draw_window_clear(win); - WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); } break; } -- cgit v1.2.3 From 189263e1d9cd1cfdb2e9a96a01761858e8deaa7c Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 20 Sep 2009 17:55:03 +0000 Subject: Sound: * Fixed mixdown volume being int instead of float * Fixed audio muting for sequencer not working * Added 3D listener settings with RNA (not working in GE yet) --- source/blender/blenkernel/intern/scene.c | 4 ++++ source/blender/blenkernel/intern/sound.c | 2 +- source/blender/blenloader/intern/readfile.c | 19 +++++++++------ source/blender/makesdna/DNA_scene_types.h | 7 ++++-- source/blender/makesrna/intern/rna_scene.c | 36 +++++++++++++++++++++++++---- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a9d7caaf5e0..4de9ff3b6d9 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -421,6 +421,10 @@ Scene *add_scene(char *name) sce->jumpframe = 10; sce->r.ffcodecdata.audio_mixrate = 44100; + sce->audio.distance_model = 2.0; + sce->audio.doppler_factor = 1.0; + sce->audio.speed_of_sound = 343.3; + strcpy(sce->r.backbuf, "//backbuf"); strcpy(sce->r.pic, U.renderdir); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index fdf6283925e..c6c4a776faf 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -340,7 +340,7 @@ void sound_update_playing(struct bContext *C) for(handle = scene->sound_handles.first; handle; handle = handle->next) { - if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute) + if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute || (scene->audio.flag & AUDIO_MUTE)) { if(handle->state == AUD_STATUS_PLAYING) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2d612cffc7d..78949d8bd8c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9352,13 +9352,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) */ //do_versions_ipos_to_animato(main); - /* toolsettings */ - for(scene= main->scene.first; scene; scene= scene->id.next) - { - scene->r.ffcodecdata.audio_mixrate = scene->audio.mixrate; - scene->r.ffcodecdata.audio_volume = scene->audio.main; - } - /* shader, composit and texture node trees have id.name empty, put something in * to have them show in RNA viewer and accessible otherwise. */ @@ -9714,6 +9707,18 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + + for(sce= main->scene.first; sce; sce= sce->id.next) + { + if(sce->audio.main == 0.0) + sce->audio.main = 1.0; + + sce->r.ffcodecdata.audio_mixrate = sce->audio.mixrate; + sce->r.ffcodecdata.audio_volume = sce->audio.main; + sce->audio.distance_model = 2.0; + sce->audio.doppler_factor = 1.0; + sce->audio.speed_of_sound = 343.3; + } } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index b41cd79b6d4..5521f0e9315 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -94,7 +94,7 @@ typedef struct FFMpegCodecData { int video_bitrate; int audio_bitrate; int audio_mixrate; - int audio_volume; + float audio_volume; int gop_size; int flags; @@ -110,8 +110,11 @@ typedef struct FFMpegCodecData { typedef struct AudioData { int mixrate; // 2.5: now in FFMpegCodecData: audio_mixrate float main; // 2.5: now in FFMpegCodecData: audio_volume + float speed_of_sound; + float doppler_factor; + int distance_model; short flag; - short pad[3]; + short pad; } AudioData; typedef struct SceneRenderLayer { diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d6991a3a624..ff8102a3111 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1516,7 +1516,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop= RNA_def_property(srna, "ffmpeg_audio_mixrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_mixrate"); RNA_def_property_range(prop, 8000, 192000); - RNA_def_property_ui_text(prop, "Sample", "Audio samplerate(samples/s)"); + RNA_def_property_ui_text(prop, "Samplerate", "Audio samplerate(samples/s)"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "ffmpeg_audio_volume", PROP_FLOAT, PROP_NONE); @@ -1915,6 +1915,16 @@ void RNA_def_scene(BlenderRNA *brna) PropertyRNA *prop; FunctionRNA *func; + static EnumPropertyItem audio_distance_model_items[] = { + {0, "NONE", 0, "None", "No distance attenuation."}, + {1, "INVERSE", 0, "Inverse", "Inverse distance model."}, + {2, "INVERSE_CLAMPED", 0, "Inverse Clamped", "Inverse distance model with clamping."}, + {3, "LINEAR", 0, "Linear", "Linear distance model."}, + {4, "LINEAR_CLAMPED", 0, "Linear Clamped", "Linear distance model with clamping."}, + {5, "EXPONENT", 0, "Exponent", "Exponent distance model."}, + {6, "EXPONENT_CLAMPED", 0, "Exponent Clamped", "Exponent distance model with clamping."}, + {0, NULL, 0, NULL, NULL}}; + /* Struct definition */ srna= RNA_def_struct(brna, "Scene", "ID"); RNA_def_struct_ui_text(srna, "Scene", "Scene consisting objects and defining time and render related settings."); @@ -2074,17 +2084,35 @@ void RNA_def_scene(BlenderRNA *brna) /* Audio Settings */ prop= RNA_def_property(srna, "mute_audio", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_MUTE); - RNA_def_property_ui_text(prop, "Mute Audio", "Play back of audio from Sequence Editor will be muted."); + RNA_def_property_ui_text(prop, "Audio Muted", "Play back of audio from Sequence Editor will be muted."); RNA_def_property_update(prop, NC_SCENE, NULL); prop= RNA_def_property(srna, "sync_audio", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC); - RNA_def_property_ui_text(prop, "Sync Audio", "Play back and sync with audio from Sequence Editor."); + RNA_def_property_ui_text(prop, "Audio Sync", "Play back and sync with audio from Sequence Editor."); RNA_def_property_update(prop, NC_SCENE, NULL); prop= RNA_def_property(srna, "scrub_audio", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SCRUB); - RNA_def_property_ui_text(prop, "Scrub Audio", "Play audio from Sequence Editor while scrubbing."); + RNA_def_property_ui_text(prop, "Audio Scrubbing", "Play audio from Sequence Editor while scrubbing."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "speed_of_sound", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "audio.speed_of_sound"); + RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_ui_text(prop, "Speed of Sound", "Speed of sound for doppler effect calculation."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "doppler_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "audio.doppler_factor"); + RNA_def_property_range(prop, FLT_MIN, FLT_MAX); + RNA_def_property_ui_text(prop, "Doppler Factor", "Pitch factor for doppler effect calculation."); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "distance_model", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "audio.distance_model"); + RNA_def_property_enum_items(prop, audio_distance_model_items); + RNA_def_property_ui_text(prop, "Distance Model", "Distance model for distance attenuation calculation."); RNA_def_property_update(prop, NC_SCENE, NULL); /* Game Settings */ -- cgit v1.2.3 From 3b4410367f1011f91cd91022b17c59917bf3ee34 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 18:26:02 +0000 Subject: 2.5 filebrowser more bugfixes: * removed refreshing code at file_init again, causes issues when resizing * free library in the filelist after use * make sure directory exists when library file for append/link doesn't exist, so browsing can continue from valid dir. --- source/blender/editors/space_file/file_ops.c | 2 ++ source/blender/editors/space_file/filelist.c | 2 ++ source/blender/editors/space_file/space_file.c | 11 +---------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 16c8733cb5b..70d8de7d509 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -518,6 +518,7 @@ int file_cancel_exec(bContext *C, wmOperator *unused) sfile->op = NULL; if (sfile->files) { + filelist_freelib(sfile->files); filelist_free(sfile->files); MEM_freeN(sfile->files); sfile->files= NULL; @@ -606,6 +607,7 @@ int file_exec(bContext *C, wmOperator *unused) fsmenu_write_file(fsmenu_get(), name); WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC); + filelist_freelib(sfile->files); filelist_free(sfile->files); MEM_freeN(sfile->files); sfile->files= NULL; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 582a5997ef5..8257aa5482f 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -804,6 +804,8 @@ static void filelist_read_library(struct FileList* filelist) if(!filelist->libfiledata) { int num; struct direntry *file; + + BLI_make_exist(filelist->dir); filelist_read_dir(filelist); file = filelist->filelist; for(num=0; numnumfiles; num++, file++) { diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 99d649b28cc..56dbdcbc645 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -156,16 +156,6 @@ static void file_free(SpaceLink *sl) static void file_init(struct wmWindowManager *wm, ScrArea *sa) { SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; - if(sfile->params) { - MEM_freeN(sfile->params); - sfile->params = 0; - ED_fileselect_set_params(sfile); - if (sfile->files) { - filelist_free(sfile->files); - MEM_freeN(sfile->files); - sfile->files= NULL; - } - } printf("file_init\n"); } @@ -213,6 +203,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) if (filelist_empty(sfile->files)) { filelist_readdir(sfile->files); + BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX); } if(params->sort!=FILE_SORT_NONE) filelist_sort(sfile->files, params->sort); -- cgit v1.2.3 From 1de250014de04fb3312725f1fecc6327fa86666d Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 20 Sep 2009 18:35:14 +0000 Subject: Sound: * 3D listener now working in GE --- source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp | 7 +++++++ source/gameengine/BlenderRoutines/CMakeLists.txt | 1 + source/gameengine/BlenderRoutines/SConscript | 1 + 3 files changed, 9 insertions(+) diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index ae46f880711..1ede16f017e 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -89,6 +89,8 @@ extern "C" { #include "DNA_scene_types.h" /***/ +#include "AUD_C-API.h" + //XXX #include "BSE_headerbuttons.h" #include "BKE_context.h" #include "../../blender/windowmanager/WM_types.h" @@ -386,6 +388,11 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, int alw if(blscene->gm.stereoflag == STEREO_DOME) ketsjiengine->InitDome(blscene->gm.dome.res, blscene->gm.dome.mode, blscene->gm.dome.angle, blscene->gm.dome.resbuf, blscene->gm.dome.tilt, blscene->gm.dome.warptext); + // initialize 3D Audio Settings + AUD_set3DSetting(AUD_3DS_SPEED_OF_SOUND, blscene->audio.speed_of_sound); + AUD_set3DSetting(AUD_3DS_DOPPLER_FACTOR, blscene->audio.doppler_factor); + AUD_set3DSetting(AUD_3DS_DISTANCE_MODEL, blscene->audio.distance_model); + if (sceneconverter) { // convert and add scene diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index ee15fd99ed5..ce85c1185b0 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -6,6 +6,7 @@ SET(INC ../../../source/kernel/gen_system ../../../intern/string ../../../intern/guardedalloc + ../../../intern/audaspace/intern ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer ../../../source/gameengine/Converter ../../../source/blender/imbuf diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript index ad6f9f23fce..1e8ff3c48e8 100644 --- a/source/gameengine/BlenderRoutines/SConscript +++ b/source/gameengine/BlenderRoutines/SConscript @@ -8,6 +8,7 @@ incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' incs += ' #source/gameengine/Converter #source/blender/imbuf' incs += ' #intern/ghost/include' +incs += ' #intern/audaspace/intern' incs += ' #intern/moto/include #source/gameengine/Ketsji #source/blender/blenlib' incs += ' #source/blender/blenkernel #source/blender' incs += ' #source/blender/blenfont #source/blender/editors/include' -- cgit v1.2.3 From 85294c6d7e1fcb4bacf39c0ff8c310c5b5a9139f Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 20 Sep 2009 18:49:46 +0000 Subject: 2.5 Game Sound: * Added Sound Buttons for Game in the Scene Buttons. --- release/ui/buttons_game.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/release/ui/buttons_game.py b/release/ui/buttons_game.py index 73ba566e23f..f3461d3e370 100644 --- a/release/ui/buttons_game.py +++ b/release/ui/buttons_game.py @@ -304,12 +304,25 @@ class SCENE_PT_game_performance(SceneButtonsPanel): col.itemL(text="Render:") col.itemR(gs, "all_frames") col.itemR(gs, "display_lists") + +class SCENE_PT_game_sound(SceneButtonsPanel): + __label__ = "Sound" + + def draw(self, context): + layout = self.layout + + scene = context.scene + + layout.itemR(scene, "distance_model") + layout.itemR(scene, "speed_of_sound", text="Speed") + layout.itemR(scene, "doppler_factor") bpy.types.register(SCENE_PT_game) bpy.types.register(SCENE_PT_game_player) bpy.types.register(SCENE_PT_game_stereo) bpy.types.register(SCENE_PT_game_shading) bpy.types.register(SCENE_PT_game_performance) +bpy.types.register(SCENE_PT_game_sound) class WorldButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' -- cgit v1.2.3 From 6d4fb84c4eeeeacca953906883a6f328fd9ffcee Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Sun, 20 Sep 2009 19:10:12 +0000 Subject: 2.5 filebrowser * fix crash in autocomplete for very long paths * allow longer paths in directory button * added some TODO comments for G.lib --- source/blender/editors/space_file/file_draw.c | 2 +- source/blender/editors/space_file/filesel.c | 5 ++++- source/blender/windowmanager/intern/wm_operators.c | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 00024ffa961..46ed6987752 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -189,7 +189,7 @@ void file_draw_buttons(const bContext *C, ARegion *ar) if (available_w > 0) { but = uiDefBut(block, TEX, B_FS_DIRNAME, "", min_x, line1_y, line1_w, btn_h, - params->dir, 0.0, (float)FILE_MAXDIR-1, 0, 0, + params->dir, 0.0, (float)FILE_MAX-1, 0, 0, "File path."); uiButSetCompleteFunc(but, autocomplete_directory, NULL); uiDefBut(block, TEX, B_FS_FILENAME, "", diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e9e09d8f60b..dd16a426899 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -417,13 +417,16 @@ void autocomplete_directory(struct bContext *C, char *str, void *arg_v) struct direntry* file = filelist_file(sfile->files, i); const char* dir = filelist_dir(sfile->files); if (file && S_ISDIR(file->type)) { - BLI_make_file_string(G.sce, tmp, dir, file->relname); + // BLI_make_file_string(G.sce, tmp, dir, file->relname); + BLI_join_dirfile(tmp, dir, file->relname); autocomplete_do_name(autocpl,tmp); } } autocomplete_end(autocpl, str); if (BLI_exists(str)) { BLI_add_slash(str); + } else { + BLI_make_exist(str); } } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a6fc575ce70..76c15043b89 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -943,7 +943,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *event) return WM_operator_call(C, op); } else { - /* XXX solve where to get last linked library from */ + /* XXX TODO solve where to get last linked library from */ RNA_string_set(op->ptr, "path", G.lib); WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; @@ -1064,6 +1064,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) DAG_ids_flush_update(0); BLO_blendhandle_close(bh); + + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, dir, FILE_MAX); WM_event_add_notifier(C, NC_WINDOW, NULL); -- cgit v1.2.3 From b11acc659b823300f8c300930494931ffcfe52c0 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Sun, 20 Sep 2009 20:14:34 +0000 Subject: Add audaspace search path. --- source/gameengine/BlenderRoutines/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile index 4b65da667ef..4a437aff97d 100644 --- a/source/gameengine/BlenderRoutines/Makefile +++ b/source/gameengine/BlenderRoutines/Makefile @@ -40,6 +40,7 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_AUDASPACE)/include # because of kernel dependency on makesdna CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I../../blender/editors/include -- cgit v1.2.3 From 76447ef615d7f9755ee46e3e07ee0c11acdaac91 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Sun, 20 Sep 2009 20:21:01 +0000 Subject: Update condition checks to match user definable CC and CCC. Also make faster to notice which FIX_NAN_WARN as not been replaced. --- source/nan_warn.mk | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/source/nan_warn.mk b/source/nan_warn.mk index b685c13604d..0dd4e0b8147 100644 --- a/source/nan_warn.mk +++ b/source/nan_warn.mk @@ -34,19 +34,19 @@ # # Force the correct redefinition -LEVEL_1_C_WARNINGS = -FIX_NAN_WARN -LEVEL_1_CPP_WARNINGS = -FIX_NAN_WARN -LEVEL_2_C_WARNINGS = -FIX_NAN_WARN -LEVEL_2_CPP_WARNINGS = -FIX_NAN_WARN -FIX_STUBS_WARNINGS = -FIX_NAN_WARN +LEVEL_1_C_WARNINGS = -FIX_NAN_WARN1A +LEVEL_1_CPP_WARNINGS = -FIX_NAN_WARN1B +LEVEL_2_C_WARNINGS = -FIX_NAN_WARN2A +LEVEL_2_CPP_WARNINGS = -FIX_NAN_WARN2B +FIX_STUBS_WARNINGS = -FIX_NAN_WARN3 ######################################################################## # Level 1: basic C warnings. -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) LEVEL_1_C_WARNINGS = -Wall LEVEL_1_C_WARNINGS += -Wno-char-subscripts else - ifeq ($(CC),cc) + ifeq (cc, $(findstring cc,$(CC))) ifeq ($(OS),irix) # MIPSpro Compilers # @@ -71,11 +71,11 @@ else endif # Level 1: basic CPP warnings. -ifeq ($(CCC),g++) +ifeq (g++, $(findstring g++,$(CCC))) LEVEL_1_CPP_WARNINGS = -Wall LEVEL_1_CPP_WARNINGS += -Wno-reorder else - ifeq ($(CCC),CC) + ifeq (CC, $(findstring CC,$(CCC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -91,7 +91,7 @@ endif ######################################################################## # Level 2: paranoia level C warnings. # DO NOT REUSE LEVEL_1_ DEFINES. -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) LEVEL_2_C_WARNINGS = -Wall LEVEL_2_C_WARNINGS += -W # deliberately enable char-subscript warnings @@ -107,7 +107,7 @@ ifeq ($(CC),gcc) LEVEL_2_C_WARNINGS += -Wnested-externs LEVEL_2_C_WARNINGS += -Wredundant-decls else - ifeq ($(CC),cc) + ifeq (cc, $(findstring cc,$(CC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -126,7 +126,7 @@ endif # Level 2: paranoia level CPP warnings. # DO NOT REUSE LEVEL_1_ DEFINES. -ifeq ($(CCC),g++) +ifeq (g++, $(findstring g++,$(CCC))) LEVEL_2_CPP_WARNINGS = -Wall LEVEL_2_CPP_WARNINGS += -W # deliberately enable char-subscript warnings @@ -144,7 +144,7 @@ ifeq ($(CCC),g++) LEVEL_2_CPP_WARNINGS += -Wsign-promo LEVEL_2_CPP_WARNINGS += -Wsynth else - ifeq ($(CCC),CC) + ifeq (CC, $(findstring CC,$(CCC))) ifeq ($(OS),irix) # MIPSpro Compilers # see warning descriptions above @@ -159,7 +159,7 @@ endif ######################################################################## # stubs warning fix -ifeq ($(CC),gcc) +ifeq (gcc, $(findstring gcc,$(CC))) FIX_STUBS_WARNINGS = -Wno-unused else FIX_STUBS_WARNINGS = -- cgit v1.2.3 From f560eb0c466e284208f37c3cda2d6c27f7e6bf58 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Mon, 21 Sep 2009 00:48:36 +0000 Subject: New transform input function for joeedh, to be used for edge slide. Like Vertical or Horizontal ratio input, but along a line defined by two points on screen. --- source/blender/editors/transform/transform.h | 6 ++- .../blender/editors/transform/transform_generics.c | 7 +++- source/blender/editors/transform/transform_input.c | 46 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e5bd405c0cd..2ff6d6d3dce 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -210,6 +210,7 @@ typedef struct MouseInput { short precision_mval[2]; /* mouse position when precision key was pressed */ int center[2]; float factor; + void *data; /* additional data, if needed by the particular function */ } MouseInput; typedef struct TransInfo { @@ -575,7 +576,8 @@ typedef enum { INPUT_HORIZONTAL_RATIO, INPUT_HORIZONTAL_ABSOLUTE, INPUT_VERTICAL_RATIO, - INPUT_VERTICAL_ABSOLUTE + INPUT_VERTICAL_ABSOLUTE, + INPUT_CUSTOM_RATIO } MouseInputMode; void initMouseInput(TransInfo *t, MouseInput *mi, int center[2], short mval[2]); @@ -583,6 +585,8 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode); int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, struct wmEvent *event); void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, short mval[2], float output[3]); +void setCustomPoints(TransInfo *t, MouseInput *mi, short start[2], short end[2]); + /*********************** Generics ********************************/ int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 0b7029adde0..d93e92616e1 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1052,7 +1052,7 @@ void postTrans (TransInfo *t) } MEM_freeN(t->data); } - + if (t->ext) MEM_freeN(t->ext); if (t->data2d) { MEM_freeN(t->data2d); @@ -1068,6 +1068,11 @@ void postTrans (TransInfo *t) if (t->customData) MEM_freeN(t->customData); } + + if (t->mouse.data) + { + MEM_freeN(t->mouse.data); + } } void applyTransObjects(TransInfo *t) diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 6bd0a8c8d42..e1e4569623b 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -163,6 +163,47 @@ void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, short mval[2], float ou output[0] = Inpf(t->viewinv[1], vec) * 2.0f; } +void setCustomPoints(TransInfo *t, MouseInput *mi, short start[2], short end[2]) +{ + short *data = mi->data; + + data[0] = start[0]; + data[1] = start[1]; + data[2] = end[0]; + data[3] = end[1]; +} + +void InputCustomRatio(TransInfo *t, MouseInput *mi, short mval[2], float output[3]) +{ + float length; + float distance; + short *data = mi->data; + short dx, dy; + + dx = data[2] - data[0]; + dy = data[3] - data[1]; + + length = (float)sqrtf(dx*dx + dy*dy); + + if (mi->precision) { + /* deal with Shift key by adding motion / 10 to motion before shift press */ + short mdx, mdy; + mdx = (mi->precision_mval[0] + (float)(mval[0] - mi->precision_mval[0]) / 10.0f) - data[2]; + mdy = (mi->precision_mval[1] + (float)(mval[1] - mi->precision_mval[1]) / 10.0f) - data[3]; + + distance = (mdx*dx + mdy*dy) / length; + } + else { + short mdx, mdy; + mdx = mval[0] - data[2]; + mdy = mval[1] - data[3]; + + distance = (mdx*dx + mdy*dy) / length; + } + + output[0] = distance / length; +} + void InputAngle(TransInfo *t, MouseInput *mi, short mval[2], float output[3]) { double dx2 = mval[0] - mi->center[0]; @@ -291,6 +332,11 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) mi->apply = InputVerticalAbsolute; t->helpline = HLP_VARROW; break; + case INPUT_CUSTOM_RATIO: + mi->apply = InputCustomRatio; + t->helpline = HLP_NONE; + mi->data = MEM_callocN(sizeof(short) * 4, "custom points"); + break; case INPUT_NONE: default: mi->apply = NULL; -- cgit v1.2.3 From 6c655aa2a762e440ba3f64ce8520c6ce41268d3e Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 21 Sep 2009 01:32:37 +0000 Subject: * Testing removing the click-region-edge-to-minimise functionality It was getting very annoying, hitting it by accident and having the region disappear. Now, you can still hide the region by resizing it down to zero, or by using the hotkeys (i.e. N, or T in the 3D View). Perhaps this minimising would be better done in a RMB menu on sub-regions (i.e. like previous Header: top/bottom/hide stuff) --- source/blender/editors/screen/screen_ops.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index ef28ff6dbd1..f4af0cd6883 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1348,9 +1348,11 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) if(event->val==0) { if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) { - ED_region_toggle_hidden(C, rmd->ar); - WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); - } + if(rmd->ar->flag & RGN_FLAG_HIDDEN) { + ED_region_toggle_hidden(C, rmd->ar); + WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); + } + } MEM_freeN(op->customdata); op->customdata = NULL; -- cgit v1.2.3 From e7abdd7d56256b57d9e33326af253188ed9d96dc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 03:16:26 +0000 Subject: Better unix filesystem integration as documented here http://wiki.blender.org/index.php/BlenderDev/Blender2.5/Unix_FHS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for scons WITH_BF_FHS enabled an alternative layout eg. scons WITH_BF_FHS=1 BF_INSTALLDIR="/usr/local" for CMake just run "make install" after make (CMAKE_INSTALL_PREFIX is used for the base path) Currently only scripts use both the system and user path correctly, other areas of blender have their own path code inline with lots of ifdefs, needs to be carefully updated. --- CMakeLists.txt | 4 + SConstruct | 59 +++++++--- config/darwin-config.py | 1 - config/irix6-config.py | 1 - config/linux2-config.py | 2 - config/linuxcross-config.py | 1 - config/openbsd3-config.py | 1 - config/sunos5-config.py | 1 - config/win32-mingw-config.py | 1 - config/win32-vc-config.py | 1 - config/win64-vc-config.py | 1 - source/blender/blenlib/BLI_util.h | 9 +- source/blender/blenlib/intern/util.c | 169 +++++++++++++++------------ source/blender/python/intern/bpy_interface.c | 99 +++++++--------- source/creator/CMakeLists.txt | 31 +++++ source/creator/SConscript | 5 + source/creator/creator.c | 24 ++++ source/gameengine/PyDoc/SConscript | 7 +- tools/Blender.py | 5 +- tools/btools.py | 8 +- 20 files changed, 270 insertions(+), 160 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c881dec03db..504ef5d8dd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,10 @@ PROJECT(Blender) SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) +# Note! - Could create this from the blender version string +# ...but thats quite involved, make sure this matches the blender version. +SET(BLENDER_VERSION 2.5) + #----------------------------------------------------------------------------- # Set default config options OPTION(WITH_PLAYER "Build Player" OFF) diff --git a/SConstruct b/SConstruct index 83ec6c1b718..402bf18faf5 100644 --- a/SConstruct +++ b/SConstruct @@ -186,6 +186,15 @@ if not env['BF_FANCY']: SetOption('num_jobs', int(env['BF_NUMJOBS'])) print "Build with %d parallel jobs" % (GetOption('num_jobs')) +# BLENDERPATH is a unix only option to enable typical style paths this is +# spesifically a data-dir, which is used a lot but cant replace BF_INSTALLDIR +# because the blender binary is installed in $BF_INSTALLDIR/bin/blender + +if env['WITH_BF_FHS']: + BLENDERPATH = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) +else: + BLENDERPATH = env['BF_INSTALLDIR'] + # disable elbeem (fluidsim) compilation? if env['BF_NO_ELBEEM'] == 1: env['CPPFLAGS'].append('-DDISABLE_ELBEEM') @@ -198,7 +207,7 @@ if env['WITH_BF_OPENMP'] == 1: env['CPPFLAGS'].append('/openmp') env['CXXFLAGS'].append('/openmp') else: - if env['CC'][-3:] == 'icc': # to be able to handle CC=/opt/bla/icc case + if env['CC'].endswith('icc'): # to be able to handle CC=/opt/bla/icc case env.Append(LINKFLAGS=['-openmp', '-static-intel']) env['CCFLAGS'].append('-openmp') env['CPPFLAGS'].append('-openmp') @@ -301,7 +310,7 @@ if env['WITH_BF_SDL'] == False and env['OURPLATFORM'] in ('win32-vc', 'win32-min # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir B.root_build_dir = env['BF_BUILDDIR'] -B.doc_build_dir = env['BF_DOCDIR'] +B.doc_build_dir = os.path.join(BLENDERPATH, 'doc') if not B.root_build_dir[-1]==os.sep: B.root_build_dir += os.sep if not B.doc_build_dir[-1]==os.sep: @@ -426,7 +435,10 @@ if env['OURPLATFORM']=='darwin': source=[dp+os.sep+f for f in df] blenderinstall.append(env.Install(dir=dir,source=source)) else: - blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list) + if env['WITH_BF_FHS']: dir= os.path.join(env['BF_INSTALLDIR'], 'bin') + else: dir= env['BF_INSTALLDIR'] + + blenderinstall = env.Install(dir=dir, source=B.program_list) #-- .blender #- dont do .blender and scripts for darwin, it is already in the bundle @@ -450,7 +462,13 @@ if env['OURPLATFORM']!='darwin': continue dotblendlist.append(os.path.join(dp, f)) - dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f) + if env['WITH_BF_FHS']: dir= os.path.join(*([BLENDERPATH] + dp.split(os.sep)[2:])) # skip bin/.blender + else: dir= os.path.join(*([BLENDERPATH] + dp.split(os.sep)[1:])) # skip bin + + # print dir+ os.sep + f + print dir + dottargetlist.append(dir + os.sep + f) + dotblenderinstall = [] for targetdir,srcfile in zip(dottargetlist, dotblendlist): @@ -464,8 +482,12 @@ if env['OURPLATFORM']!='darwin': for dp, dn, df in os.walk(scriptpath): if '.svn' in dn: dn.remove('.svn') - dir=env['BF_INSTALLDIR']+'/.blender/'+os.path.basename(scriptpath)+dp[len(scriptpath):] - source=[dp+os.sep+f for f in df] + + if env['WITH_BF_FHS']: dir = BLENDERPATH + else: dir = os.path.join(env['BF_INSTALLDIR'], '.blender') + dir += os.sep + os.path.basename(scriptpath) + dp[len(scriptpath):] + + source=[os.path.join(dp, f) for f in df] scriptinstall.append(env.Install(dir=dir,source=source)) #-- icons @@ -477,8 +499,8 @@ if env['OURPLATFORM']=='linux2': if '.svn' in tn: tn.remove('.svn') for f in tf: - iconlist.append(tp+os.sep+f) - icontargetlist.append(env['BF_INSTALLDIR']+tp[19:]+os.sep+f) + iconlist.append(os.path.join(tp, f)) + icontargetlist.append( os.path.join(*([BLENDERPATH] + tp.split(os.sep)[2:] + [f])) ) iconinstall = [] for targetdir,srcfile in zip(icontargetlist, iconlist): @@ -499,24 +521,25 @@ for tp, tn, tf in os.walk('release/plugins'): if '.svn' in tn: tn.remove('.svn') for f in tf: - pluglist.append(tp+os.sep+f) - plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f) + pluglist.append(os.path.join(tp, f)) + plugtargetlist.append( os.path.join(*([BLENDERPATH] + tp.split(os.sep)[1:] + [f])) ) + # header files for plugins pluglist.append('source/blender/blenpluginapi/documentation.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'documentation.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'documentation.h')) pluglist.append('source/blender/blenpluginapi/externdef.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'externdef.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'externdef.h')) pluglist.append('source/blender/blenpluginapi/floatpatch.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'floatpatch.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'floatpatch.h')) pluglist.append('source/blender/blenpluginapi/iff.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'iff.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'iff.h')) pluglist.append('source/blender/blenpluginapi/plugin.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'plugin.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'plugin.h')) pluglist.append('source/blender/blenpluginapi/util.h') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep +'util.h') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'util.h')) pluglist.append('source/blender/blenpluginapi/plugin.DEF') -plugtargetlist.append(env['BF_INSTALLDIR'] + os.sep + 'plugins' + os.sep + 'include' + os.sep + 'plugin.def') +plugtargetlist.append(os.path.join(BLENDERPATH, 'plugins', 'include', 'plugin.def')) plugininstall = [] for targetdir,srcfile in zip(plugtargetlist, pluglist): @@ -531,7 +554,7 @@ for tp, tn, tf in os.walk('release/text'): for f in tf: textlist.append(tp+os.sep+f) -textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist) +textinstall = env.Install(dir=BLENDERPATH, source=textlist) if env['OURPLATFORM']=='darwin': allinstall = [blenderinstall, plugininstall, textinstall] diff --git a/config/darwin-config.py b/config/darwin-config.py index 92f70d716fc..981f321e5bc 100644 --- a/config/darwin-config.py +++ b/config/darwin-config.py @@ -274,4 +274,3 @@ BF_DEBUG_CCFLAGS = ['-g'] BF_BUILDDIR='../build/darwin' BF_INSTALLDIR='../install/darwin' -BF_DOCDIR='../install/doc' diff --git a/config/irix6-config.py b/config/irix6-config.py index d38665f282a..085d1dd1e62 100644 --- a/config/irix6-config.py +++ b/config/irix6-config.py @@ -189,7 +189,6 @@ BF_DEBUG_FLAGS = '-g' BF_BUILDDIR = '../build/irix6' BF_INSTALLDIR='../install/irix6' -BF_DOCDIR='../install/doc' #Link against pthread LDIRS = [] diff --git a/config/linux2-config.py b/config/linux2-config.py index 757b8210e49..026d0a200a5 100644 --- a/config/linux2-config.py +++ b/config/linux2-config.py @@ -189,8 +189,6 @@ BF_DEBUG_CCFLAGS = ['-g'] BF_BUILDDIR = '../build/linux2' BF_INSTALLDIR='../install/linux2' -BF_DOCDIR='../install/doc' - #Link against pthread PLATFORM_LINKFLAGS = ['-pthread'] diff --git a/config/linuxcross-config.py b/config/linuxcross-config.py index a7ce2dc2908..a5c83dc3503 100644 --- a/config/linuxcross-config.py +++ b/config/linuxcross-config.py @@ -139,4 +139,3 @@ BF_PROFILE_LINKFLAGS = ['-pg'] BF_BUILDDIR = '../build/linuxcross' BF_INSTALLDIR='../install/linuxcross' -BF_DOCDIR='../install/doc' diff --git a/config/openbsd3-config.py b/config/openbsd3-config.py index 95649321c07..353d30f50b3 100644 --- a/config/openbsd3-config.py +++ b/config/openbsd3-config.py @@ -151,4 +151,3 @@ BF_DEBUG_CCFLAGS = ['-g'] BF_BUILDDIR='../build/openbsd3' BF_INSTALLDIR='../install/openbsd3' -BF_DOCDIR='../install/doc' diff --git a/config/sunos5-config.py b/config/sunos5-config.py index 8af30e4f4f3..8e4c53b5bc4 100644 --- a/config/sunos5-config.py +++ b/config/sunos5-config.py @@ -165,7 +165,6 @@ BF_DEBUG_CCFLAGS = [] BF_BUILDDIR = '../build/sunos5' BF_INSTALLDIR='../install/sunos5' -BF_DOCDIR='../install/doc' PLATFORM_LINKFLAGS = [] diff --git a/config/win32-mingw-config.py b/config/win32-mingw-config.py index e3834c41a81..04e9f5eb4d1 100644 --- a/config/win32-mingw-config.py +++ b/config/win32-mingw-config.py @@ -152,4 +152,3 @@ BF_PROFILE = False BF_BUILDDIR = '..\\build\\win32-mingw' BF_INSTALLDIR='..\\install\\win32-mingw' -BF_DOCDIR = '..\\install\\doc' diff --git a/config/win32-vc-config.py b/config/win32-vc-config.py index 1e993565e98..4f2af93d0e3 100644 --- a/config/win32-vc-config.py +++ b/config/win32-vc-config.py @@ -173,4 +173,3 @@ PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:IX86','/INCREMENTAL:NO','/N BF_BUILDDIR = '..\\build\\win32-vc' BF_INSTALLDIR='..\\install\\win32-vc' -BF_DOCDIR='..\\install\\doc' diff --git a/config/win64-vc-config.py b/config/win64-vc-config.py index ce2fd8cd405..b48e3875dd5 100644 --- a/config/win64-vc-config.py +++ b/config/win64-vc-config.py @@ -192,7 +192,6 @@ PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:X64','/INCREMENTAL:NO','/NO BF_BUILDDIR = '..\\build\\blender25-win64-vc' BF_INSTALLDIR='..\\install\\blender25-win64-vc' -BF_DOCDIR='..\\install\\blender25-win64-vc\\doc' diff --git a/source/blender/blenlib/BLI_util.h b/source/blender/blenlib/BLI_util.h index f9a84e071e7..1ce7a8cdb77 100644 --- a/source/blender/blenlib/BLI_util.h +++ b/source/blender/blenlib/BLI_util.h @@ -42,7 +42,14 @@ struct ListBase; struct direntry; char *BLI_gethome(void); -char *BLI_gethome_folder(char *folder_name); +char *BLI_gethome_folder(char *folder_name, int flag); + +/* BLI_gethome_folder flag */ +#define BLI_GETHOME_LOCAL 1<<1 /* relative location for portable binaries */ +#define BLI_GETHOME_SYSTEM 1<<2 /* system location, or set from the BLENDERPATH env variable (UNIX only) */ +#define BLI_GETHOME_USER 1<<3 /* home folder ~/.blender */ +#define BLI_GETHOME_ALL (BLI_GETHOME_SYSTEM|BLI_GETHOME_LOCAL|BLI_GETHOME_USER) + void BLI_setenv(const char *env, const char *val); void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file); diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c index c7bb7a54457..b1539d22909 100644 --- a/source/blender/blenlib/intern/util.c +++ b/source/blender/blenlib/intern/util.c @@ -856,98 +856,123 @@ char *BLI_gethome(void) { #endif } -/* this function returns the path to a blender folder, if it exists, - * trying in this order: - * - * path_to_executable/release/folder_name (in svn) - * ./release/folder_name (in svn) - * $HOME/.blender/folder_name - * path_to_executable/.blender/folder_name - * - * returns NULL if none is found. */ +/* this function returns the path to a blender folder, if it exists + * utility functions for BLI_gethome_folder */ + +/* #define PATH_DEBUG */ /* for testing paths that are checked */ + +static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name) +{ + char tmppath[FILE_MAXDIR]; + + if(path_sep) BLI_join_dirfile(tmppath, path_base, path_sep); + else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + + BLI_make_file_string("/", targetpath, tmppath, folder_name); + + if (BLI_exists(targetpath)) { +#ifdef PATH_DEBUG + printf("\tpath found: %s\n", targetpath); +#endif + return 1; + } + else { +#ifdef PATH_DEBUG + printf("\tpath missing: %s\n", targetpath); +#endif + targetpath[0] = '\0'; + return 0; + } +} -char *BLI_gethome_folder(char *folder_name) +static int gethome_path_local(char *targetpath, char *folder_name) { extern char bprogname[]; /* argv[0] from creator.c */ - static char homedir[FILE_MAXDIR] = ""; - static char fulldir[FILE_MAXDIR] = ""; - char tmpdir[FILE_MAXDIR]; char bprogdir[FILE_MAXDIR]; + char cwd[FILE_MAXDIR]; char *s; int i; - + +#ifdef PATH_DEBUG + printf("gethome_path_local...\n"); +#endif + + /* try release/folder_name (binary relative) */ /* use argv[0] (bprogname) to get the path to the executable */ s = BLI_last_slash(bprogname); - i = s - bprogname + 1; BLI_strncpy(bprogdir, bprogname, i); + + /* try ./.blender/folder_name */ + if(test_data_path(targetpath, bprogdir, ".blender", folder_name)) + return 1; + + if(test_data_path(targetpath, bprogdir, "release", folder_name)) + return 1; + + /* try release/folder_name (CWD relative) */ + if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name)) + return 1; + + return 0; +} - /* try path_to_executable/release/folder_name (in svn) */ - if (folder_name) { - BLI_snprintf(tmpdir, sizeof(tmpdir), "release/%s", folder_name); - BLI_make_file_string("/", fulldir, bprogdir, tmpdir); - if (BLI_exists(fulldir)) return fulldir; - else fulldir[0] = '\0'; - } +static int gethome_path_user(char *targetpath, char *folder_name) +{ + char *home_path= BLI_gethome(); - /* try ./release/folder_name (in svn) */ - if(folder_name) { - BLI_snprintf(fulldir, sizeof(fulldir), "./release/%s", folder_name); - if (BLI_exists(fulldir)) return fulldir; - else fulldir[0] = '\0'; - } +#ifdef PATH_DEBUG + printf("gethome_path_user...\n"); +#endif + + /* try $HOME/folder_name */ + return test_data_path(targetpath, home_path, ".blender", folder_name); +} - /* BLI_gethome() can return NULL if env vars are not set */ - s = BLI_gethome(); +static int gethome_path_system(char *targetpath, char *folder_name) +{ + extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */ + + if(!blender_path[0]) + return 0; + +#ifdef PATH_DEBUG + printf("gethome_path_system...\n"); +#endif + + /* try $BLENDERPATH/folder_name */ + return test_data_path(targetpath, blender_path, NULL, folder_name); +} - if(!s) { /* bail if no $HOME */ - printf("$HOME is NOT set\n"); - return NULL; +char *BLI_gethome_folder(char *folder_name, int flag) +{ + static char fulldir[FILE_MAXDIR] = ""; + + /* first check if this is a redistributable bundle */ + if(flag & BLI_GETHOME_LOCAL) { + if (gethome_path_local(fulldir, folder_name)) + return fulldir; } - if(strstr(s, ".blender")) - BLI_strncpy(homedir, s, FILE_MAXDIR); - else - BLI_make_file_string("/", homedir, s, ".blender"); - - /* if $HOME/.blender/folder_name exists, return it */ - if(BLI_exists(homedir)) { - if (folder_name) { - BLI_make_file_string("/", fulldir, homedir, folder_name); - if(BLI_exists(fulldir)) - return fulldir; - } - else - return homedir; - } - else - homedir[0] = '\0'; - - /* using tmpdir to preserve homedir (if) found above: - * the ideal is to have a home dir with folder_name dir inside - * it, but if that isn't available, it's possible to - * have a 'broken' home dir somewhere and a folder_name dir in the - * svn sources */ - BLI_make_file_string("/", tmpdir, bprogdir, ".blender"); - - if(BLI_exists(tmpdir)) { - if(folder_name) { - BLI_make_file_string("/", fulldir, tmpdir, folder_name); - if(BLI_exists(fulldir)) { - BLI_strncpy(homedir, tmpdir, FILE_MAXDIR); - return fulldir; - } - else { - homedir[0] = '\0'; - fulldir[0] = '\0'; - } - } - else return homedir; + /* then check if the OS has blender data files installed in a global location */ + if(flag & BLI_GETHOME_SYSTEM) { + if (gethome_path_system(fulldir, folder_name)) + return fulldir; } - + + /* now check the users home dir for data files */ + if(flag & BLI_GETHOME_USER) { + if (gethome_path_user(fulldir, folder_name)) + return fulldir; + } + return NULL; } +#ifdef PATH_DEBUG +#undef PATH_DEBUG +#endif + void BLI_setenv(const char *env, const char*val) { /* SGI or free windows */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index a850809b4a5..fd8cfc47f55 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -232,26 +232,10 @@ static PyObject *CreateGlobalDictionary( bContext *C ) return dict; } -/* Use this so we can include our own python bundle */ -#if 0 -wchar_t* Py_GetPath(void) -{ - int i; - static wchar_t py_path[FILE_MAXDIR] = L""; - char *dirname= BLI_gethome_folder("python"); - if(dirname) { - i= mbstowcs(py_path, dirname, FILE_MAXDIR); - printf("py path %s, %d\n", dirname, i); - } - return py_path; -} -#endif - - /* must be called before Py_Initialize */ void BPY_start_python_path(void) { - char *py_path_bundle= BLI_gethome_folder("python"); + char *py_path_bundle= BLI_gethome_folder("python", BLI_GETHOME_ALL); if(py_path_bundle==NULL) return; @@ -589,7 +573,8 @@ void BPY_run_ui_scripts(bContext *C, int reload) char *dirname; char path[FILE_MAX]; char *dirs[] = {"ui", "io", NULL}; - int a, err; + int path_flags[] = {BLI_GETHOME_LOCAL|BLI_GETHOME_SYSTEM, BLI_GETHOME_USER}; /* SYSTEM / NON-SYSTEM */ + int a, err, flag_iter; PyGILState_STATE gilstate; PyObject *sys_path; @@ -599,56 +584,60 @@ void BPY_run_ui_scripts(bContext *C, int reload) sys_path= PySys_GetObject("path"); /* borrow */ PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */ - for(a=0; dirs[a]; a++) { - dirname= BLI_gethome_folder(dirs[a]); + /* Scan system scripts first, then local/user */ + for(flag_iter=0; flag_iter < sizeof(path_flags)/sizeof(int); flag_iter++) { + + for(a=0; dirs[a]; a++) { + dirname= BLI_gethome_folder(dirs[a], path_flags[flag_iter]); - if(!dirname) - continue; + if(!dirname) + continue; - dir = opendir(dirname); + dir = opendir(dirname); - if(!dir) - continue; - - /* set the first dir in the sys.path for fast importing of modules */ - PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ + if(!dir) + continue; - while((de = readdir(dir)) != NULL) { - /* We could stat the file but easier just to let python - * import it and complain if theres a problem */ - err = 0; - - if (de->d_name[0] == '.') { - /* do nothing, probably .svn */ - } - else if ((file_extension = strstr(de->d_name, ".py"))) { - /* normal py files? */ - if(file_extension && file_extension[3] == '\0') { - de->d_name[(file_extension - de->d_name)] = '\0'; - err= bpy_import_module(de->d_name, reload); + /* set the first dir in the sys.path for fast importing of modules */ + PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ + + while((de = readdir(dir)) != NULL) { + /* We could stat the file but easier just to let python + * import it and complain if theres a problem */ + err = 0; + + if (de->d_name[0] == '.') { + /* do nothing, probably .svn */ + } + else if ((file_extension = strstr(de->d_name, ".py"))) { + /* normal py files? */ + if(file_extension && file_extension[3] == '\0') { + de->d_name[(file_extension - de->d_name)] = '\0'; + err= bpy_import_module(de->d_name, reload); + } } - } #ifndef __linux__ - else if( BLI_join_dirfile(path, dirname, de->d_name), S_ISDIR(BLI_exist(path))) { + else if( BLI_join_dirfile(path, dirname, de->d_name), S_ISDIR(BLI_exist(path))) { #else - else if(de->d_type==DT_DIR) { - BLI_join_dirfile(path, dirname, de->d_name); + else if(de->d_type==DT_DIR) { + BLI_join_dirfile(path, dirname, de->d_name); #endif - /* support packages */ - BLI_join_dirfile(path, path, "__init__.py"); + /* support packages */ + BLI_join_dirfile(path, path, "__init__.py"); - if(BLI_exists(path)) { - err= bpy_import_module(de->d_name, reload); + if(BLI_exists(path)) { + err= bpy_import_module(de->d_name, reload); + } } - } - if(err==-1) { - BPy_errors_to_report(NULL); - fprintf(stderr, "unable to import %s/%s\n", dirname, de->d_name); + if(err==-1) { + BPy_errors_to_report(NULL); + fprintf(stderr, "unable to import %s/%s\n", dirname, de->d_name); + } } - } - closedir(dir); + closedir(dir); + } } PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */ diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 1256881182b..410e0808580 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -66,6 +66,13 @@ IF(NOT WITH_SDL) ADD_DEFINITIONS(-DDISABLE_SDL) ENDIF(NOT WITH_SDL) +IF(UNIX AND NOT APPLE) + SET(BLENDERPATH ${CMAKE_INSTALL_PREFIX}/share/blender/${BLENDER_VERSION}) + CMAKE_POLICY(SET CMP0005 NEW) + # blender_path in creator.c + ADD_DEFINITIONS(-DBLENDERPATH="${BLENDERPATH}") +ENDIF(UNIX AND NOT APPLE) + IF(CMAKE_SYSTEM_NAME MATCHES "Linux") ADD_DEFINITIONS(-DWITH_BINRELOC) INCLUDE_DIRECTORIES(${BINRELOC_INC}) @@ -96,6 +103,9 @@ IF(WITH_INSTALL) ENDIF(UNIX) IF(UNIX AND NOT APPLE) + + # Local installation, "make install" can be done after this optionally + ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender COMMAND rm -Rf ${TARGETDIR}/.blender @@ -152,6 +162,27 @@ IF(WITH_INSTALL) COMMAND find ${TARGETDIR} -name .svn -prune -exec rm -rf {} "\;" ) + + # Above we bundle a portable distrobution in ./bin + # This is an optional "make install" which installs blender on the system. + INSTALL( + PROGRAMS ${TARGETDIR}/blender + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ) + + IF(WITH_GAMEENGINE AND WITH_PLAYER) + INSTALL( + PROGRAMS ${TARGETDIR}/blenderplayer + DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + ) + ENDIF(WITH_GAMEENGINE AND WITH_PLAYER) + + INSTALL( + DIRECTORY ${TARGETDIR}/.blender/ + DESTINATION ${BLENDERPATH} + ) + # end "make install" + ENDIF(UNIX AND NOT APPLE) IF(APPLE) diff --git a/source/creator/SConscript b/source/creator/SConscript index 75e7494ebb5..7b3d1493ed2 100644 --- a/source/creator/SConscript +++ b/source/creator/SConscript @@ -1,5 +1,6 @@ #!/usr/bin/python Import ('env') +import os sources = 'creator.c' @@ -32,4 +33,8 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_FHS']: # /usr -> /usr/share/blender/2.5 + defs.append('BLENDERPATH=\\"' + os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) + '\\"') + + env.BlenderLib ( libname = 'bf_creator', sources = Split(sources), includes = Split(incs), defines = defs, libtype='core', priority = 0 ) diff --git a/source/creator/creator.c b/source/creator/creator.c index 41b27b1c915..523273de9bf 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -116,6 +116,18 @@ extern int pluginapi_force_ref(void); /* from blenpluginapi:pluginapi.c */ char bprogname[FILE_MAXDIR+FILE_MAXFILE]; /* from blenpluginapi:pluginapi.c */ char btempdir[FILE_MAXDIR+FILE_MAXFILE]; +/* unix path support. + * defined by the compiler. eg "/usr/share/blender/2.5" "/opt/blender/2.5" */ +#ifndef BLENDERPATH +#define BLENDERPATH "" +#endif + +#if !(defined(__APPLE__) && defined(WIN32)) +char blender_path[FILE_MAXDIR+FILE_MAXFILE] = BLENDERPATH; +#else +char blender_path[FILE_MAXDIR+FILE_MAXFILE] = ""; +#endif + /* Initialise callbacks for the modules that need them */ static void setCallbacks(void); @@ -221,6 +233,12 @@ static void print_help(void) printf (" \t\t passed unchanged. Access via Python's sys.argv\n"); printf ("\nEnvironment Variables:\n"); printf (" $HOME\t\t\tStore files such as .blender/ .B.blend .Bfs .Blog here.\n"); +#if !(defined(__APPLE__) && defined(WIN32)) + printf (" $BLENDERPATH\tSystem directory to use for data files and scripts.\n"); + printf (" \tFor this build of blender the default BLENDERPATH is...\n"); + printf (" \t\"%s\"\n", blender_path); + printf (" \tseting the $BLENDERPATH will override this\n"); +#endif #ifdef WIN32 printf (" $TEMP\t\tStore temporary files here.\n"); #else @@ -305,6 +323,12 @@ int main(int argc, char **argv) BLI_where_am_i(bprogname, argv[0]); + { /* override the hard coded blender path */ + char *blender_path_env = getenv("BLENDERPATH"); + if(blender_path_env) + BLI_strncpy(blender_path, blender_path_env, sizeof(blender_path)); + } + RNA_init(); RE_engines_init(); diff --git a/source/gameengine/PyDoc/SConscript b/source/gameengine/PyDoc/SConscript index ed9712ba273..dabe004ae6a 100644 --- a/source/gameengine/PyDoc/SConscript +++ b/source/gameengine/PyDoc/SConscript @@ -1,6 +1,11 @@ #!/usr/bin/python Import ('env') +import os +if env['WITH_BF_FHS']: + BLENDERPATH = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) +else: + BLENDERPATH = env['BF_INSTALLDIR'] from optparse import OptionParser import epydoc @@ -14,7 +19,7 @@ optvalues["quiet"] = 0 optvalues["include_source_code"] = 0 optvalues["inheritance"] = "included" optvalues["show_private"] = 0 -optvalues["target"] = env["BF_DOCDIR"]+"/BGE_API/" +optvalues["target"] = os.path.join(BLENDERPATH, 'doc') optvalues["url"] = "http://www.blender.org" optvalues["top"] = "Game Engine API" optvalues["name"] = "Blender" diff --git a/tools/Blender.py b/tools/Blender.py index d7cbe1076e7..fd6272c7c32 100644 --- a/tools/Blender.py +++ b/tools/Blender.py @@ -405,8 +405,11 @@ def PyInstall(target=None, source=None, env=None): print 'Install command:', cmd commands.getoutput(cmd) + if env['WITH_BF_FHS']: dir = os.path.join(env['BF_INSTALLDIR'], 'share', 'blender', env['BF_VERSION']) # BLENDERPATH + else: dir = os.path.join(env['BF_INSTALLDIR'], '.blender') + py_src = env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] ) - py_target = env.subst( env['BF_INSTALLDIR'] + '/.blender/python/lib/python'+env['BF_PYTHON_VERSION'] ) + py_target = env.subst( dir + '/python/lib/python'+env['BF_PYTHON_VERSION'] ) # Copied from source/creator/CMakeLists.txt, keep in sync. print 'Install python from:' diff --git a/tools/btools.py b/tools/btools.py index 7cadab992b8..771c67aee1f 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -69,6 +69,8 @@ def validate_arguments(args, bc): 'WITH_BF_DOCS', 'BF_NUMJOBS', 'BF_MSVS', + 'WITH_BF_FHS', + 'BF_VERSION', ] # Have options here that scons expects to be lists @@ -91,7 +93,7 @@ def validate_arguments(args, bc): 'BF_BSC', 'BF_CONFIG', 'BF_PRIORITYLIST', 'BF_BUILDINFO','CC', 'CXX', 'BF_QUICKDEBUG', 'BF_LISTDEBUG', 'LCGDIR', 'BF_X264_CONFIG', 'BF_XVIDCORE_CONFIG', - 'BF_DOCDIR', 'BF_UNIT_TEST'] + 'BF_UNIT_TEST'] okdict = {} @@ -362,7 +364,6 @@ def read_opts(cfg, args): ('BF_BUILDDIR', 'Build dir', ''), ('BF_INSTALLDIR', 'Installation dir', ''), - ('BF_DOCDIR', 'Dir where BPy documentation will be created', ''), ('CC', 'C compiler to use', ''), ('CXX', 'C++ compiler to use', ''), @@ -387,6 +388,9 @@ def read_opts(cfg, args): ('BF_CONFIG', 'SCons python config file used to set default options', 'user_config.py'), ('BF_NUMJOBS', 'Number of build processes to spawn', '1'), ('BF_MSVS', 'Generate MSVS project files and solution', False), + + (BoolVariable('WITH_BF_FHS', 'Use the Unix "Filesystem Hierarchy Standard" rather then a redistributable directory layout', False)), + ('BF_VERSION', 'The root path for Unix (non-apple)', '2.5'), (BoolVariable('BF_UNIT_TEST', 'Build with unit test support.', False)) -- cgit v1.2.3 From ad7fab49d4346315cdb3db4bd087714ae45ffc89 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 05:56:43 +0000 Subject: 5 button mouse support from b333rt in IRC with some edits for X11. Tested in X11 where its fairly confusing. buttons 4 and 5 are used for the wheel which is well known, but it seems 6 and 7 are used for horizontal scrolling, my mouse assigns the extra 2 buttons to events 8 & 9. So the X11 events used for buttons called 4&5 in blender are 8&9 in X11. The mouse buttons can be re-ordered like this once xorg starts (swaps 6,7 with 8,9) xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" Couldn't test Win32, Apple not supported. If someone wants to add horizontal scrolling its quite easy. --- intern/ghost/GHOST_Types.h | 2 ++ intern/ghost/intern/GHOST_SystemWin32.cpp | 34 +++++++++++++++++++++- intern/ghost/intern/GHOST_SystemX11.cpp | 7 ++++- source/blender/editors/space_outliner/outliner.c | 4 +++ source/blender/makesrna/intern/rna_wm.c | 2 ++ .../blender/windowmanager/intern/wm_event_system.c | 4 +++ source/blender/windowmanager/wm_event_types.h | 3 ++ 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 73ed0bdd1fa..31819f341a0 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -132,6 +132,8 @@ typedef enum { GHOST_kButtonMaskLeft = 0, GHOST_kButtonMaskMiddle, GHOST_kButtonMaskRight, + GHOST_kButtonMaskButton4, + GHOST_kButtonMaskButton5, GHOST_kButtonNumMasks } GHOST_TButtonMask; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 8513d056795..2e89be40bcb 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -39,7 +39,6 @@ #endif #include "GHOST_SystemWin32.h" -//#include //for printf() // win64 doesn't define GWL_USERDATA #ifdef WIN32 @@ -61,6 +60,23 @@ #define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */ #endif // WHEEL_DELTA +/* + * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2. + * MSDN: Declared in Winuser.h, include Windows.h + * This does not seem to work with MinGW so we define our own here. + */ +#ifndef XBUTTON1 +#define XBUTTON1 0x0001 +#endif // XBUTTON1 +#ifndef XBUTTON2 +#define XBUTTON2 0x0002 +#endif // XBUTTON2 +#ifndef WM_XBUTTONUP +#define WM_XBUTTONUP 524 +#endif // WM_XBUTTONUP +#ifndef WM_XBUTTONDOWN +#define WM_XBUTTONDOWN 523 +#endif // WM_XBUTTONDOWN #include "GHOST_Debug.h" #include "GHOST_DisplayManagerWin32.h" @@ -672,6 +688,14 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, window->registerMouseClickEvent(true); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); break; + case WM_XBUTTONDOWN: + window->registerMouseClickEvent(true); + if ((short) HIWORD(wParam) == XBUTTON1){ + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4); + }else if((short) HIWORD(wParam) == XBUTTON2){ + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5); + } + break; case WM_LBUTTONUP: window->registerMouseClickEvent(false); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); @@ -684,6 +708,14 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, window->registerMouseClickEvent(false); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); break; + case WM_XBUTTONUP: + window->registerMouseClickEvent(false); + if ((short) HIWORD(wParam) == XBUTTON1){ + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); + }else if((short) HIWORD(wParam) == XBUTTON2){ + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); + } + break; case WM_MOUSEMOVE: event = processCursorEvent(GHOST_kEventCursorMove, window); break; diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 9f6f3b4d5b0..cdbdce9c2ca 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -444,10 +444,15 @@ GHOST_SystemX11::processEvent(XEvent *xe) XButtonEvent & xbe = xe->xbutton; GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft; - switch (xbe.button) { case Button1 : gbmask = GHOST_kButtonMaskLeft; break; case Button3 : gbmask = GHOST_kButtonMaskRight; break; + /* It seems events 6 and 7 are for horizontal scrolling. + * you can re-order button mapping like this... (swaps 6,7 with 8,9) + * xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7" + */ + case 8 : gbmask = GHOST_kButtonMaskButton4; break; /* Button4 is the wheel */ + case 9 : gbmask = GHOST_kButtonMaskButton5; break; /* Button5 is a wheel too */ default: case Button2 : gbmask = GHOST_kButtonMaskMiddle; break; } diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index a3b47d505fd..a1fdbab9ccc 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -5049,6 +5049,8 @@ static char *keymap_mouse_menu(void) str += sprintf(str, formatstr, "Left Mouse", LEFTMOUSE); str += sprintf(str, formatstr, "Middle Mouse", MIDDLEMOUSE); str += sprintf(str, formatstr, "Right Mouse", RIGHTMOUSE); + str += sprintf(str, formatstr, "Button4 Mouse ", BUTTON4MOUSE); + str += sprintf(str, formatstr, "Button5 Mouse ", BUTTON5MOUSE); str += sprintf(str, formatstr, "Action Mouse", ACTIONMOUSE); str += sprintf(str, formatstr, "Select Mouse", SELECTMOUSE); str += sprintf(str, formatstr, "Mouse Move", MOUSEMOVE); @@ -5071,6 +5073,8 @@ static char *keymap_tweak_menu(void) str += sprintf(str, formatstr, "Left Mouse", EVT_TWEAK_L); str += sprintf(str, formatstr, "Middle Mouse", EVT_TWEAK_M); str += sprintf(str, formatstr, "Right Mouse", EVT_TWEAK_R); + str += sprintf(str, formatstr, "Button4 Mouse ", BUTTON4MOUSE); + str += sprintf(str, formatstr, "Button5 Mouse ", BUTTON5MOUSE); str += sprintf(str, formatstr, "Action Mouse", EVT_TWEAK_A); str += sprintf(str, formatstr, "Select Mouse", EVT_TWEAK_S); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index fff51ad8ade..0dd9e3aed42 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -46,6 +46,8 @@ EnumPropertyItem event_type_items[] = { {LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", ""}, {MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", ""}, {RIGHTMOUSE, "RIGHTMOUSE", 0, "Right Mouse", ""}, + {BUTTON4MOUSE, "BUTTON4MOUSE", 0, "Button4 Mouse", ""}, + {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", ""}, {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action Mouse", ""}, {SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", ""}, diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 40026d27bac..ebb7adc3cd5 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1579,6 +1579,10 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) event.type= LEFTMOUSE; else if (bd->button == GHOST_kButtonMaskRight) event.type= RIGHTMOUSE; + else if (bd->button == GHOST_kButtonMaskButton4) + event.type= BUTTON4MOUSE; + else if (bd->button == GHOST_kButtonMaskButton5) + event.type= BUTTON5MOUSE; else event.type= MIDDLEMOUSE; diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index b331e036b9e..898c6358f3a 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -56,6 +56,9 @@ /* only use if you want user option switch possible */ #define ACTIONMOUSE 0x005 #define SELECTMOUSE 0x006 +/* Extra mouse buttons */ +#define BUTTON4MOUSE 0x007 +#define BUTTON5MOUSE 0x008 /* defaults from ghost */ #define WHEELUPMOUSE 0x00a #define WHEELDOWNMOUSE 0x00b -- cgit v1.2.3 From fcab32fa206838caf1c45c0cdf5facc65e2d6918 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 21 Sep 2009 06:43:20 +0000 Subject: * Added AnimData for Armature data, for animating armature/bone settings. This allows you to do funky things like animating the number of segments in a b-bone. --- source/blender/blenkernel/intern/anim_sys.c | 5 +- source/blender/blenloader/intern/readfile.c | 16 +++-- source/blender/blenloader/intern/writefile.c | 2 + .../editors/animation/anim_channels_defines.c | 71 ++++++++++++++++++++++ source/blender/editors/animation/anim_filter.c | 45 ++++++++++++++ source/blender/editors/include/ED_anim_api.h | 2 + source/blender/makesdna/DNA_action_types.h | 1 + source/blender/makesdna/DNA_armature_types.h | 6 +- source/blender/makesrna/intern/rna_armature.c | 9 ++- 9 files changed, 145 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 8b761a2ee0e..af4bcd8b0f7 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -72,7 +72,7 @@ static short id_has_animdata (ID *id) switch (GS(id->name)) { /* has AnimData */ case ID_OB: - case ID_MB: case ID_CU: + case ID_MB: case ID_CU: case ID_AR: case ID_KE: case ID_PA: case ID_MA: case ID_TE: case ID_NT: @@ -1525,6 +1525,9 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); } + /* armatures */ + EVAL_ANIM_IDS(main->armature.first, ADT_RECALC_ANIM); + /* meshes */ // TODO... diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 78949d8bd8c..af7fda82fe4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2331,6 +2331,7 @@ static void lib_link_armature(FileData *fd, Main *main) while(arm) { if(arm->id.flag & LIB_NEEDLINK) { + if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt); arm->id.flag -= LIB_NEEDLINK; } arm= arm->id.next; @@ -2357,6 +2358,7 @@ static void direct_link_armature(FileData *fd, bArmature *arm) link_list(fd, &arm->bonebase); arm->edbo= NULL; arm->sketch = NULL; + arm->adt= newdataadr(fd, arm->adt); bone=arm->bonebase.first; while (bone) { @@ -9697,15 +9699,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) sce->unit.scale_length= 1.0f; for(ob = main->object.first; ob; ob = ob->id.next) { - ModifierData *md; - - /* add backwards pointer for fluidsim modifier RNA access */ - for (md=ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Fluidsim) { - FluidsimModifierData *fluidmd= (FluidsimModifierData*) md; - fluidmd->fss->fmd = fluidmd; - } - } + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + if (fluidmd) fluidmd->fss->fmd = fluidmd; } for(sce= main->scene.first; sce; sce= sce->id.next) @@ -10434,6 +10429,9 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) { Bone *curBone; + if(arm->adt) + expand_animdata(fd, mainvar, arm->adt); + for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) { expand_bones(fd, mainvar, curBone); } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 98db27182ab..37d0ee58bb2 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2116,6 +2116,8 @@ static void write_armatures(WriteData *wd, ListBase *idbase) writestruct(wd, ID_AR, "bArmature", 1, arm); if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd); + if (arm->adt) write_animdata(wd, arm->adt); + /* Direct data */ bone= arm->bonebase.first; while(bone) { diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index e3418fa194f..7f0f2411bd0 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -1526,6 +1526,76 @@ static bAnimChannelType ACF_DSMBALL= acf_dsmball_setting_ptr /* pointer for setting */ }; +/* Armature Expander ------------------------------------------- */ + +// TODO: just get this from RNA? +static int acf_dsarm_icon(bAnimListElem *ale) +{ + return ICON_ARMATURE_DATA; +} + +/* get the appropriate flag(s) for the setting when it is valid */ +static int acf_dsarm_setting_flag(int setting, short *neg) +{ + /* clear extra return data first */ + *neg= 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return ARM_DS_EXPAND; + + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; + + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg= 1; + return ADT_CURVES_NOT_VISIBLE; + + default: /* unsupported */ + return 0; + } +} + +/* get pointer to the setting */ +static void *acf_dsarm_setting_ptr(bAnimListElem *ale, int setting, short *type) +{ + bArmature *arm= (bArmature *)ale->data; + + /* clear extra return data first */ + *type= 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + GET_ACF_FLAG_PTR(arm->flag); + + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (arm->adt) + GET_ACF_FLAG_PTR(arm->adt->flag) + else + return NULL; + + default: /* unsupported */ + return NULL; + } +} + +/* metaball expander type define */ +static bAnimChannelType ACF_DSARM= +{ + acf_generic_dataexpand_backdrop,/* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_dsarm_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsarm_setting_flag, /* flag for setting */ + acf_dsarm_setting_ptr /* pointer for setting */ +}; + + /* ShapeKey Entry ------------------------------------------- */ // XXX ... this is currently obsolete... @@ -1709,6 +1779,7 @@ void ANIM_init_channel_typeinfo_data (void) animchannelTypeInfo[type++]= &ACF_DSWOR; /* World Channel */ animchannelTypeInfo[type++]= &ACF_DSPART; /* Particle Channel */ animchannelTypeInfo[type++]= &ACF_DSMBALL; /* MetaBall Channel */ + animchannelTypeInfo[type++]= &ACF_DSARM; /* Armature Channel */ animchannelTypeInfo[type++]= NULL; /* ShapeKey */ // XXX this is no longer used for now... diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 55fb1ccace0..38b702f81e0 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -52,6 +52,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_action_types.h" +#include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_camera_types.h" #include "DNA_curve_types.h" @@ -1101,6 +1102,14 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad expanded= FILTER_MBALL_OBJD(mb); } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + + type= ANIMTYPE_DSARM; + expanded= FILTER_ARM_OBJD(arm); + } + break; } /* special exception for drivers instead of action */ @@ -1297,6 +1306,19 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B } } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + + if ((ads->filterflag & ADS_FILTER_NOARM) == 0) { + ANIMDATA_FILTER_CASES(arm, + { /* AnimData blocks - do nothing... */ }, + obdata_ok= 1;, + obdata_ok= 1;, + obdata_ok= 1;) + } + } + break; } if (obdata_ok) items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); @@ -1652,6 +1674,23 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);) } break; + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + dataOk= 0; + ANIMDATA_FILTER_CASES(arm, + if ((ads->filterflag & ADS_FILTER_NOARM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(arm); + dataOk=0; + }, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOARM);) + } + break; default: /* --- other --- */ dataOk= 0; break; @@ -1734,6 +1773,12 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int dataOk= ANIMDATA_HAS_KEYS(mb); } break; + case OB_ARMATURE: /* -------- Armature ---------- */ + { + bArmature *arm= (bArmature *)ob->data; + dataOk= ANIMDATA_HAS_KEYS(arm); + } + break; default: /* --- other --- */ dataOk= 0; break; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 799829a6e87..7e7aba85363 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -137,6 +137,7 @@ typedef enum eAnim_ChannelType { ANIMTYPE_DSWOR, ANIMTYPE_DSPART, ANIMTYPE_DSMBALL, + ANIMTYPE_DSARM, ANIMTYPE_SHAPEKEY, // XXX probably can become depreceated??? @@ -206,6 +207,7 @@ typedef enum eAnimFilter_Flags { #define FILTER_CUR_OBJD(cu) ((cu->flag & CU_DS_EXPAND)) #define FILTER_PART_OBJD(part) ((part->flag & PART_DS_EXPAND)) #define FILTER_MBALL_OBJD(mb) ((mb->flag2 & MB_DS_EXPAND)) +#define FILTER_ARM_OBJD(arm) ((arm->flag & ARM_DS_EXPAND)) /* 'Sub-object/Action' channels (flags stored in Action) */ #define SEL_ACTC(actc) ((actc->flag & ACT_SELECTED)) #define EXPANDED_ACTC(actc) ((actc->flag & ACT_COLLAPSED)==0) diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 318204e3dd8..42696eeb092 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -372,6 +372,7 @@ typedef enum DOPESHEET_FILTERFLAG { ADS_FILTER_NOSCE = (1<<15), ADS_FILTER_NOPART = (1<<16), ADS_FILTER_NOMBA = (1<<17), + ADS_FILTER_NOARM = (1<<18), /* NLA-specific filters */ ADS_FILTER_NLA_NOACT = (1<<20), /* if the AnimData block has no NLA data, don't include to just show Action-line */ diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index bb60fb107ff..590e7dadcdc 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -31,6 +31,8 @@ #include "DNA_listBase.h" #include "DNA_ID.h" +struct AnimData; + /* this system works on different transformation space levels; 1) Bone Space; with each Bone having own (0,0,0) origin @@ -69,6 +71,7 @@ typedef struct Bone { typedef struct bArmature { ID id; + struct AnimData *adt; ListBase bonebase; ListBase chainbase; ListBase *edbo; /* editbone listbase, we use pointer so we can check state */ @@ -102,7 +105,8 @@ typedef enum eArmature_Flag { ARM_AUTO_IK = (1<<9), ARM_NO_CUSTOM = (1<<10), /* made option negative, for backwards compat */ ARM_COL_CUSTOM = (1<<11), /* draw custom colours */ - ARM_GHOST_ONLYSEL = (1<<12) /* when ghosting, only show selected bones (this should belong to ghostflag instead) */ + ARM_GHOST_ONLYSEL = (1<<12), /* when ghosting, only show selected bones (this should belong to ghostflag instead) */ + ARM_DS_EXPAND = (1<<13) } eArmature_Flag; /* armature->drawtype */ diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index d06c8ccee03..379ec208bc1 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -62,6 +62,11 @@ static void rna_Armature_redraw_data(bContext *C, PointerRNA *ptr) WM_event_add_notifier(C, NC_GEOM|ND_DATA, id); } +static char *rna_Bone_path(PointerRNA *ptr) +{ + return BLI_sprintfN("bones[\"%s\"]", ((Bone*)ptr->data)->name); +} + static void rna_bone_layer_set(short *layer, const int *values) { int i, tot= 0; @@ -431,6 +436,7 @@ static void rna_def_bone(BlenderRNA *brna) srna= RNA_def_struct(brna, "Bone", NULL); RNA_def_struct_ui_text(srna, "Bone", "Bone in an Armature datablock."); RNA_def_struct_ui_icon(srna, ICON_BONE_DATA); + RNA_def_struct_path_func(srna, "rna_Bone_path"); /* pointers/collections */ /* parent (pointer) */ @@ -553,9 +559,10 @@ static void rna_def_armature(BlenderRNA *brna) srna= RNA_def_struct(brna, "Armature", "ID"); RNA_def_struct_ui_text(srna, "Armature", "Armature datablock containing a hierarchy of bones, usually used for rigging characters."); RNA_def_struct_ui_icon(srna, ICON_ARMATURE_DATA); - RNA_def_struct_sdna(srna, "bArmature"); + rna_def_animdata_common(srna); + /* Collections */ prop= RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "bonebase", NULL); -- cgit v1.2.3 From e2e0a864a8c46f4ed836ea7e8fa292276a2137b2 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Mon, 21 Sep 2009 07:25:48 +0000 Subject: * Added Armature data filter buttons in Dopesheet/Graph editor headers * Fixed an RNA typo to fix ranges in action constraint --- .../blender/editors/space_action/action_header.c | 1 + source/blender/editors/space_graph/graph_header.c | 1 + source/blender/makesrna/intern/rna_constraint.c | 22 ++++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index 4cb02f3f233..dd02302af9c 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -349,6 +349,7 @@ void action_header_buttons(const bContext *C, ARegion *ar) uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Cameras"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Curves"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display MetaBalls"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Armature/Bone"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Particles"); uiBlockEndAlign(block); xco += 30; diff --git a/source/blender/editors/space_graph/graph_header.c b/source/blender/editors/space_graph/graph_header.c index dd304cd8cf3..79d38d9c252 100644 --- a/source/blender/editors/space_graph/graph_header.c +++ b/source/blender/editors/space_graph/graph_header.c @@ -313,6 +313,7 @@ void graph_header_buttons(const bContext *C, ARegion *ar) uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Curves"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display MetaBalls"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Armature/Bone data"); uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Particles"); uiBlockEndAlign(block); xco += 30; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 04d56eb666e..1bbac8da02f 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -253,6 +253,22 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *C, PointerR return space_object_items; } +static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max) +{ + bConstraint *con= (bConstraint*)ptr->data; + bActionConstraint *acon = (bActionConstraint *)con->data; + + /* 0, 1, 2 = magic numbers for rotX, rotY, rotZ */ + if (ELEM3(acon->type, 0, 1, 2)) { + *min= -90.f; + *max= 90.f; + } else { + *min= -1000.f; + *max= 1000.f; + } +} + + #else static void rna_def_constrainttarget(BlenderRNA *brna) @@ -781,15 +797,17 @@ static void rna_def_constraint_action(BlenderRNA *brna) prop= RNA_def_property(srna, "maximum", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); - RNA_def_property_range(prop, 0.0, 1000.f); + RNA_def_property_range(prop, -1000.f, 1000.f); RNA_def_property_ui_text(prop, "Maximum", "Maximum value for target channel range."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); prop= RNA_def_property(srna, "minimum", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); - RNA_def_property_range(prop, 0.0, 1000.f); + RNA_def_property_range(prop, -1000.f, 1000.f); RNA_def_property_ui_text(prop, "Minimum", "Minimum value for target channel range."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); } static void rna_def_constraint_locked_track(BlenderRNA *brna) -- cgit v1.2.3 From 2379af27d10e21c5d471884ee2f78fba62f8534c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 09:17:14 +0000 Subject: tested running the cheat-sheet, found a number of segfaults pressing escape in the outliner was also crashing (somehow it tried to exit the file selector) --- source/blender/editors/space_buttons/buttons_ops.c | 24 ++++++++++++++-------- source/blender/editors/space_file/file_ops.c | 2 +- source/blender/editors/space_image/space_image.c | 2 +- .../editors/transform/transform_conversions.c | 12 +++++------ .../editors/transform/transform_orientations.c | 3 ++- source/blender/editors/uvedit/uvedit_ops.c | 20 ++++++++++++------ .../blender/windowmanager/intern/wm_event_system.c | 4 ++-- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 5466a06550b..4387da19341 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -738,9 +738,9 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot) static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - ParticleData *pa = psys->particles; - PTCacheEdit *edit = psys->edit; - PTCacheEditPoint *point = edit ? edit->points : NULL; + ParticleData *pa; + PTCacheEdit *edit; + PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; int i, k; @@ -751,8 +751,11 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys->part || psys->part->type != PART_HAIR) return; + + edit = psys->edit; + point= edit ? edit->points : NULL; - for(i=0; itotpart; i++,pa++) { + for(i=0, pa=psys->particles; itotpart; i++,pa++) { if(point) { ekey = point->keys; point++; @@ -820,9 +823,9 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot) static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - ParticleData *pa = psys->particles; - PTCacheEdit *edit = psys->edit; - PTCacheEditPoint *point = edit ? edit->points : NULL; + ParticleData *pa; + PTCacheEdit *edit; + PTCacheEditPoint *point; PTCacheEditKey *ekey; HairKey *key; BVHTreeFromMesh bvhtree; @@ -836,7 +839,10 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(!psys || !psys->part || psys->part->type != PART_HAIR) return; - + + edit= psys->edit; + point= edit ? edit->points : NULL; + if(psmd->dm->deformedOnly) dm= psmd->dm; else @@ -852,7 +858,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); - for(i=0; itotpart; i++,pa++) { + for(i=0, pa= psys->particles; itotpart; i++,pa++) { key = pa->hair; nearest.index = -1; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 70d8de7d509..7839cf5bf4b 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -532,7 +532,7 @@ int file_operator_poll(bContext *C) int poll = ED_operator_file_active(C); SpaceFile *sfile= CTX_wm_space_file(C); - if (!sfile->op) poll= 0; + if (!sfile || !sfile->op) poll= 0; return poll; } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index f222499ba86..f041cb00ee4 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -623,7 +623,7 @@ ImBuf *ED_space_image_buffer(SpaceImage *sima) { ImBuf *ibuf; - if(sima->image) { + if(sima && sima->image) { #if 0 if(sima->image->type==IMA_TYPE_R_RESULT && BIF_show_render_spare()) return BIF_render_spare_imbuf(); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index e59ec3746e3..64151918a47 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4262,7 +4262,7 @@ static void ObjectToTransData(bContext *C, TransInfo *t, TransData *td, Object * /* it deselects Bases, so we have to call the clear function always after */ static void set_trans_object_base_flags(bContext *C, TransInfo *t) { - Scene *sce = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); View3D *v3d = t->view; /* @@ -4279,15 +4279,15 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t) copy_baseflags(t->scene); /* handle pending update events, otherwise they got copied below */ - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { if(base->object->recalc) object_handle_update(t->scene, base->object); } - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { base->flag &= ~BA_WAS_SEL; - if(TESTBASELIB(v3d, base)) { + if(TESTBASELIB_BGMODE(v3d, base)) { Object *ob= base->object; Object *parsel= ob->parent; @@ -4319,7 +4319,7 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t) /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base= sce->base.first; base; base= base->next) { + for (base= scene->base.first; base; base= base->next) { if(base->object->recalc & OB_RECALC_OB) base->flag |= BA_HAS_RECALC_OB; if(base->object->recalc & OB_RECALC_DATA) @@ -5319,7 +5319,7 @@ void createTransData(bContext *C, TransInfo *t) { View3D *v3d = t->view; RegionView3D *rv3d = CTX_wm_region_view3d(C); - if((t->flag & T_OBJECT) && v3d->camera == OBACT && rv3d->persp==V3D_CAMOB) + if(rv3d && (t->flag & T_OBJECT) && v3d->camera == OBACT && rv3d->persp==V3D_CAMOB) { t->flag |= T_CAMERA; } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 9416425704f..d82be842596 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -353,7 +353,8 @@ void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) { void BIF_selectTransformOrientationValue(bContext *C, int orientation) { View3D *v3d = CTX_wm_view3d(C); - v3d->twmode = orientation; + if(v3d) /* currently using generic poll */ + v3d->twmode = orientation; } EnumPropertyItem *BIF_enumTransformOrientation(bContext *C) diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 611eee00d79..5597c624e23 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1439,7 +1439,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) else { sync= 0; selectmode= ts->uv_selectmode; - sticky= sima->sticky; + sticky= sima ? sima->sticky : 1; } /* find nearest element */ @@ -2471,13 +2471,18 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - Image *ima= sima->image; + Image *ima; EditFace *efa; MTFace *tface; int width= 0, height= 0; float w, h; short change = 0; + if(!sima) + return 0; + + ima= sima->image; + ED_space_image_size(sima, &width, &height); w = (float)width; h = (float)height; @@ -2657,6 +2662,7 @@ static int hide_exec(bContext *C, wmOperator *op) EditFace *efa; MTFace *tf; int swap= RNA_boolean_get(op->ptr, "unselected"); + int facemode= sima ? sima->flag & SI_SELACTFACE : 0; if(ts->uv_flag & UV_SYNC_SELECTION) { EM_hide_mesh(em, swap); @@ -2670,7 +2676,7 @@ static int hide_exec(bContext *C, wmOperator *op) for(efa= em->faces.first; efa; efa= efa->next) { if(efa->f & SELECT) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(sima->flag & SI_SELACTFACE) { + if(facemode) { /* Pretend face mode */ if(( (efa->v4==NULL && ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || @@ -2715,7 +2721,7 @@ static int hide_exec(bContext *C, wmOperator *op) if(efa->f & SELECT) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(sima->flag & SI_SELACTFACE) { + if(facemode) { if( (efa->v4==NULL && ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) { @@ -2799,6 +2805,8 @@ static int reveal_exec(bContext *C, wmOperator *op) EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); EditFace *efa; MTFace *tf; + int facemode= sima ? sima->flag & SI_SELACTFACE : 0; + int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; /* call the mesh function if we are in mesh sync sel */ if(ts->uv_flag & UV_SYNC_SELECTION) { @@ -2809,7 +2817,7 @@ static int reveal_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } - if(sima->flag & SI_SELACTFACE) { + if(facemode) { if(em->selectmode == SCE_SELECT_FACE) { for(efa= em->faces.first; efa; efa= efa->next) { if(!(efa->h) && !(efa->f & SELECT)) { @@ -2821,7 +2829,7 @@ static int reveal_exec(bContext *C, wmOperator *op) } else { /* enable adjacent faces to have disconnected UV selections if sticky is disabled */ - if(sima->sticky == SI_STICKY_DISABLE) { + if(!stickymode) { for(efa= em->faces.first; efa; efa= efa->next) { if(!(efa->h) && !(efa->f & SELECT)) { /* All verts must be unselected for the face to be selected in the UV view */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index ebb7adc3cd5..6b07e384f66 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1231,7 +1231,7 @@ void wm_event_do_handlers(bContext *C) /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? doing it on ghost queue gives errors when mousemoves go over area borders */ - if(doit && win->screen->subwinactive != win->screen->mainwin) { + if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) { win->eventstate->prevx= event->x; win->eventstate->prevy= event->y; } @@ -1244,7 +1244,7 @@ void wm_event_do_handlers(bContext *C) } /* only add mousemove when queue was read entirely */ - if(win->addmousemove) { + if(win->addmousemove && win->eventstate) { wmEvent event= *(win->eventstate); event.type= MOUSEMOVE; event.prevx= event.x; -- cgit v1.2.3 From 551ddd1002cec4200c6073a8442b931122d5dd47 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 10:54:15 +0000 Subject: Fix #19389: add lamp had no submenu to choose the type. --- release/ui/space_info.py | 4 +- .../blender/editors/interface/interface_regions.c | 2 +- source/blender/editors/object/object_add.c | 48 ++++++++++++++++++++-- source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/release/ui/space_info.py b/release/ui/space_info.py index 6e32cf9b071..539a6722cf0 100644 --- a/release/ui/space_info.py +++ b/release/ui/space_info.py @@ -124,7 +124,7 @@ class INFO_MT_add(bpy.types.Menu): layout.item_menu_enumO("object.mesh_add", "type", text="Mesh", icon='ICON_OUTLINER_OB_MESH') layout.item_menu_enumO("object.curve_add", "type", text="Curve", icon='ICON_OUTLINER_OB_CURVE') layout.item_menu_enumO("object.surface_add", "type", text="Surface", icon='ICON_OUTLINER_OB_SURFACE') - layout.item_menu_enumO("object.metaball_add", "type", 'META', icon='ICON_OUTLINER_OB_META') + layout.item_menu_enumO("object.metaball_add", "type", 'META', text="Metaball", icon='ICON_OUTLINER_OB_META') layout.itemO("object.text_add", text="Text", icon='ICON_OUTLINER_OB_FONT') layout.itemS() @@ -136,7 +136,7 @@ class INFO_MT_add(bpy.types.Menu): layout.itemS() layout.item_enumO("object.add", "type", 'CAMERA', icon='ICON_OUTLINER_OB_CAMERA') - layout.item_enumO("object.add", "type", 'LAMP', icon='ICON_OUTLINER_OB_LAMP') + layout.item_menu_enumO("object.lamp_add", "type", 'LAMP', text="Lamp", icon='ICON_OUTLINER_OB_LAMP') class INFO_MT_game(bpy.types.Menu): __space_type__ = 'INFO' diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 065d391e6d6..0f04333c6c5 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2226,7 +2226,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi } block->minbounds= minwidth; - uiTextBoundsBlock(block, 40); + uiTextBoundsBlock(block, 50); } /* if menu slides out of other menu, override direction */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ee9af61f516..d576f6e8bf6 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -32,6 +32,7 @@ #include "DNA_action_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" +#include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -165,7 +166,7 @@ static Object *object_add_type(bContext *C, int type) /* for object add operator */ static int object_add_exec(bContext *C, wmOperator *op) { - object_add_type(C, RNA_int_get(op->ptr, "type")); + object_add_type(C, RNA_enum_get(op->ptr, "type")); return OPERATOR_FINISHED; } @@ -467,7 +468,7 @@ static int object_metaball_add_invoke(bContext *C, wmOperator *op, wmEvent *even void OBJECT_OT_metaball_add(wmOperatorType *ot) { /* identifiers */ - ot->name= "Metaball"; + ot->name= "Add Metaball"; ot->description= "Add an metaball object to the scene."; ot->idname= "OBJECT_OT_metaball_add"; @@ -559,6 +560,45 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +static int object_lamp_add_exec(bContext *C, wmOperator *op) +{ + Object *ob; + int type= RNA_enum_get(op->ptr, "type"); + + ob= object_add_type(C, OB_LAMP); + if(ob && ob->data) + ((Lamp*)ob->data)->type= type; + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_lamp_add(wmOperatorType *ot) +{ + static EnumPropertyItem lamp_type_items[] = { + {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source."}, + {LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source."}, + {LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source."}, + {LA_HEMI, "HEMI", ICON_LAMP_HEMI, "Hemi", "180 degree constant light source."}, + {LA_AREA, "AREA", ICON_LAMP_AREA, "Area", "Directional area light source."}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name= "Add Lamp"; + ot->description = "Add a lamp object to the scene."; + ot->idname= "OBJECT_OT_lamp_add"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= object_lamp_add_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", ""); +} + static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *event) { uiPopupMenu *pup= uiPupMenuBegin(C, "Add Object", 0); @@ -567,7 +607,7 @@ static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *eve uiItemMenuEnumO(layout, "Mesh", ICON_OUTLINER_OB_MESH, "OBJECT_OT_mesh_add", "type"); uiItemMenuEnumO(layout, "Curve", ICON_OUTLINER_OB_CURVE, "OBJECT_OT_curve_add", "type"); uiItemMenuEnumO(layout, "Surface", ICON_OUTLINER_OB_SURFACE, "OBJECT_OT_surface_add", "type"); - uiItemMenuEnumO(layout, NULL, ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type"); + uiItemMenuEnumO(layout, "Metaball", ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type"); uiItemO(layout, "Text", ICON_OUTLINER_OB_FONT, "OBJECT_OT_text_add"); uiItemS(layout); uiItemO(layout, "Armature", ICON_OUTLINER_OB_ARMATURE, "OBJECT_OT_armature_add"); @@ -575,7 +615,7 @@ static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *eve uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_add", "type", OB_EMPTY); uiItemS(layout); uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_CAMERA, "OBJECT_OT_add", "type", OB_CAMERA); - uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_LAMP, "OBJECT_OT_add", "type", OB_LAMP); + uiItemMenuEnumO(layout, "Lamp", ICON_OUTLINER_OB_LAMP, "OBJECT_OT_lamp_add", "type"); uiPupMenuEnd(C, pup); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 315b6632051..87c4560916d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -89,6 +89,7 @@ void OBJECT_OT_surface_add(struct wmOperatorType *ot); void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); +void OBJECT_OT_lamp_add(struct wmOperatorType *ot); void OBJECT_OT_primitive_add(struct wmOperatorType *ot); /* only used as menu */ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index fdfe6ed501c..a9b4bfe68dd 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -115,6 +115,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_text_add); WM_operatortype_append(OBJECT_OT_surface_add); WM_operatortype_append(OBJECT_OT_armature_add); + WM_operatortype_append(OBJECT_OT_lamp_add); WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_primitive_add); WM_operatortype_append(OBJECT_OT_mesh_add); -- cgit v1.2.3 From 61c79adb8b1d4d955e9af6d8866970e584fcb0a1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 10:57:46 +0000 Subject: colorbands could display with no items in the colorband array, letting you set 0 and -1 colorband index. --- .../editors/interface/interface_templates.c | 34 ++++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b15ddcfae17..23ffe46eed4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1336,7 +1336,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v) /* offset aligns from bottom, standard width 300, height 115 */ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb) { - CBData *cbd; + uiBut *bt; if(coba==NULL) return; @@ -1347,7 +1347,7 @@ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, bt= uiDefBut(block, BUT, 0, "Delete", 60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position"); uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); - uiDefButS(block, NUM, 0, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Choose active color stop"); + uiDefButS(block, NUM, 0, "", 120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop"); bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", 210+xoffs, 100+yoffs, 90, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); @@ -1357,36 +1357,38 @@ static void colorband_buttons_large(uiBlock *block, ColorBand *coba, int xoffs, bt= uiDefBut(block, BUT_COLORBAND, 0, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, ""); uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - cbd= coba->data + coba->cur; + if(coba->tot) { + CBData *cbd= coba->data + coba->cur; - bt= uiDefButF(block, NUM, 0, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); - uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba); - bt= uiDefButF(block, COL, 0, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - bt= uiDefButF(block, NUMSLI, 0, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUM, 0, "Pos:", 0+xoffs,40+yoffs,100, 20, &cbd->pos, 0.0, 1.0, 10, 0, "The position of the active color stop"); + uiButSetNFunc(bt, colorband_pos_cb, MEM_dupallocN(cb), coba); + bt= uiDefButF(block, COL, 0, "", 110+xoffs,40+yoffs,80,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A ", 200+xoffs,40+yoffs,100,20, &cbd->a, 0.0, 1.0, 10, 0, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + } } static void colorband_buttons_small(uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb) { - CBData *cbd; uiBut *bt; float unit= (butr->xmax-butr->xmin)/14.0f; float xs= butr->xmin; - cbd= coba->data + coba->cur; - bt= uiDefBut(block, BUT, 0, "Add", xs,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband"); uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba); bt= uiDefBut(block, BUT, 0, "Delete", xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Delete the active position"); uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba); - bt= uiDefButF(block, COL, 0, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); - bt= uiDefButF(block, NUMSLI, 0, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); - uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + if(coba->tot) { + CBData *cbd= coba->data + coba->cur; + bt= uiDefButF(block, COL, 0, "", xs+4.0f*unit,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "The color value for the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + bt= uiDefButF(block, NUMSLI, 0, "A:", xs+6.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "The alpha value of the active color stop"); + uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + } bt= uiDefButS(block, MENU, 0, "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4", xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20, &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops"); -- cgit v1.2.3 From d2639e732b345ce32ec26c42d0e3ca6df4eb761a Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 21 Sep 2009 12:09:00 +0000 Subject: 2.5 - Partial Bugfixes for Parenting Objects to Curves (Ctrl-P) * Path Constraint option (i.e. this creates a follow-path constraint but doesn't actually parent the object to the curve) works now. Fixed a crash here too. * Follow Path option (i.e. parent the object to the curve, and follow it), is not working correctly yet. Some matrix seems to get set wrongly. --- source/blender/blenkernel/intern/constraint.c | 5 ++++- source/blender/editors/object/object_relations.c | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index e49bda0fdd2..a3d59720645 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1188,7 +1188,10 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if (cu->path && cu->path->data) { if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ - curvetime= bsystem_time(cob->scene, ct->tar, ctime, 0.0) - data->offset; + if (cob->scene) + curvetime= bsystem_time(cob->scene, ct->tar, ctime, 0.0) - data->offset; + else + curvetime= ctime - data->offset; /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated, * but this will only work if it actually is animated... diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 65061e8dfb9..17590cbaad3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -566,8 +566,9 @@ static int parent_set_exec(bContext *C, wmOperator *op) } else cu->flag |= CU_FOLLOW; - /* fall back on regular parenting now */ - partype= PAR_OBJECT; + /* fall back on regular parenting now (for follow only) */ + if(partype == PAR_FOLLOW) + partype= PAR_OBJECT; } } else if(partype==PAR_BONE) { @@ -593,7 +594,9 @@ static int parent_set_exec(bContext *C, wmOperator *op) /* apply transformation of previous parenting */ ED_object_apply_obmat(ob); - ob->parent= par; + /* set the parent (except for follow-path constraint option) */ + if(partype != PAR_PATH_CONST) + ob->parent= par; /* handle types */ if (pchan) @@ -602,7 +605,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->parsubstr[0]= 0; /* constraint */ - if(partype==PAR_PATH_CONST) { + if(partype == PAR_PATH_CONST) { bConstraint *con; bFollowPathConstraint *data; float cmat[4][4], vec[3]; @@ -620,6 +623,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->loc[0] = vec[0]; ob->loc[1] = vec[1]; + ob->loc[2] = vec[2]; } else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) { if(partype == PAR_ARMATURE_NAME) @@ -645,6 +649,8 @@ static int parent_set_exec(bContext *C, wmOperator *op) ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; + if(partype == PAR_PATH_CONST) + ; /* don't do anything here, since this is not technically "parenting" */ if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm ) ob->partype= PARSKEL; /* note, dna define, not operator property */ else if (partype == PAR_BONE) -- cgit v1.2.3 From e9ffd121337d0d5d50bc8771a36117dc3696b315 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 12:23:56 +0000 Subject: bugfix [#19392] Typing help() in the console window freezes Blender for now set the sys.stdin to None, this gives an error on input() or help() but better then locking up blender. Would be nice to support for the blender console to be used as a stdin but this isnt so simple. also quiet some warnings. --- source/blender/editors/space_file/file_ops.c | 1 - source/blender/editors/space_file/space_file.c | 2 +- source/blender/editors/transform/transform_input.c | 2 +- source/blender/python/intern/bpy_interface.c | 5 +++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 7839cf5bf4b..c717623696a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -72,7 +72,6 @@ static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short { float fx,fy; int active_file = -1; - int numfiles = filelist_numfiles(sfile->files); View2D* v2d = &ar->v2d; UI_view2d_region_to_view(v2d, x, y, &fx, &fy); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 56dbdcbc645..ca2c145c52b 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -155,7 +155,7 @@ static void file_free(SpaceLink *sl) /* spacetype; init callback, area size changes, screen set, etc */ static void file_init(struct wmWindowManager *wm, ScrArea *sa) { - SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; + //SpaceFile *sfile= (SpaceFile*)sa->spacedata.first; printf("file_init\n"); } diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index e1e4569623b..83d4a314057 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -34,7 +34,7 @@ #include "transform.h" - +#include "MEM_guardedalloc.h" /* ************************** INPUT FROM MOUSE *************************** */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index fd8cfc47f55..3e28bc7968f 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -292,6 +292,11 @@ void BPY_start_python( int argc, char **argv ) PyObject *d = PyEval_GetBuiltins( ); PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); + + /* a bit nasty but this prevents help() and input() from locking blender + * Ideally we could have some way for the console to replace sys.stdin but + * python would lock blender while waiting for a return value, not easy :| */ + PySys_SetObject("stdin", Py_None); } pyrna_alloc_types(); -- cgit v1.2.3 From cdc5fd64e5a50079ba79989f45e06dc38eb445b1 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 21 Sep 2009 12:29:53 +0000 Subject: 2.5 - Keyframes can now be marked as 'extremes' in addition to 'breakdowns' * Extremes are shown as red/pink diamonds * I've changed the order of extremes and breakdowns in the code to make for nicer sizing/ordering. This might break a couple of files out there, but it shouldn't be too many. TODO: Still on my todo is to make these tags more useful (i.e. less likely to be overwritten by keyframing) --- source/blender/editors/animation/keyframes_draw.c | 7 +++++++ source/blender/editors/animation/keyframes_edit.c | 10 ++++++++++ source/blender/editors/space_action/action_header.c | 1 + source/blender/makesdna/DNA_curve_types.h | 1 + source/blender/makesrna/intern/rna_curve.c | 1 + 5 files changed, 20 insertions(+) diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index dcb37f4d2c4..e8b25f70b06 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -419,6 +419,13 @@ void draw_keyframe_shape (float x, float y, float xscale, float hsize, short sel } break; + case BEZT_KEYTYPE_EXTREME: /* redish frames for now */ + { + if (sel) glColor3f(95.0f, 0.5f, 0.5f); + else glColor3f(0.91f, 0.70f, 0.80f); + } + break; + case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames for now */ default: { diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index ac04dc7d1a8..9666cb115b1 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -685,6 +685,13 @@ static short set_keytype_breakdown(BeztEditData *bed, BezTriple *bezt) return 0; } +static short set_keytype_extreme(BeztEditData *bed, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME; + return 0; +} + /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */ BeztEditFunc ANIM_editkeyframes_keytype(short code) { @@ -692,6 +699,9 @@ BeztEditFunc ANIM_editkeyframes_keytype(short code) case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */ return set_keytype_breakdown; + case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */ + return set_keytype_extreme; + case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */ default: return set_keytype_keyframe; diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index dd02302af9c..f602345baea 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -189,6 +189,7 @@ static void act_edit_keytypesmenu(bContext *C, uiLayout *layout, void *arg_unuse uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_KEYFRAME); uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_BREAKDOWN); + uiItemEnumO(layout, NULL, 0, "ACT_OT_keyframe_type", "type", BEZT_KEYTYPE_EXTREME); } static void act_edit_handlesmenu(bContext *C, uiLayout *layout, void *arg_unused) diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 109a9528de2..6cfeb646cf2 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -310,6 +310,7 @@ typedef enum eBezTriple_Interpolation { /* types of keyframe (used only for BezTriple->hide when BezTriple is used in F-Curves) */ typedef enum eBezTriple_KeyframeType { BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */ + BEZT_KEYTYPE_EXTREME, /* 'extreme' keyframe */ BEZT_KEYTYPE_BREAKDOWN, /* 'breakdown' keyframe */ } eBezTriple_KeyframeType; diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 4a5af56d64a..3b6bd2255f2 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -54,6 +54,7 @@ EnumPropertyItem beztriple_interpolation_mode_items[] = { EnumPropertyItem beztriple_keyframe_type_items[] = { {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", 0, "Keyframe", ""}, {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", 0, "Breakdown", ""}, + {BEZT_KEYTYPE_EXTREME, "EXTREME", 0, "Extreme", ""}, {0, NULL, 0, NULL, NULL}}; #ifdef RNA_RUNTIME -- cgit v1.2.3 From 3c5630a63d01771cea247144fd0d31cece46e681 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 13:23:47 +0000 Subject: Fix #19418: file browse button for strip filename did not work, sequence RNA now also splits up directory and filename automatic. --- .../blender/editors/interface/interface_layout.c | 2 +- source/blender/makesrna/intern/rna_sequence.c | 32 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b957ff83650..afbbfb61cba 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -533,7 +533,7 @@ void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA prevbut= but->prev; /* find the button before the active one */ - if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.id.data) { + if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) { if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) { *ptr= prevbut->rnapoin; *prop= prevbut->rnaprop; diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index 4e12aab853e..b1ac02ae17f 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -239,6 +239,35 @@ static PointerRNA rna_SequenceEdtior_meta_stack_get(CollectionPropertyIterator * return rna_pointer_inherit_refine(&iter->parent, &RNA_Sequence, ms->parseq); } +static void rna_MovieSequence_filename_set(PointerRNA *ptr, const char *value) +{ + Sequence *seq= (Sequence*)(ptr->data); + char dir[FILE_MAX], name[FILE_MAX]; + + BLI_split_dirfile_basic(value, dir, name); + BLI_strncpy(seq->strip->dir, dir, sizeof(seq->strip->dir)); + BLI_strncpy(seq->strip->stripdata->name, name, sizeof(seq->strip->stripdata->name)); +} + +static void rna_SoundSequence_filename_set(PointerRNA *ptr, const char *value) +{ + Sequence *seq= (Sequence*)(ptr->data); + char dir[FILE_MAX], name[FILE_MAX]; + + BLI_split_dirfile_basic(value, dir, name); + BLI_strncpy(seq->strip->dir, dir, sizeof(seq->strip->dir)); + BLI_strncpy(seq->strip->stripdata->name, name, sizeof(seq->strip->stripdata->name)); +} + +static void rna_SequenceElement_filename_set(PointerRNA *ptr, const char *value) +{ + StripElem *elem= (StripElem*)(ptr->data); + char name[FILE_MAX]; + + BLI_split_dirfile_basic(value, NULL, name); + BLI_strncpy(elem->name, name, sizeof(elem->name)); +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -253,6 +282,7 @@ static void rna_def_strip_element(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SequenceElement_filename_set"); } static void rna_def_strip_crop(BlenderRNA *brna) @@ -736,6 +766,7 @@ static void rna_def_movie(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "strip->stripdata->name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MovieSequence_filename_set"); prop= RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "strip->dir"); @@ -762,6 +793,7 @@ static void rna_def_sound(BlenderRNA *brna) prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "strip->stripdata->name"); RNA_def_property_ui_text(prop, "Filename", ""); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SoundSequence_filename_set"); prop= RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "strip->dir"); -- cgit v1.2.3 From e2ebb5d9e413b7dad0d63710ddeacb8e4d03718b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 13:43:11 +0000 Subject: autocomplete poll function wasn't working, added autocomplete in the console header operator docstrings with newlines and tabs show up as junk in tooltips so just use a single line. --- release/io/export_ply.py | 4 +--- release/ui/space_console.py | 13 ++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/release/io/export_ply.py b/release/io/export_ply.py index b8fbe56f01c..98ce210aa1f 100644 --- a/release/io/export_ply.py +++ b/release/io/export_ply.py @@ -232,9 +232,7 @@ def write(filename, scene, ob, \ """ class EXPORT_OT_ply(bpy.types.Operator): - ''' - Operator documentatuon text, will be used for the operator tooltip and python docs. - ''' + '''Export a single object as a stanford PLY with normals, colours and texture coordinates.''' __idname__ = "export.ply" __label__ = "Export PLY" diff --git a/release/ui/space_console.py b/release/ui/space_console.py index 136082a285a..980c11b706a 100644 --- a/release/ui/space_console.py +++ b/release/ui/space_console.py @@ -37,6 +37,9 @@ class CONSOLE_HT_header(bpy.types.Header): row = layout.row() row.enabled = sc.show_report_operator row.itemO("console.report_replay") + else: + row = layout.row(align=True) + row.itemO("console.autocomplete", text="Autocomplete") class CONSOLE_MT_console(bpy.types.Menu): __space_type__ = 'CONSOLE' @@ -107,9 +110,7 @@ def get_console(console_id): return namespace, console, stdout, stderr class CONSOLE_OT_exec(bpy.types.Operator): - ''' - Execute the current console line as a python expression. - ''' + '''Execute the current console line as a python expression.''' __idname__ = "console.execute" __label__ = "Console Execute" __register__ = False @@ -384,15 +385,13 @@ def autocomp(bcon): class CONSOLE_OT_autocomplete(bpy.types.Operator): - ''' - Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one. - ''' + '''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one.''' __idname__ = "console.autocomplete" __label__ = "Console Autocomplete" __register__ = False def poll(self, context): - return context.space_data.type == 'PYTHON' + return context.space_data.console_type == 'PYTHON' def execute(self, context): -- cgit v1.2.3 From 6fc4e2d37fae8696eb39ee4d5456f5184f374fe3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 14:30:59 +0000 Subject: Fix #19425: crash with long filename and rendering full sample. --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 8ef52991ca2..68b6f9e524c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -406,7 +406,7 @@ static int passtype_from_name(char *str) static void render_unique_exr_name(Render *re, char *str, int sample) { - char di[FILE_MAX], name[FILE_MAXFILE], fi[FILE_MAXFILE]; + char di[FILE_MAX], name[FILE_MAXFILE+MAX_ID_NAME+100], fi[FILE_MAXFILE]; BLI_strncpy(di, G.sce, FILE_MAX); BLI_splitdirstring(di, fi); -- cgit v1.2.3 From b037d280d31be3aecb05d83a2e692c096b3b8315 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 21 Sep 2009 14:45:28 +0000 Subject: * Removed an unused context callback. --- source/blender/editors/space_buttons/buttons_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index f51cb5d6f8c..9333ba9209c 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -554,7 +554,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r "world", "object", "mesh", "armature", "lattice", "curve", "meta_ball", "lamp", "camera", "material", "material_slot", "texture", "texture_slot", "bone", "edit_bone", "particle_system", - "cloth", "soft_body", "fluid", "smoke", "smoke_hr", "collision", "brush", NULL}; + "cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL}; CTX_data_dir_set(result, dir); return 1; -- cgit v1.2.3 From 4453dc330f94ab0865852145cfab444f05cbd463 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 21 Sep 2009 15:47:41 +0000 Subject: remove OS checks to use BLENDERPATH, apple or win32 should be easy to add now. --- source/creator/creator.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/creator/creator.c b/source/creator/creator.c index 523273de9bf..579825b805a 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -122,11 +122,7 @@ char btempdir[FILE_MAXDIR+FILE_MAXFILE]; #define BLENDERPATH "" #endif -#if !(defined(__APPLE__) && defined(WIN32)) char blender_path[FILE_MAXDIR+FILE_MAXFILE] = BLENDERPATH; -#else -char blender_path[FILE_MAXDIR+FILE_MAXFILE] = ""; -#endif /* Initialise callbacks for the modules that need them */ static void setCallbacks(void); @@ -233,12 +229,10 @@ static void print_help(void) printf (" \t\t passed unchanged. Access via Python's sys.argv\n"); printf ("\nEnvironment Variables:\n"); printf (" $HOME\t\t\tStore files such as .blender/ .B.blend .Bfs .Blog here.\n"); -#if !(defined(__APPLE__) && defined(WIN32)) printf (" $BLENDERPATH\tSystem directory to use for data files and scripts.\n"); printf (" \tFor this build of blender the default BLENDERPATH is...\n"); printf (" \t\"%s\"\n", blender_path); printf (" \tseting the $BLENDERPATH will override this\n"); -#endif #ifdef WIN32 printf (" $TEMP\t\tStore temporary files here.\n"); #else -- cgit v1.2.3 From 1e63545a3b6331b6c1d05a15c5dc48f4aa148f19 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 15:51:29 +0000 Subject: Second attempt at fixing #19335: holding down backspace in the text editor creates squares on some systems. Based on info from Martin, it appears the keymodifier is being set when it shouldn't. I think this is happening become some systems may be generating KM_PRESS events without a matching KM_RELEASE? Also ignore ascii values 1-32 now instead of 14-32, not sure why they were included now in 2.5 because they were not in 2.4, but I don't see a reason to do it. This fixes squares when pressing e.g. ctrl+b or ctrl+n. --- source/blender/windowmanager/intern/wm_event_system.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 6b07e384f66..4acfe1e524a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1600,7 +1600,7 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE; /* exclude arrow keys, esc, etc from text input */ - if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>14)) + if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0)) event.ascii= '\0'; /* modifiers */ @@ -1630,6 +1630,13 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) else if(event.val==KM_RELEASE && event.keymodifier==event.type) event.keymodifier= evt->keymodifier= 0; } + + /* this case happens on some systems that on holding a key pressed, + generate press events without release, we still want to keep the + modifier in win->eventstate, but for the press event of the same + key we don't want the key modifier */ + if(event.keymodifier == event.type) + event.keymodifier= 0; /* if test_break set, it catches this. XXX Keep global for now? */ if(event.type==ESCKEY) -- cgit v1.2.3 From 34a9f423f8ab1debe78ae4d883bf6c4995d9e0ee Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Mon, 21 Sep 2009 16:01:31 +0000 Subject: netrender: more load balancing rules --- release/io/netrender/balancing.py | 23 +++++++++++++++++++++-- release/io/netrender/master.py | 13 +++++++++++++ release/io/netrender/model.py | 5 ++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py index 89e1e3f7b06..62b6dcee519 100644 --- a/release/io/netrender/balancing.py +++ b/release/io/netrender/balancing.py @@ -64,12 +64,31 @@ class Balancer: class RatingCredit(RatingRule): def rate(self, job): - return -job.credits # more credit is better (sort at first in list) + return -job.credits * job.priority # more credit is better (sort at first in list) class NewJobPriority(PriorityRule): + def __init__(self, limit = 1): + self.limit = limit + + def test(self, job): + return job.countFrames(status = DISPATCHED) < self.limit + +class MinimumTimeBetweenDispatchPriority(PriorityRule): + def __init__(self, limit = 10): + self.limit = limit + def test(self, job): - return job.countFrames(status = DISPATCHED) == 0 + return (time.time() - job.last_dispatched) / 60 > self.limit class ExcludeQueuedEmptyJob(ExclusionRule): def test(self, job): return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0 + +class ExcludeSlavesLimit(ExclusionRule): + def __init__(self, count_jobs, count_slaves, limit = 0.75): + self.count_jobs = count_jobs + self.count_slaves = count_slaves + self.limit = limit + + def test(self, job): + return not ( self.count_jobs() == 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) \ No newline at end of file diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 58c6c1b2d00..1bff5f6340b 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -575,7 +575,9 @@ class RenderMasterServer(http.server.HTTPServer): self.balancer = netrender.balancing.Balancer() self.balancer.addRule(netrender.balancing.RatingCredit()) self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) + self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves)) self.balancer.addPriority(netrender.balancing.NewJobPriority()) + self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority()) if not os.path.exists(self.path): os.mkdir(self.path) @@ -607,7 +609,18 @@ class RenderMasterServer(http.server.HTTPServer): def update(self): self.balancer.balance(self.jobs) + + def countJobs(self, status = JOB_QUEUED): + total = 0 + for j in self.jobs: + if j.status == status: + total += 1 + return total + + def countSlaves(self): + return len(self.slaves) + def removeJob(self, id): job = self.jobs_map.pop(id) diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 9a6645e79cf..e8046d7ac8c 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -97,15 +97,14 @@ class RenderJob: def countFrames(self, status=QUEUED): total = 0 - for j in self.frames: - if j.status == status: + for f in self.frames: + if f.status == status: total += 1 return total def countSlaves(self): return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED))) - def framesStatus(self): results = { -- cgit v1.2.3 From 8141725342ab12953f5299d1f00300a5292a1682 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 16:08:38 +0000 Subject: Fix #19382: crash on uv edit stitch, tweaking limit property in tool area. --- source/blender/editors/uvedit/uvedit_ops.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5597c624e23..9216cfb5cdc 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -180,7 +180,13 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist { int width, height; - ED_space_image_size(sima, &width, &height); + if(sima) { + ED_space_image_size(sima, &width, &height); + } + else { + width= 256; + height= 256; + } dist[0]= pixeldist/width; dist[1]= pixeldist/height; @@ -1097,11 +1103,11 @@ static int stitch_exec(bContext *C, wmOperator *op) if(RNA_boolean_get(op->ptr, "use_limit")) { UvVertMap *vmap; UvMapVert *vlist, *iterv; - float newuv[2], limit[2], pixels; + float newuv[2], limit[2]; int a, vtot; - pixels= RNA_float_get(op->ptr, "limit"); - uvedit_pixel_to_float(sima, limit, pixels); + limit[0]= RNA_float_get(op->ptr, "limit"); + limit[1]= limit[0]; EM_init_index_arrays(em, 0, 0, 1); vmap= EM_make_uv_vert_map(em, 1, 0, limit); @@ -1255,7 +1261,7 @@ void UV_OT_stitch(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance."); - RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX); + RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX); } /* ******************** (de)select all operator **************** */ @@ -1439,7 +1445,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) else { sync= 0; selectmode= ts->uv_selectmode; - sticky= sima ? sima->sticky : 1; + sticky= (sima)? sima->sticky: 1; } /* find nearest element */ -- cgit v1.2.3 From 04ec0ea1908f8b15f167ffebd789e678fa6803c6 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 21 Sep 2009 16:21:54 +0000 Subject: 2.5 Nodes: * Wrapped Color Key and Blur Node. * Nodes using RNA properties can be animated. You can now choose if the Nodes Window should be updated while animation playback too. (Timeline>Playback Menu) --- release/ui/space_time.py | 1 + source/blender/editors/screen/screen_ops.c | 4 ++ source/blender/editors/space_node/drawnode.c | 87 ++++++++-------------------- source/blender/makesdna/DNA_space_types.h | 1 + source/blender/makesrna/intern/rna_space.c | 5 ++ 5 files changed, 34 insertions(+), 64 deletions(-) diff --git a/release/ui/space_time.py b/release/ui/space_time.py index b51b1d8af79..696dcf18623 100644 --- a/release/ui/space_time.py +++ b/release/ui/space_time.py @@ -119,6 +119,7 @@ class TIME_MT_playback(bpy.types.Menu): layout.itemR(st, "play_buttons") layout.itemR(st, "play_image") layout.itemR(st, "play_sequencer") + layout.itemR(st, "play_nodes") layout.itemS() diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f4af0cd6883..5cd992eabe9 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2176,6 +2176,10 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws) if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN)) return 1; break; + case SPACE_NODE: + if(redraws & (TIME_NODES)) + return 1; + break; case SPACE_IMAGE: if(redraws & TIME_ALL_IMAGE_WIN) return 1; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 9b73bdbb255..f42bf97bf1a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1107,58 +1107,28 @@ static void node_blur_update_sizey_cb(bContext *C, void *node, void *poin2) } static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeBlurData *nbd= node->storage; - uiBut *bt; - short dy= butr->ymin+58; - short dx= (butr->xmax-butr->xmin)/2; - char str[256]; + uiLayout *row, *col; - uiBlockBeginAlign(block); - sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH); - uiDefButS(block, MENU, B_NODE_EXEC,str, - butr->xmin, dy, dx*2, 19, - &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur"); - dy-=19; - if (nbd->filtertype != R_FILTER_FAST_GAUSS) { - uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh", - butr->xmin, dy, dx, 19, - &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!"); - uiDefButC(block, TOG, B_NODE_EXEC, "Gamma", - butr->xmin+dx, dy, dx, 19, - &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values"); - } else { - uiBlockEndAlign(block); - uiBlockBeginAlign(block); + col= uiLayoutColumn(layout, 0); + + uiItemR(col, "", 0, ptr, "filter_type", 0); + /* Only for "Fast Gaussian" */ + if (RNA_enum_get(ptr, "filter_type")!= 7) { + uiItemR(col, NULL, 0, ptr, "bokeh", 0); + uiItemR(col, NULL, 0, ptr, "gamma", 0); } - dy-=19; - bt= uiDefButS(block, TOG, B_NOP, "Relative", - butr->xmin, dy, dx*2, 19, - &nbd->relative, 0, 0, 0, 0, "Use relative (percent) values to define blur radius"); - uiButSetFunc(bt, node_blur_relative_cb, node, NULL); - - dy-=19; - if(nbd->relative) { - bt= uiDefButF(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->percentx, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizex_cb, node, NULL); - bt= uiDefButF(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->percenty, 0.0f, 1.0f, 0, 0, ""); - uiButSetFunc(bt, node_blur_update_sizey_cb, node, NULL); + + uiItemR(col, NULL, 0, ptr, "relative", 0); + row= uiLayoutRow(col, 1); + if (RNA_boolean_get(ptr, "relative")== 1) { + uiItemR(row, "X", 0, ptr, "factor_x", 0); + uiItemR(row, "Y", 0, ptr, "factor_y", 0); } + else { - uiDefButS(block, NUM, B_NODE_EXEC, "X:", - butr->xmin, dy, dx, 19, - &nbd->sizex, 0, 256, 0, 0, ""); - uiDefButS(block, NUM, B_NODE_EXEC, "Y:", - butr->xmin+dx, dy, dx, 19, - &nbd->sizey, 0, 256, 0, 0, ""); + uiItemR(row, "X", 0, ptr, "sizex", 0); + uiItemR(row, "Y", 0, ptr, "sizey", 0); } - uiBlockEndAlign(block); } static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) @@ -1455,23 +1425,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_color_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - NodeChroma *c= node->storage; - uiBlockBeginAlign(block); - - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "H: ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t1, 0.0f, 0.25f, 100, 0, "Hue tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "S: ", - butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 1.0f, 100, 0, "Saturation Tolerance for the color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "V: ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Value Tolerance for the color"); - - uiBlockEndAlign(block); + uiLayout *col; + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "h", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "s", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "v", UI_ITEM_R_SLIDER); } static void node_composit_buts_channel_matte(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 1a368877243..2cd47e340bd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -834,6 +834,7 @@ enum { #define TIME_SEQ 32 #define TIME_ALL_IMAGE_WIN 64 #define TIME_CONTINUE_PHYSICS 128 +#define TIME_NODES 256 /* sseq->mainb */ #define SEQ_DRAW_SEQUENCE 0 diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 8e783354653..9cf413c0f78 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1239,6 +1239,11 @@ static void rna_def_space_time(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequencer Windows", ""); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update"); + prop= RNA_def_property(srna, "play_nodes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_NODES); + RNA_def_property_ui_text(prop, "Node Windows", ""); + RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update"); + /* Other options */ prop= RNA_def_property(srna, "continue_physics", PROP_BOOLEAN, PROP_NONE); -- cgit v1.2.3 From 6117d9c6e27970cef86c4532dc77b18101071beb Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 16:39:07 +0000 Subject: Fix #19361: BGE keyboard sensor allowed to set mouse events too, should only be keyboard events. --- source/blender/editors/include/UI_interface.h | 2 +- source/blender/editors/interface/interface.c | 3 ++- .../blender/editors/interface/interface_handlers.c | 1 + source/blender/editors/space_logic/logic_window.c | 23 +++++++++++++++++++--- .../blender/windowmanager/intern/wm_event_system.c | 4 ++-- source/blender/windowmanager/wm_event_types.h | 7 +++++-- 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 848432b5f42..dc4744c9832 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -431,7 +431,7 @@ uiBut *uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, char * uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip); uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip); -void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip); +uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip); uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip); uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fbc3c859f20..f79f2f8c378 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -3098,10 +3098,11 @@ uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int return but; } -void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip) +uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip) { uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip); ui_check_but(but); + return but; } /* short pointers hardcoded */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e8d813d8ff9..01a8f983dc6 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -855,6 +855,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut ui_apply_but_CHARTAB(C, but, data); break; #endif + case KEYEVT: case HOTKEYEVT: ui_apply_but_BUT(C, but, data); break; diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index cd02f2c6304..b99f7b94170 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1067,6 +1067,19 @@ static void test_scenepoin_but(struct bContext *C, char *name, ID **idpp) *idpp= NULL; } + +static void test_keyboard_event(struct bContext *C, void *arg_ks, void *arg_unused) +{ + bKeyboardSensor *ks= (bKeyboardSensor*)arg_ks; + + if(!ISKEYBOARD(ks->key)) + ks->key= 0; + if(!ISKEYBOARD(ks->qual)) + ks->qual= 0; + if(!ISKEYBOARD(ks->qual2)) + ks->qual2= 0; +} + /** * Draws a toggle for pulse mode, a frequency field and a toggle to invert * the value of this sensor. Operates on the shared data block of sensors. @@ -1131,6 +1144,7 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short bJoystickSensor *joy = NULL; bActuatorSensor *as = NULL; bDelaySensor *ds = NULL; + uiBut *but; short ysize; char *str; @@ -1279,12 +1293,15 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short if ((ks->type&1)==0) { /* is All Keys option off? */ /* line 2: hotkey and allkeys toggle */ - uiDefKeyevtButS(block, 0, "", xco+40, yco-44, (width)/2, 19, &ks->key, "Key code"); + but= uiDefKeyevtButS(block, 0, "", xco+40, yco-44, (width)/2, 19, &ks->key, "Key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); /* line 3: two key modifyers (qual1, qual2) */ uiDefBut(block, LABEL, 0, "Hold", xco, yco-68, 40, 19, NULL, 0, 0, 0, 0, ""); - uiDefKeyevtButS(block, 0, "", xco+40, yco-68, (width-50)/2, 19, &ks->qual, "Modifier key code"); - uiDefKeyevtButS(block, 0, "", xco+40+(width-50)/2, yco-68, (width-50)/2, 19, &ks->qual2, "Second Modifier key code"); + but= uiDefKeyevtButS(block, 0, "", xco+40, yco-68, (width-50)/2, 19, &ks->qual, "Modifier key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); + but= uiDefKeyevtButS(block, 0, "", xco+40+(width-50)/2, yco-68, (width-50)/2, 19, &ks->qual2, "Second Modifier key code"); + uiButSetFunc(but, test_keyboard_event, ks, NULL); } /* line 4: toggle property for string logging mode */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4acfe1e524a..503eb5a1b9a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -718,7 +718,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) /* the matching rules */ if(kmitype==KM_TEXTINPUT) - if(ISKEYBOARD(winevent->type) && winevent->ascii) return 1; + if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1; if(kmitype!=KM_ANY) if(winevent->type!=kmitype) return 0; @@ -741,7 +741,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) /* key modifiers always check when event has it */ /* otherwise regular keypresses with keymodifier still work */ if(winevent->keymodifier) - if(ISKEYBOARD(winevent->type)) + if(ISTEXTINPUT(winevent->type)) if(winevent->keymodifier!=kmi->keymodifier) return 0; return 1; diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 898c6358f3a..cc6041ce529 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -194,10 +194,13 @@ /* for event checks */ /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ -#define ISKEYBOARD(event) (event >=' ' && event <=255) +#define ISTEXTINPUT(event) (event >=' ' && event <=255) + + /* test wether the event is a key on the keyboard */ +#define ISKEYBOARD(event) (event >=' ' && event <=320) /* test whether event type is acceptable as hotkey, excluding modifiers */ -#define ISHOTKEY(event) (event >=' ' && event <=320 && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) +#define ISHOTKEY(event) (ISKEYBOARD(event) && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) /* **************** BLENDER GESTURE EVENTS ********************* */ -- cgit v1.2.3 From b49e4e7bcf6279e8794afcf2d69eb9834b1dcb9d Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 16:51:04 +0000 Subject: Fix #19378: border render coordinates were not RNA wrapped. --- source/blender/makesrna/intern/rna_scene.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ff8102a3111..5def517f8b2 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1665,6 +1665,30 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", R_BORDER); RNA_def_property_ui_text(prop, "Border", "Render a user-defined border region, within the frame size."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_min_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.xmin"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Minimum X", "Sets minimum X value to for the render border."); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_min_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.ymin"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Minimum Y", "Sets minimum Y value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_max_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.xmax"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Maximum X", "Sets maximum X value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + + prop= RNA_def_property(srna, "border_max_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "border.ymax"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Border Maximum Y", "Sets maximum Y value for the render border"); + RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "crop_to_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_CROP); -- cgit v1.2.3 From fe27bb6dd4d214519816e00bb8daefcc9bdb8637 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 17:00:22 +0000 Subject: Fix #19384: missing redraw when changing transform orientation. --- source/blender/editors/space_view3d/view3d_header.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index a633969d557..a18e7da8f20 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -1801,8 +1801,10 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) ED_area_tag_redraw(sa); break; case B_NDOF: + ED_area_tag_redraw(sa); break; case B_MAN_MODE: + ED_area_tag_redraw(sa); break; case B_VIEW_BUTSEDIT: break; -- cgit v1.2.3 From c8a977db78d860e0134004083ee5e49d38dbc239 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 17:32:25 +0000 Subject: Fix #19426: loop select with occlude background geometry did not work after subdivide operator, needed a check for valid backbuf. --- source/blender/editors/mesh/editmesh_mods.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 09ea9088a16..3135863d571 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -2033,6 +2033,9 @@ static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring vc.mval[0]= mval[0]; vc.mval[1]= mval[1]; em= vc.em; + + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(&vc); eed= findnearestedge(&vc, &dist); if(eed) { @@ -2110,6 +2113,9 @@ static void mouse_mesh_shortest_path(bContext *C, short mval[2]) vc.mval[1]= mval[1]; em= vc.em; + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(&vc); + eed= findnearestedge(&vc, &dist); if(eed) { Mesh *me= vc.obedit->data; -- cgit v1.2.3 From a15ba4f35d9e6e7054164c40be03c438c1b42ca2 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 21 Sep 2009 19:26:27 +0000 Subject: * Wrong Property Range for Blur Size_Y. --- source/blender/makesrna/intern/rna_nodetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 239fd894e4f..d80ebe2da05 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -540,7 +540,7 @@ static void def_cmp_blur(StructRNA *srna) prop = RNA_def_property(srna, "sizey", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sizey"); - RNA_def_property_range(prop, 1, 256); + RNA_def_property_range(prop, 0, 256); RNA_def_property_ui_text(prop, "Size Y", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); -- cgit v1.2.3 From aae4335b9ffebe31326c8f3b1a83a1a17970e5e1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 20:50:11 +0000 Subject: Fix part of #19309: editing node vector input in a popup did not keep it open after changing one of the buttons. --- source/blender/editors/space_node/node_draw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index a87a141972b..1d57f4e0d4c 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -567,6 +567,7 @@ static uiBlock *socket_vector_menu(bContext *C, ARegion *ar, void *socket_v) } block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS); + uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); /* use this for a fake extra empy space around the buttons */ uiDefBut(block, LABEL, 0, "", -4, -4, 188, 68, NULL, 0, 0, 0, 0, ""); -- cgit v1.2.3 From 862ddcc0c458f2d188ba8410460540ee2d04711d Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 21:03:50 +0000 Subject: Fix part of #19307: modifier cage button not working as a toggle button. --- source/blender/editors/interface/interface_templates.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 23ffe46eed4..51678327cdd 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -405,10 +405,12 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v) { Object *ob = ob_v; - ModifierData *md; - + ModifierData *md= md_v; int i, cageIndex = modifiers_getCageIndex(ob, NULL ); + /* undo button operation */ + md->mode ^= eModifierMode_OnCage; + for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) { if(md == md_v) { if(i >= cageIndex) @@ -517,9 +519,10 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i /* XXX uiBlockSetEmboss(block, UI_EMBOSSR); */ if(ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) { - /* XXX uiBlockSetCol(block, color); */ - but = uiDefIconBut(block, BUT, 0, ICON_MESH_DATA, 0, 0, 16, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode"); + but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, 16, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode"); + if(index < cageIndex) + uiButSetFlag(but, UI_BUT_DISABLED); uiButSetFunc(but, modifiers_setOnCage, ob, md); uiBlockEndAlign(block); /* XXX uiBlockSetCol(block, TH_AUTO); */ -- cgit v1.2.3 From d601a51e03ca0dc8d714b36ad7ae7a5005119bc3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 21:19:58 +0000 Subject: RNA: added a "factor" subtype next to "percentage", and only display % sign for percentage assuming it is between 0-100, while factor is for values 0-1. Move collision setting absorption from modifier to collision settings, was inconsistent to have it there as the only one, and made it have range 0.0-1.0 instead of 0-100. --- release/ui/buttons_object_constraint.py | 2 +- release/ui/buttons_physics_field.py | 2 +- source/blender/blenkernel/BKE_collision.h | 2 +- source/blender/blenkernel/intern/collision.c | 27 ++++++------- source/blender/blenkernel/intern/effect.c | 11 ++++-- source/blender/editors/curve/editcurve.c | 2 +- source/blender/editors/interface/interface_utils.c | 2 +- source/blender/editors/mesh/editmesh_mods.c | 2 +- source/blender/editors/transform/transform_ops.c | 2 +- source/blender/editors/uvedit/uvedit_unwrap_ops.c | 2 +- source/blender/makesdna/DNA_modifier_types.h | 4 +- source/blender/makesdna/DNA_object_force.h | 2 + source/blender/makesrna/RNA_define.h | 2 + source/blender/makesrna/RNA_types.h | 7 ++-- source/blender/makesrna/intern/makesrna.c | 1 + source/blender/makesrna/intern/rna_camera.c | 2 +- source/blender/makesrna/intern/rna_constraint.c | 8 ++-- source/blender/makesrna/intern/rna_define.c | 19 +++++++++- source/blender/makesrna/intern/rna_material.c | 44 +++++++++++----------- source/blender/makesrna/intern/rna_modifier.c | 6 --- source/blender/makesrna/intern/rna_nodetree.c | 4 +- source/blender/makesrna/intern/rna_object_force.c | 6 +++ source/blender/makesrna/intern/rna_rna.c | 1 + source/blender/makesrna/intern/rna_scene.c | 2 +- source/blender/makesrna/intern/rna_userdef.c | 2 +- 25 files changed, 94 insertions(+), 70 deletions(-) diff --git a/release/ui/buttons_object_constraint.py b/release/ui/buttons_object_constraint.py index 1d2f9a5cb49..8671f9e25a8 100644 --- a/release/ui/buttons_object_constraint.py +++ b/release/ui/buttons_object_constraint.py @@ -130,7 +130,7 @@ class ConstraintButtonsPanel(bpy.types.Panel): col = split.column() col.itemR(con, "use_fixed_position") if con.use_fixed_position: - col.itemR(con, "offset_percentage", text="Offset") + col.itemR(con, "offset_factor", text="Offset") else: col.itemR(con, "offset") diff --git a/release/ui/buttons_physics_field.py b/release/ui/buttons_physics_field.py index 252b3bdb08a..f6b50844fc8 100644 --- a/release/ui/buttons_physics_field.py +++ b/release/ui/buttons_physics_field.py @@ -212,7 +212,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel): sub.itemR(settings, "inner_thickness", text="Inner", slider=True) layout.itemL(text="Force Fields:") - layout.itemR(md, "absorption", text="Absorption") + layout.itemR(settings, "absorption", text="Absorption") col = split.column() col.itemL(text="") diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index e4eed084a3d..e0df75f41b9 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -139,7 +139,7 @@ void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], ///////////////////////////////////////////////// // used in effect.c ///////////////////////////////////////////////// -CollisionModifierData **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj); +Object **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj); ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 8ef1c285370..aa4aae2422c 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1296,15 +1296,15 @@ static int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierDa // return all collision objects in scene // collision object will exclude self -CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *numcollobj) +Object **get_collisionobjects(Scene *scene, Object *self, int *numcollobj) { Base *base=NULL; - CollisionModifierData **objs = NULL; + Object **objs = NULL; Object *coll_ob = NULL; CollisionModifierData *collmd = NULL; int numobj = 0, maxobj = 100; - objs = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); + objs = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); // check all collision objects for ( base = scene->base.first; base; base = base->next ) { @@ -1330,16 +1330,16 @@ CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *nu { // realloc int oldmax = maxobj; - CollisionModifierData **tmp; + Object **tmp; maxobj *= 2; - tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); - memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + tmp = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(Object *)*oldmax); MEM_freeN(objs); objs = tmp; } - objs[numobj] = collmd; + objs[numobj] = coll_ob; numobj++; } else @@ -1374,15 +1374,15 @@ CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *nu { // realloc int oldmax = maxobj; - CollisionModifierData **tmp; + Object **tmp; maxobj *= 2; - tmp = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); - memcpy(tmp, objs, sizeof(CollisionModifierData *)*oldmax); + tmp = MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); + memcpy(tmp, objs, sizeof(Object *)*oldmax); MEM_freeN(objs); objs = tmp; } - objs[numobj] = collmd; + objs[numobj] = coll_ob; numobj++; } } @@ -1459,7 +1459,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl int rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; - CollisionModifierData **collobjs = NULL; + Object **collobjs = NULL; int numcollobj = 0; if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->bvhtree ) ) @@ -1498,7 +1498,8 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl // check all collision objects for(i = 0; i < numcollobj; i++) { - CollisionModifierData *collmd = collobjs[i]; + Object *collob= collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); BVHTreeOverlap *overlap = NULL; int result = 0; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index e3c4f12184e..acf906e3163 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -258,10 +258,10 @@ static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BV // get visibility of a wind ray static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir) { - CollisionModifierData **collobjs = NULL; + Object **collobjs = NULL; int numcollobj = 0, i; float norm[3], len = 0.0; - float visibility = 1.0; + float visibility = 1.0, absorption = 0.0; collobjs = get_collisionobjects(scene, ob, &numcollobj); @@ -275,7 +275,8 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir // check all collision objects for(i = 0; i < numcollobj; i++) { - CollisionModifierData *collmd = collobjs[i]; + Object *collob= collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); if(collmd->bvhtree) { @@ -287,8 +288,10 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir // check if the way is blocked if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0) { + absorption= (collob->pd)? collob->pd->absorption: 0.0f; + // visibility is only between 0 and 1, calculated from 1-absorption - visibility *= MAX2(0.0, MIN2(1.0, (1.0-((float)collmd->absorption)*0.01))); + visibility *= CLAMPIS(1.0f-absorption, 0.0f, 1.0f); if(visibility <= 0.0f) break; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 8dabe24de91..a18815d04a6 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1078,7 +1078,7 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ - RNA_def_float_percentage(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f); + RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f); } /******************* set radius operator ******************/ diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 00dec9a06c2..1d56ed4fb6a 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -73,7 +73,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind if(RNA_property_subtype(prop) == PROP_COLOR) but= uiDefButR(block, COL, 0, name, x1, y1, x2, y2, ptr, propname, 0, 0, 0, -1, -1, NULL); } - else if(RNA_property_subtype(prop) == PROP_PERCENTAGE) + else if(RNA_property_subtype(prop) == PROP_PERCENTAGE || RNA_property_subtype(prop) == PROP_FACTOR) but= uiDefButR(block, NUMSLI, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); else but= uiDefButR(block, NUM, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 3135863d571..93f8bdb6669 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -3553,7 +3553,7 @@ void MESH_OT_select_random(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* props */ - RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f); + RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f); } void EM_select_by_material(EditMesh *em, int index) diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f9597b81114..4bf0e44de7f 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -523,7 +523,7 @@ void TFM_OT_tosphere(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_areaactive; - RNA_def_float_percentage(ot->srna, "value", 0, 0, 1, "Percentage", "", 0, 1); + RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); Properties_Proportional(ot); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index b848bd4fb09..c7258e616fa 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -423,7 +423,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry."); - RNA_def_float_percentage(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f); + RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f); RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively.", 0, 100); } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 54433fd4254..bcb85b5f87e 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -438,9 +438,7 @@ typedef struct CollisionModifierData { unsigned int numverts; unsigned int numfaces; - short absorption; /* used for forces, in % */ - short pad; - float time; /* cfra time of modifier */ + float time, pad; /* cfra time of modifier */ struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ } CollisionModifierData; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 986a75f1a96..468ad35de85 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -62,6 +62,8 @@ typedef struct PartDeflect { float pdef_sbift; /* inner face thickness for softbody deflection */ float pdef_sboft; /* outer face thickness for softbody deflection */ + float absorption, pad; /* used for forces */ + /* variables for guide curve */ float clump_fac, clump_pow; float kink_freq, kink_shape, kink_amp, free_end; diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 595562503aa..37b175fbf12 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -102,6 +102,8 @@ PropertyRNA *RNA_def_float_dynamic_array(StructOrFunctionRNA *cont, const char * */ PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); +PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, + const char *ui_name, const char *ui_description, float softmin, float softmax); PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont, const char *identifier, const char *type, const char *ui_name, const char *ui_description); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 353c859cf27..5fff2af29ff 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -94,9 +94,10 @@ typedef enum PropertySubType { /* numbers */ PROP_UNSIGNED = 13, PROP_PERCENTAGE = 14, - PROP_ANGLE = 15|PROP_UNIT_ROTATION, - PROP_TIME = 16|PROP_UNIT_TIME, - PROP_DISTANCE = 17|PROP_UNIT_LENGTH, + PROP_FACTOR = 15, + PROP_ANGLE = 16|PROP_UNIT_ROTATION, + PROP_TIME = 17|PROP_UNIT_TIME, + PROP_DISTANCE = 18|PROP_UNIT_LENGTH, /* number arrays */ PROP_COLOR = 20, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index c734cdfec87..3e610005113 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1406,6 +1406,7 @@ static const char *rna_property_subtypename(PropertyType type) case PROP_DIRPATH: return "PROP_DIRPATH"; case PROP_UNSIGNED: return "PROP_UNSIGNED"; case PROP_PERCENTAGE: return "PROP_PERCENTAGE"; + case PROP_FACTOR: return "PROP_FACTOR"; case PROP_ANGLE: return "PROP_ANGLE"; case PROP_TIME: return "PROP_TIME"; case PROP_DISTANCE: return "PROP_DISTANCE"; diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 9c33b0afb00..eaf647e02a2 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -62,7 +62,7 @@ void RNA_def_camera(BlenderRNA *brna) /* Number values */ - prop= RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "passepartalpha"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view."); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 1bbac8da02f..86aa2a1d135 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -591,7 +591,7 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna) srna= RNA_def_struct(brna, "CopyLocationConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Copy Location Constraint", "Copies the location of the target."); - prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, "bConstraint", "headtail"); RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); @@ -893,10 +893,10 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Offset", "Offset from the position corresponding to the time frame."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); - prop= RNA_def_property(srna, "offset_percentage", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "offset_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "offset"); // XXX we might be better with another var or some hackery? RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Offset Percentage", "Percentage value defining target position along length of bone."); + RNA_def_property_ui_text(prop, "Offset Factor", "Percentage value defining target position along length of bone."); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); prop= RNA_def_property(srna, "forward", PROP_ENUM, PROP_NONE); @@ -1617,7 +1617,7 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Proxy Local", "Constraint was added in this proxy instance (i.e. did not belong to source Armature)."); /* values */ - prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "enforce"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Influence", "Amount of influence constraint will have on the final solution."); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 45517546c16..cc86da18a0b 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -890,7 +890,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier fprop->softmin= 0.0f; fprop->softmax= 1.0f; } - else if(subtype == PROP_PERCENTAGE) { + else if(subtype == PROP_FACTOR) { fprop->softmin= fprop->hardmin= 0.0f; fprop->softmax= fprop->hardmax= 1.0f; } @@ -1530,7 +1530,7 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const iprop->softmax= 10000; } - if(prop->subtype == PROP_UNSIGNED || prop->subtype == PROP_PERCENTAGE) + if(prop->subtype == PROP_UNSIGNED || prop->subtype == PROP_PERCENTAGE || prop->subtype == PROP_FACTOR) iprop->hardmin= iprop->softmin= 0; } } @@ -2261,6 +2261,21 @@ PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont_, const char *id return prop; } +PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, float default_value, + float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax) +{ + ContainerRNA *cont= cont_; + PropertyRNA *prop; + + prop= RNA_def_property(cont, identifier, PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_default(prop, default_value); + if(hardmin != hardmax) RNA_def_property_range(prop, hardmin, hardmax); + RNA_def_property_ui_text(prop, ui_name, ui_description); + RNA_def_property_ui_range(prop, softmin, softmax, 1, 3); + + return prop; +} + PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont_, const char *identifier, const char *type, const char *ui_name, const char *ui_description) { diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 18c0dc42e17..23aeacb97f2 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -645,12 +645,12 @@ static void rna_def_material_colors(StructRNA *srna) RNA_def_property_ui_text(prop, "Mirror Color", "Mirror color of the material."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Alpha", "Alpha transparency of the material."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW, NULL); - prop= RNA_def_property(srna, "specular_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spectra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Specular Alpha", "Alpha transparency for specular areas."); @@ -725,7 +725,7 @@ static void rna_def_material_diffuse(StructRNA *srna) RNA_def_property_ui_text(prop, "Diffuse Shader Model", ""); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "ref"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Diffuse Intensity", "Amount of diffuse reflection."); @@ -742,7 +742,7 @@ static void rna_def_material_diffuse(StructRNA *srna) RNA_def_property_ui_text(prop, "Diffuse Toon Size", "Size of diffuse toon area."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "diffuse_toon_smooth", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "diffuse_toon_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "param[1]"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Diffuse Toon Smooth", "Smoothness of diffuse toon area."); @@ -786,7 +786,7 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Enabled", "Enable raytraced reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "reflect_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "reflect_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "ray_mirror"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Reflectivity", "Sets the amount mirror reflection for raytrace."); @@ -798,19 +798,19 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for mirror reflection."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "fresnel_mir_i"); RNA_def_property_range(prop, 0.0f, 5.0f); RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "gloss_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Amount", "The shininess of the reflection. Values < 1.0 give diffuse, blurry reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_anisotropic", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_anisotropic", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "aniso_gloss_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Anisotropy", "The shape of the reflection, from 0.0 (circular) to 1.0 (fully stretched along the tangent."); @@ -822,7 +822,7 @@ static void rna_def_material_raymirror(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry reflections."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_mir"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Threshold", "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped."); @@ -869,13 +869,13 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for transparency (Ray or ZTransp)."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "fresnel_tra_i"); RNA_def_property_range(prop, 1.0f, 5.0f); RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "gloss_tra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Amount", "The clarity of the refraction. Values < 1.0 give diffuse, blurry refractions."); @@ -887,7 +887,7 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry refractions."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_tra"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Gloss Threshold", "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped."); @@ -899,7 +899,7 @@ static void rna_def_material_raytra(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Depth", "Maximum allowed number of light inter-refractions."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "filter", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "filter", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "filter"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Filter", "Amount to blend in the material's diffuse color in raytraced transparency (simulating absorption)."); @@ -1011,7 +1011,7 @@ static void rna_def_material_volume(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Depth Cutoff", "Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "density"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Density", "The base density of the volume"); @@ -1093,7 +1093,7 @@ static void rna_def_material_halo(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hardness", "Sets the hardness of the halo."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "add", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "add", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "add"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Add", "Sets the strength of the add effect."); @@ -1239,13 +1239,13 @@ static void rna_def_material_sss(BlenderRNA *brna) RNA_def_property_ui_text(prop, "IOR", "Index of refraction (higher values are denser)."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "sss_colfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Color Factor", "Blend factor for SSS colors."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "texture_factor", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "texture_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "sss_texfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Texture Factor", "Texture scatting blend factor."); @@ -1287,7 +1287,7 @@ static void rna_def_material_specularity(StructRNA *srna) RNA_def_property_ui_text(prop, "Specular Shader Model", ""); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spec"); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Specular Intensity", ""); @@ -1316,7 +1316,7 @@ static void rna_def_material_specularity(StructRNA *srna) RNA_def_property_ui_text(prop, "Specular Toon Size", "Size of specular toon area."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "specular_toon_smooth", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "specular_toon_smooth", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "param[3]"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Specular Toon Smooth", "Ssmoothness of specular toon area."); @@ -1474,7 +1474,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Transparency Method", "Method to use for rendering transparency."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "amb"); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Ambient", "Amount of global ambient color the material receives."); @@ -1486,7 +1486,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Emit", "Amount of light to emit."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); - prop= RNA_def_property(srna, "translucency", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "translucency", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Translucency", "Amount of diffuse shading on the back side."); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); @@ -1511,7 +1511,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Factor to multiply shadow buffer bias with (0 is ignore.)"); - prop= RNA_def_property(srna, "shadow_casting_alpha", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "shadow_casting_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shad_alpha"); RNA_def_property_range(prop, 0.001, 1); RNA_def_property_ui_text(prop, "Shadow Casting Alpha", "Shadow casting alpha, only in use for Irregular Shadowbuffer."); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ffc2d78a6ce..480abff19cb 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1619,12 +1619,6 @@ static void rna_def_modifier_collision(BlenderRNA *brna) RNA_def_property_struct_type(prop, "CollisionSettings"); RNA_def_property_pointer_funcs(prop, "rna_CollisionModifier_settings_get", NULL, NULL); RNA_def_property_ui_text(prop, "Settings", ""); - - prop= RNA_def_property(srna, "absorption", PROP_INT, PROP_PERCENTAGE); - RNA_def_property_int_sdna(prop, NULL, "absorption"); - RNA_def_property_ui_range(prop, 0, 100, 1, 2); - RNA_def_property_ui_text(prop, "Absorption %", "How much of effector force gets lost during collision with this object (in percent)."); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_bevel(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d80ebe2da05..ebd032bb0b1 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1118,7 +1118,7 @@ static void def_cmp_splitviewer(StructRNA *srna) RNA_def_property_ui_text(prop, "Axis", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PERCENTAGE); + prop = RNA_def_property(srna, "factor", PROP_INT, PROP_FACTOR); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Factor", ""); @@ -1140,7 +1140,7 @@ static void def_cmp_map_uv(StructRNA *srna) { PropertyRNA *prop; - prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_PERCENTAGE); + prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_FACTOR); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Alpha", ""); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 3dfbfcccacf..1f0d01ce784 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -617,6 +617,12 @@ static void rna_def_collision(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Collision from Stack", "Pick collision object from modifier stack (softbody only)"); RNA_def_property_update(prop, 0, "rna_CollisionSettings_update"); */ + + prop= RNA_def_property(srna, "absorption", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2); + RNA_def_property_ui_text(prop, "Absorption", "How much of effector force gets lost during collision with this object (in percent)."); + RNA_def_property_update(prop, 0, "rna_CollisionSettings_update"); } static void rna_def_field(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 37a1c9fb186..8dd751cd26a 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -842,6 +842,7 @@ static void rna_def_property(BlenderRNA *brna) {PROP_DIRPATH, "DIRECTORY_PATH", 0, "Directory Path", ""}, {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned Number", ""}, {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, + {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, {PROP_TIME, "TIME", 0, "Time", ""}, {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 5def517f8b2..cac639a64ed 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -523,7 +523,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, mesh_select_mode_items); RNA_def_property_ui_text(prop, "Mesh Selection Mode", "Mesh selection and display mode."); - prop= RNA_def_property(srna, "vertex_group_weight", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "vertex_group_weight", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "vgroup_weight"); RNA_def_property_ui_text(prop, "Vertex Group Weight", "Weight to assign in vertex groups."); } diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b9c5739e7eb..e9fcb299c53 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -316,7 +316,7 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Driven Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop= RNA_def_property(srna, "blend", PROP_FLOAT, PROP_PERCENTAGE); + prop= RNA_def_property(srna, "blend", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Blend", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); } -- cgit v1.2.3 From 3448f675cb20ad38691a4d40ed90f44722243ae9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 21:26:04 +0000 Subject: Fix #19427, problem in blenfont not computing the width of text correct, particularly text including spaces. This gave some problems with placing the cursor and selection, and clipping text inside buttons. --- source/blender/blenfont/intern/blf_font.c | 4 ++-- source/blender/editors/interface/interface_widgets.c | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 0a3dd259f6c..8721e49f06b 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -353,8 +353,8 @@ void blf_font_boundbox(FontBLF *font, char *str, rctf *box) pen_x += delta.x >> 6; } - gbox.xmin= g->box.xmin + pen_x; - gbox.xmax= g->box.xmax + pen_x; + gbox.xmin= pen_x; + gbox.xmax= pen_x + g->advance; gbox.ymin= g->box.ymin + pen_y; gbox.ymax= g->box.ymax + pen_y; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 90b2c920613..ac8750f84e6 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -773,7 +773,8 @@ static void widget_draw_icon(uiBut *but, BIFIconID icon, int blend, rcti *rect) /* sets but->ofs to make sure text is correctly visible */ static void ui_text_leftclip(uiFontStyle *fstyle, uiBut *but, rcti *rect) { - int okwidth= rect->xmax-rect->xmin; + int border= (but->flag & UI_BUT_ALIGN_RIGHT)? 8: 10; + int okwidth= rect->xmax-rect->xmin - border; /* need to set this first */ uiStyleFontSet(fstyle); @@ -842,11 +843,8 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b but->drawstr[selend_tmp]= ch; - /* if at pos 0, leave a bit more to the left */ - t= (pos == 0)? 0: 1; - glColor3ubv((unsigned char*)wcol->item); - glRects(rect->xmin+selsta_draw+1, rect->ymin+2, rect->xmin+selwidth_draw+1, rect->ymax-2); + glRects(rect->xmin+selsta_draw, rect->ymin+2, rect->xmin+selwidth_draw, rect->ymax-2); } } else { /* text cursor */ @@ -861,9 +859,6 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b but->drawstr[pos]= ch; } - /* if at pos 0, leave a bit more to the left */ - t += (pos == 0)? 0: 1; - glColor3ub(255,0,0); glRects(rect->xmin+t, rect->ymin+2, rect->xmin+t+2, rect->ymax-2); } -- cgit v1.2.3 From 345169d1fb82ad4d68f867e5b33276e2886bd6f0 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Mon, 21 Sep 2009 21:28:48 +0000 Subject: Updated some colors in node space and file browser to better match the color theme in 2.5. --- source/blender/editors/interface/resources.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index c54e09b2b40..87026bd1a5d 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -517,10 +517,12 @@ void ui_theme_init_userdef(void) /* space file */ /* to have something initialized */ btheme->tfile= btheme->tv3d; - SETCOL(btheme->tfile.back, 90, 90, 90, 255); + SETCOLF(btheme->tfile.back, 0.3, 0.3, 0.3, 1); + SETCOLF(btheme->tfile.panel, 0.3, 0.3, 0.3, 1); + SETCOLF(btheme->tfile.list, 0.4, 0.4, 0.4, 1); SETCOL(btheme->tfile.text, 250, 250, 250, 255); SETCOL(btheme->tfile.text_hi, 15, 15, 15, 255); - SETCOL(btheme->tfile.panel, 180, 180, 180, 255); // bookmark/ui regions + SETCOL(btheme->tfile.panel, 145, 145, 145, 255); // bookmark/ui regions SETCOL(btheme->tfile.active, 130, 130, 130, 255); // selected files SETCOL(btheme->tfile.hilite, 255, 140, 25, 255); // selected files @@ -604,11 +606,11 @@ void ui_theme_init_userdef(void) /* space node, re-uses syntax color storage */ btheme->tnode= btheme->tv3d; SETCOL(btheme->tnode.edge_select, 255, 255, 255, 255); - SETCOL(btheme->tnode.syntaxl, 150, 150, 150, 255); /* TH_NODE, backdrop */ - SETCOL(btheme->tnode.syntaxn, 129, 131, 144, 255); /* in/output */ - SETCOL(btheme->tnode.syntaxb, 127,127,127, 255); /* operator */ - SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */ - SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */ + SETCOL(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */ + SETCOL(btheme->tnode.syntaxn, 100, 100, 100, 255); /* in/output */ + SETCOL(btheme->tnode.syntaxb, 108, 105, 111, 255); /* operator */ + SETCOL(btheme->tnode.syntaxv, 104, 106, 117, 255); /* generator */ + SETCOL(btheme->tnode.syntaxc, 105, 117, 110, 255); /* group */ /* space logic */ btheme->tlogic= btheme->tv3d; -- cgit v1.2.3 From 9182dc3b8f5e2478d3784741b6a77ad6073ac0a1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 21 Sep 2009 21:37:19 +0000 Subject: Fix #19391: quiting BGE could give drawing errors. Blender now restores the default OpenGL state after exiting the game engine, and also removed settings the default state on start, since the game engine already does this. --- source/blender/editors/space_view3d/view3d_view.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 7831d604ddf..b15a7d3c837 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1416,8 +1416,6 @@ static void SaveState(bContext *C) glPushAttrib(GL_ALL_ATTRIB_BITS); - GPU_state_init(); - if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(1); @@ -1446,6 +1444,8 @@ static void RestoreState(bContext *C) win->queue= queue_back; + GPU_state_init(); + glPopAttrib(); } -- cgit v1.2.3 From b55919069e98ecf877d8d44189a0560982583b36 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 22 Sep 2009 01:27:48 +0000 Subject: 2.5 - Keyframe types are now preserved after inserting keyframes which would overwrite the existing keyframes --- source/blender/editors/animation/keyframing.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index e8451b0f979..e3e72a532e2 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -207,8 +207,13 @@ int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt, short flag) // TODO: perform some other operations? } else { + char oldKeyType= BEZKEYTYPE(fcu->bezt + i); + /* just brutally replace the values */ *(fcu->bezt + i) = *bezt; + + /* special exception for keyframe type - copy value back so that this info isn't lost */ + BEZKEYTYPE(fcu->bezt + i)= oldKeyType; } } } -- cgit v1.2.3 From 7ead925ce42509c0f528a1f8919f80f10cb7c799 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 22 Sep 2009 04:40:16 +0000 Subject: - removed View3D->localview since it wasnt set on entering localview (making many tools fail, add objects for eg.), check localvd instead. - Accent (`) key now sets all layers (like in 2.4x) - added Alt+C keybinding for converting object types. --- source/blender/blenlib/intern/arithb.c | 2 +- source/blender/blenloader/intern/readfile.c | 1 - source/blender/editors/mesh/meshtools.c | 2 +- source/blender/editors/object/object_add.c | 2 +- source/blender/editors/object/object_ops.c | 1 + source/blender/editors/object/object_relations.c | 2 +- source/blender/editors/space_view3d/space_view3d.c | 1 - source/blender/editors/space_view3d/view3d_draw.c | 4 +- .../blender/editors/space_view3d/view3d_header.c | 55 +++++++++++++--------- source/blender/editors/space_view3d/view3d_ops.c | 1 + source/blender/editors/space_view3d/view3d_view.c | 4 +- source/blender/makesdna/DNA_view3d_types.h | 2 +- source/blender/makesrna/intern/rna_space.c | 6 +-- 13 files changed, 45 insertions(+), 38 deletions(-) diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index ac79894d827..26bbbf040f3 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -4843,7 +4843,7 @@ static float lambda_cp_line(float p[3], float l1[3], float l2[3]) /* useful to calculate an even width shell, by taking the angle between 2 planes. * The return value is a scale on the offset. * no angle between planes is 1.0, as the angle between the 2 planes approches 180d - * the distance gets very hight, 180d would be inf, but this case isnt valid */ + * the distance gets very high, 180d would be inf, but this case isn't valid */ float AngleToLength(const float angle) { return (angle < SMALL_NUMBER) ? 1.0f : fabsf(1.0f / cosf(angle * (M_PI/180.0f))); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index af7fda82fe4..d9db02e630f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4688,7 +4688,6 @@ void lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene) v3d->layact= v3d->localvd->layact; MEM_freeN(v3d->localvd); v3d->localvd= NULL; - v3d->localview= 0; } */ } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 4aa99820a6e..00893f10165 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -632,7 +632,7 @@ void sort_faces(Scene *scene, View3D *v3d) if (event == 1) Mat4MulMat4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */ else if (event == 2) { /* sort from cursor */ - if( v3d && v3d->localview ) { + if( v3d && v3d->localvd ) { VECCOPY(cur, v3d->cursor); } else { VECCOPY(cur, scene->cursor); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d576f6e8bf6..05905cd42a4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -110,7 +110,7 @@ void ED_object_base_init_from_view(bContext *C, Base *base) VECCOPY(ob->loc, scene->cursor); } else { - if (v3d->localview) { + if (v3d->localvd) { base->lay= ob->lay= v3d->layact | v3d->lay; VECCOPY(ob->loc, v3d->cursor); } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a9b4bfe68dd..7397cead505 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -244,6 +244,7 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0)->ptr, "linked", 1); WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "OBJECT_OT_convert", CKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_proxy_make", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); // XXX this should probably be in screen instead... here for testing purposes in the meantime... - Aligorith diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 17590cbaad3..4a0c812f7b1 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -994,7 +994,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op) if(lay==0) return OPERATOR_CANCELLED; - if(v3d && v3d->localview) { + if(v3d && v3d->localvd) { /* now we can move out of localview. */ // XXX if (!okee("Move from localview")) return; CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index a73a16f38ba..6e415ec731d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -259,7 +259,6 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) if(v3do->localvd) { v3do->localvd= NULL; v3do->properties_storage= NULL; - v3do->localview= 0; v3do->lay= v3dn->localvd->lay; v3do->lay &= 0xFFFFFF; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f8584b14e2b..5612e60e899 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -732,7 +732,7 @@ static void draw_viewport_name(ARegion *ar, View3D *v3d) char *name = view3d_get_name(v3d, rv3d); char *printable = NULL; - if (v3d->localview) { + if (v3d->localvd) { printable = malloc(strlen(name) + strlen(" (Local)_")); /* '_' gives space for '\0' */ strcpy(printable, name); strcat(printable, " (Local)"); @@ -745,7 +745,7 @@ static void draw_viewport_name(ARegion *ar, View3D *v3d) BLF_draw_default(22, ar->winy-17, 0.0f, printable); } - if (v3d->localview) { + if (v3d->localvd) { free(printable); } } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index a18e7da8f20..45828d654aa 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -177,7 +177,7 @@ static void handle_view3d_lock(bContext *C) View3D *v3d= CTX_wm_view3d(C); if (v3d != NULL && sa != NULL) { - if(v3d->localview==0 && v3d->scenelock && sa->spacetype==SPACE_VIEW3D) { + if(v3d->localvd==NULL && v3d->scenelock && sa->spacetype==SPACE_VIEW3D) { /* copy to scene */ scene->lay= v3d->lay; @@ -195,27 +195,38 @@ static int layers_exec(bContext *C, wmOperator *op) View3D *v3d= sa->spacedata.first; int nr= RNA_int_get(op->ptr, "nr"); - if(nr<=0) + if(nr < 0) return OPERATOR_CANCELLED; - nr--; - - if(RNA_boolean_get(op->ptr, "extend")) - v3d->lay |= (1<lay = (1<lay & (1<layact= 1<lay & v3d->layact)==0) { - int bit= 0; + + + if(nr == 0) { + /* all layers */ + v3d->lay |= (1<<20)-1; + + if(!v3d->layact) + v3d->layact= 1; + } + else { + nr--; + + if(RNA_boolean_get(op->ptr, "extend")) + v3d->lay |= (1<lay = (1<lay & (1<layact= 1<lay & (1<layact= 1<lay & v3d->layact)==0) { + int bit= 0; + + while(bit<32) { + if(v3d->lay & (1<layact= 1<flag= OPTYPE_REGISTER|OPTYPE_UNDO; - RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "", 0, 20); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); + RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "The layer number to set, zero for all layers", 0, 20); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Add this layer to the current view layers"); } #if 0 @@ -2078,7 +2089,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } /* LAYERS */ - if(obedit==NULL && v3d->localview==0) { + if(obedit==NULL && v3d->localvd==NULL) { int ob_lay = ob ? ob->lay : 0; uiBlockBeginAlign(block); for(a=0; a<5; a++) { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 3569e2a79e3..57176dc2592 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -157,6 +157,7 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW3D_OT_game_start", PKEY, KM_PRESS, 0, 0); /* layers, shift + alt are properties set in invoke() */ + RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", TWOKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 2); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", THREEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 3); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b15a7d3c837..b6b6f654909 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -110,7 +110,7 @@ void view3d_operator_needs_opengl(const bContext *C) float *give_cursor(Scene *scene, View3D *v3d) { - if(v3d && v3d->localview) return v3d->cursor; + if(v3d && v3d->localvd) return v3d->cursor; else return scene->cursor; } @@ -1303,7 +1303,6 @@ static void initlocalview(Scene *scene, ScrArea *sa) base->object->lay= base->lay; } } - v3d->localview= 0; } } @@ -1325,7 +1324,6 @@ static void restore_localviewdata(ScrArea *sa, int free) if(free) { MEM_freeN(v3d->localvd); v3d->localvd= NULL; - v3d->localview= 0; } for(ar= sa->regionbase.first; ar; ar= ar->next) { diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index d42ccd62694..f67a242b469 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -144,7 +144,7 @@ typedef struct View3D { * The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID, * OB_SHADED or OB_TEXTURE */ short drawtype; - short localview; + short pad2; short scenelock, around, pad3; short flag, flag2; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 9cf413c0f78..df956670eb3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -602,11 +602,9 @@ static void rna_def_space_3dview(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View."); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); - prop= RNA_def_property(srna, "localview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "localview", 0); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop= RNA_def_property(srna, "local_view", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "localvd"); RNA_def_property_ui_text(prop, "Local View", "Display an isolated sub-set of objects, apart from the scene visibility."); - RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); prop= RNA_def_property(srna, "lens", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "lens"); -- cgit v1.2.3 From b1d4d75aab81eecf409956f15bf9c795715dfe86 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Tue, 22 Sep 2009 08:41:03 +0000 Subject: brought back edge slide. --- source/blender/editors/include/ED_mesh.h | 8 + source/blender/editors/include/ED_transform.h | 3 +- source/blender/editors/mesh/editmesh_tools.c | 6 +- source/blender/editors/mesh/mesh_intern.h | 6 - source/blender/editors/mesh/mesh_ops.c | 1 + source/blender/editors/transform/transform.c | 669 +++++++++++++++++++++ source/blender/editors/transform/transform.h | 32 + .../blender/editors/transform/transform_generics.c | 4 + source/blender/editors/transform/transform_ops.c | 1 + 9 files changed, 721 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index a2dba89ec20..a871ab555a5 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -175,5 +175,13 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int ver struct MDeformWeight *ED_vgroup_weight_verify(struct MDeformVert *dv, int defgroup); struct MDeformWeight *ED_vgroup_weight_get(struct MDeformVert *dv, int defgroup); +/*needed by edge slide*/ +struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *eve); +struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2); +int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); +int editface_containsVert(struct EditFace *efa, struct EditVert *eve); +int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); +short sharesFace(struct EditMesh *em, struct EditEdge *e1, struct EditEdge *e2); + #endif /* ED_MESH_H */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 96425f725e9..bf3111de5dc 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -75,7 +75,8 @@ enum { TFM_BAKE_TIME, TFM_BEVEL, TFM_BWEIGHT, - TFM_ALIGN + TFM_ALIGN, + TFM_EDGE_SLIDE } TfmMode; /* TRANSFORM CONTEXTS */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 46b941f70df..2c20e4a147c 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3868,11 +3868,11 @@ typedef struct SlideVert { EditVert origvert; } SlideVert; +#if 0 int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc) { return 0; /* XXX REFACTOR - #if 0'd for now, otherwise can't make 64bit windows builds on 64bit machine */ -#if 0 useless: goto useless // because it doesn't do anything right now @@ -4654,11 +4654,12 @@ useless: } return 1; -#endif // END OF XXX } +#endif // END OF XXX int EdgeLoopDelete(EditMesh *em, wmOperator *op) { +#if 0 //XXX won't work with new edgeslide /* temporal flag setting so we keep UVs when deleting edge loops, * this is a bit of a hack but it works how you would want in almost all cases */ @@ -4677,6 +4678,7 @@ int EdgeLoopDelete(EditMesh *em, wmOperator *op) EM_select_flush(em); // DAG_id_flush_update(obedit->data, OB_RECALC_DATA); return 1; +#endif } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 11a974f2c49..37a6d0f384f 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -61,12 +61,6 @@ extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct Ed extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges); extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2); -EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve); -EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2); -int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); -int editface_containsVert(struct EditFace *efa, struct EditVert *eve); -int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); - void em_setup_viewcontext(struct bContext *C, ViewContext *vc); void MESH_OT_separate(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index f22adc597c7..3f1bbbb9097 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -113,6 +113,7 @@ static int edge_specials_invoke(bContext *C, wmOperator *op, wmEvent *event) uiItemEnumO(layout, "Rotate Edge CCW", 0, "MESH_OT_edge_rotate", "direction", 2); //uiItemO(layout, "Loopcut", 0, "MESH_OT_loop_cut"); // CutEdgeloop(em, 1); //uiItemO(layout, "Edge Slide", 0, "MESH_OT_edge_slide"); // EdgeSlide(em, 0,0.0); + uiItemEnumO(layout, "Edge Slide", 0, "TFM_OT_transform", "mode", TFM_EDGE_SLIDE); uiItemO(layout, "Edge Loop", 0, "MESH_OT_loop_multi_select"); uiItemBooleanO(layout, "Edge Ring", 0, "MESH_OT_loop_multi_select", "ring", 1); uiItemO(layout, NULL, 0, "MESH_OT_loop_to_region"); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index e877f1fecae..8f3fcfedd18 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -100,6 +100,7 @@ #include "ED_markers.h" #include "ED_util.h" #include "ED_view3d.h" +#include "ED_mesh.h" #include "UI_view2d.h" #include "WM_types.h" @@ -108,6 +109,8 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" #include "PIL_time.h" /* sleep */ @@ -1428,6 +1431,9 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int case TFM_BONE_ENVELOPE: initBoneEnvelope(t); break; + case TFM_EDGE_SLIDE: + initEdgeSlide(t); + break; case TFM_BONE_ROLL: initBoneRoll(t); break; @@ -4029,6 +4035,669 @@ int BoneEnvelope(TransInfo *t, short mval[2]) return 1; } +/* ******************** Edge Slide *************** */ + +static int createSlideVerts(TransInfo *t) +{ + Mesh *me = t->obedit->data; + EditMesh *em = me->edit_mesh; + EditFace *efa; + EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; + EditVert *ev, *nearest = NULL; + LinkNode *edgelist = NULL, *vertlist=NULL, *look; + GHash *vertgh; + TransDataSlideVert *tempsv; + float perc = 0, percp = 0,vertdist; // XXX, projectMat[4][4]; + float shiftlabda= 0.0f,len = 0.0f; + int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; + int wasshift = 0; + /* UV correction vars */ + GHash **uvarray= NULL; + SlideData *sld = MEM_callocN(sizeof(*sld), "sld"); + int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + int uvlay_idx; + TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; + RegionView3D *v3d = t->ar->regiondata; + float projectMat[4][4]; + float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f}; + float vec[3]; + //short mval[2], mvalo[2]; + float labda = 0.0f, totvec=0.0; + + view3d_get_object_project_mat(v3d, t->obedit, projectMat); + + //mvalo[0] = -1; mvalo[1] = -1; + numsel =0; + + // Get number of selected edges and clear some flags + for(eed=em->edges.first;eed;eed=eed->next) { + eed->f1 = 0; + eed->f2 = 0; + if(eed->f & SELECT) numsel++; + } + + for(ev=em->verts.first;ev;ev=ev->next) { + ev->f1 = 0; + } + + //Make sure each edge only has 2 faces + // make sure loop doesn't cross face + for(efa=em->faces.first;efa;efa=efa->next) { + int ct = 0; + if(efa->e1->f & SELECT) { + ct++; + efa->e1->f1++; + if(efa->e1->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e2->f & SELECT) { + ct++; + efa->e2->f1++; + if(efa->e2->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e3->f & SELECT) { + ct++; + efa->e3->f1++; + if(efa->e3->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + if(efa->e4 && efa->e4->f & SELECT) { + ct++; + efa->e4->f1++; + if(efa->e4->f1 > 2) { + //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); + return 0; + } + } + // Make sure loop is not 2 edges of same face + if(ct > 1) { + //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself"); + return 0; + } + } + + // Get # of selected verts + for(ev=em->verts.first;ev;ev=ev->next) { + if(ev->f & SELECT) vertsel++; + } + + // Test for multiple segments + if(vertsel > numsel+1) { + //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop"); + return 0; + } + + // Get the edgeloop in order - mark f1 with SELECT once added + for(eed=em->edges.first;eed;eed=eed->next) { + if((eed->f & SELECT) && !(eed->f1 & SELECT)) { + // If this is the first edge added, just put it in + if(!edgelist) { + BLI_linklist_prepend(&edgelist,eed); + numadded++; + first = eed; + last = eed; + eed->f1 = SELECT; + } else { + if(editedge_getSharedVert(eed, last)) { + BLI_linklist_append(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + last = eed; + } else if(editedge_getSharedVert(eed, first)) { + BLI_linklist_prepend(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + first = eed; + } + } + } + if(eed->next == NULL && numadded != numsel) { + eed=em->edges.first; + timesthrough++; + } + + // It looks like there was an unexpected case - Hopefully should not happen + if(timesthrough >= numsel*2) { + BLI_linklist_free(edgelist,NULL); + //BKE_report(op->reports, RPT_ERROR, "Could not order loop"); + return 0; + } + } + + // Put the verts in order in a linklist + look = edgelist; + while(look) { + eed = look->link; + if(!vertlist) { + if(look->next) { + temp = look->next->link; + + //This is the first entry takes care of extra vert + if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + } else { + //This is the case that we only have 1 edge + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } + } + // for all the entries + if(eed->v1->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else if(eed->v2->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + look = look->next; + } + + // populate the SlideVerts + + vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + look = vertlist; + while(look) { + i=0; + j=0; + ev = look->link; + tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert"); + tempsv->up = NULL; + tempsv->down = NULL; + tempsv->origvert.co[0] = ev->co[0]; + tempsv->origvert.co[1] = ev->co[1]; + tempsv->origvert.co[2] = ev->co[2]; + tempsv->origvert.no[0] = ev->no[0]; + tempsv->origvert.no[1] = ev->no[1]; + tempsv->origvert.no[2] = ev->no[2]; + // i is total edges that vert is on + // j is total selected edges that vert is on + + for(eed=em->edges.first;eed;eed=eed->next) { + if(eed->v1 == ev || eed->v2 == ev) { + i++; + if(eed->f & SELECT) { + j++; + } + } + } + // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges + if(i == 4 && j == 2) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev)) { + if(!(eed->f & SELECT)) { + if(!tempsv->up) { + tempsv->up = eed; + } else if (!(tempsv->down)) { + tempsv->down = eed; + } + } + } + } + } + // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected + if(i >= 3 && j == 1) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev) && eed->f & SELECT) { + for(efa = em->faces.first;efa;efa=efa->next) { + if(editface_containsEdge(efa, eed)) { + if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e1; + } else if (!(tempsv->down)) { + tempsv->down = efa->e1; + } + } + if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e2; + } else if (!(tempsv->down)) { + tempsv->down = efa->e2; + } + } + if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e3; + } else if (!(tempsv->down)) { + tempsv->down = efa->e3; + } + } + if(efa->e4) { + if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e4; + } else if (!(tempsv->down)) { + tempsv->down = efa->e4; + } + } + } + + } + } + } + } + } + if(i > 4 && j == 2) { + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + BLI_ghash_insert(vertgh,ev,tempsv); + + look = look->next; + } + + // make sure the UPs nad DOWNs are 'faceloops' + // Also find the nearest slidevert to the cursor + + look = vertlist; + nearest = NULL; + vertdist = -1; + while(look) { + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + if(!tempsv->up || !tempsv->down) { + //BKE_report(op->reports, RPT_ERROR, "Missing rails"); + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + + if(me->drawflag & ME_DRAW_EDGELEN) { + if(!(tempsv->up->f & SELECT)) { + tempsv->up->f |= SELECT; + tempsv->up->f2 |= 16; + } else { + tempsv->up->f2 |= ~16; + } + if(!(tempsv->down->f & SELECT)) { + tempsv->down->f |= SELECT; + tempsv->down->f2 |= 16; + } else { + tempsv->down->f2 |= ~16; + } + } + + if(look->next != NULL) { + TransDataSlideVert *sv; + + ev = (EditVert*)look->next->link; + sv = BLI_ghash_lookup(vertgh, ev); + + if(sv) { + float co[3], co2[3], vec[3]; + + if(!sharesFace(em, tempsv->up,sv->up)) { + EditEdge *swap; + swap = sv->up; + sv->up = sv->down; + sv->down = swap; + } + + view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat); + view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat); + + if (ev == sv->up->v1) { + VecSubf(vec, co, co2); + } else { + VecSubf(vec, co2, co); + } + + VecAddf(start, start, vec); + + view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat); + view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat); + + if (ev == sv->down->v1) { + VecSubf(vec, co2, co); + } else { + VecSubf(vec, co, co2); + } + + VecAddf(end, end, vec); + + totvec += 1.0f; + nearest = (EditVert*)look->link; + } + } + + + + look = look->next; + } + + VecAddf(start, start, end); + VecMulf(start, 0.5*(1.0/totvec)); + VECCOPY(vec, start); + start[0] = t->mval[0]; + start[1] = t->mval[1]; + VecAddf(end, start, vec); + + sld->start[0] = (short) start[0]; + sld->start[1] = (short) start[1]; + sld->end[0] = (short) end[0]; + sld->end[1] = (short) end[1]; + + if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + int maxnum = 0; + + uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); + sld->totuv = uvlay_tot; + suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */ + suv = NULL; + + for (uvlay_idx=0; uvlay_idxverts.first;ev;ev=ev->next) { + ev->tmp.l = 0; + } + look = vertlist; + while(look) { + float *uv_new; + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + ev = look->link; + suv = NULL; + for(efa = em->faces.first;efa;efa=efa->next) { + if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ + int k=-1; /* face corner */ + + /* Is this vert in the faces corner? */ + if (efa->v1==ev) k=0; + else if (efa->v2==ev) k=1; + else if (efa->v3==ev) k=2; + else if (efa->v4 && efa->v4==ev) k=3; + + if (k != -1) { + MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); + EditVert *ev_up, *ev_down; + + uv_new = tf->uv[k]; + + if (ev->tmp.l) { + if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) { + ev->tmp.l = -1; /* Tag as invalid */ + BLI_linklist_free(suv->fuv_list,NULL); + suv->fuv_list = NULL; + BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); + suv = NULL; + break; + } + } else { + ev->tmp.l = 1; + suv = suv_last; + + suv->fuv_list = NULL; + suv->uv_up = suv->uv_down = NULL; + suv->origuv[0] = uv_new[0]; + suv->origuv[1] = uv_new[1]; + + BLI_linklist_prepend(&suv->fuv_list, uv_new); + BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); + + suv_last++; /* advance to next slide UV */ + maxnum++; + } + + /* Now get the uvs along the up or down edge if we can */ + if (suv) { + if (!suv->uv_up) { + ev_up = editedge_getOtherVert(tempsv->up,ev); + if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; + else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; + else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; + } + if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ + ev_down = editedge_getOtherVert(tempsv->down,ev); + if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; + else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; + else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; + } + + /* Copy the pointers to the face UV's */ + BLI_linklist_prepend(&suv->fuv_list, uv_new); + } + } + } + } + look = look->next; + } + } /* end uv layer loop */ + } /* end uvlay_tot */ + + sld->uvhash = uvarray; + sld->slideuv = slideuvs; + sld->vhash = vertgh; + sld->nearest = nearest; + sld->vertlist = vertlist; + sld->edgelist = edgelist; + sld->suv_last = suv_last; + sld->uvlay_tot = uvlay_tot; + + // we should have enough info now to slide + + t->customData = sld; + + return 1; +} + +void initEdgeSlide(TransInfo *t) +{ + SlideData *sld; + + t->mode = TFM_EDGE_SLIDE; + t->transform = EdgeSlide; + + createSlideVerts(t); + sld = t->customData; + + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); + setCustomPoints(t, &t->mouse, sld->end, sld->start); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = (float)((5.0/180)*M_PI); + t->snap[2] = t->snap[1] * 0.2f; + + t->flag |= T_NO_CONSTRAINT; +} + +int doEdgeSlide(TransInfo *t, float perc) +{ + Mesh *me= t->obedit->data; + EditMesh *em = me->edit_mesh; + SlideData *sld = t->customData; + EditEdge *first=NULL,*last=NULL, *temp = NULL; + EditVert *ev, *nearest = sld->nearest; + EditVert *centerVert, *upVert, *downVert; + LinkNode *edgelist = sld->edgelist, *vertlist=sld->vertlist, *look; + GHash *vertgh = sld->vhash; + TransDataSlideVert *tempsv; + float shiftlabda= 0.0f,len = 0.0f; + int i = 0, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; + int wasshift = 0; + /* UV correction vars */ + GHash **uvarray= sld->uvhash; + int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + int uvlay_idx; + TransDataSlideUv *slideuvs=sld->slideuv, *suv=sld->slideuv, *suv_last=NULL; + float uv_tmp[2]; + LinkNode *fuv_link; + float labda = 0.0f; + + len = 0.0f; + + tempsv = BLI_ghash_lookup(vertgh,nearest); + + centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); + upVert = editedge_getOtherVert(tempsv->up, centerVert); + downVert = editedge_getOtherVert(tempsv->down, centerVert); + + len = MIN2(perc, VecLenf(upVert->co,downVert->co)); + len = MAX2(len, 0); + + //Adjust Edgeloop + if(prop) { + look = vertlist; + while(look) { + EditVert *tempev; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + + tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); + VecLerpf(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); + + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + for (uvlay_idx=0; uvlay_idxfuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + + look = look->next; + } + } + else { + //Non prop code + look = vertlist; + while(look) { + float newlen; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + newlen = (len / VecLenf(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co)); + if(newlen > 1.0) {newlen = 1.0;} + if(newlen < 0.0) {newlen = 0.0;} + if(flip == 0) { + VecLerpf(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idxfuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } else{ + VecLerpf(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); + + if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idxfuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } + look = look->next; + } + + } + + return 1; +} + +void freeSlideVerts(TransInfo *t) +{ + TransDataSlideUv *suv; + SlideData *sld = t->customData; + int uvlay_idx; + + //BLI_ghash_free(edgesgh, freeGHash, NULL); + BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(sld->vertlist, NULL); + BLI_linklist_free(sld->edgelist, NULL); + + if (sld->uvlay_tot) { + for (uvlay_idx=0; uvlay_idxuvlay_tot; uvlay_idx++) { + BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); + } + MEM_freeN(sld->slideuv); + MEM_freeN(sld->uvhash); + + suv = sld->suv_last-1; + while (suv >= sld->slideuv) { + if (suv->fuv_list) { + BLI_linklist_free(suv->fuv_list,NULL); + } + suv--; + } + } + + MEM_freeN(sld); +} + +int EdgeSlide(TransInfo *t, short mval[2]) +{ + TransData *td = t->data; + char str[50]; + float final; + + final = t->values[0]; + + snapGrid(t, &final); + + if (hasNumInput(&t->num)) { + char c[20]; + + applyNumInput(&t->num, &final); + + outputNumInput(&(t->num), c); + + sprintf(str, "Edge Slide Percent: %s", &c[0]); + } + else { + sprintf(str, "Edge Slide Percent: %.2f", final); + } + + CLAMP(final, -1.0f, 1.0f); + + /*do stuff here*/ + doEdgeSlide(t, final); + + recalcData(t); + + ED_area_headerprint(t->sa, str); + + return 1; +} /* ******************** EditBone roll *************** */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 2ff6d6d3dce..404257a55ff 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -32,6 +32,8 @@ #include "ED_transform.h" +#include "BLI_editVert.h" + /* ************************** Types ***************************** */ struct TransInfo; @@ -179,6 +181,31 @@ typedef struct TransDataNla { int handle; /* handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends */ } TransDataNla; +struct LinkNode; +struct EditEdge; +struct EditVert; +struct GHash; +typedef struct TransDataSlideUv { + float origuv[2]; + float *uv_up, *uv_down; + //float *fuv[4]; + struct LinkNode *fuv_list; +} TransDataSlideUv; + +typedef struct TransDataSlideVert { + struct EditEdge *up, *down; + struct EditVert origvert; +} TransDataSlideVert; + +typedef struct SlideData { + TransDataSlideUv *slideuv, *suv_last; + int totuv, uvlay_tot; + struct GHash *vhash, **uvhash; + struct EditVert *nearest; + struct LinkNode *edgelist, *vertlist; + short start[2], end[2]; +} SlideData; + typedef struct TransData { float dist; /* Distance needed to affect element (for Proportionnal Editing) */ float rdist; /* Distance to the nearest element (for Proportionnal Editing) */ @@ -467,6 +494,9 @@ int BoneEnvelope(TransInfo *t, short mval[2]); void initBoneRoll(TransInfo *t); int BoneRoll(TransInfo *t, short mval[2]); +void initEdgeSlide(TransInfo *t); +int EdgeSlide(TransInfo *t, short mval[2]); + void initTimeTranslate(TransInfo *t); int TimeTranslate(TransInfo *t, short mval[2]); @@ -667,6 +697,8 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla int createSpaceNormal(float mat[3][3], float normal[3]); int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]); +void freeSlideVerts(TransInfo *t); + #endif diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index d93e92616e1..59429d65e7b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1073,6 +1073,10 @@ void postTrans (TransInfo *t) { MEM_freeN(t->mouse.data); } + + if (t->mode == TFM_EDGE_SLIDE) { + freeSlideVerts(t); + } } void applyTransObjects(TransInfo *t) diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 4bf0e44de7f..69819da8cc2 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -578,6 +578,7 @@ void TFM_OT_transform(struct wmOperatorType *ot) {TFM_BEVEL, "BEVEL", 0, "Bevel", ""}, {TFM_BWEIGHT, "BWEIGHT", 0, "Bweight", ""}, {TFM_ALIGN, "ALIGN", 0, "Align", ""}, + {TFM_EDGE_SLIDE, "EDGESLIDE", 0, "Edge Slide", ""}, {0, NULL, 0, NULL, NULL} }; -- cgit v1.2.3 From cea8e6b6ed834c2607c44a65fe46c5204edad7fd Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Tue, 22 Sep 2009 08:57:00 +0000 Subject: * ensure mingw toolset is recognised properly for python debug when doing BF_DEBUG=1 --- tools/Blender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Blender.py b/tools/Blender.py index fd6272c7c32..1b0573cfda4 100644 --- a/tools/Blender.py +++ b/tools/Blender.py @@ -171,7 +171,7 @@ def setup_syslibs(lenv): syslibs += Split(lenv['BF_FREETYPE_LIB']) if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']: - if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'): + if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): syslibs.append(lenv['BF_PYTHON_LIB']+'_d') else: syslibs.append(lenv['BF_PYTHON_LIB']) -- cgit v1.2.3 From 3c8d34b94e8c615c0349a01e3ea5e6381feaeefa Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Tue, 22 Sep 2009 09:04:43 +0000 Subject: fixed a crash in edge slide --- source/blender/editors/transform/transform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 8f3fcfedd18..7e381b24186 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4508,6 +4508,9 @@ void initEdgeSlide(TransInfo *t) createSlideVerts(t); sld = t->customData; + if (!sld) + return; + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); setCustomPoints(t, &t->mouse, sld->end, sld->start); -- cgit v1.2.3 From 92145d5950b3c069418a097055cc8ae0e5710423 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 22 Sep 2009 09:12:39 +0000 Subject: Changes to allow python to do redraws through the timer operator, a reliable way to test the overhead of the python api (printed to the consoel on exit). - rename WM_OT_ten_timer to WM_OT_redraw_timer - added iterations argument to run more then 10 times (10 is default still) - use report api rather then always calling a popup directly. - added a new test that draws every region without swapping. - dont show the info popup when operators are called from python. - operators called from python now print reports, useful with the interactive console. eg. >>> bpy.ops.wm.redraw_timer(type='DRAW_WIN', iterations=300) Info: 300 x Draw Window: 4168.56 ms, average: 13.8952 --- source/blender/blenkernel/intern/report.c | 2 +- source/blender/makesrna/intern/rna_sequence.c | 1 + source/blender/python/intern/bpy_operator.c | 10 +++ .../blender/windowmanager/intern/wm_event_system.c | 4 +- source/blender/windowmanager/intern/wm_operators.c | 75 +++++++++++++++------- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 391adfb762a..e524359d2bc 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -230,7 +230,7 @@ char *BKE_reports_string(ReportList *reports, ReportType level) DynStr *ds; char *cstring; - if(!reports) + if(!reports || !reports->list.first) return NULL; ds= BLI_dynstr_new(); diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index b1ac02ae17f..51e81d6dd3a 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -520,6 +520,7 @@ static void rna_def_sequence(BlenderRNA *brna) prop= RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "machine"); + RNA_def_property_range(prop, 0, MAXSEQ-1); RNA_def_property_ui_text(prop, "Channel", "Y position of the sequence strip."); RNA_def_property_int_funcs(prop, NULL, "rna_SequenceEditor_channel_set",NULL); // overlap test RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, NULL); diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index f2e2dd77e6d..301204d3e2b 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -89,6 +89,16 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) if(BPy_reports_to_error(reports)) error_val = -1; + /* operator output is nice to have in the terminal/console too */ + if(reports->list.first) { + char *report_str= BKE_reports_string(reports, 0); /* all reports */ + + if(report_str) { + PySys_WriteStdout(report_str); + MEM_freeN(report_str); + } + } + BKE_reports_clear(reports); if ((reports->flag & RPT_FREE) == 0) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 503eb5a1b9a..03e13329bbd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -415,7 +415,9 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P else printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */ - if(!(retval & OPERATOR_RUNNING_MODAL)) { + /* Note, if the report is given as an argument then assume the caller will deal with displaying them + * currently python only uses this */ + if(!(retval & OPERATOR_RUNNING_MODAL) && reports==NULL) { if(op->reports->list.first) /* only show the report if the report list was not given in the function */ uiPupMenuReports(C, op->reports); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 76c15043b89..0b5c2944624 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1979,17 +1979,19 @@ void WM_OT_radial_control_partial(wmOperatorType *ot) /* uses no type defines, fully local testing function anyway... ;) */ -static int ten_timer_exec(bContext *C, wmOperator *op) +static int redraw_timer_exec(bContext *C, wmOperator *op) { ARegion *ar= CTX_wm_region(C); double stime= PIL_check_seconds_timer(); int type = RNA_int_get(op->ptr, "type"); - int a, time; - char tmpstr[128]; + int iter = RNA_int_get(op->ptr, "iterations"); + int a; + float time; + char *infostr= ""; WM_cursor_wait(1); - - for(a=0; a<10; a++) { + + for(a=0; aareabase.first; sa; sa= sa->next) { + ARegion *ar_iter; + CTX_wm_area_set(C, sa); + + for(ar_iter= sa->regionbase.first; ar_iter; ar_iter= ar_iter->next) { + CTX_wm_region_set(C, ar_iter); + ED_region_do_draw(C, ar_iter); + } + } + + CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ + + CTX_wm_area_set(C, sa_back); + CTX_wm_region_set(C, ar_back); + } + else if (type==3) { + wmWindow *win= CTX_wm_window(C); + ScrArea *sa; + for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) ED_area_tag_redraw(sa); wm_draw_update(C); CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ } - else if (type==3) { + else if (type==4) { Scene *scene= CTX_data_scene(C); if(a & 1) scene->r.cfra--; @@ -2024,40 +2048,43 @@ static int ten_timer_exec(bContext *C, wmOperator *op) } } - time= (int) ((PIL_check_seconds_timer()-stime)*1000); + time= ((PIL_check_seconds_timer()-stime)*1000); - if(type==0) sprintf(tmpstr, "10 x Draw Region: %d ms", time); - if(type==1) sprintf(tmpstr, "10 x Draw Region and Swap: %d ms", time); - if(type==2) sprintf(tmpstr, "10 x Draw Window and Swap: %d ms", time); - if(type==3) sprintf(tmpstr, "Anim Step: %d ms", time); - if(type==4) sprintf(tmpstr, "10 x Undo/Redo: %d ms", time); + if(type==0) infostr= "Draw Region"; + if(type==1) infostr= "Draw Region and Swap"; + if(type==2) infostr= "Draw Window"; + if(type==3) infostr= "Draw Window and Swap"; + if(type==4) infostr= "Animation Steps"; + if(type==5) infostr= "Undo/Redo"; WM_cursor_wait(0); - uiPupMenuNotice(C, tmpstr); + BKE_reportf(op->reports, RPT_INFO, "%d x %s: %.2f ms, average: %.4f", iter, infostr, time, time/iter); return OPERATOR_FINISHED; } -static void WM_OT_ten_timer(wmOperatorType *ot) +static void WM_OT_redraw_timer(wmOperatorType *ot) { static EnumPropertyItem prop_type_items[] = { {0, "DRAW", 0, "Draw Region", ""}, - {1, "DRAWSWAP", 0, "Draw Region + Swap", ""}, - {2, "DRAWWINSWAP", 0, "Draw Window + Swap", ""}, - {3, "ANIMSTEP", 0, "Anim Step", ""}, - {4, "UNDO", 0, "Undo/Redo", ""}, + {1, "DRAW_SWAP", 0, "Draw Region + Swap", ""}, + {2, "DRAW_WIN", 0, "Draw Window", ""}, + {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", ""}, + {4, "ANIM_STEP", 0, "Anim Step", ""}, + {5, "UNDO", 0, "Undo/Redo", ""}, {0, NULL, 0, NULL, NULL}}; - ot->name= "Ten Timer"; - ot->idname= "WM_OT_ten_timer"; - ot->description="Ten Timer operator."; + ot->name= "Redraw Timer"; + ot->idname= "WM_OT_redraw_timer"; + ot->description="Simple redraw timer to test the speed of updating the interface."; ot->invoke= WM_menu_invoke; - ot->exec= ten_timer_exec; + ot->exec= redraw_timer_exec; ot->poll= WM_operator_winactive; RNA_def_enum(ot->srna, "type", prop_type_items, 0, "Type", ""); + RNA_def_int(ot->srna, "iterations", 10, 1,INT_MAX, "Iterations", "Number of times to redraw", 1,1000); } @@ -2092,7 +2119,7 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_jobs_timer); WM_operatortype_append(WM_OT_save_as_mainfile); WM_operatortype_append(WM_OT_save_mainfile); - WM_operatortype_append(WM_OT_ten_timer); + WM_operatortype_append(WM_OT_redraw_timer); WM_operatortype_append(WM_OT_debug_menu); WM_operatortype_append(WM_OT_search_menu); } @@ -2127,7 +2154,7 @@ void wm_window_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "WM_OT_exit_blender", QKEY, KM_PRESS, KM_CTRL, 0); /* debug/testing */ - WM_keymap_verify_item(keymap, "WM_OT_ten_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); + WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0); -- cgit v1.2.3 From 87f5f194bcf8a4bb8a22b8402d8bb088084d6489 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 22 Sep 2009 11:45:30 +0000 Subject: 2.5 - Animation Tweaks * delta-transforms for objects should work again. These were basically extra transforms that could get added on top of the values calculated from animation values. * Added some skeleton code for fixing paths when some data needs to be renamed. --- source/blender/blenkernel/intern/anim_sys.c | 103 +++++++++++++++++++++++++--- source/blender/blenkernel/intern/object.c | 53 +++++--------- 2 files changed, 112 insertions(+), 44 deletions(-) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index af4bcd8b0f7..ca16c62436b 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -211,25 +211,110 @@ static void make_local_strips(ListBase *strips) { NlaStrip *strip; - for(strip=strips->first; strip; strip=strip->next) { - if(strip->act) make_local_action(strip->act); - if(strip->remap && strip->remap->target) make_local_action(strip->remap->target); - + for (strip=strips->first; strip; strip=strip->next) { + if (strip->act) make_local_action(strip->act); + //if (strip->remap && strip->remap->target) make_local_action(strip->remap->target); + make_local_strips(&strip->strips); } } +/* Use local copy instead of linked copy of various ID-blocks */ void BKE_animdata_make_local(AnimData *adt) { NlaTrack *nlt; + + /* Actions - Active and Temp */ + if (adt->action) make_local_action(adt->action); + if (adt->tmpact) make_local_action(adt->tmpact); + /* Remaps */ + if (adt->remap && adt->remap->target) make_local_action(adt->remap->target); + + /* Drivers */ + // TODO: need to remap the ID-targets too? + + /* NLA Data */ + for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next) + make_local_strips(&nlt->strips); +} - if(adt->action) make_local_action(adt->action); - if(adt->tmpact) make_local_action(adt->tmpact); - if(adt->remap && adt->remap->target) make_local_action(adt->remap->target); +/* Path Validation -------------------------------------------- */ - for(nlt=adt->nla_tracks.first; nlt; nlt=nlt->next) - make_local_strips(&nlt->strips); +#if 0 +/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate */ +static char *rna_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, char *oldpath) +{ + return oldpath; // FIXME!!! +} + +/* Check RNA-Paths for a list of F-Curves */ +static void fcurves_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, ListBase *curves) +{ + FCurve *fcu; + + /* we need to check every curve... */ + for (fcu= curves->first; fcu; fcu= fcu->next) { + /* firstly, handle the F-Curve's own path */ + fcu->rna_path= rna_path_rename_fix(owner_id, modPtr, newName, fcu->rna_path); + + /* driver? */ + if (fcu->driver) { + ChannelDriver *driver= fcu->driver; + DriverTarget *dtar; + + /* driver targets */ + for (dtar= driver->targets.first; dtar; dtar=dtar->next) { + dtat->rna_path= rna_path_rename_fix(owner_id, modPtr, newName, dtar->rna_path); + } + } + } +} + +/* Fix all RNA-Paths for Actions linked to NLA Strips */ +static void nlastrips_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, ListBase *strips) +{ + NlaStrip *strip; + + /* recursively check strips, fixing only actions... */ + for (strip= strips->first; strip; strip= strip->next) { + /* fix strip's action */ + if (strip->act) + fcurves_path_rename_fix(owner_id, modPtr, newName, &strip->act->curves); + /* ignore own F-Curves, since those are local... */ + + /* check sub-strips (if metas) */ + nlastrips_path_rename_fix(owner_id, modPtr, newName, &strip->strips); + } +} + +/* Fix all RNA-Paths in the AnimData block used by the given ID block + * - the pointer of interest must not have had its new name assigned already, otherwise + * path matching for this will never work + */ +void BKE_animdata_fix_paths_rename (ID *owner_id, PointerRNA *modPtr, char *newName) +{ + AnimData *adt= BKE_animdata_from_id(owner_id); + NlaTrack *nlt; + + /* if no AnimData, no need to proceed */ + if (ELEM4(NULL, owner_id, adt, modPtr, newName)) + return; + + /* Active action and temp action */ + if (adt->action) + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->action->curves); + if (adt->tmpact) + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->tmpact->curves); + + /* Drivers - Drivers are really F-Curves */ + fcurves_path_rename_fix(owner_id, modPtr, newName, &adt->drivers); + + /* NLA Data - Animation Data for Strips */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + + } } +#endif /* *********************************** */ /* KeyingSet API */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 35514e9697e..c98e2d5970b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1553,13 +1553,11 @@ float bsystem_time(struct Scene *scene, Object *ob, float cfra, float ofs) cfra+= bluroffs+fieldoffs; /* global time */ - cfra*= scene->r.framelen; + if (scene) + cfra*= scene->r.framelen; #if 0 // XXX old animation system if (ob) { - if (no_speed_curve==0 && ob->ipo) - cfra= calc_ipo_time(ob->ipo, cfra); - /* ofset frames */ if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) cfra-= give_timeoffset(ob); @@ -1574,29 +1572,22 @@ float bsystem_time(struct Scene *scene, Object *ob, float cfra, float ofs) void object_scale_to_mat3(Object *ob, float mat[][3]) { float vec[3]; - if(ob->ipo) { - vec[0]= ob->size[0]+ob->dsize[0]; - vec[1]= ob->size[1]+ob->dsize[1]; - vec[2]= ob->size[2]+ob->dsize[2]; - SizeToMat3(vec, mat); - } - else { - SizeToMat3(ob->size, mat); - } + + vec[0]= ob->size[0]+ob->dsize[0]; + vec[1]= ob->size[1]+ob->dsize[1]; + vec[2]= ob->size[2]+ob->dsize[2]; + SizeToMat3(vec, mat); } +// TODO: this should take rotation orders into account later... void object_rot_to_mat3(Object *ob, float mat[][3]) { float vec[3]; - if(ob->ipo) { - vec[0]= ob->rot[0]+ob->drot[0]; - vec[1]= ob->rot[1]+ob->drot[1]; - vec[2]= ob->rot[2]+ob->drot[2]; - EulToMat3(vec, mat); - } - else { - EulToMat3(ob->rot, mat); - } + + vec[0]= ob->rot[0]+ob->drot[0]; + vec[1]= ob->rot[1]+ob->drot[1]; + vec[2]= ob->rot[2]+ob->drot[2]; + EulToMat3(vec, mat); } void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ @@ -1611,13 +1602,8 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ /* rot */ /* Quats arnt used yet */ /*if(ob->transflag & OB_QUAT) { - if(ob->ipo) { - QuatMul(q1, ob->quat, ob->dquat); - QuatToMat3(q1, rmat); - } - else { - QuatToMat3(ob->quat, rmat); - } + QuatMul(q1, ob->quat, ob->dquat); + QuatToMat3(q1, rmat); } else {*/ object_rot_to_mat3(ob, rmat); @@ -1633,12 +1619,9 @@ void object_to_mat4(Object *ob, float mat[][4]) Mat4CpyMat3(mat, tmat); - VECCOPY(mat[3], ob->loc); - if(ob->ipo) { - mat[3][0]+= ob->dloc[0]; - mat[3][1]+= ob->dloc[1]; - mat[3][2]+= ob->dloc[2]; - } + mat[3][0]= ob->loc[0] + ob->dloc[0]; + mat[3][1]= ob->loc[1] + ob->dloc[1]; + mat[3][2]= ob->loc[2] + ob->dloc[2]; } int enable_cu_speed= 1; -- cgit v1.2.3 From d86864027d449114868ec531b9ccf6dd19dbe67f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 22 Sep 2009 16:23:46 +0000 Subject: PyConsole improvements - Commands from the history wont get modified in-place when you cycle back and re-use them. - Ctrl Left/Right skip words. - Autocompletion on a variable that has no alternatives adds a '.' 'bpy' -> 'bpy.', generally more useful since autocomp again will give the members of bpy also moved text_check_* functions into BKE_text.h for the console to access. --- release/ui/space_console.py | 12 ++- source/blender/blenkernel/BKE_text.h | 8 ++ source/blender/blenkernel/intern/text.c | 57 +++++++++++++ source/blender/editors/space_console/console_ops.c | 99 +++++++++++++++++++++- .../blender/editors/space_console/space_console.c | 8 +- source/blender/editors/space_text/text_draw.c | 54 ------------ 6 files changed, 173 insertions(+), 65 deletions(-) diff --git a/release/ui/space_console.py b/release/ui/space_console.py index 980c11b706a..4641d7900cb 100644 --- a/release/ui/space_console.py +++ b/release/ui/space_console.py @@ -246,11 +246,17 @@ def autocomp(bcon): break else: autocomp_prefix_ret += char_soup.pop() - - print(autocomp_prefix_ret) + return autocomp_prefix_ret, autocomp_members elif len(autocomp_members) == 1: - return autocomp_members[0][len(autocomp_prefix):], [] + if autocomp_prefix == autocomp_members[0]: + # the variable matched the prefix exactly + # add a '.' so you can quickly continue. + # Could try add [] or other possible extensions rather then '.' too if we had the variable. + return '.', [] + else: + # finish off the of the word word + return autocomp_members[0][len(autocomp_prefix):], [] else: return '', [] diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 07e05756ea3..185e32ecdfa 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -104,6 +104,14 @@ struct TextMarker *txt_next_marker (struct Text *text, struct TextMarker *marke struct TextMarker *txt_prev_marker_color (struct Text *text, struct TextMarker *marker); struct TextMarker *txt_next_marker_color (struct Text *text, struct TextMarker *marker); +/* utility functions, could be moved somewhere more generic but are python/text related */ +int text_check_bracket(char ch); +int text_check_delim(char ch); +int text_check_digit(char ch); +int text_check_identifier(char ch); +int text_check_whitespace(char ch); + + /* Undo opcodes */ /* Simple main cursor movement */ diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 270cd873ff5..8bf0f6b8bdf 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2832,3 +2832,60 @@ TextMarker *txt_next_marker(Text *text, TextMarker *marker) { } return NULL; /* Only if marker==NULL */ } + + +/*******************************/ +/* Character utility functions */ +/*******************************/ + +int text_check_bracket(char ch) +{ + int a; + char opens[] = "([{"; + char close[] = ")]}"; + + for(a=0; a<(sizeof(opens)-1); a++) { + if(ch==opens[a]) + return a+1; + else if(ch==close[a]) + return -(a+1); + } + return 0; +} + +int text_check_delim(char ch) +{ + int a; + char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; + + for(a=0; a<(sizeof(delims)-1); a++) { + if(ch==delims[a]) + return 1; + } + return 0; +} + +int text_check_digit(char ch) +{ + if(ch < '0') return 0; + if(ch <= '9') return 1; + return 0; +} + +int text_check_identifier(char ch) +{ + if(ch < '0') return 0; + if(ch <= '9') return 1; + if(ch < 'A') return 0; + if(ch <= 'Z' || ch == '_') return 1; + if(ch < 'a') return 0; + if(ch <= 'z') return 1; + return 0; +} + +int text_check_whitespace(char ch) +{ + if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') + return 1; + return 0; +} diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index 2120b97becf..ccf7dbff946 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -51,6 +51,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_text.h" /* only for character utility funcs */ #include "WM_api.h" #include "WM_types.h" @@ -119,6 +120,48 @@ static int console_line_cursor_set(ConsoleLine *cl, int cursor) return 1; } +static char cursor_char(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + return cl->line[cl->cursor]; +} + +static char cursor_char_prev(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + if(cl->cursor <= 0) + return '\0'; + + return cl->line[cl->cursor-1]; +} + +static char cursor_char_next(ConsoleLine *cl) +{ + /* assume cursor is clamped */ + if(cl->cursor + 1 >= cl->len) + return '\0'; + + return cl->line[cl->cursor+1]; +} + +static void console_lb_debug__internal(ListBase *lb) +{ + ConsoleLine *cl; + + printf("%d: ", BLI_countlist(lb)); + for(cl= lb->first; cl; cl= cl->next) + printf("<%s> ", cl->line); + printf("\n"); + +} + +static void console_history_debug(const bContext *C) +{ + SpaceConsole *sc= CTX_wm_space_console(C); + + console_lb_debug__internal(&sc->history); +} + static ConsoleLine *console_lb_add__internal(ListBase *lb, ConsoleLine *from) { ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add"); @@ -251,7 +294,7 @@ static EnumPropertyItem move_type_items[]= { {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, {0, NULL, 0, NULL, NULL}}; - + static int move_exec(bContext *C, wmOperator *op) { ConsoleLine *ci= console_history_verify(C); @@ -272,6 +315,37 @@ static int move_exec(bContext *C, wmOperator *op) case NEXT_CHAR: done= console_line_cursor_set(ci, ci->cursor+1); break; + + /* - if the character is a delimiter then skip delimiters (including white space) + * - when jump over the word */ + case PREV_WORD: + while(text_check_delim(cursor_char_prev(ci))) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + while(text_check_delim(cursor_char_prev(ci))==FALSE) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + /* This isnt used for NEXT_WORD because when going back + * its more useful to have the cursor directly after a word then whitespace */ + while(text_check_whitespace(cursor_char_prev(ci))==TRUE) + if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) + break; + + done= 1; /* assume changed */ + break; + case NEXT_WORD: + while(text_check_delim(cursor_char(ci))==TRUE) + if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) + break; + + while(text_check_delim(cursor_char(ci))==FALSE) + if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) + break; + + done= 1; /* assume changed */ + break; } if(done) { @@ -466,7 +540,16 @@ static int history_cycle_exec(bContext *C, wmOperator *op) ConsoleLine *ci= console_history_verify(C); /* TODO - stupid, just prevernts crashes when no command line */ short reverse= RNA_boolean_get(op->ptr, "reverse"); /* assumes down, reverse is up */ - + + /* keep a copy of the line above so when history is cycled + * this is the only function that needs to know about the double-up */ + if(ci->prev) { + ConsoleLine *ci_prev= (ConsoleLine *)ci->prev; + + if(strcmp(ci->line, ci_prev->line)==0) + console_history_free(sc, ci_prev); + } + if(reverse) { /* last item in mistory */ ci= sc->history.last; BLI_remlink(&sc->history, ci); @@ -477,9 +560,17 @@ static int history_cycle_exec(bContext *C, wmOperator *op) BLI_remlink(&sc->history, ci); BLI_addtail(&sc->history, ci); } - + + { /* add a duplicate of the new arg and remove all other instances */ + ConsoleLine *cl; + while((cl= console_history_find(sc, ci->line, ci))) + console_history_free(sc, cl); + + console_history_add(C, (ConsoleLine *)sc->history.last); + } + ED_area_tag_redraw(CTX_wm_area(C)); - + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 6526b569bbb..234f3b5baf2 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -233,13 +233,13 @@ void console_keymap(struct wmWindowManager *wm) { wmKeyMap *keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); - #ifdef __APPLE__ +#ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_END); - #endif +#endif - RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_BEGIN); - RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_END); + RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD); + RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 9721fbc2b9c..5996770c206 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -425,60 +425,6 @@ static void format_draw_color(char formatchar) } } -/*********************** utilities ************************/ - -int text_check_bracket(char ch) -{ - int a; - char opens[] = "([{"; - char close[] = ")]}"; - - for(a=0; a<3; a++) { - if(ch==opens[a]) - return a+1; - else if(ch==close[a]) - return -(a+1); - } - return 0; -} - -int text_check_delim(char ch) -{ - int a; - char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; - - for(a=0; a<28; a++) { - if(ch==delims[a]) - return 1; - } - return 0; -} - -int text_check_digit(char ch) -{ - if(ch < '0') return 0; - if(ch <= '9') return 1; - return 0; -} - -int text_check_identifier(char ch) -{ - if(ch < '0') return 0; - if(ch <= '9') return 1; - if(ch < 'A') return 0; - if(ch <= 'Z' || ch == '_') return 1; - if(ch < 'a') return 0; - if(ch <= 'z') return 1; - return 0; -} - -int text_check_whitespace(char ch) -{ - if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') - return 1; - return 0; -} - /************************** draw text *****************************/ /***********************/ /* -- cgit v1.2.3 From b4ef0c7d8d9b4197d209193743e76099cf042ec7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 22 Sep 2009 17:50:29 +0000 Subject: minor fixes for merge of soc-2009-kazanbas, rev23422 - Use CTX_data_main(C) over G.main - no need to define object_type_items inline. - rna_mesh.c - dynamic length array was commented out, not sure why this was needed. Povray and PLY scripts rely on faces having 3/4 verts rather then checking the 4th index is 0 (ok in C, not nice in py). --- source/blender/editors/mesh/editmesh_tools.c | 1 + source/blender/makesrna/intern/rna_main_api.c | 16 +--------------- source/blender/makesrna/intern/rna_mesh.c | 4 +--- source/blender/makesrna/intern/rna_object_api.c | 5 ++++- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 2c20e4a147c..26bee09c925 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4679,6 +4679,7 @@ int EdgeLoopDelete(EditMesh *em, wmOperator *op) // DAG_id_flush_update(obedit->data, OB_RECALC_DATA); return 1; #endif + return 0; } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 9d42c473f50..379cf75d450 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -31,6 +31,7 @@ #include "RNA_define.h" #include "RNA_types.h" +#include "RNA_enum_types.h" #include "DNA_object_types.h" #include "DNA_material_types.h" @@ -135,21 +136,6 @@ void RNA_api_main(StructRNA *srna) FunctionRNA *func; 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."); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index cfc1e017f3c..ecfe59a0142 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -978,13 +978,11 @@ static void rna_def_mface(BlenderRNA *brna) // XXX allows creating invalid meshes prop= RNA_def_property(srna, "verts", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "v1"); RNA_def_property_array(prop, 4); - /* RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_dynamic_array_funcs(prop, "rna_MeshFace_verts_get_length"); RNA_def_property_int_funcs(prop, "rna_MeshFace_verts_get", "rna_MeshFace_verts_set", NULL); - */ + RNA_def_property_ui_text(prop, "Vertices", "Vertex indices"); prop= RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index f809868c130..af6254a99b0 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -114,7 +114,7 @@ static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports /* nurbs_to_mesh changes the type to a mesh, check it worked */ if (tmpobj->type != OB_MESH) { - free_libblock_us( &G.main->object, tmpobj ); + free_libblock_us( &(CTX_data_main(C)->object), tmpobj ); BKE_report(reports, RPT_ERROR, "cant convert curve to mesh. Does the curve have any segments?"); return NULL; } @@ -125,6 +125,9 @@ static Mesh *rna_Object_create_mesh(Object *ob, bContext *C, ReportList *reports case OB_MBALL: /* metaballs don't have modifiers, so just convert to mesh */ ob = find_basis_mball( sce, ob ); + /* todo, re-generatre for render-res */ + /* metaball_polygonize(scene, ob) */ + tmpmesh = add_mesh("Mesh"); mball_to_mesh( &ob->disp, tmpmesh ); break; -- cgit v1.2.3 From a2b3650e926814b5a8b8ce08a69ab7edda6e83ea Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Tue, 22 Sep 2009 18:47:28 +0000 Subject: fixed some edge slide issues --- source/blender/editors/transform/transform.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 7e381b24186..6dec51945ce 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4340,6 +4340,8 @@ static int createSlideVerts(TransInfo *t) if(sv) { float co[3], co2[3], vec[3]; + ev = (EditVert*)look->link; + if(!sharesFace(em, tempsv->up,sv->up)) { EditEdge *swap; swap = sv->up; @@ -4350,7 +4352,7 @@ static int createSlideVerts(TransInfo *t) view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat); view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat); - if (ev == sv->up->v1) { + if (ev == tempsv->up->v1) { VecSubf(vec, co, co2); } else { VecSubf(vec, co2, co); @@ -4361,7 +4363,7 @@ static int createSlideVerts(TransInfo *t) view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat); view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat); - if (ev == sv->down->v1) { + if (ev == tempsv->down->v1) { VecSubf(vec, co2, co); } else { VecSubf(vec, co, co2); -- cgit v1.2.3 From 986f8a9ea34e8c994ae1e19fa47f49e7e0c544e6 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Tue, 22 Sep 2009 19:09:04 +0000 Subject: SVN maintenance. --- intern/guardedalloc/MEM_guardedalloc.h | 2 -- release/io/export_x3d.py | 2 +- source/blender/editors/armature/poseSlide.c | 2 +- source/blender/makesdna/DNA_windowmanager_types.h | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 1d4c753802b..9e3927314d3 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -27,8 +27,6 @@ */ /** - - * $Id$ * Copyright (C) 2001 NaN Technologies B.V. * Guarded memory (de)allocation * diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py index 3e89a5202de..3661d78a343 100644 --- a/release/io/export_x3d.py +++ b/release/io/export_x3d.py @@ -25,7 +25,7 @@ Known issues:
""" -# $Id: export_x3d.py 23222 2009-09-14 14:55:49Z kazanbas $ +# $Id$ # #------------------------------------------------------------------------ # X3D exporter for blender 2.36 or above diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index 353503967ec..24bd2ebe5ad 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -1,5 +1,5 @@ /** - * $Id: poseSlide.c 23179 2009-09-13 12:34:00Z aligorith $ + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index f1ce3491d0a..ea9d0e86c38 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * -- cgit v1.2.3 From 930542540ade1ac181c1fbff2ca8f23715d377fb Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Tue, 22 Sep 2009 20:16:56 +0000 Subject: Make edge slide a proper operator Clean up a couple of things in transform (PET settings, custom data, ...) --- source/blender/editors/mesh/mesh_ops.c | 2 +- source/blender/editors/transform/transform.c | 72 ++++++++++-------- source/blender/editors/transform/transform.h | 1 + .../editors/transform/transform_conversions.c | 2 + .../blender/editors/transform/transform_generics.c | 86 ++++++++++++---------- source/blender/editors/transform/transform_ops.c | 23 ++++++ 6 files changed, 115 insertions(+), 71 deletions(-) diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 3f1bbbb9097..a79b42dcbb8 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -113,7 +113,7 @@ static int edge_specials_invoke(bContext *C, wmOperator *op, wmEvent *event) uiItemEnumO(layout, "Rotate Edge CCW", 0, "MESH_OT_edge_rotate", "direction", 2); //uiItemO(layout, "Loopcut", 0, "MESH_OT_loop_cut"); // CutEdgeloop(em, 1); //uiItemO(layout, "Edge Slide", 0, "MESH_OT_edge_slide"); // EdgeSlide(em, 0,0.0); - uiItemEnumO(layout, "Edge Slide", 0, "TFM_OT_transform", "mode", TFM_EDGE_SLIDE); + uiItemO(layout, "Edge Slide", 0, "TFM_OT_edge_slide"); uiItemO(layout, "Edge Loop", 0, "MESH_OT_loop_multi_select"); uiItemBooleanO(layout, "Edge Ring", 0, "MESH_OT_loop_multi_select", "ring", 1); uiItemO(layout, NULL, 0, "MESH_OT_loop_to_region"); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 6dec51945ce..ca9981bc590 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1321,7 +1321,12 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (t->flag & T_MODAL) { ts->prop_mode = t->prop_mode; - ts->proportional = proportional; + + /* only save back if it wasn't automatically disabled */ + if ((t->options & CTX_NO_PET) == 0) + { + ts->proportional = proportional; + } if(t->spacetype == SPACE_VIEW3D) { @@ -4500,19 +4505,52 @@ static int createSlideVerts(TransInfo *t) return 1; } +void freeSlideVerts(TransInfo *t) +{ + TransDataSlideUv *suv; + SlideData *sld = t->customData; + int uvlay_idx; + + //BLI_ghash_free(edgesgh, freeGHash, NULL); + BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(sld->vertlist, NULL); + BLI_linklist_free(sld->edgelist, NULL); + + if (sld->uvlay_tot) { + for (uvlay_idx=0; uvlay_idxuvlay_tot; uvlay_idx++) { + BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); + } + MEM_freeN(sld->slideuv); + MEM_freeN(sld->uvhash); + + suv = sld->suv_last-1; + while (suv >= sld->slideuv) { + if (suv->fuv_list) { + BLI_linklist_free(suv->fuv_list,NULL); + } + suv--; + } + } + + MEM_freeN(sld); + t->customData = NULL; +} + void initEdgeSlide(TransInfo *t) { SlideData *sld; t->mode = TFM_EDGE_SLIDE; t->transform = EdgeSlide; - + createSlideVerts(t); sld = t->customData; if (!sld) return; + t->customFree = freeSlideVerts; + initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); setCustomPoints(t, &t->mouse, sld->end, sld->start); @@ -4639,36 +4677,6 @@ int doEdgeSlide(TransInfo *t, float perc) return 1; } -void freeSlideVerts(TransInfo *t) -{ - TransDataSlideUv *suv; - SlideData *sld = t->customData; - int uvlay_idx; - - //BLI_ghash_free(edgesgh, freeGHash, NULL); - BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(sld->vertlist, NULL); - BLI_linklist_free(sld->edgelist, NULL); - - if (sld->uvlay_tot) { - for (uvlay_idx=0; uvlay_idxuvlay_tot; uvlay_idx++) { - BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); - } - MEM_freeN(sld->slideuv); - MEM_freeN(sld->uvhash); - - suv = sld->suv_last-1; - while (suv >= sld->slideuv) { - if (suv->fuv_list) { - BLI_linklist_free(suv->fuv_list,NULL); - } - suv--; - } - } - - MEM_freeN(sld); -} - int EdgeSlide(TransInfo *t, short mval[2]) { TransData *td = t->data; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 404257a55ff..66d5ecd4d66 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -291,6 +291,7 @@ typedef struct TransInfo { struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */ void *customData; /* Per Transform custom data */ + void (*customFree)(struct TransInfo *); /* if a special free function is needed */ /*************** NEW STUFF *********************/ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 64151918a47..543bbf13fcc 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5312,6 +5312,8 @@ void createTransData(bContext *C, TransInfo *t) } else { t->flag &= ~T_PROP_EDIT; /* no proportional edit in object mode */ + t->options |= CTX_NO_PET; + createTransObject(C, t); t->flag |= T_OBJECT; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 59429d65e7b..ea5653dc130 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -978,51 +978,60 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event) } } - /* setting PET flag */ - if (op && RNA_struct_find_property(op->ptr, "proportional") && RNA_property_is_set(op->ptr, "proportional")) + /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ + if (op && RNA_struct_find_property(op->ptr, "proportional")) { - switch(RNA_enum_get(op->ptr, "proportional")) + if (RNA_property_is_set(op->ptr, "proportional")) { - case 2: /* XXX connected constant */ - t->flag |= T_PROP_CONNECTED; - case 1: /* XXX prop on constant */ - t->flag |= T_PROP_EDIT; - break; + switch(RNA_enum_get(op->ptr, "proportional")) + { + case 2: /* XXX connected constant */ + t->flag |= T_PROP_CONNECTED; + case 1: /* XXX prop on constant */ + t->flag |= T_PROP_EDIT; + break; + } } - } - else - { - if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) { - t->flag |= T_PROP_EDIT; + else + { + if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) { + t->flag |= T_PROP_EDIT; - if(ts->proportional == 2) - t->flag |= T_PROP_CONNECTED; // yes i know, has to become define + if(ts->proportional == 2) + t->flag |= T_PROP_CONNECTED; // yes i know, has to become define + } } - } - if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size")) - { - t->prop_size = RNA_float_get(op->ptr, "proportional_size"); - } - else - { - t->prop_size = ts->proportional_size; - } + if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size")) + { + t->prop_size = RNA_float_get(op->ptr, "proportional_size"); + } + else + { + t->prop_size = ts->proportional_size; + } - if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff")) - { - t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff"); + + /* TRANSFORM_FIX_ME rna restrictions */ + if (t->prop_size <= 0) + { + t->prop_size = 1.0f; + } + + if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff")) + { + t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff"); + } + else + { + t->prop_mode = ts->prop_mode; + } } - else + else /* add not pet option to context when not available */ { - t->prop_mode = ts->prop_mode; + t->options |= CTX_NO_PET; } - /* TRANSFORM_FIX_ME rna restrictions */ - if (t->prop_size <= 0) - { - t->prop_size = 1.0f; - } setTransformViewMatrices(t); initNumInput(&t->num); @@ -1065,8 +1074,6 @@ void postTrans (TransInfo *t) ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL); } else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { - if (t->customData) - MEM_freeN(t->customData); } if (t->mouse.data) @@ -1074,8 +1081,11 @@ void postTrans (TransInfo *t) MEM_freeN(t->mouse.data); } - if (t->mode == TFM_EDGE_SLIDE) { - freeSlideVerts(t); + if (t->customFree) { + t->customFree(t); + } + else if (t->customData) { + MEM_freeN(t->customData); } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 69819da8cc2..b6f8d2c8c22 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -99,6 +99,7 @@ char OP_SHRINK_FATTEN[] = "TFM_OT_shrink_fatten"; char OP_TILT[] = "TFM_OT_tilt"; char OP_TRACKBALL[] = "TFM_OT_trackball"; char OP_MIRROR[] = "TFM_OT_mirror"; +char OP_EDGE_SLIDE[] = "TFM_OT_edge_slide"; TransformModeItem transform_modes[] = @@ -113,6 +114,7 @@ TransformModeItem transform_modes[] = {OP_TILT, TFM_TILT}, {OP_TRACKBALL, TFM_TRACKBALL}, {OP_MIRROR, TFM_MIRROR}, + {OP_EDGE_SLIDE, TFM_EDGE_SLIDE}, {NULL, 0} }; @@ -549,6 +551,26 @@ void TFM_OT_mirror(struct wmOperatorType *ot) Properties_Constraints(ot); } +void TFM_OT_edge_slide(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Tilt"; + ot->description= "Tilt selected control vertices of 3d curve."; + ot->idname = OP_EDGE_SLIDE; + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editmesh; + + RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); + + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + void TFM_OT_transform(struct wmOperatorType *ot) { static EnumPropertyItem transform_mode_types[] = { @@ -618,6 +640,7 @@ void transform_operatortypes(void) WM_operatortype_append(TFM_OT_tilt); WM_operatortype_append(TFM_OT_trackball); WM_operatortype_append(TFM_OT_mirror); + WM_operatortype_append(TFM_OT_edge_slide); WM_operatortype_append(TFM_OT_select_orientation); } -- cgit v1.2.3 From 7b1e5f4d8e38fa39e2b97f4602031bd990ec8524 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 23 Sep 2009 00:53:30 +0000 Subject: * Tweak to fix: [#8358] Performance regression with raytraced refraction Now shadows are only sampled once in reflections/refractions. For cases where this would be a problem (perfect specular reflection/refraction), the full OSA takes care of it. --- source/blender/render/intern/source/rayshade.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index d2599f6050c..c1d0c943ca9 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -1900,7 +1900,8 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * else max_samples = 1; } else { if (do_soft) max_samples = lar->ray_totsamp; - else max_samples = (R.osa > 4)?R.osa:5; + else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5; + else max_samples = 1; } ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco); -- cgit v1.2.3 From d98700360838e5dbb52ac633d0a32c5558754eb7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 23 Sep 2009 01:35:45 +0000 Subject: remove rna function convert_to_triface because it uses an internal editmesh function and only the OBJ exporter called this. Converting to tri's on export isnt very important. --- release/io/export_obj.py | 6 ++++- source/blender/blenkernel/BKE_image.h | 3 +++ source/blender/editors/mesh/editmesh_tools.c | 16 ++++++------ source/blender/makesrna/intern/rna_object_api.c | 34 ------------------------- 4 files changed, 16 insertions(+), 43 deletions(-) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index d52ee8ec158..bd323b6586a 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -451,6 +451,9 @@ def write(filename, objects, scene, else: faceuv = False + # XXX - todo, find a better way to do triangulation + # ...removed convert_to_triface because it relies on editmesh + ''' # We have a valid mesh if EXPORT_TRI and me.faces: # Add a dummy object to it. @@ -468,7 +471,8 @@ def write(filename, objects, scene, 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 ] diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 816baa20467..47ab6f324d3 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -125,6 +125,9 @@ void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf); /* called on frame change or before render */ void BKE_image_user_calc_imanr(struct ImageUser *iuser, int cfra, int fieldnr); +/* produce image export path */ +int BKE_get_image_export_path(struct Image *im, const char *dest_dir, char *abs, int abs_size, char *rel, int rel_size); + /* fix things in ImageUser when new image gets assigned */ void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 26bee09c925..6e5ce92c904 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -140,7 +140,7 @@ static int vergface(const void *v1, const void *v2) /* *********************************** */ -void convert_to_triface(EditMesh *em, int direction) +static void convert_to_triface(EditMesh *em, int direction) { EditFace *efa, *efan, *next; float fac; @@ -5638,7 +5638,7 @@ static void collapseuvs(EditMesh *em, EditVert *mergevert) } } -int collapseEdges(EditMesh *em) +static int collapseEdges(EditMesh *em) { EditVert *eve; EditEdge *eed; @@ -5704,7 +5704,7 @@ int collapseEdges(EditMesh *em) return mergecount; } -int merge_firstlast(EditMesh *em, int first, int uvmerge) +static int merge_firstlast(EditMesh *em, int first, int uvmerge) { EditVert *eve,*mergevert; EditSelection *ese; @@ -5738,7 +5738,7 @@ int merge_firstlast(EditMesh *em, int first, int uvmerge) return removedoublesflag(em, 1, 0, MERGELIMIT); } -void em_snap_to_center(EditMesh *em) +static void em_snap_to_center(EditMesh *em) { EditVert *eve; float cent[3] = {0.0f, 0.0f, 0.0f}; @@ -5763,7 +5763,7 @@ void em_snap_to_center(EditMesh *em) } } -void em_snap_to_cursor(EditMesh *em, bContext *C) +static void em_snap_to_cursor(EditMesh *em, bContext *C) { Scene *scene = CTX_data_scene(C); Object *ob= CTX_data_edit_object(C); @@ -5784,7 +5784,7 @@ void em_snap_to_cursor(EditMesh *em, bContext *C) } } -int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) +static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) { EditVert *eve; @@ -5927,7 +5927,7 @@ typedef struct PathEdge { #define PATH_SELECT_EDGE_LENGTH 0 #define PATH_SELECT_TOPOLOGICAL 1 -int select_vertex_path_exec(bContext *C, wmOperator *op) +static int select_vertex_path_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); @@ -7140,7 +7140,7 @@ void MESH_OT_edge_flip(wmOperatorType *ot) /********************** Smooth/Solid Operators *************************/ -void mesh_set_smooth_faces(EditMesh *em, short smooth) +static void mesh_set_smooth_faces(EditMesh *em, short smooth) { EditFace *efa; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index af6254a99b0..098604c1eab 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -260,34 +260,6 @@ static void rna_Object_free_duplilist(Object *ob, ReportList *reports) } } -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_select_all(me->edit_mesh); - - convert_to_triface(me->edit_mesh, 0); - - load_editMesh(sce, ob); - - if (!ob_editing) - free_editMesh(me->edit_mesh); - - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); -} - static bDeformGroup *rna_Object_add_vertex_group(Object *ob, char *group_name) { return ED_vgroup_add_name(ob, group_name); @@ -408,12 +380,6 @@ void RNA_api_object(StructRNA *srna) 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, "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); - /* duplis */ 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."); -- cgit v1.2.3 From efa757fd8d57891f6feb3fc85fdd3e2ab88e7623 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 23 Sep 2009 01:59:57 +0000 Subject: netrender. first draft of html master details. Just point a browser at the master's address and port, et voila. Gives a list of jobs and slaves and well as per frame status for each job and access to slave output logs per frame --- release/io/netrender/__init__.py | 1 + release/io/netrender/client.py | 2 +- release/io/netrender/master.py | 10 ++- release/io/netrender/master_html.py | 119 ++++++++++++++++++++++++++++++++++++ release/io/netrender/model.py | 5 +- release/io/netrender/utils.py | 7 +++ 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 release/io/netrender/master_html.py diff --git a/release/io/netrender/__init__.py b/release/io/netrender/__init__.py index b313d64ccbb..4a1dd2238e3 100644 --- a/release/io/netrender/__init__.py +++ b/release/io/netrender/__init__.py @@ -5,6 +5,7 @@ import operators import client import slave import master +import master_html import utils import balancing import ui diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py index f445fe2f608..65b2937867f 100644 --- a/release/io/netrender/client.py +++ b/release/io/netrender/client.py @@ -1,5 +1,5 @@ import bpy -import sys, os +import sys, os, re import http, http.client, http.server, urllib import subprocess, shutil, time, hashlib diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 1bff5f6340b..0e3c7063cab 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -5,6 +5,7 @@ import subprocess, shutil, time, hashlib from netrender.utils import * import netrender.model import netrender.balancing +import netrender.master_html class MRenderFile: def __init__(self, filepath, start, end): @@ -126,9 +127,9 @@ class MRenderFrame(netrender.model.RenderFrame): # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- class RenderHandler(http.server.BaseHTTPRequestHandler): - def send_head(self, code = http.client.OK, headers = {}): + def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"): self.send_response(code) - self.send_header("Content-type", "application/octet-stream") + self.send_header("Content-type", content) for key, value in headers.items(): self.send_header(key, value) @@ -342,7 +343,10 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head() self.wfile.write(bytes(repr(message), encoding='utf8')) - + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + else: + # hand over the rest to the html section + netrender.master_html.get(self) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py new file mode 100644 index 00000000000..6a337c8d71d --- /dev/null +++ b/release/io/netrender/master_html.py @@ -0,0 +1,119 @@ +import re + +from netrender.utils import * + + +def get(handler): + def output(text): + handler.wfile.write(bytes(text, encoding='utf8')) + + def link(text, url): + return "%s" % (url, text) + + def startTable(border=1): + output("" % border) + + def headerTable(*headers): + output("") + + for c in headers: + output("") + + output("") + + def rowTable(*data): + output("") + + for c in data: + output("") + + output("") + + def endTable(): + output("
" + c + "
" + str(c) + "
") + + handler.send_head(content = "text/html") + + if handler.path == "/html" or handler.path == "/": + output("NetRender") + + output("

Master

") + + output("

Slaves

") + + startTable() + headerTable("id", "name", "address", "stats") + + for slave in handler.server.slaves: + rowTable(slave.id, slave.name, slave.address[0], slave.stats) + + endTable() + + output("

Jobs

") + + startTable() + headerTable("id", "name", "length", "done", "dispatched", "error") + + for job in handler.server.jobs: + results = job.framesStatus() + rowTable(link(job.id, "/html/job" + job.id), job.name, len(job), results[DONE], results[DISPATCHED], results[ERROR]) + + endTable() + + output("") + + elif handler.path.startswith("/html/job"): + job_id = handler.path[9:] + + output("NetRender") + + job = handler.server.getJobByID(job_id) + + if job: + output("

Frames

") + + startTable() + headerTable("no", "status", "render time", "slave", "log") + + for frame in job.frames: + rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else " ", link("view log", "/html/log%s_%i" % (job_id, frame.number)) if frame.log_path else " ") + + endTable() + else: + output("no such job") + + output("") + + elif handler.path.startswith("/html/log"): + pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)") + + output("NetRender") + + match = pattern.match(handler.path[9:]) + if match: + job_id = match.groups()[0] + frame_number = int(match.groups()[1]) + + job = handler.server.getJobByID(job_id) + + if job: + frame = job[frame_number] + + if frame: + f = open(frame.log_path, 'rb') + + output("
")
+						
+						shutil.copyfileobj(f, handler.wfile)
+						
+						output("
") + + f.close() + else: + output("no such frame") + else: + output("no such job") + else: + output("malformed url") + + output("") diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index e8046d7ac8c..9cacfb54a35 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -32,7 +32,7 @@ class RenderSlave: def __init__(self): self.id = "" self.name = "" - self.address = (0,0) + self.address = ("",0) self.stats = "" self.total_done = 0 self.total_error = 0 @@ -173,6 +173,9 @@ class RenderFrame: self.status = QUEUED self.slave = None + def statusText(self): + return STATUS_TEXT[self.status] + def serialize(self): return { "number": self.number, diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index 50ca08d1723..62288aecf94 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -19,6 +19,13 @@ DISPATCHED = 1 DONE = 2 ERROR = 3 +STATUS_TEXT = { + QUEUED: "Queued", + DISPATCHED: "Dispatched", + DONE: "Done", + ERROR: "Error" + } + def rnaType(rna_type): bpy.types.register(rna_type) return rna_type -- cgit v1.2.3 From 9e110a6d00e791b7fa7cc4ba559b68acac029c5b Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 23 Sep 2009 07:28:26 +0000 Subject: A few quick bugfixes: * Vertex Groups list now has a more normal length (2 rows by default) * Copy vertex groups button now has an icon * Pose Sliding tools now allow events which it doesn't process to pass through (i.e. zooming the view now works, and also moving around using the numpad works too) --- release/ui/buttons_data_mesh.py | 6 +++--- source/blender/editors/armature/poseSlide.c | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/release/ui/buttons_data_mesh.py b/release/ui/buttons_data_mesh.py index 33b3960b381..a93d7b66397 100644 --- a/release/ui/buttons_data_mesh.py +++ b/release/ui/buttons_data_mesh.py @@ -60,15 +60,15 @@ class DATA_PT_vertex_groups(DataButtonsPanel): ob = context.object row = layout.row() - row.template_list(ob, "vertex_groups", ob, "active_vertex_group_index") + row.template_list(ob, "vertex_groups", ob, "active_vertex_group_index", rows=2) col = row.column(align=True) col.itemO("object.vertex_group_add", icon='ICON_ZOOMIN', text="") col.itemO("object.vertex_group_remove", icon='ICON_ZOOMOUT', text="") - col.itemO("object.vertex_group_copy", icon='ICON_BLANK1', text="") + col.itemO("object.vertex_group_copy", icon='ICON_COPYDOWN', text="") if ob.data.users > 1: - col.itemO("object.vertex_group_copy_to_linked", icon='ICON_BLANK1', text="") + col.itemO("object.vertex_group_copy_to_linked", icon='ICON_COPYDOWN', text="") group = ob.active_vertex_group if group: diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index 24bd2ebe5ad..7c63954767f 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -721,6 +721,10 @@ static int pose_slide_modal (bContext *C, wmOperator *op, wmEvent *evt) pose_slide_apply(C, op, pso); } break; + + default: /* unhandled event (maybe it was some view manip? */ + /* allow to pass through */ + return OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH; } /* still running... */ -- cgit v1.2.3 From e2a7168e9680f3dd86875777f7fd9e211ce1d6d2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 23 Sep 2009 11:26:16 +0000 Subject: fly mode back as a modal operator view3d.fly - access with the F key, Ctrl+Alt+F in editmode, View->Navigation menu - camera, perspective & 4split (perspective view only) - uses modal keymap, (same as 2.4x). - bugfix since 2.4x, when flying upside down, turning left/right was inverted. - bugfix for "Align Camera To View", was using deprecated v3d->ofs rather then rv3d->ofs, fixed for NDof fly too. checked v3d->ofs is only used in readfile.c Todo - Warping the cursor removed in 2.5, no way to place the cursor in the middle of the view. - Adding keyframes while in flymode to record the path is missing. - Not getting MMB mouse release events (used for pan). need to look into why. --- release/ui/space_view3d.py | 4 + source/blender/editors/mesh/mesh_ops.c | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 2 +- .../blender/editors/space_view3d/view3d_intern.h | 3 + source/blender/editors/space_view3d/view3d_ops.c | 4 + source/blender/editors/space_view3d/view3d_view.c | 815 ++++++++++++++++++++- 6 files changed, 822 insertions(+), 8 deletions(-) diff --git a/release/ui/space_view3d.py b/release/ui/space_view3d.py index fd06853625e..23f3b8a10ac 100644 --- a/release/ui/space_view3d.py +++ b/release/ui/space_view3d.py @@ -136,6 +136,10 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu): layout.item_floatO("view3d.zoom", "delta", 1.0, text="Zoom In") layout.item_floatO("view3d.zoom", "delta", -1.0, text="Zoom Out") + + layout.itemS() + + layout.itemO("view3d.fly") class VIEW3D_MT_view_align(bpy.types.Menu): __space_type__ = 'VIEW_3D' diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index a79b42dcbb8..96f5e7452d1 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -429,7 +429,7 @@ void ED_keymap_mesh(wmWindowManager *wm) WM_keymap_add_item(keymap, "MESH_OT_edge_face_add", FKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0); /* use KM_RELEASE because same key is used for tweaks */ WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", LEFTMOUSE, KM_RELEASE, KM_CTRL, 0); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index b788dc28311..24ec0d124c6 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -2338,7 +2338,7 @@ void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode) if (use_sel) { QuatConj(q1); /* conj == inv for unit quat */ - VecSubf(v3d->ofs, v3d->ofs, obofs); + VecSubf(rv3d->ofs, rv3d->ofs, obofs); QuatMulVecf(q1, rv3d->ofs); VecAddf(rv3d->ofs, rv3d->ofs, obofs); } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 52505fad521..d532d2b2cc8 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -124,6 +124,7 @@ void VIEW3D_OT_smoothview(struct wmOperatorType *ot); void VIEW3D_OT_setcameratoview(struct wmOperatorType *ot); void VIEW3D_OT_localview(struct wmOperatorType *ot); void VIEW3D_OT_game_start(struct wmOperatorType *ot); +void VIEW3D_OT_fly(struct wmOperatorType *ot); int boundbox_clip(RegionView3D *rv3d, float obmat[][4], struct BoundBox *bb); @@ -135,6 +136,8 @@ void smooth_view(struct bContext *C, Object *, Object *, float *ofs, float *quat void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); /* rect: for picking */ void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d); +void fly_modal_keymap(struct wmWindowManager *wm); + /* view3d_buttons.c */ void VIEW3D_OT_properties(struct wmOperatorType *ot); void view3d_buttons_register(struct ARegionType *art); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 57176dc2592..06480d3e2db 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -85,6 +85,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_drawtype); WM_operatortype_append(VIEW3D_OT_localview); WM_operatortype_append(VIEW3D_OT_game_start); + WM_operatortype_append(VIEW3D_OT_fly); WM_operatortype_append(VIEW3D_OT_layers); WM_operatortype_append(VIEW3D_OT_properties); @@ -123,6 +124,8 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center", PADPERIOD, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_ANY, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1); @@ -218,5 +221,6 @@ void view3d_keymap(wmWindowManager *wm) transform_keymap_for_space(wm, keymap, SPACE_VIEW3D); + fly_modal_keymap(wm); } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b6b6f654909..f722a97963d 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -56,9 +56,11 @@ #include "BKE_object.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" +#include "BKE_depsgraph.h" /* for fly mode updating */ #include "RE_pipeline.h" // make_stars @@ -384,26 +386,31 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot) ot->poll= ED_operator_view3d_active; } -static int view3d_setcameratoview_exec(bContext *C, wmOperator *op) +static void setcameratoview3d(View3D *v3d, RegionView3D *rv3d, Object *ob) { - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d= CTX_wm_region_view3d(C); - Object *ob; float dvec[3]; - ob= v3d->camera; dvec[0]= rv3d->dist*rv3d->viewinv[2][0]; dvec[1]= rv3d->dist*rv3d->viewinv[2][1]; dvec[2]= rv3d->dist*rv3d->viewinv[2][2]; VECCOPY(ob->loc, dvec); - VecSubf(ob->loc, ob->loc, v3d->ofs); + VecSubf(ob->loc, ob->loc, rv3d->ofs); rv3d->viewquat[0]= -rv3d->viewquat[0]; QuatToEul(rv3d->viewquat, ob->rot); rv3d->viewquat[0]= -rv3d->viewquat[0]; ob->recalc= OB_RECALC_OB; +} + + +static int view3d_setcameratoview_exec(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d= CTX_wm_region_view3d(C); + + setcameratoview3d(v3d, rv3d, v3d->camera); WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C)); @@ -1572,6 +1579,802 @@ void VIEW3D_OT_game_start(wmOperatorType *ot) ot->poll= game_engine_poll; } + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +#define FLY_MODAL_CANCEL 1 +#define FLY_MODAL_CONFIRM 2 +#define FLY_MODAL_ACCELERATE 3 +#define FLY_MODAL_DECELERATE 4 +#define FLY_MODAL_PAN_ENABLE 5 +#define FLY_MODAL_PAN_DISABLE 6 +#define FLY_MODAL_DIR_FORWARD 7 +#define FLY_MODAL_DIR_BACKWARD 8 +#define FLY_MODAL_DIR_LEFT 9 +#define FLY_MODAL_DIR_RIGHT 10 +#define FLY_MODAL_DIR_UP 11 +#define FLY_MODAL_DIR_DOWN 12 +#define FLY_MODAL_AXIS_LOCK_X 13 +#define FLY_MODAL_AXIS_LOCK_Z 14 +#define FLY_MODAL_PRECISION_ENABLE 15 +#define FLY_MODAL_PRECISION_DISABLE 16 + +/* called in transform_ops.c, on each regeneration of keymaps */ +void fly_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {FLY_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {FLY_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""}, + {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""}, + + {FLY_MODAL_PAN_ENABLE, "PAN_ENABLE", 0, "Pan Enable", ""}, + {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""}, + + {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""}, + {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""}, + {FLY_MODAL_DIR_LEFT, "LEFT", 0, "Fly Left", ""}, + {FLY_MODAL_DIR_RIGHT, "RIGHT", 0, "Fly Right", ""}, + {FLY_MODAL_DIR_UP, "UP", 0, "Fly Up", ""}, + {FLY_MODAL_DIR_DOWN, "DOWN", 0, "Fly Down", ""}, + + {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"}, + {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"}, + + {FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision Enable", ""}, + {FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision Disable", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Fly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Fly Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE); + WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE); + WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE); + WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE); + + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE); + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); /* XXX - Bug in the event system, middle mouse release doesnt work */ + + /* WASD */ + WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); + WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); + WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); + WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); + WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); + WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); + + WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); + WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); + + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); + +} + +typedef struct FlyInfo { + /* context stuff */ + RegionView3D *rv3d; + View3D *v3d; + ARegion *ar; + Scene *scene; + + wmTimer *timer; /* needed for redraws */ + + short state; + short use_precision; + short redraw; + short mval[2]; + + /* fly state state */ + float speed; /* the speed the view is moving per redraw */ + short axis; /* Axis index to move allong by default Z to move allong the view */ + short pan_view; /* when true, pan the view instead of rotating */ + + /* relative view axis locking - xlock, zlock + 0; disabled + 1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed + when the mouse moves, locking is set to 2 so checks are done. + 2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */ + short xlock, zlock; + float xlock_momentum, zlock_momentum; /* nicer dynamics */ + float grid; /* world scale 1.0 default */ + + /* backup values */ + float dist_backup; /* backup the views distance since we use a zero dist for fly mode */ + float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */ + float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */ + short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */ + + /* compare between last state */ + double time_lastwheel; /* used to accelerate when using the mousewheel a lot */ + double time_lastdraw; /* time between draws */ + + /* use for some lag */ + float dvec_prev[3]; /* old for some lag */ + +} FlyInfo; + +/* FlyInfo->state */ +#define FLY_RUNNING 0 +#define FLY_CANCEL 1 +#define FLY_CONFIRM 2 + +int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event) +{ + float upvec[3]; // tmp + float mat[3][3]; + + fly->rv3d= CTX_wm_region_view3d(C); + fly->v3d = CTX_wm_view3d(C); + fly->ar = CTX_wm_region(C); + fly->scene= CTX_data_scene(C); + + if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->id.lib) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); + return FALSE; + } + + if(fly->v3d->ob_centre) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object"); + return FALSE; + } + + if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->constraints.first) { + BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints"); + return FALSE; + } + + fly->state= FLY_RUNNING; + fly->speed= 0.0f; + fly->axis= 2; + fly->pan_view= FALSE; + fly->xlock= FALSE; + fly->zlock= TRUE; + fly->xlock_momentum=0.0f; + fly->zlock_momentum=0.0f; + fly->grid= 1.0f; + fly->use_precision= 0; + + fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f; + + fly->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f); + + + /* we have to rely on events to give proper mousecoords after a warp_pointer */ +//XXX2.5 warp_pointer(cent_orig[0], cent_orig[1]); + //fly->mval[0]= (fly->sa->winx)/2; + //fly->mval[1]= (fly->sa->winy)/2; + + fly->mval[0] = event->x - fly->ar->winrct.xmin; + fly->mval[1] = event->y - fly->ar->winrct.ymin; + + + fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer(); + + fly->rv3d->rflag |= RV3D_FLYMODE; /* so we draw the corner margins */ + + /* detect weather to start with Z locking */ + upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f; + Mat3CpyMat4(mat, fly->rv3d->viewinv); + Mat3MulVecfl(mat, upvec); + if (fabs(upvec[2]) < 0.1) + fly->zlock = 1; + upvec[0]=0; upvec[1]=0; upvec[2]=0; + + fly->persp_backup= fly->rv3d->persp; + fly->dist_backup= fly->rv3d->dist; + if (fly->rv3d->persp==V3D_CAMOB) { + /* store the origoinal camera loc and rot */ + VECCOPY(fly->ofs_backup, fly->v3d->camera->loc); + VECCOPY(fly->rot_backup, fly->v3d->camera->rot); + + where_is_object(fly->scene, fly->v3d->camera); + VECCOPY(fly->rv3d->ofs, fly->v3d->camera->obmat[3]); + VecMulf(fly->rv3d->ofs, -1.0f); /*flip the vector*/ + + fly->rv3d->dist=0.0; + fly->rv3d->viewbut=0; + + /* used for recording */ +//XXX2.5 if(v3d->camera->ipoflag & OB_ACTION_OB) +//XXX2.5 actname= "Object"; + + } else { + /* perspective or ortho */ + if (fly->rv3d->persp==V3D_ORTHO) + fly->rv3d->persp= V3D_PERSP; /*if ortho projection, make perspective */ + QUATCOPY(fly->rot_backup, fly->rv3d->viewquat); + VECCOPY(fly->ofs_backup, fly->rv3d->ofs); + fly->rv3d->dist= 0.0; + + upvec[2]= fly->dist_backup; /*x and y are 0*/ + Mat3MulVecfl(mat, upvec); + VecSubf(fly->rv3d->ofs, fly->rv3d->ofs, upvec); + /*Done with correcting for the dist*/ + } + + return 1; +} + +static int flyEnd(bContext *C, FlyInfo *fly) +{ + RegionView3D *rv3d= fly->rv3d; + View3D *v3d = fly->v3d; + + float upvec[3]; + + if(fly->state == FLY_RUNNING) + return OPERATOR_RUNNING_MODAL; + + WM_event_remove_window_timer(CTX_wm_window(C), fly->timer); + + rv3d->dist= fly->dist_backup; + + if (fly->state == FLY_CANCEL) { + /* Revert to original view? */ + if (fly->persp_backup==V3D_CAMOB) { /* a camera view */ + rv3d->viewbut=1; + VECCOPY(v3d->camera->loc, fly->ofs_backup); + VECCOPY(v3d->camera->rot, fly->rot_backup); + DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB); + } else { + /* Non Camera we need to reset the view back to the original location bacause the user canceled*/ + QUATCOPY(rv3d->viewquat, fly->rot_backup); + VECCOPY(rv3d->ofs, fly->ofs_backup); + rv3d->persp= fly->persp_backup; + } + } + else if (fly->persp_backup==V3D_CAMOB) { /* camera */ + float mat3[3][3]; + Mat3CpyMat4(mat3, v3d->camera->obmat); + Mat3ToCompatibleEul(mat3, v3d->camera->rot, fly->rot_backup); + + DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB); +#if 0 //XXX2.5 + if (IS_AUTOKEY_MODE(NORMAL)) { + allqueue(REDRAWIPO, 0); + allspace(REMAKEIPO, 0); + allqueue(REDRAWNLA, 0); + allqueue(REDRAWTIME, 0); + } +#endif + } + else { /* not camera */ + /* Apply the fly mode view */ + /*restore the dist*/ + float mat[3][3]; + upvec[0]= upvec[1]= 0; + upvec[2]= fly->dist_backup; /*x and y are 0*/ + Mat3CpyMat4(mat, rv3d->viewinv); + Mat3MulVecfl(mat, upvec); + VecAddf(rv3d->ofs, rv3d->ofs, upvec); + /*Done with correcting for the dist */ + } + + rv3d->rflag &= ~RV3D_FLYMODE; +//XXX2.5 BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */ + + + if(fly->state == FLY_CONFIRM) { + MEM_freeN(fly); + return OPERATOR_FINISHED; + } + + MEM_freeN(fly); + return OPERATOR_CANCELLED; +} + +void flyEvent(FlyInfo *fly, wmEvent *event) +{ + if (event->type == TIMER) { + fly->redraw = 1; + } + else if (event->type == MOUSEMOVE) { + fly->mval[0] = event->x - fly->ar->winrct.xmin; + fly->mval[1] = event->y - fly->ar->winrct.ymin; + } /* handle modal keymap first */ + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case FLY_MODAL_CANCEL: + fly->state = FLY_CANCEL; + break; + case FLY_MODAL_CONFIRM: + fly->state = FLY_CONFIRM; + break; + + case FLY_MODAL_ACCELERATE: + { + double time_currwheel; + float time_wheel; + + time_currwheel= PIL_check_seconds_timer(); + time_wheel = (float)(time_currwheel - fly->time_lastwheel); + fly->time_lastwheel = time_currwheel; + /*printf("Wheel %f\n", time_wheel);*/ + /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/ + time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */ + + if (fly->speed<0.0f) fly->speed= 0.0f; + else { + if (event->shift) + fly->speed+= fly->grid*time_wheel*0.1; + else + fly->speed+= fly->grid*time_wheel; + } + break; + } + case FLY_MODAL_DECELERATE: + { + double time_currwheel; + float time_wheel; + + time_currwheel= PIL_check_seconds_timer(); + time_wheel = (float)(time_currwheel - fly->time_lastwheel); + fly->time_lastwheel = time_currwheel; + time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */ + + if (fly->speed>0) fly->speed=0; + else { + if (event->shift) + fly->speed-= fly->grid*time_wheel*0.1; + else + fly->speed-= fly->grid*time_wheel; + } + break; + } + case FLY_MODAL_PAN_ENABLE: + fly->pan_view= TRUE; + break; + case FLY_MODAL_PAN_DISABLE: +//XXX2.5 warp_pointer(cent_orig[0], cent_orig[1]); + fly->pan_view= FALSE; + break; + + /* impliment WASD keys */ + case FLY_MODAL_DIR_FORWARD: + if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather then stopping, game like motion */ + else fly->speed += fly->grid; /* increse like mousewheel if were alredy moving in that difection*/ + fly->axis= 2; + break; + case FLY_MODAL_DIR_BACKWARD: + if (fly->speed>0) fly->speed= -fly->speed; + else fly->speed -= fly->grid; + fly->axis= 2; + break; + case FLY_MODAL_DIR_LEFT: + if (fly->speed < 0.0f) fly->speed= -fly->speed; + fly->axis= 0; + break; + case FLY_MODAL_DIR_RIGHT: + if (fly->speed > 0.0f) fly->speed= -fly->speed; + fly->axis= 0; + break; + + case FLY_MODAL_DIR_UP: + if (fly->speed < 0.0f) fly->speed= -fly->speed; + fly->axis= 1; + break; + + case FLY_MODAL_DIR_DOWN: + if (fly->speed > 0.0f) fly->speed= -fly->speed; + fly->axis= 1; + break; + + case FLY_MODAL_AXIS_LOCK_X: + if (fly->xlock) fly->xlock=0; + else { + fly->xlock = 2; + fly->xlock_momentum = 0.0; + } + break; + case FLY_MODAL_AXIS_LOCK_Z: + if (fly->zlock) fly->zlock=0; + else { + fly->zlock = 2; + fly->zlock_momentum = 0.0; + } + break; + + case FLY_MODAL_PRECISION_ENABLE: + fly->use_precision= TRUE; + break; + case FLY_MODAL_PRECISION_DISABLE: + fly->use_precision= FALSE; + break; + + } + } +} + +//int fly_exec(bContext *C, wmOperator *op) +int flyApply(FlyInfo *fly) +{ + /* + fly mode - Shift+F + a fly loop where the user can move move the view as if they are flying + */ + RegionView3D *rv3d= fly->rv3d; + View3D *v3d = fly->v3d; + ARegion *ar = fly->ar; + Scene *scene= fly->scene; + + float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */ + dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */ + + /* Camera Uprighting variables */ + upvec[3]={0,0,0}, /* stores the view's up vector */ + + moffset[2], /* mouse offset from the views center */ + tmp_quat[4]; /* used for rotating the view */ + + int cent_orig[2], /* view center */ +//XXX- can avoid using // cent[2], /* view center modified */ + xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */ + unsigned char + apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/ + + /* for recording */ +#if 0 //XXX2.5 todo, get animation recording working again. + int playing_anim = 0; //XXX has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM); + int cfra = -1; /*so the first frame always has a key added */ + char *actname=""; +#endif + /* the dist defines a vector that is infront of the offset + to rotate the view about. + this is no good for fly mode because we + want to rotate about the viewers center. + but to correct the dist removal we must + alter offset so the view doesn't jump. */ + + xmargin= ar->winx/20.0f; + ymargin= ar->winy/20.0f; + + cent_orig[0]= ar->winrct.xmin + ar->winx/2; + cent_orig[1]= ar->winrct.ymin + ar->winy/2; + + { + + /* mouse offset from the center */ + moffset[0]= fly->mval[0]- ar->winx/2; + moffset[1]= fly->mval[1]- ar->winy/2; + + /* enforce a view margin */ + if (moffset[0]>xmargin) moffset[0]-=xmargin; + else if (moffset[0] < -xmargin) moffset[0]+=xmargin; + else moffset[0]=0; + + if (moffset[1]>ymargin) moffset[1]-=ymargin; + else if (moffset[1] < -ymargin) moffset[1]+=ymargin; + else moffset[1]=0; + + + /* scale the mouse movement by this value - scales mouse movement to the view size + * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y) + * + * the mouse moves isnt linear */ + + if(moffset[0]) { + moffset[0] /= ar->winx - (xmargin*2); + moffset[0] *= fabs(moffset[0]); + } + + if(moffset[1]) { + moffset[1] /= ar->winy - (ymargin*2); + moffset[1] *= fabs(moffset[1]); + } + + /* Should we redraw? */ + if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) { + float dvec_tmp[3]; + double time_current, time_redraw; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */ + float time_redraw_clamped; + + time_current= PIL_check_seconds_timer(); + time_redraw= (float)(time_current - fly->time_lastdraw); + time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */ + fly->time_lastdraw= time_current; + /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */ + + /* Scale the time to use shift to scale the speed down- just like + shift slows many other areas of blender down */ + if (fly->use_precision) + fly->speed= fly->speed * (1.0f-time_redraw_clamped); + + Mat3CpyMat4(mat, rv3d->viewinv); + + if (fly->pan_view==TRUE) { + /* pan only */ + dvec_tmp[0]= -moffset[0]; + dvec_tmp[1]= -moffset[1]; + dvec_tmp[2]= 0; + + if (fly->use_precision) { + dvec_tmp[0] *= 0.1; + dvec_tmp[1] *= 0.1; + } + + Mat3MulVecfl(mat, dvec_tmp); + VecMulf(dvec_tmp, time_redraw*200.0 * fly->grid); + + } else { + float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/ + + /* rotate about the X axis- look up/down */ + if (moffset[1]) { + upvec[0]=1; + upvec[1]=0; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + if (fly->xlock) fly->xlock = 2; /*check for rotation*/ + if (fly->zlock) fly->zlock = 2; + fly->xlock_momentum= 0.0f; + } + + /* rotate about the Y axis- look left/right */ + if (moffset[0]) { + + /* if we're upside down invert the moffset */ + upvec[0]=0; + upvec[1]=1; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + + if(upvec[2] < 0.0f) + moffset[0]= -moffset[0]; + + /* make the lock vectors */ + if (fly->zlock) { + upvec[0]=0; + upvec[1]=0; + upvec[2]=1; + } else { + upvec[0]=0; + upvec[1]=1; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + } + + VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + if (fly->xlock) fly->xlock = 2;/*check for rotation*/ + if (fly->zlock) fly->zlock = 2; + } + + if (fly->zlock==2) { + upvec[0]=1; + upvec[1]=0; + upvec[2]=0; + Mat3MulVecfl(mat, upvec); + + /*make sure we have some z rolling*/ + if (fabs(upvec[2]) > 0.00001f) { + roll= upvec[2]*5; + upvec[0]=0; /*rotate the view about this axis*/ + upvec[1]=0; + upvec[2]=1; + + Mat3MulVecfl(mat, upvec); + VecRotToQuat( upvec, roll*time_redraw_clamped*fly->zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + fly->zlock_momentum += 0.05f; + } else { + fly->zlock=1; /* dont check until the view rotates again */ + fly->zlock_momentum= 0.0f; + } + } + + if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/ + upvec[0]=0; + upvec[1]=0; + upvec[2]=1; + Mat3MulVecfl(mat, upvec); + /*make sure we have some z rolling*/ + if (fabs(upvec[2]) > 0.00001) { + roll= upvec[2] * -5; + + upvec[0]= 1.0f; /*rotate the view about this axis*/ + upvec[1]= 0.0f; + upvec[2]= 0.0f; + + Mat3MulVecfl(mat, upvec); + + VecRotToQuat( upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f, tmp_quat); /* Rotate about the relative up vec */ + QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat); + + fly->xlock_momentum += 0.05f; + } else { + fly->xlock=1; /* see above */ + fly->xlock_momentum= 0.0f; + } + } + + + if (apply_rotation) { + /* Normal operation */ + /* define dvec, view direction vector */ + dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f; + /* move along the current axis */ + dvec_tmp[fly->axis]= 1.0f; + + Mat3MulVecfl(mat, dvec_tmp); + + VecMulf(dvec_tmp, fly->speed * time_redraw * 0.25f); + } + } + + /* impose a directional lag */ + VecLerpf(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f)))); + + if (rv3d->persp==V3D_CAMOB) { + if (v3d->camera->protectflag & OB_LOCK_LOCX) + dvec[0] = 0.0; + if (v3d->camera->protectflag & OB_LOCK_LOCY) + dvec[1] = 0.0; + if (v3d->camera->protectflag & OB_LOCK_LOCZ) + dvec[2] = 0.0; + } + + VecAddf(rv3d->ofs, rv3d->ofs, dvec); +#if 0 //XXX2.5 + if (fly->zlock && fly->xlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else if (fly->zlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else if (fly->xlock) + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); + else + headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); +#endif + +//XXX2.5 do_screenhandlers(G.curscreen); /* advance the next frame */ + + /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */ + if (rv3d->persp==V3D_CAMOB) { + rv3d->persp= V3D_PERSP; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */ + setviewmatrixview3d(scene, v3d, rv3d); + + setcameratoview3d(v3d, rv3d, v3d->camera); + + { //XXX - some reason setcameratoview3d doesnt copy, shouldnt not be needed! + VECCOPY(v3d->camera->loc, rv3d->ofs); + VecNegf(v3d->camera->loc); + } + + rv3d->persp= V3D_CAMOB; +#if 0 //XXX2.5 + /* record the motion */ + if (IS_AUTOKEY_MODE(NORMAL) && (!playing_anim || cfra != G.scene->r.cfra)) { + cfra = G.scene->r.cfra; + + if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) { + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_X, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Y, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Z, 0); + } + if (fly->speed) { + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_X, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Y, 0); + insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Z, 0); + } + } +#endif + } +//XXX2.5 scrarea_do_windraw(curarea); +//XXX2.5 screen_swapbuffers(); + } else + /*were not redrawing but we need to update the time else the view will jump */ + fly->time_lastdraw= PIL_check_seconds_timer(); + /* end drawing */ + VECCOPY(fly->dvec_prev, dvec); + } + +/* moved to flyEnd() */ + + return OPERATOR_FINISHED; +} + + + +static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + RegionView3D *rv3d= CTX_wm_region_view3d(C); + FlyInfo *fly; + + if(rv3d->viewlock) + return OPERATOR_CANCELLED; + + fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation"); + + op->customdata= fly; + + if(initFlyInfo(C, fly, op, event)==FALSE) { + MEM_freeN(op->customdata); + return OPERATOR_CANCELLED; + } + + flyEvent(fly, event); + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int fly_cancel(bContext *C, wmOperator *op) +{ + FlyInfo *fly = op->customdata; + + fly->state = FLY_CANCEL; + flyEnd(C, fly); + op->customdata= NULL; + + return OPERATOR_CANCELLED; +} + +static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + int exit_code; + + FlyInfo *fly = op->customdata; + + fly->redraw= 0; + + flyEvent(fly, event); + + if(event->type==TIMER) + flyApply(fly); + + if(fly->redraw) {; + ED_region_tag_redraw(CTX_wm_region(C)); + } + + exit_code = flyEnd(C, fly); + + if(exit_code!=OPERATOR_RUNNING_MODAL) + ED_region_tag_redraw(CTX_wm_region(C)); + + return exit_code; +} + +void VIEW3D_OT_fly(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Fly Navigation"; + ot->description= "Interactively fly around the scene."; + ot->idname= "VIEW3D_OT_fly"; + + /* api callbacks */ + ot->invoke= fly_invoke; + ot->cancel= fly_cancel; + ot->modal= fly_modal; + ot->poll= ED_operator_view3d_active; + + /* flags */ + ot->flag= OPTYPE_BLOCKING; + +} + /* ************************************** */ void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3]) -- cgit v1.2.3 From 762d3ad1457a515dd7b64635b96ae55e6640d8e5 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 23 Sep 2009 11:49:12 +0000 Subject: Some UI tweaks as listed by William (http://wiki.blender.org/index.php/BlenderDev/Blender2.5/Todo/UserInterface) * Removed panel docking. "It is too easy to do by accident when reordering panels, is very hard to control and use, and has no real benefit." * Scoll bars have minimum size now, so that the 'thumb' doesn't disappear in long lists. --- source/blender/editors/interface/interface_panel.c | 9 ++++- source/blender/editors/interface/view2d.c | 38 +++++++++++++--------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index cf29a1ddb58..fa24aa72b9f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -963,6 +963,7 @@ static void check_panel_overlap(ARegion *ar, Panel *panel) } } +#if 0 // XXX panel docking/tabbing code that's no longer used static void test_add_new_tabs(ARegion *ar) { Panel *pa, *pasel=NULL, *palap=NULL; @@ -1016,6 +1017,7 @@ static void test_add_new_tabs(ARegion *ar) pa= pa->next; } } +#endif /************************ panel dragging ****************************/ @@ -1382,7 +1384,12 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat if(state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) { if(data && data->state != PANEL_STATE_ANIMATION) { - test_add_new_tabs(ar); // also copies locations of tabs in dragged panel + /* XXX: + * - the panel tabbing function call below (test_add_new_tabs()) has been commented out + * "It is too easy to do by accident when reordering panels, is very hard to control and use, and has no real benefit." - BillRey + * Aligorith, 2009Sep + */ + //test_add_new_tabs(ar); // also copies locations of tabs in dragged panel check_panel_overlap(ar, NULL); // clears } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f9fb7a9306f..be58a78ca85 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1351,7 +1351,7 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short vert= v2d->vert; hor= v2d->hor; - /* slider rects smaller than region */ + /* slider rects need to be smaller than region */ hor.xmin+=4; hor.xmax-=4; if (scroll & V2D_SCROLL_BOTTOM) @@ -1393,13 +1393,18 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short else scrollers->hor_max= (int)(hor.xmin + (fac2 * scrollsize)); + /* prevent inverted sliders */ if (scrollers->hor_min > scrollers->hor_max) scrollers->hor_min= scrollers->hor_max; + /* prevent sliders from being too small, and disappearing */ + if ((scrollers->hor_max - scrollers->hor_min) < V2D_SCROLLER_HANDLE_SIZE) + scrollers->hor_max+= V2D_SCROLLER_HANDLE_SIZE; /* check whether sliders can disappear */ - if(v2d->keeptot) + if(v2d->keeptot) { if(fac1 <= 0.0f && fac2 >= 1.0f) scrollers->horfull= 1; + } } /* vertical scrollers */ @@ -1420,13 +1425,18 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, short else scrollers->vert_max= (int)(vert.ymin + (fac2 * scrollsize)); + /* prevent inverted sliders */ if (scrollers->vert_min > scrollers->vert_max) scrollers->vert_min= scrollers->vert_max; + /* prevent sliders from being too small, and disappearing */ + if ((scrollers->vert_max - scrollers->vert_min) < V2D_SCROLLER_HANDLE_SIZE) + scrollers->vert_max+= V2D_SCROLLER_HANDLE_SIZE; /* check whether sliders can disappear */ - if(v2d->keeptot) + if(v2d->keeptot) { if(fac1 <= 0.0f && fac2 >= 1.0f) scrollers->vertfull= 1; + } } /* grid markings on scrollbars */ @@ -1550,14 +1560,6 @@ static void scroll_printstr(View2DScrollers *scrollers, Scene *scene, float x, f BLF_draw_default(x, y, 0.0f, str); } -/* local defines for scrollers drawing */ - /* radius of scroller 'button' caps */ -#define V2D_SCROLLCAP_RAD 5 - /* shading factor for scroller 'bar' */ -#define V2D_SCROLLBAR_SHADE 0.1f - /* shading factor for scroller 'button' caps */ -#define V2D_SCROLLCAP_SHADE 0.2f - /* Draw scrollbars in the given 2d-region */ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *vs) { @@ -1571,7 +1573,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* horizontal scrollbar */ if (scroll & V2D_SCROLL_HORIZONTAL) { - + /* only draw scrollbar when it doesn't fill the entire space */ if(vs->horfull==0) { bTheme *btheme= U.themes.first; uiWidgetColors wcol= btheme->tui.wcol_scroll; @@ -1584,13 +1586,15 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v slider.ymax= hor.ymax; state= (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE)?UI_SCROLL_PRESSED:0; + + // TODO: disable this for button regions... if (!(v2d->keepzoom & V2D_LOCKZOOM_X)) state |= UI_SCROLL_ARROWS; + uiWidgetScrollDraw(&wcol, &hor, &slider, state); } /* scale indicators */ - // XXX will need to update the font drawing when the new stuff comes in if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) { View2DGrid *grid= vs->grid; float fac, dfac, fac2, val; @@ -1667,7 +1671,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* vertical scrollbar */ if (scroll & V2D_SCROLL_VERTICAL) { - + /* only draw scrollbar when it doesn't fill the entire space */ if(vs->vertfull==0) { bTheme *btheme= U.themes.first; uiWidgetColors wcol= btheme->tui.wcol_scroll; @@ -1680,14 +1684,16 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v slider.ymax= vs->vert_max; state= (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE)?UI_SCROLL_PRESSED:0; - if (!(v2d->keepzoom & V2D_LOCKZOOM_Y)) + + // TODO: disable this for button regions... + if (!(v2d->keepzoom & V2D_LOCKZOOM_Y)) state |= UI_SCROLL_ARROWS; + uiWidgetScrollDraw(&wcol, &vert, &slider, state); } /* scale indiators */ - // XXX will need to update the font drawing when the new stuff comes in if ((scroll & V2D_SCROLL_SCALE_VERTICAL) && (vs->grid)) { View2DGrid *grid= vs->grid; float fac, dfac, val; -- cgit v1.2.3 From ebbb4ad753c1424f24cb5d1ff34169582a7c9917 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Wed, 23 Sep 2009 12:10:56 +0000 Subject: * fixes for compiling with scons/mingw when BF_DEBUG=1. Needs svn up in lib/windows, where I added necessary mingw libs. --- SConstruct | 4 ++-- config/win32-mingw-config.py | 3 ++- config/win32-vc-config.py | 1 + config/win64-vc-config.py | 1 + tools/btools.py | 3 ++- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 402bf18faf5..7e3d23970cb 100644 --- a/SConstruct +++ b/SConstruct @@ -583,9 +583,9 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc'): dllsources.append('${LCGDIR}/release/python' + ver + '.zip') dllsources.append('${LCGDIR}/release/zlib.pyd') if env['BF_DEBUG']: - dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_LIB}_d.dll') + dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}_d.dll') else: - dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_LIB}.dll') + dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}.dll') if env['WITH_BF_ICONV']: if env['OURPLATFORM'] == 'win64-vc': pass # we link statically to iconv on win64 diff --git a/config/win32-mingw-config.py b/config/win32-mingw-config.py index 04e9f5eb4d1..6b10b410715 100644 --- a/config/win32-mingw-config.py +++ b/config/win32-mingw-config.py @@ -6,7 +6,8 @@ BF_PYTHON_VERSION = '3.1' WITH_BF_STATICPYTHON = False BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' -BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}' +BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}mw' +BF_PYTHON_DLL = 'python31' BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' BF_PYTHON_LIB_STATIC = '${BF_PYTHON}/lib/libpython${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}.a' diff --git a/config/win32-vc-config.py b/config/win32-vc-config.py index 4f2af93d0e3..291aa023ec8 100644 --- a/config/win32-vc-config.py +++ b/config/win32-vc-config.py @@ -13,6 +13,7 @@ BF_PYTHON_VERSION = '3.1' BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' BF_PYTHON_LIB = 'python31' +BF_PYTHON_DLL = '${BF_PYTHON_LIB}' BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' WITH_BF_OPENAL = True diff --git a/config/win64-vc-config.py b/config/win64-vc-config.py index b48e3875dd5..5bb01ff16b5 100644 --- a/config/win64-vc-config.py +++ b/config/win64-vc-config.py @@ -13,6 +13,7 @@ BF_PYTHON_VERSION = '3.1' BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' BF_PYTHON_LIB = 'python31' +BF_PYTHON_DLL = '${BF_PYTHON_LIB}' BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' WITH_BF_OPENAL = False diff --git a/tools/btools.py b/tools/btools.py index 771c67aee1f..e3f3827ff45 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -27,7 +27,7 @@ def print_arguments(args, bc): def validate_arguments(args, bc): opts_list = [ - 'WITH_BF_PYTHON', 'BF_PYTHON', 'BF_PYTHON_VERSION', 'BF_PYTHON_INC', 'BF_PYTHON_BINARY', 'BF_PYTHON_LIB', 'BF_PYTHON_LIBPATH', 'WITH_BF_STATICPYTHON', 'BF_PYTHON_LIB_STATIC', + 'WITH_BF_PYTHON', 'BF_PYTHON', 'BF_PYTHON_VERSION', 'BF_PYTHON_INC', 'BF_PYTHON_BINARY', 'BF_PYTHON_LIB', 'BF_PYTHON_LIBPATH', 'WITH_BF_STATICPYTHON', 'BF_PYTHON_LIB_STATIC', 'BF_PYTHON_DLL', 'WITH_BF_OPENAL', 'BF_OPENAL', 'BF_OPENAL_INC', 'BF_OPENAL_LIB', 'BF_OPENAL_LIBPATH', 'WITH_BF_STATICOPENAL', 'BF_OPENAL_LIB_STATIC', 'WITH_BF_SDL', 'BF_SDL', 'BF_SDL_INC', 'BF_SDL_LIB', 'BF_SDL_LIBPATH', 'BF_LIBSAMPLERATE', 'BF_LIBSAMPLERATE_INC', 'BF_LIBSAMPLERATE_LIB', 'BF_LIBSAMPLERATE_LIBPATH', @@ -158,6 +158,7 @@ def read_opts(cfg, args): ('BF_PYTHON_INC', 'include path for Python headers', ''), ('BF_PYTHON_BINARY', 'Path to the Python interpreter', ''), ('BF_PYTHON_LIB', 'Python library', ''), + ('BF_PYTHON_DLL', 'Python dll - used on Windows only', ''), ('BF_PYTHON_LIB_STATIC', 'Python static libraries', ''), ('BF_PYTHON_LIBPATH', 'Library path', ''), ('BF_PYTHON_LINKFLAGS', 'Python link flags', ''), -- cgit v1.2.3 From 6e941a728a2e491f67832504550bb269655b6022 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 23 Sep 2009 13:09:09 +0000 Subject: 2 Anim Bugfixes: * Loading old (2.4x) files with keyframes now inits them properly so that keyframes are tagged as normal keyframes not breakdowns * TrackTo consraint was flagged wrongly for adding it with a target. This meant that the target didn't get set when using the Ctrl-Shift-C hotkey. --- source/blender/blenkernel/intern/ipo.c | 6 ++++++ source/blender/editors/object/object_constraint.c | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 62f44d92d25..dd7904b4782 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1214,6 +1214,9 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha /* interpolation can only be constant... */ dst->ipo= BEZT_IPO_CONST; + /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ + dst->hide= BEZT_KEYTYPE_KEYFRAME; + /* correct values, by checking if the flag of interest is set */ if ( ((int)(dst->vec[1][1])) & (abp->bit) ) dst->vec[0][1]= dst->vec[1][1]= dst->vec[2][1] = 1.0f; @@ -1264,6 +1267,9 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha if (icu->ipo != IPO_MIXED) dst->ipo= icu->ipo; + /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ + dst->hide= BEZT_KEYTYPE_KEYFRAME; + /* correct values for euler rotation curves - they were degrees/10 */ // XXX for now, just make them into radians as RNA sets/reads directly in that form if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index eee6659c6b2..efdef506331 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -919,7 +919,6 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ /* curve-based constraints - set the only_curve and only_ob flags */ - case CONSTRAINT_TYPE_TRACKTO: case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: only_curve= 1; -- cgit v1.2.3 From 6c79d757acf4bccf3dc5b53f1916826bdb99cc8b Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Wed, 23 Sep 2009 21:26:24 +0000 Subject: Initial sketch of file access wrappers. It compiles but does nothing useful yet. The "//" comments are notes to remember what to do in each block. --- source/blender/blenlib/BLI_bfile.h | 138 ++++++++++++++++++ source/blender/blenlib/intern/BLI_bfile.c | 231 ++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 source/blender/blenlib/BLI_bfile.h create mode 100644 source/blender/blenlib/intern/BLI_bfile.c diff --git a/source/blender/blenlib/BLI_bfile.h b/source/blender/blenlib/BLI_bfile.h new file mode 100644 index 00000000000..92543558a19 --- /dev/null +++ b/source/blender/blenlib/BLI_bfile.h @@ -0,0 +1,138 @@ +/* + * $Id$ + * + * ***** 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 by Stichting Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * BFILE* based abstraction of file access. + */ + +#ifndef BLI_BFILE_H +#define BLI_BFILE_H + +/* For fopen's FILE */ +#include + +/** + Defines for the bflags param. + */ +/* Special handling: */ +/* For "symmetry" of flags */ +#define BFILE_NORMAL (0) +/* No supervision, just translate // if needed, RISKY */ +#define BFILE_RAW (1<<0) +/* Path is relative to config dirs */ +#define BFILE_CONFIG (1<<1) +/* Path is for current session temp file */ +#define BFILE_TEMP (1<<2) + +/* Config handling, special cases: */ +#define BFILE_USERONLY (1<<3) +#define BFILE_SYSONLY (1<<4) + +/* Compression to apply on close: */ +#define BFILE_GZIP (1<<5) + +/** + File descriptor for Blender abstracted file access. + */ +typedef struct { + FILE *stream; + int fd; + + /* Anything below should not be touched directly */ + int uflags; /* Special options requested by upper level, copy of bflags */ + char *fpath; /* Final/requested path name */ + char *tpath; /* Temp path name if applicable */ + int type; /* Own flags, common classification of open and fopen */ + int error; /* An op caused an error, unsafe to replace older files */ +} BFILE; + +/** + Open a BFILE* with fopen()-like syntax. + */ +BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags); + +/** + Open a BFILE* with open()-like syntax. + */ +BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags); + +/** + Get the FILE* associated with the BFILE*. + */ +FILE *BLI_bfile_file_from_bfile(BFILE *bfile); + +/** + Get the fd associated with the BFILE*. + */ +int BLI_bfile_fd_from_bfile(BFILE *bfile); + +/** + write()-like using BFILE*. + */ +ssize_t BLI_bfile_write(BFILE *f, const void *buf, size_t count); + +/** + read()-like using BFILE*. + */ +ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count); + +/** + fwrite()-like using BFILE*. + */ +size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f); + +/** + fread()-like using BFILE*. + */ +size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f); + +/** + Close a BFILE, to match close() and fclose(). + */ +void BLI_bfile_close(BFILE *bfile); + +/** + Clear error status. + Call it only if the error has been really handled. + */ +void BLI_bfile_clear_error(BFILE *bfile); + +/** + Set the error status. + Call it to mark writing by a 3rd party failed (libjpeg reported error, ie). + */ +void BLI_bfile_set_error(BFILE *bfile, int error); + +/* +TODO +Maybe also provide more OS/libc things like: +fflush +fprintf and related +fscanf +fgetc/fputc and related +fseek and related + +Probably good to do: +readdir (compacted list showing all files for a "directory" (user versions on top of system's)) +*/ + +#endif /* ifndef BLI_BFILE_H */ diff --git a/source/blender/blenlib/intern/BLI_bfile.c b/source/blender/blenlib/intern/BLI_bfile.c new file mode 100644 index 00000000000..06e75a9a3ca --- /dev/null +++ b/source/blender/blenlib/intern/BLI_bfile.c @@ -0,0 +1,231 @@ +/* + * $Id$ + * + * ***** 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 by Stichting Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * BFILE* based abstraction for file access. + */ + +#include + +#include + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_bfile.h" + +// This would provide config paths and their oldest viable version +// so if there is an uncompatible change, user's old versions are not loaded +//#include "bfile_tables.h" + +/* Internal bfile type flags */ +#define BTF_OPEN (0) +#define BTF_FOPEN (1<<0) +#define BTF_READ (1<<1) +#define BTF_WRITE (1<<2) +#define BTF_AT_END (1<<3) +#define BTF_DISCARD (1<<4) + + +void fill_paths(BFILE *bfile, const char *path) { + char* source_path = NULL; + int bflags = bfile->uflags; + + if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) { +// bfile->fpath is path with // replaced + } + if(bflags & BFILE_TEMP) { +// bfile->fpath is tempdir+path + } + if(bflags & BFILE_CONFIG) { +// bfile->fpath is userdir+version+path +// source_path is first hit in (if using fallback to older versions) +// userdir+curversion+path (... userdir+limitversion+path) sysdir+path +// (limitversion is based in path, using some kind of regex or "tables") + } + + if(bfile->type & BTF_WRITE && !(bflags & BFILE_RAW)) { + /* Generate temp path */ + // bfile->tpath is fpath+randstring + if(!(bfile->type & BTF_DISCARD)) { + /* Copy data to tpath */ + if(source_path) { + // copy it from older version or sys version + } + } + } else { + bfile->tpath = bfile->fpath; + } +} + +BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags) { + BFILE *bfile; + + bfile = MEM_mallocN(sizeof(BFILE), "bfile-fopen"); + bfile->type = BTF_FOPEN; + bfile->uflags = bflags; + + /* From fopen() doc, we can guess some logic: + r BTF_READ + r+ BTF_READ | BTF_WRITE + w BTF_DISCARD | BTF_WRITE + w+ BTF_DISCARD | BTF_WRITE | BTF_READ + a BTF_AT_END | BTF_WRITE + a+ BTF_AT_END | BTF_WRITE | BTF_READ + */ + if(strchr(mode, 'r')) + bfile->type |= BTF_READ; + if(strchr(mode, 'w')) + bfile->type |= (BTF_DISCARD | BTF_WRITE); + if(strchr(mode, 'a')) + bfile->type |= (BTF_AT_END | BTF_WRITE); + if(strchr(mode, '+')) + bfile->type |= (BTF_READ | BTF_WRITE); + + fill_paths(bfile, path); + + bfile->stream = fopen(bfile->tpath, mode); + // detect failed fopen + bfile->fd = fileno(bfile->stream); + return bfile; +} + + +BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags) { + BFILE *bfile; + + bfile = MEM_mallocN(sizeof(BFILE), "bfile-open"); + bfile->type = BTF_OPEN; + bfile->uflags = bflags; + + /* Easy mapping for open() */ + if(flags & O_RDONLY) + bfile->type |= BTF_READ; + if(flags & O_WRONLY) + bfile->type |= BTF_WRITE; + if(flags & O_RDWR) + bfile->type |= (BTF_READ | BTF_WRITE); + if(flags & O_APPEND) + bfile->type |= BTF_AT_END; + if(flags & O_TRUNC) + bfile->type |= BTF_DISCARD; + + fill_paths(bfile, pathname); + + bfile->fd = open(bfile->tpath, flags); + // detect failed open +// bfile->stream = fdopen(bfile->fd, XXX); /* MSWindows _fdopen? */ + return bfile; +} + + +FILE *BLI_bfile_file_from_bfile(BFILE *bfile) { + return bfile->stream; +} + + +int BLI_bfile_fd_from_bfile(BFILE *bfile) { + return bfile->fd; +} + + +ssize_t BLI_bfile_write(BFILE *f, const void *buf, size_t count) { + ssize_t ret; + + ret = write((f->fd), buf, count); + if (ret == -1) { + f->error = 1; + } + + return ret; +} + + +ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count) { + ssize_t ret; + + ret = read((f->fd), buf, count); + if (ret == -1) { + f->error = 1; + } + + return ret; +} + + +size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f) { + size_t ret; + + ret = fwrite(ptr, size, nmemb, f->stream); + if (ret < 0) { + f->error = 1; + } + + return ret; +} + + +size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) { + size_t ret; + + ret = fread(ptr, size, nmemb, f->stream); + if ((ret < 0) && ferror(f->stream)) { + f->error = 1; + } + + return ret; +} + + +void BLI_bfile_close(BFILE *bfile) { + if((bfile->type | BTF_WRITE) && + !(bfile->uflags | BFILE_RAW)) { + /* Make sure data is on disk */ + /* Move to final name if no errors */ + } + + /* Normal close */ + + /* Cleanup */ + if(bfile->fpath) { + MEM_freeN(bfile->fpath); + } + if(bfile->tpath) { + MEM_freeN(bfile->tpath); + } +} + + +void BLI_bfile_clear_error(BFILE *bfile) { + bfile->error = 0; +} + + +void BLI_bfile_set_error(BFILE *bfile, int error) { + /* No cheating, use clear_error() for 0 */ + if (error) { + bfile->error = error; + } +} -- cgit v1.2.3 From b82b50417c9d521a670ede49c7759b784edf2e1c Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 23 Sep 2009 21:46:29 +0000 Subject: netrender: load balancer fixes, cancel all jobs button and small html interface changes --- release/io/netrender/balancing.py | 6 +++--- release/io/netrender/master.py | 30 +++++++++++++++++++++++------- release/io/netrender/master_html.py | 6 ++++-- release/io/netrender/operators.py | 34 ++++++++++++++++++++++++++++++++++ release/io/netrender/ui.py | 1 + release/io/netrender/utils.py | 5 +++-- 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py index 62b6dcee519..b1a461bf0ca 100644 --- a/release/io/netrender/balancing.py +++ b/release/io/netrender/balancing.py @@ -71,14 +71,14 @@ class NewJobPriority(PriorityRule): self.limit = limit def test(self, job): - return job.countFrames(status = DISPATCHED) < self.limit + return job.countFrames(status = DONE) < self.limit class MinimumTimeBetweenDispatchPriority(PriorityRule): def __init__(self, limit = 10): self.limit = limit def test(self, job): - return (time.time() - job.last_dispatched) / 60 > self.limit + return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit class ExcludeQueuedEmptyJob(ExclusionRule): def test(self, job): @@ -91,4 +91,4 @@ class ExcludeSlavesLimit(ExclusionRule): self.limit = limit def test(self, job): - return not ( self.count_jobs() == 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) \ No newline at end of file + return not ( self.count_jobs() == 1 or self.count_slaves() == 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 0e3c7063cab..84a6ad8cca1 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -50,6 +50,7 @@ class MRenderJob(netrender.model.RenderJob): self.last_dispatched = time.time() # special server properties + self.last_update = 0 self.save_path = "" self.files_map = {path: MRenderFile(path, start, end) for path, start, end in files} self.status = JOB_WAITING @@ -68,13 +69,23 @@ class MRenderJob(netrender.model.RenderJob): self.start() return True + def testFinished(self): + for f in self.frames: + if f.status == QUEUED or f.status == DISPATCHED: + break + else: + self.status = JOB_FINISHED + def start(self): self.status = JOB_QUEUED - + def update(self): - self.credits -= 5 # cost of one frame - self.credits += (time.time() - self.last_dispatched) / 60 - self.last_dispatched = time.time() + if self.last_update == 0: + self.credits += (time.time() - self.last_dispatched) / 60 + else: + self.credits += (time.time() - self.last_update) / 60 + + self.last_update = time.time() def addLog(self, frames): log_name = "_".join(("%04d" % f for f in frames)) + ".log" @@ -98,7 +109,8 @@ class MRenderJob(netrender.model.RenderJob): frames = [] for f in self.frames: if f.status == QUEUED: - self.update() + self.credits -= 1 # cost of one frame + self.last_dispatched = time.time() frames.append(f) if len(frames) >= self.chunks: break @@ -512,7 +524,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_time = float(self.headers['job-time']) frame = job[job_frame] - + if job_result == DONE: length = int(self.headers['content-length']) buf = self.rfile.read(length) @@ -527,6 +539,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): frame.status = job_result frame.time = job_time + + job.testFinished() self.server.updateSlave(self.headers['slave-id']) @@ -581,7 +595,7 @@ class RenderMasterServer(http.server.HTTPServer): self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves)) self.balancer.addPriority(netrender.balancing.NewJobPriority()) - self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority()) + self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority(limit = 2)) if not os.path.exists(self.path): os.mkdir(self.path) @@ -612,6 +626,8 @@ class RenderMasterServer(http.server.HTTPServer): self.jobs = [] def update(self): + for job in self.jobs: + job.update() self.balancer.balance(self.jobs) def countJobs(self, status = JOB_QUEUED): diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py index 6a337c8d71d..8e11c86a88c 100644 --- a/release/io/netrender/master_html.py +++ b/release/io/netrender/master_html.py @@ -52,11 +52,13 @@ def get(handler): output("

Jobs

") startTable() - headerTable("id", "name", "length", "done", "dispatched", "error") + headerTable("id", "name", "credits", "time since last", "length", "done", "dispatched", "error", "priority", "exception") + + handler.server.update() for job in handler.server.jobs: results = job.framesStatus() - rowTable(link(job.id, "/html/job" + job.id), job.name, len(job), results[DONE], results[DISPATCHED], results[ERROR]) + rowTable(link(job.id, "/html/job" + job.id), job.name, round(job.credits, 1), int(time.time() - job.last_dispatched), len(job), results[DONE], results[DISPATCHED], results[ERROR], handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)) endTable() diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index bfc67c25285..498edd74529 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -262,12 +262,46 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): response = conn.getresponse() print( response.status, response.reason ) + + netsettings.jobs.remove(netsettings.active_job_index) return ('FINISHED',) def invoke(self, context, event): return self.execute(context) +@rnaOperator +class RENDER_OT_netclientcancelall(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientcancelall" + __label__ = "Net Render Client Cancel All" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + conn = clientConnection(context.scene) + + if conn: + conn.request("POST", "/cancel") + + response = conn.getresponse() + print( response.status, response.reason ) + + while(len(netsettings.jobs) > 0): + netsettings.jobs.remove(0) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + @rnaOperator class netclientdownload(bpy.types.Operator): '''Operator documentation text, will be used for the operator tooltip and python docs.''' diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index 2ec0b62de4a..3aad8362c43 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -165,6 +165,7 @@ class SCENE_PT_network_jobs(RenderButtonsPanel): subcol = col.column(align=True) subcol.itemO("render.netclientstatus", icon="ICON_FILE_REFRESH", text="") subcol.itemO("render.netclientcancel", icon="ICON_ZOOMOUT", text="") + subcol.itemO("render.netclientcancelall", icon="ICON_ZOOMOUT", text="") subcol.itemO("render.netclientdownload", icon='ICON_RENDER_ANIMATION', text="") if len(bpy.data.netrender_jobs) == 0 and len(netsettings.jobs) > 0: diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index 62288aecf94..06393a738a0 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -11,7 +11,8 @@ VERSION = b"0.5" # Jobs status JOB_WAITING = 0 # before all data has been entered JOB_PAUSED = 1 # paused by user -JOB_QUEUED = 2 # ready to be dispatched +JOB_FINISHED = 2 # finished rendering +JOB_QUEUED = 3 # ready to be dispatched # Frames status QUEUED = 0 @@ -82,4 +83,4 @@ def prefixPath(prefix_directory, file_path, prefix_path): else: full_path = prefix_directory + file_path - return full_path \ No newline at end of file + return full_path -- cgit v1.2.3 From 0c68fe3a61f9927dbc5c5d402c600743c611a8a4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 01:32:23 +0000 Subject: brush curve - use clamped values (0-1) for everything except sculpt which can have positive and negative values. --- source/blender/blenkernel/BKE_brush.h | 3 ++- source/blender/blenkernel/intern/brush.c | 27 ++++++++++++++++------- source/blender/editors/sculpt_paint/paint_image.c | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 01566648557..f302618e60d 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -60,7 +60,8 @@ typedef enum { BRUSH_PRESET_MAX } BrushCurvePreset; void brush_curve_preset(struct Brush *b, BrushCurvePreset preset); -float brush_curve_strength(struct Brush *br, float p, const float len); +float brush_curve_strength_clamp(struct Brush *br, float p, const float len); +float brush_curve_strength(struct Brush *br, float p, const float len); /* used for sculpt */ /* sampling */ void brush_sample_tex(struct Brush *brush, float *xy, float *rgba); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 6c3c97399e4..115d31b587c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -442,7 +442,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); VECCOPY(dstf, brush->rgb); - dstf[3]= brush->alpha*brush_curve_strength(brush, dist, maxsize); + dstf[3]= brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize); } else if (texfall == 1) { brush_sample_tex(brush, xy, dstf); @@ -455,7 +455,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dstf[0] = rgba[0]*brush->rgb[0]; dstf[1] = rgba[1]*brush->rgb[1]; dstf[2] = rgba[2]*brush->rgb[2]; - dstf[3] = rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize); + dstf[3] = rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize); } } } @@ -494,7 +494,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]); dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]); dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]); - dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength(brush, dist, maxsize)); + dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize)); } } } @@ -952,12 +952,23 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl } /* Uses the brush curve control to find a strength value between 0 and 1 */ +float brush_curve_strength_clamp(Brush *br, float p, const float len) +{ + if(p >= len) p= 1.0f; + else p= p/len; + + p= curvemapping_evaluateF(br->curve, 0, p); + if(p < 0.0) p= 0.0f; + else if(p > 1.0f) p= 1.0f; + return p; +} +/* same as above but can return negative values if the curve enables + * used for sculpt only */ float brush_curve_strength(Brush *br, float p, const float len) { - float f; - if(p > len) p= len; - f= curvemapping_evaluateF(br->curve, 0, p/len); - return (f > 0.0f) ? f:0.0f; + if(p >= len) p= 1.0f; + else p= p/len; + return curvemapping_evaluateF(br->curve, 0, p); } /* TODO: should probably be unified with BrushPainter stuff? */ @@ -1024,7 +1035,7 @@ static struct ImBuf *brush_gen_radial_control_imbuf(Brush *br) for(i=0; irect_float[i*side + j]= brush_curve_strength(br, magn, half); + im->rect_float[i*side + j]= brush_curve_strength_clamp(br, magn, half); } } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 91ee2fa55d1..d223c423690 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -3731,7 +3731,7 @@ static void *do_projectpaint_thread(void *ph_v) /*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */ if (dist_nosqrt < brush_size_sqared && (dist=sqrtf(dist_nosqrt)) < size_half) { - falloff = brush_curve_strength(ps->brush, dist, size_half); + falloff = brush_curve_strength_clamp(ps->brush, dist, size_half); if (falloff > 0.0f) { if (ps->is_texbrush) { brush_sample_tex(ps->brush, projPixel->projCoSS, rgba); -- cgit v1.2.3 From 20998fdcfa6e7dd74adc0f38af6135fdddbefdc0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 06:48:03 +0000 Subject: Use Shift+F for fly-mode (like 2.4x) rather then Any+F --- source/blender/editors/space_view3d/view3d_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 06480d3e2db..23dd092ce38 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -124,7 +124,7 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center", PADPERIOD, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_ANY, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); -- cgit v1.2.3 From b94ed5d7e469c6c3ea421919138da8c04a3f01e3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 07:03:18 +0000 Subject: - cmake/make/scons didnt define INTERNATIONAL when buidling blenfont - BLF_lang_init used confusing IFDEF's, unlikely this was well tested. Split this into 3 functions for Apple/Win32/Unix, Unix uses BLI_gethome_folder(), cant test others, ideally they should use BLI_gethome_folder too but needs testing. Possibly each os cant be made to use BLI_gethome_folder and the separate func's can be removed (please test). - units, hectometers were displayed wrong. --- source/blender/blenfont/CMakeLists.txt | 1 + source/blender/blenfont/Makefile | 4 +++ source/blender/blenfont/SConscript | 8 +++-- source/blender/blenfont/intern/blf_lang.c | 55 +++++++++++++++++-------------- source/blender/blenkernel/intern/unit.c | 4 +-- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 844a6899bf5..9b7e950526d 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -32,6 +32,7 @@ SET(INC IF(WITH_INTERNATIONAL) SET(INC ${INC} ${GETTEXT_INC}) + ADD_DEFINITIONS(-DINTERNATIONAL) ENDIF(WITH_INTERNATIONAL) IF(WIN32) diff --git a/source/blender/blenfont/Makefile b/source/blender/blenfont/Makefile index 70dd2e5052b..be62c87cbf4 100644 --- a/source/blender/blenfont/Makefile +++ b/source/blender/blenfont/Makefile @@ -28,3 +28,7 @@ SOURCEDIR = source/blender/blenfont DIRS = intern include nan_subdirs.mk + +ifeq ($(INTERNATIONAL), true) + CPPFLAGS += -DINTERNATIONAL +endif diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript index d070d985247..91edc46ba8b 100644 --- a/source/blender/blenfont/SConscript +++ b/source/blender/blenfont/SConscript @@ -9,9 +9,13 @@ incs += ' #/extern/glew/include' incs += ' ' + env['BF_FREETYPE_INC'] incs += ' ' + env['BF_GETTEXT_INC'] -defs = '' +defs = [] if sys.platform == 'win32': - defs += ' _WIN32 USE_GETTEXT_DLL' + defs.append('_WIN32') + defs.append('USE_GETTEXT_DLL') + +if env['WITH_BF_INTERNATIONAL']: + defs.append('INTERNATIONAL') env.BlenderLib ( 'bf_blenfont', sources, Split(incs), Split(defs), libtype=['core','player'], priority=[210,210] ) diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 024172d6db4..ed684eda46f 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -60,17 +60,14 @@ char global_messagepath[1024]; char global_language[32]; char global_encoding_name[32]; - -void BLF_lang_init(void) +#if defined(__APPLE__) +void BLF_lang_init(void) /* Apple Only, todo - use BLI_gethome_folder */ { -#ifdef __APPLE__ char *bundlepath; -#endif strcpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT); /* set messagepath directory */ - #ifndef LOCALEDIR #define LOCALEDIR "/usr/share/locale" #endif @@ -81,44 +78,52 @@ void BLF_lang_init(void) BLI_make_file_string("/", global_messagepath, BLI_gethome(), ".blender/locale"); if (!BLI_exist(global_messagepath)) { /* locale not in home dir */ -#ifdef WIN32 - BLI_make_file_string("/", global_messagepath, BLI_gethome(), "/locale"); - if (!BLI_exist(global_messagepath)) { -#endif -#ifdef __APPLE__ /* message catalogs are stored inside the application bundle */ bundlepath= BLI_getbundle(); strcpy(global_messagepath, bundlepath); strcat(global_messagepath, "/Contents/Resources/locale"); if (!BLI_exist(global_messagepath)) { /* locale not in bundle (now that's odd..) */ -#endif strcpy(global_messagepath, LOCALEDIR); if (!BLI_exist(global_messagepath)) { /* locale not in LOCALEDIR */ strcpy(global_messagepath, "message"); /* old compatibility as last */ } -#ifdef WIN32 } -#endif -#ifdef __APPLE__ - } -#endif } } } - -void BLF_lang_set(const char *str) +#elif defined(_WIN32) +void BLF_lang_init(void) /* Windows Only, todo - use BLI_gethome_folder */ { -#if defined (_WIN32) || defined(__APPLE__) - char envstr[12]; + strcpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT); + + strcpy(global_messagepath, ".blender/locale"); + + if (!BLI_exist(global_messagepath)) { /* locale not in current dir */ + BLI_make_file_string("/", global_messagepath, BLI_gethome(), ".blender/locale"); - sprintf(envstr, "LANG=%s", str); - envstr[strlen(envstr)]= '\0'; -#ifdef _WIN32 - gettext_putenv(envstr); + if (!BLI_exist(global_messagepath)) { /* locale not in home dir */ + BLI_make_file_string("/", global_messagepath, BLI_gethome(), "/locale"); + } + } +} #else - putenv(envstr); +void BLF_lang_init(void) /* not win or mac */ +{ + char *messagepath= BLI_gethome_folder("locale", BLI_GETHOME_ALL); + + if(messagepath) + strncpy(global_messagepath, messagepath, sizeof(global_messagepath)); + else + global_messagepath[0]= '\0'; + +} #endif + +void BLF_lang_set(const char *str) +{ +#if defined (_WIN32) || defined(__APPLE__) + BLI_setenv("LANG", str); #else char *locreturn= setlocale(LC_ALL, str); if (locreturn == NULL) { diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index f8e3b3c5ad2..1f72c894cc8 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -75,7 +75,7 @@ static struct bUnitCollection buDummyCollecton = {buDummyDef, 0, 0, sizeof(buDum /* Lengths */ static struct bUnitDef buMetricLenDef[] = { {"kilometer", "kilometers", "km", NULL, "Kilometers", 1000.0, 0.0, B_UNIT_DEF_NONE}, - {"hectometer", "hectometers", "hm", NULL, "10 Meters", 100.0, 0.0, B_UNIT_DEF_SUPPRESS}, + {"hectometer", "hectometers", "hm", NULL, "100 Meters", 100.0, 0.0, B_UNIT_DEF_SUPPRESS}, {"dekameter", "dekameters", "dkm",NULL, "10 Meters", 10.0, 0.0, B_UNIT_DEF_SUPPRESS}, {"meter", "meters", "m", NULL, "Meters", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {"decimetre", "decimetres", "dm", NULL, "10 Centimeters", 0.1, 0.0, B_UNIT_DEF_SUPPRESS}, @@ -485,7 +485,7 @@ int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pre if(unit==NULL) unit= unit_default(usys); - /* add the unit prefic and re-run, use brackets incase there was an expression given */ + /* add the unit prefix and re-run, use brackets incase there was an expression given */ if(snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) { strncpy(str, str_tmp, len_max); return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type); -- cgit v1.2.3 From 3e59a88450b9a26b09e671e38170b0f6f17a9182 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Thu, 24 Sep 2009 09:29:59 +0000 Subject: Fix compilation problem in Windows and update project files --- projectfiles_vc9/blender/blenlib/BLI_blenlib.vcproj | 8 ++++++++ projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj | 16 ++++++++++++++++ .../gameengine/blenderhook/KX_blenderhook.vcproj | 4 ++-- source/blender/blenlib/BLI_winstuff.h | 6 ++++++ source/blender/blenlib/intern/BLI_bfile.c | 7 ++++++- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/projectfiles_vc9/blender/blenlib/BLI_blenlib.vcproj b/projectfiles_vc9/blender/blenlib/BLI_blenlib.vcproj index a6630c81aca..6d111ea4b4f 100644 --- a/projectfiles_vc9/blender/blenlib/BLI_blenlib.vcproj +++ b/projectfiles_vc9/blender/blenlib/BLI_blenlib.vcproj @@ -482,6 +482,10 @@ RelativePath="..\..\..\source\blender\blenlib\intern\arithb.c" >
+ + @@ -619,6 +623,10 @@ RelativePath="..\..\..\source\blender\blenlib\BLI_arithb.h" > + + diff --git a/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj b/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj index a9d78d8b69a..227b4856143 100644 --- a/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj +++ b/projectfiles_vc9/blender/makesrna/RNA_makesrna.vcproj @@ -602,6 +602,10 @@ RelativePath="..\..\..\source\blender\makesrna\intern\rna_action.c" > + + @@ -682,6 +686,10 @@ RelativePath="..\..\..\source\blender\makesrna\intern\rna_image.c" > + + @@ -706,6 +714,10 @@ RelativePath="..\..\..\source\blender\makesrna\intern\rna_material.c" > + + @@ -754,6 +766,10 @@ RelativePath="..\..\..\source\blender\makesrna\intern\rna_pose.c" > + + diff --git a/projectfiles_vc9/gameengine/blenderhook/KX_blenderhook.vcproj b/projectfiles_vc9/gameengine/blenderhook/KX_blenderhook.vcproj index ea387c4e976..4d3d74ca949 100644 --- a/projectfiles_vc9/gameengine/blenderhook/KX_blenderhook.vcproj +++ b/projectfiles_vc9/gameengine/blenderhook/KX_blenderhook.vcproj @@ -43,7 +43,7 @@ -#include +#ifndef WIN32 + #include +#else + #include +#include "BLI_winstuff.h" +#endif #include #include -- cgit v1.2.3 From 71027be7f60bf55b8961c06f33a579cdef0f5cd8 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Thu, 24 Sep 2009 10:04:43 +0000 Subject: Fix more problem with mingw this time --- source/blender/blenlib/BLI_winstuff.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 03828bf6bf3..69dbb0acdb9 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -91,11 +91,14 @@ extern "C" { typedef unsigned int mode_t; #endif +#ifndef _SSIZE_T_ +#define _SSIZE_T_ #if defined(_WIN64) typedef __int64 ssize_t; #else typedef _W64 int ssize_t; #endif +#endif struct dirent { int d_ino; -- cgit v1.2.3 From f16d2b7eaac2f9225075d85e3d570e437407d513 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 10:35:04 +0000 Subject: fix for middle mouse up events not working with modal keymaps (used for fly mode). With mouse events event->val started as 0/1 for press/release but later the tweak function made LMB and RMB zero value into KM_RELEASE, somehow MMB didnt get used by the tweak function so was left at 0 and the modal keymap function failed when comparing MMB Mouse ups. now initialize event->val as KM_PRESS/KM_RELEASE --- source/blender/editors/animation/anim_ops.c | 2 +- source/blender/editors/armature/editarmature_sketch.c | 2 +- source/blender/editors/interface/interface_handlers.c | 2 +- source/blender/editors/interface/view2d_ops.c | 6 +++--- source/blender/editors/mesh/loopcut.c | 2 +- source/blender/editors/screen/screen_ops.c | 8 ++++---- source/blender/editors/sculpt_paint/paint_stroke.c | 2 +- source/blender/editors/space_image/image_ops.c | 4 ++-- source/blender/editors/space_node/node_select.c | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 6 +++--- source/blender/windowmanager/intern/wm_event_system.c | 10 +++++----- source/blender/windowmanager/intern/wm_operators.c | 8 ++++---- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 80077a6d4b3..40c5b8893a1 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -193,7 +193,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init * the modal op) doesn't work for some reason */ - if (event->val==0) { + if (event->val==KM_RELEASE) { change_frame_exit(C, op); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 7f2f2a3410c..74876691dac 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -2675,7 +2675,7 @@ static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short retval = OPERATOR_CANCELLED; break; case LEFTMOUSE: - if (event->val == 0) + if (event->val == KM_RELEASE) { if (gesture == 0) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 01a8f983dc6..b5de855cb80 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1660,7 +1660,7 @@ static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, u break; } case LEFTMOUSE: - if(event->val == 0) + if(event->val == KM_RELEASE) button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval= WM_UI_HANDLER_BREAK; break; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index ae4fe4eed1b..0af5a5cac97 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -237,7 +237,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { /* calculate overall delta mouse-movement for redo */ RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx)); RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); @@ -836,7 +836,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { /* for redo, store the overall deltas - need to respect zoom-locks here... */ if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) RNA_float_set(op->ptr, "deltax", vzd->dx); @@ -1244,7 +1244,7 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if (event->val==0) { + if (event->val==KM_RELEASE) { scroller_activate_exit(C, op); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index c322a169679..1adac71f40e 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -380,7 +380,7 @@ static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event) switch (event->type) { case RIGHTMOUSE: case LEFTMOUSE: /* confirm */ // XXX hardcoded - if (event->val == 0) { + if (event->val == KM_RELEASE) { /* finish */ ED_region_tag_redraw(lcd->ar); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 5cd992eabe9..5f7be1fd2bc 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -604,7 +604,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event) sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y); break; case LEFTMOUSE: /* release LMB */ - if(event->val==0) { + if(event->val==KM_RELEASE) { if(!sad->sa2 || sad->sa1 == sad->sa2) { return area_swap_cancel(C, op); @@ -1225,7 +1225,7 @@ static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if(event->val==0) { /* mouse up */ + if(event->val==KM_RELEASE) { /* mouse up */ area_split_exit(C, op); return OPERATOR_FINISHED; } @@ -1345,7 +1345,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) break; case LEFTMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) { if(rmd->ar->flag & RGN_FLAG_HIDDEN) { @@ -1828,7 +1828,7 @@ static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event) } break; case LEFTMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { area_join_apply(C, op); WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); area_join_exit(C, op); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index bd9ea50e0f8..b83352ae70c 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -263,7 +263,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) } /* TODO: fix hardcoded event here */ - if(event->type == LEFTMOUSE && event->val == 0) { + if(event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* Exit stroke, free data */ if(stroke->smooth_stroke_cursor) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 483d2fc6043..317a058d20e 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -224,7 +224,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) view_pan_exec(C, op); break; case MIDDLEMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { view_pan_exit(C, op, 0); return OPERATOR_FINISHED; } @@ -339,7 +339,7 @@ static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event) ED_area_tag_redraw(CTX_wm_area(C)); break; case MIDDLEMOUSE: - if(event->val==0) { + if(event->val==KM_RELEASE) { view_zoom_exit(C, op, 0); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 94691dd0ed2..5e482758c9d 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -140,7 +140,7 @@ static int node_select_modal(bContext *C, wmOperator *op, wmEvent *event) printf("%d %d\n", event->x, event->y); break; case SELECTMOUSE: - //if (event->val==0) { + //if (event->val==KM_RELEASE) { /* calculate overall delta mouse-movement for redo */ printf("done translating\n"); //WM_cursor_restore(CTX_wm_window(C)); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 24ec0d124c6..5e3a6ae0e02 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -505,7 +505,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event) default: /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { + if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { request_depth_update(CTX_wm_region_view3d(C)); MEM_freeN(vod); @@ -606,7 +606,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) default: /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { + if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { request_depth_update(CTX_wm_region_view3d(C)); MEM_freeN(vod); @@ -767,7 +767,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event) default: /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) { + if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { request_depth_update(CTX_wm_region_view3d(C)); MEM_freeN(vod); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 03e13329bbd..af1339323f3 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1004,7 +1004,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) int always_pass; if(handlers==NULL) return action; - + /* modal handlers can get removed in this loop, we keep the loop this way */ for(handler= handlers->first; handler; handler= nexthandler) { nexthandler= handler->next; @@ -1157,7 +1157,7 @@ void wm_event_do_handlers(bContext *C) while( (event= win->queue.first) ) { int action; - + CTX_wm_window_set(C, win); /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ @@ -1176,7 +1176,7 @@ void wm_event_do_handlers(bContext *C) /* builtin tweak, if action is break it removes tweak */ wm_tweakevent_test(C, event, action); - + if(action==WM_HANDLER_CONTINUE) { ScrArea *sa; ARegion *ar; @@ -1189,7 +1189,7 @@ void wm_event_do_handlers(bContext *C) /* for regions having custom cursors */ wm_paintcursor_test(C, event); } - + for(sa= win->screen->areabase.first; sa; sa= sa->next) { if(wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); @@ -1575,7 +1575,7 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) case GHOST_kEventButtonDown: case GHOST_kEventButtonUp: { GHOST_TEventButtonData *bd= customdata; - event.val= (type==GHOST_kEventButtonDown); + event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */ if (bd->button == GHOST_kButtonMaskLeft) event.type= LEFTMOUSE; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 0b5c2944624..486a887b354 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1485,7 +1485,7 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: case RIGHTMOUSE: - if(event->val==0) { /* key release */ + if(event->val==KM_RELEASE) { /* key release */ wm_gesture_end(C, op); return OPERATOR_FINISHED; } @@ -1568,7 +1568,7 @@ static void tweak_gesture_modal(bContext *C, wmEvent *event) if(gesture->event_type==event->type) { WM_gesture_end(C, gesture); window->tweak= NULL; - + /* when tweak fails we should give the other keymap entries a chance */ event->val= KM_RELEASE; } @@ -1586,7 +1586,7 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action) if(win->tweak==NULL) { if(CTX_wm_region(C)) { - if(event->val) { // pressed + if(event->val==KM_PRESS) { // pressed if( ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) ) win->tweak= WM_gesture_new(C, event, WM_GESTURE_TWEAK); } @@ -1686,7 +1686,7 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case MIDDLEMOUSE: case RIGHTMOUSE: - if(event->val==0) { /* key release */ + if(event->val==KM_RELEASE) { /* key release */ gesture_lasso_apply(C, op, event->type); return OPERATOR_FINISHED; } -- cgit v1.2.3 From 813f292fc961300343ff5c6b94591d69a69f7890 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Thu, 24 Sep 2009 10:41:28 +0000 Subject: 3rd attempt to fix ssize_t problem in MSVC and mingw --- source/blender/blenlib/BLI_winstuff.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 69dbb0acdb9..3de4981417a 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -91,12 +91,13 @@ extern "C" { typedef unsigned int mode_t; #endif +/* mingw using _SSIZE_T_ to declare ssize_t type */ #ifndef _SSIZE_T_ #define _SSIZE_T_ -#if defined(_WIN64) -typedef __int64 ssize_t; -#else -typedef _W64 int ssize_t; +/* python uses HAVE_SSIZE_T */ +#ifndef HAVE_SSIZE_T +#define HAVE_SSIZE_T 1 +typedef long ssize_t; #endif #endif -- cgit v1.2.3 From 300df490601a4267a9c77239b5638e494672a38f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 24 Sep 2009 10:46:52 +0000 Subject: Fix #19446: merge operator needs to be undone twice, interface was still doing undo pushes in cases it was not needed. --- source/blender/editors/interface/interface.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index f79f2f8c378..1b05958b679 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2271,8 +2271,9 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short } } - if(!ELEM7(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, SEARCH_MENU)) - but->flag |= UI_BUT_UNDO; + if(ELEM8(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, SEARCH_MENU, BUTM)); + else if(ELEM5(but->type, SCROLL, SEPR, LINK, INLINK, FTPREVIEW)); + else but->flag |= UI_BUT_UNDO; BLI_addtail(&block->buttons, but); -- cgit v1.2.3 From 4aade8ad7e2e0f941579533fcedb51a87704af18 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 11:37:33 +0000 Subject: fix for [#19437] Console (Python): first run doesn't have the ">>>" --- source/blender/editors/space_console/space_console.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 234f3b5baf2..19fb575ed16 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -174,6 +174,9 @@ static void console_main_area_draw(const bContext *C, ARegion *ar) console_scrollback_add_str(C, "Autocomplete: Ctrl+Space", 0); console_scrollback_add_str(C, "Ctrl +/- Wheel: Zoom", 0); console_scrollback_add_str(C, "Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.ui", 0); + + /* This is normally set by python but to start with its easier just to set it like this rather then running python with no args */ + strcpy(sc->prompt, ">>> "); } /* clear and setup matrix */ -- cgit v1.2.3 From 24128d2e862773200da935310b4ba8a08733a8d3 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 24 Sep 2009 11:46:17 +0000 Subject: mingw - silencing the warnings about '#pragma' warnings being unrecognised or being ignored. This should still work fine for msvc, and other platforms though. --- source/blender/blenlib/BLI_winstuff.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 3de4981417a..bbdbc2def8d 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -28,7 +28,10 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +#ifndef FREE_WINDOWS #pragma warning(once: 4761 4305 4244 4018) +#endif #define WIN32_LEAN_AND_MEAN -- cgit v1.2.3 From be380138f123b42334e06d450ce42cad7208b2e0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 24 Sep 2009 12:15:17 +0000 Subject: Fix for panorama backwards compatibility not working correct. --- source/blender/blenloader/intern/readfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d9db02e630f..d26a2a79f05 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9366,7 +9366,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) strcpy(sce->nodetree->id.name, "NTComposit Nodetree"); /* move to cameras */ - if(sce->r.scemode & R_PANORAMA) { + if(sce->r.mode & R_PANORAMA) { for(base=sce->base.first; base; base=base->next) { ob= newlibadr(fd, lib, base->object); @@ -9376,7 +9376,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - sce->r.scemode &= ~R_PANORAMA; + sce->r.mode &= ~R_PANORAMA; } } /* and texture trees */ -- cgit v1.2.3 From b0785030580735bc09a1d5037b070849bbb10775 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 12:27:20 +0000 Subject: imagewrap was using uninitialized vars from do_material_tex found while looking into a different bug. --- source/blender/render/intern/source/texture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 2d2c01e0bf1..f25a167600f 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1631,7 +1631,7 @@ void do_material_tex(ShadeInput *shi) float fact, facm, factt, facmm, stencilTin=1.0; float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0; int tex_nr, rgbnor= 0, warpdone=0; - float nu[3], nv[3], nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping + float nu[3] = {0,0,0}, nv[3] = {0,0,0}, nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping int nunvdone= 0; if (R.r.scemode & R_NO_TEX) return; -- cgit v1.2.3 From a8bb3136294268cd4762986699b773688b543679 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Sep 2009 15:36:00 +0000 Subject: add buildinfo to cmake (no win32 support) --- CMakeLists.txt | 20 ++++++++++---------- source/creator/CMakeLists.txt | 20 ++++++++++++++++---- source/creator/creator.c | 1 + 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 504ef5d8dd8..92c670f572c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ OPTION(WITH_FFTW3 "Enable FFTW3 support" OFF) OPTION(WITH_JACK "Enable Jack Support (http://www.jackaudio.org)" OFF) OPTION(WITH_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF) OPTION(WITH_CXX_GUARDEDALLOC "Enable GuardedAlloc for C++ memory allocation" OFF) -# OPTION(WITH_BUILDINFO "Include extra build details" ON) +OPTION(WITH_BUILDINFO "Include extra build details" ON) OPTION(WITH_INSTALL "Install accompanying scripts and language files needed to run blender" ON) IF(NOT WITH_GAMEENGINE AND WITH_PLAYER) @@ -517,15 +517,15 @@ IF(CMAKE_SYSTEM_NAME MATCHES "Linux") ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux") -# TODO - buildinfo -# IF(UNIX) -# IF(WITH_BUILDINFO) -# EXEC_PROGRAM("date \"+%Y-%m-%d\"" OUTPUT_VARIABLE BUILD_DATE) -# EXEC_PROGRAM("date \"+%H:%M:%S\"" OUTPUT_VARIABLE BUILD_TIME) -# EXEC_PROGRAM("svnversion ${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE BUILD_REV) -# SET(BUILD_TYPE ${CMAKE_BUILD_TYPE}) -# ENDIF(WITH_BUILDINFO) -# ENDIF(UNIX) +# buildinfo +IF(UNIX) + IF(WITH_BUILDINFO) + EXEC_PROGRAM("date \"+%Y-%m-%d\"" OUTPUT_VARIABLE BUILD_DATE) + EXEC_PROGRAM("date \"+%H:%M:%S\"" OUTPUT_VARIABLE BUILD_TIME) + EXEC_PROGRAM("svnversion ${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE BUILD_REV) + # BUILD_PLATFORM and BUILD_PLATFORM are taken from CMake + ENDIF(WITH_BUILDINFO) +ENDIF(UNIX) #----------------------------------------------------------------------------- # Common. diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 410e0808580..51a52ee6861 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -78,14 +78,26 @@ IF(CMAKE_SYSTEM_NAME MATCHES "Linux") INCLUDE_DIRECTORIES(${BINRELOC_INC}) ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux") -MESSAGE(STATUS "Configuring blender") +# Setup the exe sources and buildinfo +SET(EXESRC creator.c) IF(WIN32) - ADD_EXECUTABLE(blender ${EXETYPE} creator.c ../icons/winblender.rc) -ELSE(WIN32) - ADD_EXECUTABLE(blender ${EXETYPE} creator.c) + SET(EXESRC ${EXESRC} ../icons/winblender.rc) ENDIF(WIN32) +IF(WITH_BUILDINFO) + ADD_DEFINITIONS(-DBUILD_DATE="${BUILD_DATE}") + ADD_DEFINITIONS(-DBUILD_TIME="${BUILD_TIME}") + ADD_DEFINITIONS(-DBUILD_REV="${BUILD_REV}") + ADD_DEFINITIONS(-DBUILD_PLATFORM="${CMAKE_SYSTEM_NAME}") + ADD_DEFINITIONS(-DBUILD_TYPE="${CMAKE_BUILD_TYPE}") + + SET(EXESRC ${EXESRC} buildinfo.c) +ENDIF(WITH_BUILDINFO) + +MESSAGE(STATUS "Configuring blender") + +ADD_EXECUTABLE(blender ${EXETYPE} ${EXESRC}) # Post build steps for bundling/packaging. diff --git a/source/creator/creator.c b/source/creator/creator.c index 579825b805a..6f64628b467 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -101,6 +101,7 @@ #ifdef BUILD_DATE extern char * build_date; extern char * build_time; +extern char * build_rev; extern char * build_platform; extern char * build_type; #endif -- cgit v1.2.3 From 22d027dcb2f46fc7db359834b8f58c4120bf2c78 Mon Sep 17 00:00:00 2001 From: Kent Mein Date: Thu, 24 Sep 2009 16:18:17 +0000 Subject: fixed some indentation, and removed declaration of index in a couple of places because it was already defined and safe to use the old def. Kent --- intern/smoke/intern/FLUID_3D_STATIC.cpp | 38 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp index 2d3ec125c2b..0215dfc417f 100644 --- a/intern/smoke/intern/FLUID_3D_STATIC.cpp +++ b/intern/smoke/intern/FLUID_3D_STATIC.cpp @@ -54,23 +54,21 @@ void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res) float yTotal = dx * res[1]; float zTotal = dx * res[2]; - float heighMin = 0.05; - float heighMax = 0.10; - - for (int y = 0; y < res[2]; y++) - for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++) - for (int x = 0; x < res[0]; x++) - { - float xLength = x * dx - xTotal * 0.4f; - float yLength = y * dx - yTotal * 0.5f; - float radius = sqrtf(xLength * xLength + yLength * yLength); - - if (radius < 0.075f * xTotal) - { - int index = x + y * res[0] + z * slabSize; - field[index] = 1.0f; - } - } + float heighMin = 0.05; + float heighMax = 0.10; + + for (int y = 0; y < res[2]; y++) + for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++) + for (int x = 0; x < res[0]; x++) { + float xLength = x * dx - xTotal * 0.4f; + float yLength = y * dx - yTotal * 0.5f; + float radius = sqrtf(xLength * xLength + yLength * yLength); + + if (radius < 0.075f * xTotal) { + int index = x + y * res[0] + z * slabSize; + field[index] = 1.0f; + } + } } @@ -98,7 +96,7 @@ void FLUID_3D::setNeumannX(float* field, Vec3Int res) for (int z = 0; z < res[2]; z++) { // top slab - int index = y * res[0] + z * slabSize; + index = y * res[0] + z * slabSize; index += res[0] - 1; if(field[index]<0.) field[index] = 0.; index -= 1; @@ -130,7 +128,7 @@ void FLUID_3D::setNeumannY(float* field, Vec3Int res) for (int x = 0; x < res[0]; x++) { // top slab - int index = x + z * slabSize; + index = x + z * slabSize; index += slabSize - res[0]; if(field[index]<0.) field[index] = 0.; index -= res[0]; @@ -164,7 +162,7 @@ void FLUID_3D::setNeumannZ(float* field, Vec3Int res) for (int x = 0; x < res[0]; x++) { // top slab - int index = x + y * res[0]; + index = x + y * res[0]; index += totalCells - slabSize; if(field[index]<0.) field[index] = 0.; index -= slabSize; -- cgit v1.2.3 From 2a63c4ab7b55cd4eb4301b54e5ca934c71a5e3b4 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Thu, 24 Sep 2009 19:50:15 +0000 Subject: * fix snprintf error with mingw * move header guards to the right place. --- source/blender/blenlib/BLI_winstuff.h | 8 ++++---- source/gameengine/BlenderRoutines/KX_BlenderGL.cpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index bbdbc2def8d..757b3605203 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -29,6 +29,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __WINSTUFF_H__ +#define __WINSTUFF_H__ + #ifndef FREE_WINDOWS #pragma warning(once: 4761 4305 4244 4018) #endif @@ -59,10 +62,7 @@ #undef small -#ifndef __WINSTUFF_H__ -#define __WINSTUFF_H__ - - // These definitions are also in arithb for simplicity +// These definitions are also in arithb for simplicity #ifdef __cplusplus extern "C" { diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index dba6d1113c9..bb02f3b372e 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -44,6 +44,7 @@ extern "C" { * This little block needed for linking to Blender... */ #ifdef WIN32 +#include #include "BLI_winstuff.h" #endif -- cgit v1.2.3 From ddb46e12f9489efa03e86e2e03efc19913d6c775 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Thu, 24 Sep 2009 19:52:32 +0000 Subject: netrender: draft code for cluster usage per job calculations. Eventually, this will be used for load balancing --- release/io/netrender/balancing.py | 2 +- release/io/netrender/master.py | 80 ++++++++++++++++++++++++++++++++----- release/io/netrender/master_html.py | 17 ++++++-- release/io/netrender/ui.py | 2 +- 4 files changed, 86 insertions(+), 15 deletions(-) diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py index b1a461bf0ca..c167594e1c5 100644 --- a/release/io/netrender/balancing.py +++ b/release/io/netrender/balancing.py @@ -91,4 +91,4 @@ class ExcludeSlavesLimit(ExclusionRule): self.limit = limit def test(self, job): - return not ( self.count_jobs() == 1 or self.count_slaves() == 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) + return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 84a6ad8cca1..8a0b0434bf3 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -29,7 +29,7 @@ class MRenderSlave(netrender.model.RenderSlave): self.last_seen = time.time() self.job = None - self.frame = None + self.job_frames = [] netrender.model.RenderSlave._slave_map[self.id] = self @@ -50,6 +50,7 @@ class MRenderJob(netrender.model.RenderJob): self.last_dispatched = time.time() # special server properties + self.usage = 0.0 self.last_update = 0 self.save_path = "" self.files_map = {path: MRenderFile(path, start, end) for path, start, end in files} @@ -300,6 +301,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): f.status = DISPATCHED f.slave = slave + slave.job = job + slave.job_frames = [f.number for f in frames] + self.send_head(headers={"job-id": job.id}) message = job.serialize(frames) @@ -536,7 +540,11 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): elif job_result == ERROR: # blacklist slave on this job on error job.blacklist.append(slave.id) - + + slave.job_frames.remove(job_frame) + if not slave.job_frames: + slave.job = None + frame.status = job_result frame.time = job_time @@ -590,6 +598,10 @@ class RenderMasterServer(http.server.HTTPServer): self.job_id = 0 self.path = path + "master_" + str(os.getpid()) + os.sep + self.slave_timeout = 2 + + self.first_usage = True + self.balancer = netrender.balancing.Balancer() self.balancer.addRule(netrender.balancing.RatingCredit()) self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) @@ -611,6 +623,10 @@ class RenderMasterServer(http.server.HTTPServer): return slave.id + def removeSlave(self, slave): + self.slaves.remove(slave) + self.slaves_map.pop(slave.id) + def getSlave(self, slave_id): return self.slaves_map.get(slave_id, None) @@ -621,9 +637,46 @@ class RenderMasterServer(http.server.HTTPServer): return slave + def timeoutSlaves(self): + removed = [] + + t = time.time() + + for slave in self.slaves: + if (t - slave.last_seen) / 60 > self.slave_timeout: + removed.append(slave) + + if slave.job: + for f in slave.job_frames: + slave.job[f].status = ERROR + + for slave in removed: + self.removeSlave(slave) + + def updateUsage(self): + m = 1.0 + + if not self.first_usage: + for job in self.jobs: + job.usage *= 0.5 + + m = 0.5 + else: + self.first_usage = False + + if self.slaves: + slave_usage = m / self.countSlaves() + + for slave in self.slaves: + if slave.job: + slave.job.usage += slave_usage + + def clear(self): - self.jobs_map = {} - self.jobs = [] + removed = self.jobs[:] + + for job in removed: + self.removeJob(job) def update(self): for job in self.jobs: @@ -646,6 +699,11 @@ class RenderMasterServer(http.server.HTTPServer): if job: self.jobs.remove(job) + + for slave in self.slaves: + if slave.job == job: + slave.job = None + slave.job_frames = [] def addJob(self, job): self.jobs.append(job) @@ -687,8 +745,12 @@ def runMaster(address, broadcast, path, update_stats, test_break): while not test_break(): httpd.handle_request() - if broadcast: - if time.time() - start_time >= 10: # need constant here - print("broadcasting address") - s.sendto(bytes("%i" % address[1], encoding='utf8'), 0, ('', 8000)) - start_time = time.time() + if time.time() - start_time >= 10: # need constant here + httpd.timeoutSlaves() + + httpd.updateUsage() + + if broadcast: + print("broadcasting address") + s.sendto(bytes("%i" % address[1], encoding='utf8'), 0, ('', 8000)) + start_time = time.time() diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py index 8e11c86a88c..bafc0f44b7f 100644 --- a/release/io/netrender/master_html.py +++ b/release/io/netrender/master_html.py @@ -42,23 +42,32 @@ def get(handler): output("

Slaves

") startTable() - headerTable("id", "name", "address", "stats") + headerTable("name", "address", "last seen", "stats", "job") for slave in handler.server.slaves: - rowTable(slave.id, slave.name, slave.address[0], slave.stats) + rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None") endTable() output("

Jobs

") startTable() - headerTable("id", "name", "credits", "time since last", "length", "done", "dispatched", "error", "priority", "exception") + headerTable("name", "credits", "usage", "time since last", "length", "done", "dispatched", "error", "priority", "exception") handler.server.update() for job in handler.server.jobs: results = job.framesStatus() - rowTable(link(job.id, "/html/job" + job.id), job.name, round(job.credits, 1), int(time.time() - job.last_dispatched), len(job), results[DONE], results[DISPATCHED], results[ERROR], handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)) + rowTable( link(job.name, "/html/job" + job.id), + round(job.credits, 1), + "%0.1f%%" % (job.usage * 100), + int(time.time() - job.last_dispatched), + len(job), + results[DONE], + results[DISPATCHED], + results[ERROR], + handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job) + ) endTable() diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index 3aad8362c43..7ee0b64d150 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -165,7 +165,7 @@ class SCENE_PT_network_jobs(RenderButtonsPanel): subcol = col.column(align=True) subcol.itemO("render.netclientstatus", icon="ICON_FILE_REFRESH", text="") subcol.itemO("render.netclientcancel", icon="ICON_ZOOMOUT", text="") - subcol.itemO("render.netclientcancelall", icon="ICON_ZOOMOUT", text="") + subcol.itemO("render.netclientcancelall", icon="ICON_PANEL_CLOSE", text="") subcol.itemO("render.netclientdownload", icon='ICON_RENDER_ANIMATION', text="") if len(bpy.data.netrender_jobs) == 0 and len(netsettings.jobs) > 0: -- cgit v1.2.3 From ebfc93de214f308a4c76a7c64c5c4b0e45b2182d Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Thu, 24 Sep 2009 20:20:43 +0000 Subject: * explicit cast needed for mingw. --- source/gameengine/Expressions/PyObjectPlus.h | 4 ++-- source/gameengine/Ketsji/KX_PyMath.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index f9edb7877b0..d8ab007dde9 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -112,13 +112,13 @@ typedef struct PyObjectPlus_Proxy { static PyAttributeDef Attributes[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ - virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; #ifdef WITH_CXX_GUARDEDALLOC #define Py_Header __Py_Header \ void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ - void operator delete( void *mem ) { MEM_freeN(mem); } \ + void operator delete( void *mem ) { MEM_freeN(mem); } #else #define Py_Header __Py_Header diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 17102905607..1ce8bcafbb6 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -157,7 +157,7 @@ bool PyVecTo(PyObject* pyval, T& vec) return true; } - else if (PyObject_TypeCheck(pyval, &PyObjectPlus::Type)) + else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&PyObjectPlus::Type)) { /* note, include this check because PySequence_Check does too much introspection * on the PyObject (like getting its __class__, on a BGE type this means searching up * the parent list each time only to discover its not a sequence. -- cgit v1.2.3 From c995c605f640d8d688e6e58e0fe247ca83f91696 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Thu, 24 Sep 2009 21:05:54 +0000 Subject: netrender: usage based balancer. more useful than credits --- release/io/netrender/balancing.py | 8 +++++++- release/io/netrender/master.py | 7 ++++--- release/io/netrender/master_html.py | 22 ++++++++++++++++++---- release/io/netrender/model.py | 3 +++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py index c167594e1c5..372ea7d95b7 100644 --- a/release/io/netrender/balancing.py +++ b/release/io/netrender/balancing.py @@ -64,7 +64,13 @@ class Balancer: class RatingCredit(RatingRule): def rate(self, job): - return -job.credits * job.priority # more credit is better (sort at first in list) + # more credit is better (sort at first in list) + return -job.credits * job.priority + +class RatingUsage(RatingRule): + def rate(self, job): + # less usage is better + return job.usage / job.priority class NewJobPriority(PriorityRule): def __init__(self, limit = 1): diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 8a0b0434bf3..1202b94840f 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -45,12 +45,12 @@ class MRenderJob(netrender.model.RenderJob): self.frames = [] self.chunks = chunks self.priority = priority + self.usage = 0.0 self.credits = credits self.blacklist = blacklist self.last_dispatched = time.time() # special server properties - self.usage = 0.0 self.last_update = 0 self.save_path = "" self.files_map = {path: MRenderFile(path, start, end) for path, start, end in files} @@ -603,9 +603,10 @@ class RenderMasterServer(http.server.HTTPServer): self.first_usage = True self.balancer = netrender.balancing.Balancer() - self.balancer.addRule(netrender.balancing.RatingCredit()) + #self.balancer.addRule(netrender.balancing.RatingCredit()) + self.balancer.addRule(netrender.balancing.RatingUsage()) self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) - self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves)) + self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves, limit = 0.9)) self.balancer.addPriority(netrender.balancing.NewJobPriority()) self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority(limit = 2)) diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py index bafc0f44b7f..7513971e6cf 100644 --- a/release/io/netrender/master_html.py +++ b/release/io/netrender/master_html.py @@ -52,22 +52,36 @@ def get(handler): output("

Jobs

") startTable() - headerTable("name", "credits", "usage", "time since last", "length", "done", "dispatched", "error", "priority", "exception") + headerTable( + "name", + "priority", + "credits", + "usage", + "wait", + "length", + "done", + "dispatched", + "error", + "first", + "exception" + ) handler.server.update() for job in handler.server.jobs: results = job.framesStatus() - rowTable( link(job.name, "/html/job" + job.id), + rowTable( + link(job.name, "/html/job" + job.id), + job.priority, round(job.credits, 1), "%0.1f%%" % (job.usage * 100), - int(time.time() - job.last_dispatched), + "%is" % int(time.time() - job.last_dispatched), len(job), results[DONE], results[DISPATCHED], results[ERROR], handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job) - ) + ) endTable() diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 9cacfb54a35..91a7c8a035f 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -81,6 +81,7 @@ class RenderJob: self.chunks = 0 self.priority = 0 self.credits = 0 + self.usage = 0.0 self.blacklist = [] self.last_dispatched = 0.0 @@ -143,6 +144,7 @@ class RenderJob: "frames": [f.serialize() for f in self.frames if not frames or f in frames], "chunks": self.chunks, "priority": self.priority, + "usage": self.usage, "credits": self.credits, "blacklist": self.blacklist, "last_dispatched": self.last_dispatched @@ -160,6 +162,7 @@ class RenderJob: job.frames = [RenderFrame.materialize(f) for f in data["frames"]] job.chunks = data["chunks"] job.priority = data["priority"] + job.usage = data["usage"] job.credits = data["credits"] job.blacklist = data["blacklist"] job.last_dispatched = data["last_dispatched"] -- cgit v1.2.3 From ee6cf88d4d1571afd2a6922b09937efd9ab6b622 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Thu, 24 Sep 2009 22:11:35 +0000 Subject: * some fixes to have scons/mingw compile the sources too, even with BF_DEBUG=1 and WITH_BF_GAMEENGINE=1 --- intern/itasc/kdl/utilities/utility.h | 3 ++- source/gameengine/Ketsji/SConscript | 2 +- source/gameengine/VideoTexture/SConscript | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/itasc/kdl/utilities/utility.h b/intern/itasc/kdl/utilities/utility.h index e7dcc55d8a8..9c38eacbceb 100644 --- a/intern/itasc/kdl/utilities/utility.h +++ b/intern/itasc/kdl/utilities/utility.h @@ -254,7 +254,8 @@ inline double Norm(double arg) { return fabs( (double)arg ); } -#ifdef __WIN32__ + +#if defined(__WIN32__) && !defined(__GNUC__) inline double hypot(double y,double x) { return ::_hypot(y,x);} inline double abs(double x) { return ::fabs(x);} #endif diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 5f38020780b..b20da20d0e2 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -29,7 +29,7 @@ if env['WITH_BF_SDL']: else: defs.append('DISABLE_SDL') -if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') # for Python diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript index 119bd1c9954..dac0b6d32ab 100644 --- a/source/gameengine/VideoTexture/SConscript +++ b/source/gameengine/VideoTexture/SConscript @@ -15,12 +15,11 @@ incs += ' #source/blender/gpu #source/kernel/gen_system #intern/string #intern/m incs += ' #intern/guardedalloc #extern/glew/include' defs = [] -if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc','win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') incs += ' ' + env['BF_PYTHON_INC'] -#incs += ' ' + env['BF_OPENGL_INC'] if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') -- cgit v1.2.3 From 5eb2b4b40d6a687659aeae8810c0e36dd29d6715 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Fri, 25 Sep 2009 01:13:07 +0000 Subject: SVN maintenance. --- extern/Eigen2/eigen-update.sh | 0 intern/itasc/Armature.cpp | 2 +- intern/itasc/Cache.cpp | 2 +- intern/itasc/ConstraintSet.cpp | 2 +- intern/itasc/ControlledObject.cpp | 2 +- intern/itasc/CopyPose.cpp | 2 +- intern/itasc/Distance.cpp | 2 +- intern/itasc/FixedObject.cpp | 2 +- intern/itasc/Makefile | 2 +- intern/itasc/MovingFrame.cpp | 2 +- intern/itasc/Scene.cpp | 2 +- intern/itasc/UncontrolledObject.cpp | 2 +- intern/itasc/WDLSSolver.cpp | 2 +- intern/itasc/WSDLSSolver.cpp | 2 +- intern/itasc/WorldObject.cpp | 2 +- intern/itasc/eigen_types.cpp | 2 +- intern/itasc/kdl/Makefile | 2 +- intern/itasc/kdl/frameacc.cpp | 2 +- intern/itasc/kdl/framevel.cpp | 2 +- intern/itasc/kdl/utilities/Makefile | 2 +- intern/itasc/kdl/utilities/error.h | 2 +- intern/itasc/kdl/utilities/error_stack.cpp | 2 +- intern/itasc/kdl/utilities/rall1d.h | 2 +- intern/itasc/kdl/utilities/rall2d.h | 2 +- intern/itasc/kdl/utilities/utility.h | 2 +- intern/itasc/kdl/utilities/utility_io.cpp | 2 +- intern/itasc/kdl/utilities/utility_io.h | 2 +- 27 files changed, 26 insertions(+), 26 deletions(-) mode change 100644 => 100755 extern/Eigen2/eigen-update.sh diff --git a/extern/Eigen2/eigen-update.sh b/extern/Eigen2/eigen-update.sh old mode 100644 new mode 100755 diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp index cd059505b4a..2491b0f8c9f 100644 --- a/intern/itasc/Armature.cpp +++ b/intern/itasc/Armature.cpp @@ -1,4 +1,4 @@ -/* $Id: Armature.cpp 21152 2009-06-25 11:57:19Z ben2610 $ +/* $Id$ * Armature.cpp * * Created on: Feb 3, 2009 diff --git a/intern/itasc/Cache.cpp b/intern/itasc/Cache.cpp index 68c281910e3..1a1a3b4d009 100644 --- a/intern/itasc/Cache.cpp +++ b/intern/itasc/Cache.cpp @@ -1,4 +1,4 @@ -/* $Id: Cache.cpp 21152 2009-06-25 11:57:19Z ben2610 $ +/* $Id$ * Cache.cpp * * Created on: Feb 24, 2009 diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp index f47af4246e4..eaffc2a52f9 100644 --- a/intern/itasc/ConstraintSet.cpp +++ b/intern/itasc/ConstraintSet.cpp @@ -1,4 +1,4 @@ -/* $Id: ConstraintSet.cpp 19905 2009-04-23 13:29:54Z ben2610 $ +/* $Id$ * ConstraintSet.cpp * * Created on: Jan 5, 2009 diff --git a/intern/itasc/ControlledObject.cpp b/intern/itasc/ControlledObject.cpp index f9e819d2950..b987e176031 100644 --- a/intern/itasc/ControlledObject.cpp +++ b/intern/itasc/ControlledObject.cpp @@ -1,4 +1,4 @@ -/* $Id: ControlledObject.cpp 19905 2009-04-23 13:29:54Z ben2610 $ +/* $Id$ * ControlledObject.cpp * * Created on: Jan 5, 2009 diff --git a/intern/itasc/CopyPose.cpp b/intern/itasc/CopyPose.cpp index df0bc38b704..3bf7edd7975 100644 --- a/intern/itasc/CopyPose.cpp +++ b/intern/itasc/CopyPose.cpp @@ -1,4 +1,4 @@ -/* $Id: CopyPose.cpp 20622 2009-06-04 12:47:59Z ben2610 $ +/* $Id$ * CopyPose.cpp * * Created on: Mar 17, 2009 diff --git a/intern/itasc/Distance.cpp b/intern/itasc/Distance.cpp index 03fa1762567..0f61e7666b2 100644 --- a/intern/itasc/Distance.cpp +++ b/intern/itasc/Distance.cpp @@ -1,4 +1,4 @@ -/* $Id: Distance.cpp 20603 2009-06-03 15:17:52Z ben2610 $ +/* $Id$ * Distance.cpp * * Created on: Jan 30, 2009 diff --git a/intern/itasc/FixedObject.cpp b/intern/itasc/FixedObject.cpp index 1360c3c152b..fad77d4825e 100644 --- a/intern/itasc/FixedObject.cpp +++ b/intern/itasc/FixedObject.cpp @@ -1,4 +1,4 @@ -/* $Id: FixedObject.cpp 19905 2009-04-23 13:29:54Z ben2610 $ +/* $Id$ * FixedObject.cpp * * Created on: Feb 10, 2009 diff --git a/intern/itasc/Makefile b/intern/itasc/Makefile index 463f7763cd2..6ac0d142b72 100644 --- a/intern/itasc/Makefile +++ b/intern/itasc/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile 19907 2009-04-23 13:41:59Z ben2610 $ +# $Id$ # # ***** BEGIN GPL LICENSE BLOCK ***** # diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp index 545f9bd38e9..c0995383c4b 100644 --- a/intern/itasc/MovingFrame.cpp +++ b/intern/itasc/MovingFrame.cpp @@ -1,4 +1,4 @@ -/* $Id: MovingFrame.cpp 20853 2009-06-13 12:29:46Z ben2610 $ +/* $Id$ * MovingFrame.cpp * * Created on: Feb 10, 2009 diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp index c50769e9c1d..8aa423584f1 100644 --- a/intern/itasc/Scene.cpp +++ b/intern/itasc/Scene.cpp @@ -1,4 +1,4 @@ -/* $Id: Scene.cpp 20874 2009-06-14 13:50:34Z ben2610 $ +/* $Id$ * Scene.cpp * * Created on: Jan 5, 2009 diff --git a/intern/itasc/UncontrolledObject.cpp b/intern/itasc/UncontrolledObject.cpp index e05a8682d20..4db44aaf7dc 100644 --- a/intern/itasc/UncontrolledObject.cpp +++ b/intern/itasc/UncontrolledObject.cpp @@ -1,4 +1,4 @@ -/* $Id: UncontrolledObject.cpp 19907 2009-04-23 13:41:59Z ben2610 $ +/* $Id$ * UncontrolledObject.cpp * * Created on: Jan 5, 2009 diff --git a/intern/itasc/WDLSSolver.cpp b/intern/itasc/WDLSSolver.cpp index 91278c7ad3b..e8bfc95e5dd 100644 --- a/intern/itasc/WDLSSolver.cpp +++ b/intern/itasc/WDLSSolver.cpp @@ -1,4 +1,4 @@ -/* $Id: WDLSSolver.cpp 20749 2009-06-09 11:27:30Z ben2610 $ +/* $Id$ * WDLSSolver.hpp.cpp * * Created on: Jan 8, 2009 diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp index 1f99ad08334..971fb7f482e 100644 --- a/intern/itasc/WSDLSSolver.cpp +++ b/intern/itasc/WSDLSSolver.cpp @@ -1,4 +1,4 @@ -/* $Id: WSDLSSolver.cpp 20749 2009-06-09 11:27:30Z ben2610 $ +/* $Id$ * WDLSSolver.hpp.cpp * * Created on: Jan 8, 2009 diff --git a/intern/itasc/WorldObject.cpp b/intern/itasc/WorldObject.cpp index ba3f8549f06..99cb8773e77 100644 --- a/intern/itasc/WorldObject.cpp +++ b/intern/itasc/WorldObject.cpp @@ -1,4 +1,4 @@ -/* $Id: WorldObject.cpp 19907 2009-04-23 13:41:59Z ben2610 $ +/* $Id$ * WorldObject.cpp * * Created on: Feb 10, 2009 diff --git a/intern/itasc/eigen_types.cpp b/intern/itasc/eigen_types.cpp index a1b28e01210..2aa942f38c7 100644 --- a/intern/itasc/eigen_types.cpp +++ b/intern/itasc/eigen_types.cpp @@ -1,4 +1,4 @@ -/* $Id: eigen_types.cpp 19905 2009-04-23 13:29:54Z ben2610 $ +/* $Id$ * eigen_types.cpp * * Created on: March 19, 2009 diff --git a/intern/itasc/kdl/Makefile b/intern/itasc/kdl/Makefile index e87795fd3b7..e34c991db38 100644 --- a/intern/itasc/kdl/Makefile +++ b/intern/itasc/kdl/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile 19905 2009-04-23 13:29:54Z ben2610 $ +# $Id$ # # ***** BEGIN GPL LICENSE BLOCK ***** # diff --git a/intern/itasc/kdl/frameacc.cpp b/intern/itasc/kdl/frameacc.cpp index 85c4179379a..9defce0a00e 100644 --- a/intern/itasc/kdl/frameacc.cpp +++ b/intern/itasc/kdl/frameacc.cpp @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: frameacc.cpp 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ diff --git a/intern/itasc/kdl/framevel.cpp b/intern/itasc/kdl/framevel.cpp index c0a94d64947..f70bef2e923 100644 --- a/intern/itasc/kdl/framevel.cpp +++ b/intern/itasc/kdl/framevel.cpp @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: framevel.cpp 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ diff --git a/intern/itasc/kdl/utilities/Makefile b/intern/itasc/kdl/utilities/Makefile index 26bd7cfb470..6dedc24181e 100644 --- a/intern/itasc/kdl/utilities/Makefile +++ b/intern/itasc/kdl/utilities/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile 19905 2009-04-23 13:29:54Z ben2610 $ +# $Id$ # # ***** BEGIN GPL LICENSE BLOCK ***** # diff --git a/intern/itasc/kdl/utilities/error.h b/intern/itasc/kdl/utilities/error.h index c6cf916c151..868daef3db3 100644 --- a/intern/itasc/kdl/utilities/error.h +++ b/intern/itasc/kdl/utilities/error.h @@ -39,7 +39,7 @@ * - $log$ * * \par Release - * $Id: error.h 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ #ifndef ERROR_H_84822 // to make it unique, a random number diff --git a/intern/itasc/kdl/utilities/error_stack.cpp b/intern/itasc/kdl/utilities/error_stack.cpp index aabf47ad191..d55308c7346 100644 --- a/intern/itasc/kdl/utilities/error_stack.cpp +++ b/intern/itasc/kdl/utilities/error_stack.cpp @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: error_stack.cpp 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ diff --git a/intern/itasc/kdl/utilities/rall1d.h b/intern/itasc/kdl/utilities/rall1d.h index 617683ffce6..98bd4385d1e 100644 --- a/intern/itasc/kdl/utilities/rall1d.h +++ b/intern/itasc/kdl/utilities/rall1d.h @@ -19,7 +19,7 @@ * - $log$ * * \par Release - * $Id: rall1d.h 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ diff --git a/intern/itasc/kdl/utilities/rall2d.h b/intern/itasc/kdl/utilities/rall2d.h index ca4c67319f5..cbd9e70b04f 100644 --- a/intern/itasc/kdl/utilities/rall2d.h +++ b/intern/itasc/kdl/utilities/rall2d.h @@ -19,7 +19,7 @@ * - $log$ * * \par Release - * $Id: rall2d.h 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ ****************************************************************************/ diff --git a/intern/itasc/kdl/utilities/utility.h b/intern/itasc/kdl/utilities/utility.h index 9c38eacbceb..7151792536e 100644 --- a/intern/itasc/kdl/utilities/utility.h +++ b/intern/itasc/kdl/utilities/utility.h @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: utility.h 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ * \file * Included by most lrl-files to provide some general diff --git a/intern/itasc/kdl/utilities/utility_io.cpp b/intern/itasc/kdl/utilities/utility_io.cpp index ae65047fdbc..994567dfdfc 100644 --- a/intern/itasc/kdl/utilities/utility_io.cpp +++ b/intern/itasc/kdl/utilities/utility_io.cpp @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: utility_io.cpp 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ * \todo * make IO routines more robust against the differences between DOS/UNIX end-of-line style. diff --git a/intern/itasc/kdl/utilities/utility_io.h b/intern/itasc/kdl/utilities/utility_io.h index 7c3d4f91296..2a71ce870a3 100644 --- a/intern/itasc/kdl/utilities/utility_io.h +++ b/intern/itasc/kdl/utilities/utility_io.h @@ -9,7 +9,7 @@ * - $log$ * * \par Release - * $Id: utility_io.h 19905 2009-04-23 13:29:54Z ben2610 $ + * $Id$ * $Name: $ * * \file utility_io.h -- cgit v1.2.3 From 2060127e1fc2b71b10fa1784cf7c58bc6a2ef539 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 01:29:30 +0000 Subject: missing includes --- source/blender/ikplugin/intern/iksolver_plugin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 262185fef1b..68afbcd0db2 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -34,6 +34,7 @@ #include "BLI_arithb.h" #include "BKE_armature.h" +#include "BKE_constraint.h" #include "BKE_utildefines.h" #include "DNA_object_types.h" #include "DNA_action_types.h" @@ -43,6 +44,8 @@ #include "IK_solver.h" #include "iksolver_plugin.h" +#include /* memcpy */ + /* ********************** THE IK SOLVER ******************* */ /* allocates PoseTree, and links that to root bone/channel */ -- cgit v1.2.3 From 558626714ebd903fb48d2eb2d121ba1cf54d6c1d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Sep 2009 01:30:32 +0000 Subject: Bugfixes: * #19459: Shape Keys not Animateable Shape Keys were missing the appropriate 'path' callbacks. * #19458: 3D Viewport doesn't refresh when adding new bone in editmode (using Shift-A) The 'wrong' notifier was being sent. Currently, Armature EditMode only responds to NC_OBJECT|ND_TRANSFORM, which isn't strictly that correct for all cases. * Alignment code for constraints headers (i.e. enable/disable lumped with the delete constraint button) was causing the delete button to not work anymore. Removed the offending code (it shouldn't have been there to start off with). * When object's don't have their own AnimData (i.e. if you only animate the values of some shapekeys), a space is no longer left beside the object's name for a visibility toggle in the Graph Editor. --- source/blender/editors/animation/anim_channels_defines.c | 5 ++++- source/blender/editors/armature/editarmature.c | 3 ++- source/blender/editors/interface/interface_templates.c | 3 +-- source/blender/makesrna/intern/rna_key.c | 6 ++++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 7f0f2411bd0..c6ecad03be8 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -461,6 +461,9 @@ static void acf_object_name(bAnimListElem *ale, char *name) /* check if some setting exists for this channel */ static short acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting) { + Base *base= (Base *)ale->data; + Object *ob= base->object; + switch (setting) { /* muted only in NLA */ case ACHANNEL_SETTING_MUTE: @@ -468,7 +471,7 @@ static short acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, int /* visible only in Graph Editor */ case ACHANNEL_SETTING_VISIBLE: - return ((ac) && (ac->spacetype == SPACE_IPO)); + return ((ac) && (ac->spacetype == SPACE_IPO) && (ob->adt)); /* only select and expand supported otherwise */ case ACHANNEL_SETTING_SELECT: diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index bc210fbcb54..5c224fbd4db 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -3448,7 +3448,8 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) else VecAddf(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z - WM_event_add_notifier(C, NC_OBJECT, obedit); + /* note, notifier might evolve */ + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, obedit); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 31f371c5553..af4a4c13c80 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -905,10 +905,9 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ uiBlockSetEmboss(block, UI_EMBOSSN); - uiBlockBeginAlign(block); uiDefIconButBitS(block, ICONTOGN, CONSTRAINT_OFF, B_CONSTRAINT_TEST, ICON_CHECKBOX_DEHLT, xco+243, yco, 19, 19, &con->flag, 0.0, 0.0, 0.0, 0.0, "enable/disable constraint"); + uiDefIconButO(block, BUT, "CONSTRAINT_OT_delete", WM_OP_INVOKE_DEFAULT, ICON_X, xco+262, yco, 19, 19, "Delete constraint"); - uiBlockEndAlign(block); uiBlockSetEmboss(block, UI_EMBOSS); } diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index e66ee683e61..e1551404438 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -257,6 +257,11 @@ static PointerRNA rna_ShapeKey_data_get(CollectionPropertyIterator *iter) return rna_pointer_inherit_refine(&iter->parent, type, rna_iterator_array_get(iter)); } +static char *rna_ShapeKey_path(PointerRNA *ptr) +{ + return BLI_sprintfN("keys[\"%s\"]", ((KeyBlock*)ptr->data)->name); +} + static void rna_Key_update_data(bContext *C, PointerRNA *ptr) { Main *bmain= CTX_data_main(C); @@ -343,6 +348,7 @@ static void rna_def_keyblock(BlenderRNA *brna) srna= RNA_def_struct(brna, "ShapeKey", NULL); RNA_def_struct_ui_text(srna, "Shape Key", "Shape key in a shape keys datablock."); RNA_def_struct_sdna(srna, "KeyBlock"); + RNA_def_struct_path_func(srna, "rna_ShapeKey_path"); RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA); prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); -- cgit v1.2.3 From 83c3780d8c7f4bedfcd34d7a1dbb1aea9183ac32 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Sep 2009 01:43:34 +0000 Subject: Quick tweaks to commonly debated mesh-editing hotkeys: * Loopcut is now just Ctrl-R. The preview will be activated when you do this, and you can just click to confirm as in 2.4x and also like when this was activated from the toolshelf. This is less error prone than having to click at the same time as picking the loop as with the previous hotkey. * Knife is now just: hold k-key and lmb click+drag to draw a cut line and cut the mesh. This is more direct than the (rather arcane) Ctrl-X-LMB-drag, and is quite similar to what's done for Grease Pencil now. --- source/blender/editors/mesh/mesh_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 96f5e7452d1..21148e59153 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -356,7 +356,7 @@ void ED_keymap_mesh(wmWindowManager *wm) keymap= WM_keymap_find(wm, "EditMesh", 0, 0); keymap->poll= ED_operator_editmesh; - WM_keymap_add_item(keymap, "MESH_OT_loopcut", ACTIONMOUSE, KM_PRESS, KM_CTRL, RKEY); + WM_keymap_add_item(keymap, "MESH_OT_loopcut", RKEY, KM_PRESS, KM_CTRL, 0); /* selecting */ /* standard mouse selection goes via space_view3d */ @@ -438,7 +438,7 @@ void ED_keymap_mesh(wmWindowManager *wm) WM_keymap_add_item(keymap, "MESH_OT_fgon_make", FKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "MESH_OT_fgon_clear", FKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); - WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_CTRL, XKEY); + WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, 0, KKEY); /* menus */ WM_keymap_add_item(keymap, "MESH_OT_vertex_specials", VKEY, KM_PRESS, KM_CTRL, 0); -- cgit v1.2.3 From 5fdb839865436b98d021d4708e5d5141646f6e0e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 01:49:06 +0000 Subject: needed for linking with cmake on unix --- source/creator/CMakeLists.txt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 51a52ee6861..0cc0d5d496b 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -362,6 +362,7 @@ IF(UNIX) blender_ONL bf_python bf_gen_python + bf_ikplugin bf_blenkernel bf_nodes bf_gpu @@ -376,15 +377,12 @@ IF(UNIX) bf_readblenfile blender_bop bf_kernel - bf_decimation bf_elbeem bf_IK bf_memutil bf_guardedalloc blender_CTR bf_moto - bf_windowmanager - bf_editors bf_blroutines bf_converter bf_dummy @@ -399,17 +397,11 @@ IF(UNIX) bf_oglrasterizer bf_expressions bf_scenegraph - bf_moto - bf_blroutines kx_network - bf_kernel bf_ngnetwork extern_bullet bf_loopbacknetwork - bf_common - bf_moto - bf_python - bf_gen_python + bf_ITASC extern_binreloc extern_glew extern_libopenjpeg -- cgit v1.2.3 From b4f235adc0a61a74b753db4704af0c02229eb856 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Fri, 25 Sep 2009 01:59:43 +0000 Subject: Shell script exit values should be non-negative. Exact error with dash as sh "exit: 12: Illegal number: -1". The rest are just changes to whitespace and polishing. --- extern/Eigen2/eigen-update.sh | 26 +++++++++++++------------- source/blender/blenfont/Makefile | 2 +- source/blender/blenlib/intern/BLI_bfile.c | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/extern/Eigen2/eigen-update.sh b/extern/Eigen2/eigen-update.sh index 26155ed428b..926a36ef120 100755 --- a/extern/Eigen2/eigen-update.sh +++ b/extern/Eigen2/eigen-update.sh @@ -1,28 +1,28 @@ #!/bin/sh -echo "*** EIGEN2-SVN Update utility" -echo "*** This gets a new eigen2-svn tree and adapts it to blenders build structure" +echo "*** EIGEN2-HG Update utility" +echo "*** This gets a new eigen2-hg tree and adapts it to blenders build structure" echo "*** Warning! This script will wipe all the header file" -echo "*** Please run again with --i-really-know-what-im-doing ..." if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then - echo proceeding... + echo Proceeding as requested by command line ... else - exit -1 + echo "*** Please run again with --i-really-know-what-im-doing ..." + exit 1 fi # get the latest revision from repository. hg clone http://bitbucket.org/eigen/eigen2 if [ -d eigen2 ] then - cd eigen2 - # put here the version you want to use - hg up 2.0.6 - rm -f `find Eigen/ -type f -name "CMakeLists.txt"` - cp -r Eigen .. - cd .. - rm -rf eigen2 + cd eigen2 + # put here the version you want to use + hg up 2.0.6 + rm -f `find Eigen/ -type f -name "CMakeLists.txt"` + cp -r Eigen .. + cd .. + rm -rf eigen2 else - echo "Did you install Mercurial?" + echo "Did you install Mercurial?" fi diff --git a/source/blender/blenfont/Makefile b/source/blender/blenfont/Makefile index be62c87cbf4..43eda027855 100644 --- a/source/blender/blenfont/Makefile +++ b/source/blender/blenfont/Makefile @@ -30,5 +30,5 @@ DIRS = intern include nan_subdirs.mk ifeq ($(INTERNATIONAL), true) - CPPFLAGS += -DINTERNATIONAL + CPPFLAGS += -DINTERNATIONAL endif diff --git a/source/blender/blenlib/intern/BLI_bfile.c b/source/blender/blenlib/intern/BLI_bfile.c index 4789df593ef..a7ce1df5712 100644 --- a/source/blender/blenlib/intern/BLI_bfile.c +++ b/source/blender/blenlib/intern/BLI_bfile.c @@ -30,7 +30,7 @@ #include #else #include -#include "BLI_winstuff.h" + #include "BLI_winstuff.h" #endif #include -- cgit v1.2.3 From 314d460eb87ec6f383358e0dbb77e9fdf5c99f23 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 02:40:10 +0000 Subject: options WITH_LZO and WITH_LZMA for cmake and scons (default to true) pointcache.c also needed to have checks for these defines. --- CMakeLists.txt | 2 ++ extern/CMakeLists.txt | 9 ++++++-- extern/Makefile | 6 ++--- extern/SConscript | 7 ++++-- source/blender/SConscript | 2 +- source/blender/blenkernel/CMakeLists.txt | 12 ++++++++-- source/blender/blenkernel/SConscript | 12 +++++++--- source/blender/blenkernel/intern/Makefile | 18 +++++++++++---- source/blender/blenkernel/intern/pointcache.c | 32 ++++++++++++++++++++------- tools/btools.py | 4 ++++ 10 files changed, 79 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92c670f572c..d8c5a132995 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,8 @@ OPTION(WITH_WEBPLUGIN "Enable Web Plugin (Unix only)" OFF) OPTION(WITH_FFTW3 "Enable FFTW3 support" OFF) OPTION(WITH_JACK "Enable Jack Support (http://www.jackaudio.org)" OFF) OPTION(WITH_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF) +OPTION(WITH_LZO "Enable fast LZO compression, used for pointcache" ON) +OPTION(WITH_LZMA "Enable best LZMA compression, used for pointcache" ON) OPTION(WITH_CXX_GUARDEDALLOC "Enable GuardedAlloc for C++ memory allocation" OFF) OPTION(WITH_BUILDINFO "Include extra build details" ON) OPTION(WITH_INSTALL "Install accompanying scripts and language files needed to run blender" ON) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 44e47aaf88d..35271d24a2d 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -38,5 +38,10 @@ IF(WITH_OPENJPEG) ADD_SUBDIRECTORY(libopenjpeg) ENDIF(WITH_OPENJPEG) -ADD_SUBDIRECTORY(lzo) -ADD_SUBDIRECTORY(lzma) +IF(WITH_LZO) + ADD_SUBDIRECTORY(lzo) +ENDIF(WITH_LZO) + +IF(WITH_LZMA) + ADD_SUBDIRECTORY(lzma) +ENDIF(WITH_LZMA) diff --git a/extern/Makefile b/extern/Makefile index b81fbd2b91a..a30cd1d7ca3 100644 --- a/extern/Makefile +++ b/extern/Makefile @@ -33,9 +33,9 @@ DIR = $(OCGDIR)/extern DIRS = glew/src # Cloth requires it -#ifneq ($(NAN_NO_KETSJI), true) -DIRS += bullet2 -#endif +ifeq ($(NAN_USE_BULLET), true) + DIRS += bullet2 +endif ifeq ($(WITH_BINRELOC), true) DIRS += binreloc diff --git a/extern/SConscript b/extern/SConscript index 20604d87e45..af057a73927 100644 --- a/extern/SConscript +++ b/extern/SConscript @@ -22,5 +22,8 @@ if env['WITH_BF_REDCODE'] and env['BF_REDCODE_LIB'] == '': if env['OURPLATFORM'] == 'linux2': SConscript(['binreloc/SConscript']); -SConscript(['lzo/SConscript']) -SConscript(['lzma/SConscript']) +if env['WITH_BF_LZO']: + SConscript(['lzo/SConscript']) + +if env['WITH_BF_LZMA']: + SConscript(['lzma/SConscript']) diff --git a/source/blender/SConscript b/source/blender/SConscript index af2c81a3b45..3625678f610 100644 --- a/source/blender/SConscript +++ b/source/blender/SConscript @@ -18,7 +18,7 @@ SConscript(['avi/SConscript', 'nodes/SConscript', 'ikplugin/SConscript', 'windowmanager/SConscript', - 'blenfont/SConscript']) + 'blenfont/SConscript']) diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 3473950ab3a..f60cade61ed 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -34,8 +34,6 @@ SET(INC ../nodes ../../../extern/glew/include ../gpu ../makesrna ../../../intern/smoke/extern ../../../intern/bsp/extern ../blenfont ../../../intern/audaspace/intern - ../../../extern/lzo/minilzo - ../../../extern/lzma ${ZLIB_INC} ) @@ -76,6 +74,16 @@ IF(NOT WITH_ELBEEM) ADD_DEFINITIONS(-DDISABLE_ELBEEM) ENDIF(NOT WITH_ELBEEM) +IF(WITH_LZO) + SET(INC ${INC} ../../../extern/lzo/minilzo) + ADD_DEFINITIONS(-DWITH_LZO) +ENDIF(WITH_LZO) + +IF(WITH_LZMA) + SET(INC ${INC} ../../../extern/lzma) + ADD_DEFINITIONS(-DWITH_LZMA) +ENDIF(WITH_LZMA) + IF(WIN32) SET(INC ${INC} ${PTHREADS_INC}) ENDIF(WIN32) diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 944667e2963..63631ddc40f 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -11,8 +11,6 @@ incs += ' #/extern/bullet2/src' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' incs += ' #/intern/smoke/extern' -incs += ' #/extern/lzo/minilzo' -incs += ' #/extern/lzma' incs += ' #/intern/audaspace/intern' incs += ' ' + env['BF_OPENGL_INC'] @@ -61,7 +59,15 @@ if env['BF_NO_ELBEEM']: if env['WITH_BF_LCMS']: defs.append('WITH_LCMS') - + +if env['WITH_BF_LZO']: + incs += ' #/extern/lzo/minilzo' + defs.append('WITH_LZO') + +if env['WITH_BF_LZMA']: + incs += ' #/extern/lzma' + defs.append('WITH_LZMA') + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile index f16b57c8469..26b9b9ef0dd 100644 --- a/source/blender/blenkernel/intern/Makefile +++ b/source/blender/blenkernel/intern/Makefile @@ -86,14 +86,24 @@ CPPFLAGS += -I../../gpu # path to our own external headerfiles CPPFLAGS += -I.. -# path to bullet2, for cloth -CPPFLAGS += -I$(NAN_BULLET2)/include CPPFLAGS += -I$(NAN_FREETYPE)/include CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 +# path to bullet2, for cloth +ifeq ($(NAN_USE_BULLET), true) + CPPFLAGS += -I$(NAN_BULLET2)/include +endif + # lzo and lzma, for pointcache -CPPFLAGS += -I$(NAN_LZO)/minilzo -CPPFLAGS += -I$(NAN_LZMA) +ifeq ($(WITH_LZO),true) + CPPFLAGS += -I$(NAN_LZO)/minilzo + CPPFLAGS += -DWITH_LZO +endif + +ifeq ($(WITH_LZO),true) + CPPFLAGS += -I$(NAN_LZMA) + CPPFLAGS += -DWITH_LZMA +endif ifeq ($(WITH_FFMPEG),true) CPPFLAGS += -DWITH_FFMPEG diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index e5f89727ab8..3915a6901a0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -62,10 +62,17 @@ /* both in intern */ #include "smoke_API.h" + +#ifdef WITH_LZO #include "minilzo.h" +#else +/* used for non-lzo cases */ +#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3) +#endif +#ifdef WITH_LZMA #include "LzmaLib.h" - +#endif /* needed for directory lookup */ /* untitled blend's need getpid for a unique name */ @@ -625,20 +632,25 @@ static int ptcache_file_write(PTCacheFile *pf, void *f, size_t tot, int size); static int ptcache_compress_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode) { int r = 0; - unsigned char compressed; - LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS); - unsigned int out_len = LZO_OUT_LEN(in_len); + unsigned char compressed = 0; + unsigned int out_len= 0; unsigned char *props = MEM_callocN(16*sizeof(char), "tmp"); size_t sizeOfIt = 5; +#ifdef WITH_LZO + out_len= LZO_OUT_LEN(in_len); if(mode == 1) { + LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS); + r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem); if (!(r == LZO_E_OK) || (out_len >= in_len)) compressed = 0; else compressed = 1; } - else if(mode == 2) { +#endif +#ifdef WITH_LZMA + if(mode == 2) { r = LzmaCompress(out, (size_t *)&out_len, in, in_len,//assume sizeof(char)==1.... props, &sizeOfIt, 5, 1 << 24, 3, 0, 2, 32, 2); @@ -648,7 +660,8 @@ static int ptcache_compress_write(PTCacheFile *pf, unsigned char *in, unsigned i else compressed = 2; } - +#endif + ptcache_file_write(pf, &compressed, 1, sizeof(unsigned char)); if(compressed) { ptcache_file_write(pf, &out_len, 1, sizeof(unsigned int)); @@ -762,16 +775,19 @@ static int ptcache_compress_read(PTCacheFile *pf, unsigned char *result, unsigne in = (unsigned char *)MEM_callocN(sizeof(unsigned char)*in_len, "pointcache_compressed_buffer"); ptcache_file_read(pf, in, in_len, sizeof(unsigned char)); +#ifdef WITH_LZO if(compressed == 1) r = lzo1x_decompress(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, NULL); - else if(compressed == 2) +#endif +#ifdef WITH_LZMA + if(compressed == 2) { size_t leni = in_len, leno = out_len; ptcache_file_read(pf, &sizeOfIt, 1, sizeof(unsigned int)); ptcache_file_read(pf, props, sizeOfIt, sizeof(unsigned char)); r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt); } - +#endif MEM_freeN(in); } else { diff --git a/tools/btools.py b/tools/btools.py index e3f3827ff45..b1584ae8784 100755 --- a/tools/btools.py +++ b/tools/btools.py @@ -56,6 +56,7 @@ def validate_arguments(args, bc): 'WITH_BF_PLAYER', 'WITH_BF_NOBLENDER', 'WITH_BF_BINRELOC', + 'WITH_BF_LZO', 'WITH_BF_LZMA', 'LCGDIR', 'BF_CXX', 'WITH_BF_STATICCXX', 'BF_CXX_LIB_STATIC', 'BF_TWEAK_MODE', 'BF_SPLIT_SRC', @@ -379,6 +380,9 @@ def read_opts(cfg, args): (BoolVariable('BF_QUIET', 'Enable silent output if true', True)), (BoolVariable('WITH_BF_BINRELOC', 'Enable relocatable binary (linux only)', False)), + (BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)), + (BoolVariable('WITH_BF_LZMA', 'Enable best LZMA pointcache compression', True)), + (BoolVariable('WITH_BF_LCMS', 'Enable color correction with lcms', False)), ('BF_LCMS_LIB', 'LCMSlibrary', 'lcms'), -- cgit v1.2.3 From 0aa08fce7236eaf263409b813b7ea072f791479d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 04:25:40 +0000 Subject: still doesn't work but this fixes make clean --- intern/Makefile | 2 +- source/nan_definitions.mk | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/intern/Makefile b/intern/Makefile index 32375f16b7a..ed0b0cfff28 100644 --- a/intern/Makefile +++ b/intern/Makefile @@ -32,7 +32,7 @@ SOURCEDIR = intern # include nan_subdirs.mk ALLDIRS = string ghost guardedalloc moto container memutil -ALLDIRS += decimation iksolver itasc bsp SoundSystem opennl elbeem boolop smoke audaspace +ALLDIRS += decimation iksolver itasc bsp opennl elbeem boolop smoke audaspace all:: @for i in $(ALLDIRS); do \ diff --git a/source/nan_definitions.mk b/source/nan_definitions.mk index 6d4a7139d5b..1aff7e1dea7 100644 --- a/source/nan_definitions.mk +++ b/source/nan_definitions.mk @@ -81,6 +81,8 @@ ifndef CONFIG_GUESS endif export NAN_MOTO ?= $(LCGDIR)/moto + export NAN_ITASC ?= $(LCGDIR)/itasc + export BF_PROFILE ?= false export NAN_USE_BULLET ?= true export NAN_BULLET2 ?= $(LCGDIR)/bullet2 -- cgit v1.2.3 From 2d22ea1f926e54da80f517278a3e7aa02b522583 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Sep 2009 04:51:04 +0000 Subject: Drivers: Copy/Paste tools for the RMB Menu Drivers can now be copied/pasted for single properties, allowing drivers set up on one property to be added to a few other properties relatively easily. Also, added description strings for the other driver-button operators. --- source/blender/blenkernel/intern/constraint.c | 2 +- source/blender/editors/animation/anim_ops.c | 2 + source/blender/editors/animation/drivers.c | 237 ++++++++++++++++++++- source/blender/editors/include/ED_keyframing.h | 18 +- source/blender/editors/interface/interface_anim.c | 19 ++ .../blender/editors/interface/interface_intern.h | 2 + .../blender/editors/interface/interface_layout.c | 2 +- source/blender/windowmanager/intern/wm_init_exit.c | 2 + 8 files changed, 271 insertions(+), 13 deletions(-) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b8d6b333674..4de6b53d26a 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -688,7 +688,7 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) { \ bPoseChannel *pchan= get_pose_channel(ct->tar->pose, ct->subtarget); \ ct->type = CONSTRAINT_OBTYPE_BONE; \ - ct->rotOrder= pchan->rotmode; \ + ct->rotOrder= (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \ }\ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { \ ct->type = CONSTRAINT_OBTYPE_VERT; \ diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 40c5b8893a1..a4038028062 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -399,6 +399,8 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_add_driver_button); WM_operatortype_append(ANIM_OT_remove_driver_button); + WM_operatortype_append(ANIM_OT_copy_driver_button); + WM_operatortype_append(ANIM_OT_paste_driver_button); WM_operatortype_append(ANIM_OT_add_keyingset_button); WM_operatortype_append(ANIM_OT_remove_keyingset_button); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 8b9224511ba..363a5a80f00 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -80,6 +80,10 @@ /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, * for the given Animation Data block. This assumes that all the destinations are valid. + * + * - add: 0 - don't add anything if not found, + * 1 - add new Driver FCurve, + * -1 - add new Driver FCurve without driver stuff (for pasting) */ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add) { @@ -115,11 +119,14 @@ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_ind fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); fcu->array_index= array_index; - /* add some new driver data */ - fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); - - /* add simple generator modifier for driver so that there is some visible representation */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ + if (add > 0) { + /* add some new driver data */ + fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + + /* add simple generator modifier for driver so that there is some visible representation */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + } /* just add F-Curve to end of driver list */ BLI_addtail(&adt->drivers, fcu); @@ -144,7 +151,7 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla /* validate pointer first - exit if failure */ RNA_id_pointer_create(id, &id_ptr); if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { - printf("Insert Key: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + printf("Add Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); return 0; } @@ -163,7 +170,7 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla float fval; if (proptype == PROP_BOOLEAN) { - if(!array) val= RNA_property_boolean_get(&ptr, prop); + if (!array) val= RNA_property_boolean_get(&ptr, prop); else val= RNA_property_boolean_get_index(&ptr, prop, array_index); BLI_strncpy(expression, (val)? "True": "False", maxlen); @@ -180,7 +187,6 @@ short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short fla BLI_snprintf(expression, maxlen, "%.3f", fval); } - } } @@ -218,6 +224,127 @@ short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, return 0; } +/* ************************************************** */ +/* Driver Management API - Copy/Paste Drivers */ + +/* Copy/Paste Buffer for Driver Data... */ +static FCurve *channeldriver_copypaste_buf = NULL; + +/* This function frees any MEM_calloc'ed copy/paste buffer data */ +// XXX find some header to put this in! +void free_anim_drivers_copybuf (void) +{ + /* free the buffer F-Curve if it exists, as if it were just another F-Curve */ + if (channeldriver_copypaste_buf) + free_fcurve(channeldriver_copypaste_buf); + channeldriver_copypaste_buf= NULL; +} + +/* Checks if there is a driver in the copy/paste buffer */ +short ANIM_driver_can_paste (void) +{ + return (channeldriver_copypaste_buf != NULL); +} + +/* ------------------- */ + +/* Main Driver Management API calls: + * Make a copy of the driver for the specified property on the given ID block + */ +short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { + printf("Copy Driver: Could not find Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + return 0; + } + + /* try to get F-Curve with Driver */ + fcu= verify_driver_fcurve(id, rna_path, array_index, 0); + + /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ + free_anim_drivers_copybuf(); + + /* copy this to the copy/paste buf if it exists */ + if (fcu && fcu->driver) { + /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily + * so that we don't end up wasting memory storing the path which won't get used ever... + */ + char *tmp_path = fcu->rna_path; + fcu->rna_path= NULL; + + /* make a copy of the F-Curve with */ + channeldriver_copypaste_buf= copy_fcurve(fcu); + + /* restore the path */ + fcu->rna_path= tmp_path; + + /* copied... */ + return 1; + } + + /* done */ + return 0; +} + +/* Main Driver Management API calls: + * Add a new driver for the specified property on the given ID block or replace an existing one + * with the driver + driver-curve data from the buffer + */ +short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { + printf("Paste Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path); + return 0; + } + + /* if the buffer is empty, cannot paste... */ + if (channeldriver_copypaste_buf == NULL) { + printf("Paste Driver: No Driver to paste. \n"); + return 0; + } + + /* create Driver F-Curve, but without data which will be copied across... */ + fcu= verify_driver_fcurve(id, rna_path, array_index, -1); + + if (fcu) { + /* copy across the curve data from the buffer curve + * NOTE: this step needs care to not miss new settings + */ + /* keyframes/samples */ + fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt); + fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt); + fcu->totvert= channeldriver_copypaste_buf->totvert; + + /* modifiers */ + copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers); + + /* flags - on a per-relevant-flag basis */ + if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES) + fcu->flag |= FCURVE_AUTO_HANDLES; + else + fcu->flag &= ~FCURVE_AUTO_HANDLES; + /* extrapolation mode */ + fcu->extend= channeldriver_copypaste_buf->extend; + + /* the 'juicy' stuff - the driver */ + fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver); + } + + /* done */ + return (fcu != NULL); +} /* ************************************************** */ /* UI-Button Interface */ @@ -272,10 +399,11 @@ void ANIM_OT_add_driver_button (wmOperatorType *ot) /* identifiers */ ot->name= "Add Driver"; ot->idname= "ANIM_OT_add_driver_button"; + ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button."; /* callbacks */ ot->exec= add_driver_button_exec; - //op->poll= ??? + //op->poll= ??? // TODO: need to have some animateable property to do this /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -335,10 +463,11 @@ void ANIM_OT_remove_driver_button (wmOperatorType *ot) /* identifiers */ ot->name= "Remove Driver"; ot->idname= "ANIM_OT_remove_driver_button"; + ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button."; /* callbacks */ ot->exec= remove_driver_button_exec; - //op->poll= ??? + //op->poll= ??? // TODO: need to have some driver to be able to do this... /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -347,4 +476,92 @@ void ANIM_OT_remove_driver_button (wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array."); } +/* Copy Driver Button Operator ------------------------ */ + +static int copy_driver_button_exec (bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop= NULL; + char *path; + short success= 0; + int index; + + /* try to create driver using property retrieved from UI */ + memset(&ptr, 0, sizeof(PointerRNA)); + uiAnimContextProperty(C, &ptr, &prop, &index); + + if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) { + path= RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + /* only copy the driver for the button that this was involved for */ + success= ANIM_copy_driver(ptr.id.data, path, index, 0); + + MEM_freeN(path); + } + } + + /* since we're just copying, we don't really need to do anything else...*/ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; +} + +void ANIM_OT_copy_driver_button (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Driver"; + ot->idname= "ANIM_OT_copy_driver_button"; + ot->description= "Copy the driver for the highlighted button."; + + /* callbacks */ + ot->exec= copy_driver_button_exec; + //op->poll= ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* Paste Driver Button Operator ------------------------ */ + +static int paste_driver_button_exec (bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop= NULL; + char *path; + short success= 0; + int index; + + /* try to create driver using property retrieved from UI */ + memset(&ptr, 0, sizeof(PointerRNA)); + uiAnimContextProperty(C, &ptr, &prop, &index); + + if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) { + path= RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + /* only copy the driver for the button that this was involved for */ + success= ANIM_paste_driver(ptr.id.data, path, index, 0); + + MEM_freeN(path); + } + } + + /* since we're just copying, we don't really need to do anything else...*/ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; +} + +void ANIM_OT_paste_driver_button (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Paste Driver"; + ot->idname= "ANIM_OT_paste_driver_button"; + ot->description= "Paste the driver in the copy/paste buffer for the highlighted button."; + + /* callbacks */ + ot->exec= paste_driver_button_exec; + //op->poll= ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ************************************************** */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 20c2301d2ac..d30fccfe4de 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -163,6 +163,9 @@ void ANIM_OT_remove_keyingset_button(struct wmOperatorType *ot); /* ************ Drivers ********************** */ +/* Returns whether there is a driver in the copy/paste buffer to paste */ +short ANIM_driver_can_paste(void); + /* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block */ @@ -171,11 +174,24 @@ short ANIM_add_driver (struct ID *id, const char rna_path[], int array_index, sh /* Main Driver Management API calls: * Remove the driver for the specified property on the given ID block (if available) */ -short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag); +short ANIM_remove_driver(struct ID *id, const char rna_path[], int array_index, short flag); + +/* Main Driver Management API calls: + * Make a copy of the driver for the specified property on the given ID block + */ +short ANIM_copy_driver(struct ID *id, const char rna_path[], int array_index, short flag); + +/* Main Driver Management API calls: + * Add a new driver for the specified property on the given ID block or replace an existing one + * with the driver + driver-curve data from the buffer + */ +short ANIM_paste_driver(struct ID *id, const char rna_path[], int array_index, short flag); /* Driver management operators for UI buttons */ void ANIM_OT_add_driver_button(struct wmOperatorType *ot); void ANIM_OT_remove_driver_button(struct wmOperatorType *ot); +void ANIM_OT_copy_driver_button(struct wmOperatorType *ot); +void ANIM_OT_paste_driver_button(struct wmOperatorType *ot); /* ************ Auto-Keyframing ********************** */ /* Notes: diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 8c41726b81b..8037a609a2f 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -209,6 +209,18 @@ void ui_but_anim_remove_driver(bContext *C) WM_operator_name_call(C, "ANIM_OT_remove_driver_button", WM_OP_INVOKE_DEFAULT, NULL); } +void ui_but_anim_copy_driver(bContext *C) +{ + /* this operator calls uiAnimContextProperty above */ + WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL); +} + +void ui_but_anim_paste_driver(bContext *C) +{ + /* this operator calls uiAnimContextProperty above */ + WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL); +} + void ui_but_anim_add_keyingset(bContext *C) { /* this operator calls uiAnimContextProperty above */ @@ -264,6 +276,10 @@ void ui_but_anim_menu(bContext *C, uiBut *but) } else uiItemBooleanO(layout, "Delete Driver", 0, "ANIM_OT_remove_driver_button", "all", 0); + + uiItemO(layout, "Copy Driver", 0, "ANIM_OT_copy_driver_button"); + if (ANIM_driver_can_paste()) + uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button"); } else if(but->flag & UI_BUT_ANIMATED_KEY); else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) { @@ -275,6 +291,9 @@ void ui_but_anim_menu(bContext *C, uiBut *but) } else uiItemBooleanO(layout, "Add Driver", 0, "ANIM_OT_add_driver_button", "all", 0); + + if (ANIM_driver_can_paste()) + uiItemO(layout, "Paste Driver", 0, "ANIM_OT_paste_driver_button"); } if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 7ab99a83c4b..885005ba06e 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -470,6 +470,8 @@ void ui_but_anim_insert_keyframe(struct bContext *C); void ui_but_anim_delete_keyframe(struct bContext *C); void ui_but_anim_add_driver(struct bContext *C); void ui_but_anim_remove_driver(struct bContext *C); +void ui_but_anim_copy_driver(struct bContext *C); +void ui_but_anim_paste_driver(struct bContext *C); void ui_but_anim_add_keyingset(struct bContext *C); void ui_but_anim_remove_keyingset(struct bContext *C); void ui_but_anim_menu(struct bContext *C, uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index afbbfb61cba..e3c392a145e 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -480,7 +480,7 @@ static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int icon_only) { uiLayout *sub; - uiBut *but; + uiBut *but=NULL; PropertyType type; PropertySubType subtype; int labelw; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 5c78b32f3f8..1074c424663 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -166,6 +166,7 @@ extern wchar_t *copybufinfo; // XXX copy/paste buffer stuff... extern void free_anim_copybuf(); +extern void free_anim_drivers_copybuf(); extern void free_posebuf(); /* called in creator.c even... tsk, split this! */ @@ -213,6 +214,7 @@ void WM_exit(bContext *C) free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); free_anim_copybuf(); + free_anim_drivers_copybuf(); free_posebuf(); // free_vertexpaint(); // free_imagepaint(); -- cgit v1.2.3 From b8c7910be12aab527fedfad7cab9337eaa5782a7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 05:25:44 +0000 Subject: - use pythons time module rather then bpy.sys.time() - comment poll functions, maybe could check for editable scene later - importing OBJs imports triangle meshes. --- release/io/import_3ds.py | 6 +++--- release/io/import_obj.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py index f2dc99d5b7e..d57911df83c 100644 --- a/release/io/import_3ds.py +++ b/release/io/import_3ds.py @@ -1154,10 +1154,10 @@ class IMPORT_OT_3ds(bpy.types.Operator): wm = context.manager wm.add_fileselect(self.__operator__) return ('RUNNING_MODAL',) - - def poll(self, context): # Poll isnt working yet + ''' + def poll(self, context): print("Poll") - return context.active_object != None + return context.active_object != None''' bpy.ops.add(IMPORT_OT_3ds) diff --git a/release/io/import_obj.py b/release/io/import_obj.py index 34f6575dba2..9a00dc1cc2a 100644 --- a/release/io/import_obj.py +++ b/release/io/import_obj.py @@ -41,7 +41,7 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo # -------------------------------------------------------------------------- import os - +import time import bpy import Mathutils import Geometry @@ -993,7 +993,7 @@ def load_obj(filepath, if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: POLYGROUPS = False - time_main= bpy.sys.time() + time_main= time.time() # time_main= sys.time() verts_loc= [] @@ -1032,7 +1032,7 @@ def load_obj(filepath, context_multi_line= '' print('\tparsing obj file "%s"...' % filepath) - time_sub= bpy.sys.time() + time_sub= time.time() # time_sub= sys.time() file= open(filepath, 'rU') @@ -1241,7 +1241,7 @@ def load_obj(filepath, ''' file.close() - time_new= bpy.sys.time() + time_new= time.time() # time_new= sys.time() print('%.4f sec' % (time_new-time_sub)) time_sub= time_new @@ -1250,7 +1250,7 @@ def load_obj(filepath, print('\tloading materials and images...') create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) - time_new= bpy.sys.time() + time_new= time.time() # time_new= sys.time() print('%.4f sec' % (time_new-time_sub)) time_sub= time_new @@ -1307,7 +1307,7 @@ def load_obj(filepath, # for ob in new_objects: # ob.RotX = -1.570796326794896558 - time_new= bpy.sys.time() + time_new= time.time() # time_new= sys.time() print('%.4f sec' % (time_new-time_sub)) @@ -1585,9 +1585,9 @@ class IMPORT_OT_obj(bpy.types.Operator): bpy.props.BoolProperty(attr="IMAGE_SEARCH", name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True), ] + ''' def poll(self, context): - print("Poll") - return context.active_object != None + return True ''' def execute(self, context): # print("Selected: " + context.active_object.name) -- cgit v1.2.3 From 7c9bb3c40aecbb6e8e8045637c501433eed251f0 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Fri, 25 Sep 2009 07:44:29 +0000 Subject: Fix OSX compilation problem with malloc.h in itasc --- intern/itasc/Armature.cpp | 4 +++- intern/itasc/Cache.cpp | 5 +++-- intern/itasc/CopyPose.cpp | 1 - intern/itasc/Distance.cpp | 1 - intern/itasc/MovingFrame.cpp | 1 - 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp index 2491b0f8c9f..6ae60089cd8 100644 --- a/intern/itasc/Armature.cpp +++ b/intern/itasc/Armature.cpp @@ -7,8 +7,10 @@ #include "Armature.hpp" #include -#include #include +#ifndef __STDC__ +#include +#endif namespace iTaSC { diff --git a/intern/itasc/Cache.cpp b/intern/itasc/Cache.cpp index 1a1a3b4d009..d61e5a9eab5 100644 --- a/intern/itasc/Cache.cpp +++ b/intern/itasc/Cache.cpp @@ -6,11 +6,12 @@ */ #include #include +#include +#ifndef __STDC__ #include +#endif #include "Cache.hpp" -#include - namespace iTaSC { CacheEntry::~CacheEntry() diff --git a/intern/itasc/CopyPose.cpp b/intern/itasc/CopyPose.cpp index 3bf7edd7975..7977089d280 100644 --- a/intern/itasc/CopyPose.cpp +++ b/intern/itasc/CopyPose.cpp @@ -8,7 +8,6 @@ #include "CopyPose.hpp" #include "kdl/kinfam_io.hpp" #include -#include #include namespace iTaSC diff --git a/intern/itasc/Distance.cpp b/intern/itasc/Distance.cpp index 0f61e7666b2..bf19a978888 100644 --- a/intern/itasc/Distance.cpp +++ b/intern/itasc/Distance.cpp @@ -8,7 +8,6 @@ #include "Distance.hpp" #include "kdl/kinfam_io.hpp" #include -#include #include namespace iTaSC diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp index c0995383c4b..e923b1fab27 100644 --- a/intern/itasc/MovingFrame.cpp +++ b/intern/itasc/MovingFrame.cpp @@ -6,7 +6,6 @@ */ #include "MovingFrame.hpp" -#include #include namespace iTaSC{ -- cgit v1.2.3 From 5eecb2ab48547449cfd9d668b92cb257bbd8da86 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 25 Sep 2009 09:33:46 +0000 Subject: Warning fixes for ITASC. Also, use instead of , it works everywhere. --- intern/itasc/Armature.cpp | 14 +++++++----- intern/itasc/Cache.cpp | 4 +--- intern/itasc/ConstraintSet.cpp | 8 +++---- intern/itasc/CopyPose.cpp | 4 ++-- intern/itasc/WSDLSSolver.hpp | 2 ++ intern/itasc/kdl/jacobian.cpp | 4 ++-- intern/itasc/kdl/treefksolverpos_recursive.cpp | 1 - source/blender/ikplugin/intern/ikplugin_api.c | 2 -- source/blender/ikplugin/intern/itasc_plugin.cpp | 29 +++++++++---------------- 9 files changed, 30 insertions(+), 38 deletions(-) diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp index 6ae60089cd8..7776b6aa3b6 100644 --- a/intern/itasc/Armature.cpp +++ b/intern/itasc/Armature.cpp @@ -8,9 +8,7 @@ #include "Armature.hpp" #include #include -#ifndef __STDC__ -#include -#endif +#include namespace iTaSC { @@ -37,9 +35,9 @@ Armature::Armature(): m_newqKdl(), m_qdotKdl(), m_jac(NULL), + m_armlength(0.0), m_jacsolver(NULL), - m_fksolver(NULL), - m_armlength(0.0) + m_fksolver(NULL) { } @@ -119,6 +117,8 @@ Armature::JointConstraint_struct::JointConstraint_struct(SegmentMap::const_itera values[1].id = value[1].id = ID_JOINT_RZ; v_nr = 2; break; + case Joint::None: + break; } } @@ -734,6 +734,8 @@ bool Armature::setControlParameter(unsigned int constraintId, unsigned int value case ACT_ALPHA: pConstraint->values[i].alpha = value; break; + default: + break; } } } else { @@ -755,6 +757,8 @@ bool Armature::setControlParameter(unsigned int constraintId, unsigned int value case ACT_ALPHA: pConstraint->values[i].alpha = value; break; + case ACT_NONE: + break; } } } diff --git a/intern/itasc/Cache.cpp b/intern/itasc/Cache.cpp index d61e5a9eab5..ccd9cef4655 100644 --- a/intern/itasc/Cache.cpp +++ b/intern/itasc/Cache.cpp @@ -7,9 +7,7 @@ #include #include #include -#ifndef __STDC__ -#include -#endif +#include #include "Cache.hpp" namespace iTaSC { diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp index eaffc2a52f9..a38db445ea2 100644 --- a/intern/itasc/ConstraintSet.cpp +++ b/intern/itasc/ConstraintSet.cpp @@ -12,13 +12,13 @@ namespace iTaSC { ConstraintSet::ConstraintSet(unsigned int _nc,double accuracy,unsigned int maximum_iterations): m_nc(_nc), - m_Jf(e_identity_matrix(6,6)), m_Cf(e_zero_matrix(m_nc,6)), - m_U(e_identity_matrix(6,6)),m_V(e_identity_matrix(6,6)),m_B(e_zero_matrix(6,6)), - m_Jf_inv(e_zero_matrix(6,6)), m_Wy(e_scalar_vector(m_nc,1.0)), - m_chi(e_zero_vector(6)),m_y(m_nc),m_ydot(e_zero_vector(m_nc)), + m_y(m_nc),m_ydot(e_zero_vector(m_nc)),m_chi(e_zero_vector(6)), m_S(6),m_temp(6),m_tdelta(6), + m_Jf(e_identity_matrix(6,6)), + m_U(e_identity_matrix(6,6)),m_V(e_identity_matrix(6,6)),m_B(e_zero_matrix(6,6)), + m_Jf_inv(e_zero_matrix(6,6)), m_internalPose(F_identity), m_externalPose(F_identity), m_constraintCallback(NULL), m_constraintParam(NULL), m_toggle(false),m_substep(false), diff --git a/intern/itasc/CopyPose.cpp b/intern/itasc/CopyPose.cpp index 7977089d280..69722909ed1 100644 --- a/intern/itasc/CopyPose.cpp +++ b/intern/itasc/CopyPose.cpp @@ -21,7 +21,7 @@ CopyPose::CopyPose(unsigned int control_output, unsigned int dynamic_output, dou { m_maxerror = armlength/2.0; m_outputControl = (control_output & CTL_ALL); - int _nc = nBitsOn(m_outputControl); + unsigned int _nc = nBitsOn(m_outputControl); if (!_nc) return; // reset the constraint set @@ -284,7 +284,7 @@ void CopyPose::updateJacobian() void CopyPose::updateState(ConstraintValues* _values, ControlState* _state, unsigned int mask, double timestep) { - int id = (mask == CTL_ROTATIONX) ? ID_ROTATIONX : ID_POSITIONX; + unsigned int id = (mask == CTL_ROTATIONX) ? ID_ROTATIONX : ID_POSITIONX; ControlState::ControlValue* _yval; ConstraintSingleValue* _data; int i, j, k; diff --git a/intern/itasc/WSDLSSolver.hpp b/intern/itasc/WSDLSSolver.hpp index 90f89f4e853..1341cf2af66 100644 --- a/intern/itasc/WSDLSSolver.hpp +++ b/intern/itasc/WSDLSSolver.hpp @@ -31,6 +31,8 @@ public: case DLS_QMAX: m_qmax = value; break; + default: + break; } } }; diff --git a/intern/itasc/kdl/jacobian.cpp b/intern/itasc/kdl/jacobian.cpp index 4166a341fe7..f8f46b32619 100644 --- a/intern/itasc/kdl/jacobian.cpp +++ b/intern/itasc/kdl/jacobian.cpp @@ -55,13 +55,13 @@ namespace KDL double Jacobian::operator()(int i,int j)const { - assert(i<6*nr_blocks&&jsecond; p_out = recursiveFk(q_in, it, baseit); return 0; } diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c index 714843fc5e5..f106302dbaf 100644 --- a/source/blender/ikplugin/intern/ikplugin_api.c +++ b/source/blender/ikplugin/intern/ikplugin_api.c @@ -72,8 +72,6 @@ static IKPlugin ikplugin_tab[BIK_SOLVER_COUNT] = { static IKPlugin *get_plugin(bPose *pose) { - IKPlugin *plugin; - if (!pose || pose->iksolver < 0 || pose->iksolver >= BIK_SOLVER_COUNT) return NULL; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index b6278e40ea5..4aebda1347c 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -354,7 +354,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co static bool is_cartesian_constraint(bConstraint *con) { - bKinematicConstraint* data=(bKinematicConstraint*)con->data; + //bKinematicConstraint* data=(bKinematicConstraint*)con->data; return true; } @@ -379,12 +379,8 @@ static bool constraint_valid(bConstraint *con) int initialize_scene(Object *ob, bPoseChannel *pchan_tip) { - bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan; - PoseTree *tree; - PoseTarget *target; bConstraint *con; - bKinematicConstraint *data; - int a, segcount= 0, size, newsize, *oldparent, parent, rootbone, treecount; + int treecount; /* find all IK constraints and validate them */ treecount = 0; @@ -456,6 +452,7 @@ static void RemoveEulerAngleFromMatrix(KDL::Rotation& R, double angle, int axis) R = R*T; } +#if 0 static void GetEulerXZY(const KDL::Rotation& R, double& X,double& Z,double& Y) { if (fabs(R(0,1)) > 1.0 - KDL::epsilon ) { @@ -481,6 +478,7 @@ static void GetEulerXYZ(const KDL::Rotation& R, double& X,double& Y,double& Z) Z = KDL::atan2(-R(0,1), R(0,0)); } } +#endif static void GetJointRotation(KDL::Rotation& boneRot, int type, double* rot) { @@ -660,9 +658,6 @@ static bool copypose_callback(const iTaSC::Timestamp& timestamp, iTaSC::Constrai bKinematicConstraint *condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; iTaSC::ConstraintValues* values = _values; bItasc* ikparam = (bItasc*) iktarget->owner->pose->ikparam; - iTaSC::ConstraintSingleValue* value; - double error; - int i; // we need default parameters if (!ikparam) @@ -839,7 +834,7 @@ static bool joint_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintV break; } if (dof >= 0) { - for (int i=0; i<_nvalues; i++, dof++) { + for (unsigned int i=0; i<_nvalues; i++, dof++) { _values[i].values[0].yd = ikchan->jointValue[dof]; _values[i].alpha = chan->ikrotweight; _values[i].feedback = ikparam->feedback; @@ -853,7 +848,6 @@ static int convert_channels(IK_Scene *ikscene, PoseTree *tree) { IK_Channel *ikchan; bPoseChannel *pchan; - PoseTarget* target; Bone *bone; int a, flag, njoint; @@ -1046,11 +1040,11 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) KDL::Frame initPose; KDL::Rotation boneRot; Bone *bone; - int a, t, numtarget; + int a, numtarget; + unsigned int t; float length; bool ret = true, ingame; double *rot; - double lmin[3], lmax[3]; if (tree->totchannel == 0) return NULL; @@ -1105,7 +1099,6 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) double weight[3]; // assume uniform scaling and take Y scale as general scale for the armature float scale = VecLength(ob->obmat[1]); - double X, Y, Z; // build the array of joints corresponding to the IK chain convert_channels(ikscene, tree); if (ingame) { @@ -1366,8 +1359,8 @@ static IK_Scene* convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan) } // set the weight e_matrix& Wq = arm->getWq(); - assert(Wq.cols() == weights.size()); - for (unsigned int q=0; qpose->ikdata) { for(IK_Scene* scene = ((IK_Data*)ob->pose->ikdata)->first; scene != NULL; @@ -1559,7 +1550,7 @@ static void execute_scene(Scene* blscene, IK_Scene* ikscene, bItasc* ikparam, fl } if (ikscene->cache && !reiterate && simulation) { - iTaSC::CacheTS sts, cts, dts; + iTaSC::CacheTS sts, cts; sts = cts = (iTaSC::CacheTS)(timestamp*1000.0+0.5); if (ikscene->cache->getPreviousCacheItem(ikscene->armature, 0, &cts) == NULL || cts == 0) { // the cache is empty before this time, reiterate -- cgit v1.2.3 From 40c175f8f6073d57a80f1ee86efe6d57ad691633 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 10:24:42 +0000 Subject: modal kaymaps for view3d rotate/move/zoom removed redundant 'view' prefix from these operators. --- source/blender/editors/space_view3d/view3d_edit.c | 221 ++++++++++++++++----- .../blender/editors/space_view3d/view3d_intern.h | 7 +- source/blender/editors/space_view3d/view3d_ops.c | 11 +- 3 files changed, 188 insertions(+), 51 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 5e3a6ae0e02..640252287fe 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -239,9 +239,10 @@ typedef struct ViewOpsData { float ofs[3], obofs[3]; float reverse, dist0; float grid, far; + short axis_snap; /* view rotate only */ int origx, origy, oldx, oldy; - int origkey; + int origkey; /* the key that triggered the operator */ } ViewOpsData; @@ -289,7 +290,7 @@ static void viewops_data(bContext *C, wmOperator *op, wmEvent *event) QUATCOPY(vod->oldquat, rv3d->viewquat); vod->origx= vod->oldx= event->x; vod->origy= vod->oldy= event->y; - vod->origkey= event->type; + vod->origkey= event->type; /* the key that triggered the operator. */ /* lookup, we dont pass on v3d to prevent confusement */ vod->grid= v3d->grid; @@ -357,11 +358,52 @@ static float snapquats[39][6] = { {0.0, 0.0, 0.0, 1.0, 0, 0} }; +enum { + VIEW_PASS= 0, + VIEW_APPLY, + VIEW_CONFIRM +}; + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */ +#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2 +#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3 + + +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewrotate_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Cancel", ""}, + + {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""}, + {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Enable Axis Snap", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Rotate Modal"); -static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Rotate Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); + +} + +static void viewrotate_apply(ViewOpsData *vod, int x, int y) { RegionView3D *rv3d= vod->rv3d; - int use_sel= 0; /* XXX */ + int use_sel= U.uiflag & USER_ORBIT_SELECTION; rv3d->view= 0; /* need to reset everytime because of view snapping */ @@ -462,7 +504,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) } /* check for view snap */ - if (ctrl){ + if (vod->axis_snap){ int i; float viewmat[3][3]; @@ -496,23 +538,41 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl) static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event) { ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewrotate_apply(vod, event->x, event->y, event->ctrl); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + case VIEWROT_MODAL_AXIS_SNAP_ENABLE: + vod->axis_snap= TRUE; + event_code= VIEW_APPLY; + break; + case VIEWROT_MODAL_AXIS_SNAP_DISABLE: + vod->axis_snap= FALSE; + event_code= VIEW_APPLY; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewrotate_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; @@ -547,13 +607,13 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) } -void VIEW3D_OT_viewrotate(wmOperatorType *ot) +void VIEW3D_OT_rotate(wmOperatorType *ot) { /* identifiers */ ot->name= "Rotate view"; ot->description = "Rotate the view."; - ot->idname= "VIEW3D_OT_viewrotate"; + ot->idname= "VIEW3D_OT_rotate"; /* api callbacks */ ot->invoke= viewrotate_invoke; @@ -566,6 +626,33 @@ void VIEW3D_OT_viewrotate(wmOperatorType *ot) /* ************************ viewmove ******************************** */ + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ + +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewmove_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Move Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Move Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); +} + + static void viewmove_apply(ViewOpsData *vod, int x, int y) { if(vod->rv3d->persp==V3D_CAMOB) { @@ -596,24 +683,35 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) { + ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewmove_apply(vod, event->x, event->y); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewmove_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; @@ -631,13 +729,13 @@ static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) } -void VIEW3D_OT_viewmove(wmOperatorType *ot) +void VIEW3D_OT_move(wmOperatorType *ot) { /* identifiers */ ot->name= "Move view"; ot->description = "Move the view."; - ot->idname= "VIEW3D_OT_viewmove"; + ot->idname= "VIEW3D_OT_move"; /* api callbacks */ ot->invoke= viewmove_invoke; @@ -650,6 +748,29 @@ void VIEW3D_OT_viewmove(wmOperatorType *ot) /* ************************ viewzoom ******************************** */ +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewzoom_modal_keymap(wmWindowManager *wm) +{ + static EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Zoom Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return; + + keymap= WM_modalkeymap_add(wm, "View3D Zoom Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); +} + static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my) { RegionView3D *rv3d= ar->regiondata; @@ -758,23 +879,33 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y) static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event) { ViewOpsData *vod= op->customdata; + short event_code= VIEW_PASS; /* execute the events */ - switch(event->type) { - case MOUSEMOVE: - viewzoom_apply(vod, event->x, event->y); - break; + if(event->type==MOUSEMOVE) { + event_code= VIEW_APPLY; + } + else if(event->type==EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code= VIEW_CONFIRM; + break; + } + } + else if(event->type==vod->origkey && event->val==KM_RELEASE) { + event_code= VIEW_CONFIRM; + } - default: - /* origkey may be zero when invoked from a button */ - if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==KM_RELEASE)) { - request_depth_update(CTX_wm_region_view3d(C)); + if(event_code==VIEW_APPLY) { + viewzoom_apply(vod, event->x, event->y); + } + else if (event_code==VIEW_CONFIRM) { + request_depth_update(CTX_wm_region_view3d(C)); - MEM_freeN(vod); - op->customdata= NULL; + MEM_freeN(vod); + op->customdata= NULL; - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index d532d2b2cc8..e7ab79ab955 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -66,8 +66,8 @@ void view3d_keymap(struct wmWindowManager *wm); /* view3d_edit.c */ void VIEW3D_OT_zoom(struct wmOperatorType *ot); -void VIEW3D_OT_viewmove(struct wmOperatorType *ot); -void VIEW3D_OT_viewrotate(struct wmOperatorType *ot); +void VIEW3D_OT_move(struct wmOperatorType *ot); +void VIEW3D_OT_rotate(struct wmOperatorType *ot); void VIEW3D_OT_view_all(struct wmOperatorType *ot); void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot); void VIEW3D_OT_view_center(struct wmOperatorType *ot); @@ -137,6 +137,9 @@ void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); /* rect: for pick void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d); void fly_modal_keymap(struct wmWindowManager *wm); +void viewrotate_modal_keymap(struct wmWindowManager *wm); +void viewmove_modal_keymap(struct wmWindowManager *wm); +void viewzoom_modal_keymap(struct wmWindowManager *wm); /* view3d_buttons.c */ void VIEW3D_OT_properties(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 23dd092ce38..f9cedbd28a1 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -62,8 +62,8 @@ void view3d_operatortypes(void) { - WM_operatortype_append(VIEW3D_OT_viewrotate); - WM_operatortype_append(VIEW3D_OT_viewmove); + WM_operatortype_append(VIEW3D_OT_rotate); + WM_operatortype_append(VIEW3D_OT_move); WM_operatortype_append(VIEW3D_OT_zoom); WM_operatortype_append(VIEW3D_OT_view_all); WM_operatortype_append(VIEW3D_OT_viewnumpad); @@ -119,8 +119,8 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_viewrotate", MIDDLEMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_viewmove", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center", PADPERIOD, KM_PRESS, 0, 0); @@ -222,5 +222,8 @@ void view3d_keymap(wmWindowManager *wm) transform_keymap_for_space(wm, keymap, SPACE_VIEW3D); fly_modal_keymap(wm); + viewrotate_modal_keymap(wm); + viewmove_modal_keymap(wm); + viewzoom_modal_keymap(wm); } -- cgit v1.2.3 From ff7157d6f840acbd818c83ccf6ae8e06f1784788 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Sep 2009 10:52:29 +0000 Subject: Graph Editor: Drawing + Selection Tweaks * Deselect all now selects/deselects F-Curves too * Tangents of unselected F-Curves now draw 'faded' like the curves they belong to. This experimental change is quite subtle, but can be made stronger still if people want. * Cleaned up some old comments in the code too... --- source/blender/editors/space_graph/graph_draw.c | 72 +++++++++++++++-------- source/blender/editors/space_graph/graph_select.c | 9 ++- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 9ae7e8263ee..38430045bef 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -90,6 +90,26 @@ /* XXX */ extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); +/* *************************** */ +/* Utility Drawing Defines */ + +/* determine the alpha value that should be used when + * drawing components for some F-Curve (fcu) + * - selected F-Curves should be more visible than partially visible ones + */ +#define drawFCurveFade(fcu) ( ((fcu)->flag & FCURVE_SELECTED)? 1.0f : 0.5f ) + +/* set the colour for some point from some value given packed into an int + * - intV: integer value containing color info packed into an int + * - alpha: float value describing the + */ +#define cpackA(intVC, alpha) \ + { \ + float _cpackCol[3]; \ + cpack_to_rgb(intVC, &_cpackCol[0], &_cpackCol[1], &_cpackCol[2]); \ + glColor4f(_cpackCol[0], _cpackCol[1], _cpackCol[2], alpha); \ + } + /* *************************** */ /* F-Curve Modifier Drawing */ @@ -258,22 +278,20 @@ static void draw_fcurve_vertices_handles (FCurve *fcu, View2D *v2d, short sel) /* helper func - set color to draw F-Curve data with */ static void set_fcurve_vertex_color (SpaceIpo *sipo, FCurve *fcu, short sel) { -#if 0 - if (sipo->showkey) { - if (sel) UI_ThemeColor(TH_TEXT_HI); - else UI_ThemeColor(TH_TEXT); - } -#endif - if ((fcu->flag & FCURVE_PROTECTED)==0) { - /* Curve's points are being edited */ - if (sel) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - else { - /* Curve's points cannot be edited */ - if (sel) UI_ThemeColor(TH_TEXT_HI); - else UI_ThemeColor(TH_TEXT); - } + /* Fade the 'intensity' of the vertices based on the selection of the curves too */ + int alphaOffset= (int)((drawFCurveFade(fcu) - 1.0f) * 255); + + /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */ + if ((fcu->flag & FCURVE_PROTECTED)==0) { + /* Curve's points ARE BEING edited */ + if (sel) UI_ThemeColorShadeAlpha(TH_VERTEX_SELECT, 0, alphaOffset); + else UI_ThemeColorShadeAlpha(TH_VERTEX, 0, alphaOffset); + } + else { + /* Curve's points CANNOT BE edited */ + if (sel) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, alphaOffset); + else UI_ThemeColorShadeAlpha(TH_TEXT, 0, alphaOffset); + } } @@ -322,7 +340,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) if ((sipo->flag & SIPO_NOHANDLES) || (fcu->flag & FCURVE_PROTECTED) || (fcu->flag & FCURVE_INT_VALUES)) return; - /* slightly hacky, but we want to draw unselected points before selected ones*/ + /* slightly hacky, but we want to draw unselected points before selected ones */ for (sel= 0; sel < 2; sel++) { BezTriple *bezt=fcu->bezt, *prevbezt=NULL; float *fp; @@ -337,7 +355,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw first handle if previous segment had handles */ if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) { - cpack(col[(unsigned char)bezt->h1]); + cpackA(col[(unsigned char)bezt->h1], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); glEnd(); @@ -347,7 +365,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) /* only draw second handle if this segment is bezier */ if (bezt->ipo == BEZT_IPO_BEZ) { - cpack(col[(unsigned char)bezt->h2]); + cpackA(col[(unsigned char)bezt->h2], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp+3); glVertex2fv(fp+6); glEnd(); @@ -359,7 +377,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) ) { fp= bezt->vec[0]; - cpack(col[(unsigned char)bezt->h1]); + cpackA(col[(unsigned char)bezt->h1], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -371,7 +389,7 @@ static void draw_fcurve_handles (SpaceIpo *sipo, ARegion *ar, FCurve *fcu) (bezt->ipo == BEZT_IPO_BEZ) ) { fp= bezt->vec[1]; - cpack(col[(unsigned char)bezt->h2]); + cpackA(col[(unsigned char)bezt->h2], drawFCurveFade(fcu)); glBegin(GL_LINE_STRIP); glVertex2fv(fp); glVertex2fv(fp+3); @@ -410,7 +428,6 @@ static void draw_fcurve_sample_control (float x, float y, float xscale, float ys glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f); /* anti-aliased lines for more consistent appearance */ - // XXX needed here? glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); @@ -506,7 +523,6 @@ static void draw_fcurve_curve (FCurve *fcu, SpaceIpo *sipo, View2D *v2d, View2DG } /* helper func - draw a samples-based F-Curve */ -// TODO: add offset stuff... static void draw_fcurve_curve_samples (FCurve *fcu, View2D *v2d) { FPoint *prevfpt= fcu->fpt; @@ -647,7 +663,7 @@ static void draw_fcurve_curve_bezts (FCurve *fcu, View2D *v2d, View2DGrid *grid) */ /* resol not depending on horizontal resolution anymore, drivers for example... */ - // XXX need to take into account the scale + // TODO: would be nice to make this depend on the scale of the graph too... if (fcu->driver) resol= 32; else @@ -809,7 +825,7 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri /* set whatever color the curve has set * - unselected curves draw less opaque to help distinguish the selected ones */ - glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], ((sel) ? 1.0f : 0.5f)); + glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], drawFCurveFade(fcu)); } /* anti-aliased lines for less jagged appearance */ @@ -842,6 +858,9 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri * - if the option to only show controls if the F-Curve is selected is enabled, we must obey this */ if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) { + /* enable blending to allow fading of curves */ + glEnable(GL_BLEND); + if (fcurve_needs_draw_fmodifier_controls(fcu, fcm)) { /* only draw controls if this is the active modifier */ if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) { @@ -863,6 +882,9 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri draw_fcurve_samples(sipo, ar, fcu); } } + + /* restore settings */ + glDisable(GL_BLEND); } /* undo mapping of keyframes for drawing if scaled F-Curve */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 728c9310a47..7eec9f31d86 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -142,9 +142,13 @@ static void deselect_graph_keys (bAnimContext *ac, short test, short sel) /* Keyframes First */ ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, sel_cb, NULL); - /* deactivate the F-Curve, and deselect if deselecting keyframes */ + /* deactivate the F-Curve, and deselect if deselecting keyframes. + * otherwise select the F-Curve too since we've selected all the keyframes + */ if (sel == SELECT_SUBTRACT) fcu->flag &= ~FCURVE_SELECTED; + else + fcu->flag |= FCURVE_SELECTED; fcu->flag &= ~FCURVE_ACTIVE; } @@ -259,8 +263,9 @@ static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, sho /* select the curve too * NOTE: this should really only happen if the curve got touched... */ - if (selectmode == SELECT_ADD) + if (selectmode == SELECT_ADD) { fcu->flag |= FCURVE_SELECTED; + } } /* cleanup */ -- cgit v1.2.3 From f49a18f30be875d9cae5a1872f40dc02ce0f1473 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 25 Sep 2009 12:20:31 +0000 Subject: Graph Editor: F-Modifiers can now be added to multiple selected F-Curves at once with the Ctrl-Shift-M hotkey. * All the selected F-Curves will get the same type of F-Modifier added. * The button in the properties region will still only added the F-Modifier to the active F-Curve though * For now, there must be an active F-Curve in either case, otherwise the poll() callback fails. --- source/blender/editors/space_graph/graph_edit.c | 53 +++++++++++++++---------- source/blender/editors/space_graph/graph_ops.c | 2 +- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index d718ef28e99..9e0d574ffa3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1710,13 +1710,18 @@ static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *eve /* start from 1 to skip the 'Invalid' modifier type */ for (i = 1; i < FMODIFIER_NUM_TYPES; i++) { FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i); + PointerRNA props_ptr; /* check if modifier is valid for this context */ if (fmi == NULL) continue; - /* add entry to add this type of modifier */ - uiItemEnumO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", "type", i); + /* create operator menu item with relevant properties filled in */ + props_ptr= uiItemFullO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS); + /* the only thing that gets set from the menu is the type of F-Modifier to add */ + RNA_enum_set(&props_ptr, "type", i); + /* the following properties are just repeats of existing ones... */ + RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active")); } uiItemS(layout); @@ -1728,36 +1733,41 @@ static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *eve static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) { bAnimContext ac; + ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - FCurve *fcu; - FModifier *fcm; + int filter; short type; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - - // xxx call the raw methods here instead? - ale= get_active_fcurve_channel(&ac); - if (ale == NULL) - return OPERATOR_CANCELLED; - fcu= (FCurve *)ale->data; - MEM_freeN(ale); - if (fcu == NULL) - return OPERATOR_CANCELLED; - /* get type of modifier to add */ type= RNA_enum_get(op->ptr, "type"); - /* add F-Modifier of specified type to active F-Curve, and make it the active one */ - fcm= add_fmodifier(&fcu->modifiers, type); - if (fcm) - set_active_fmodifier(&fcu->modifiers, fcm); - else { - BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details."); - return OPERATOR_CANCELLED; + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + if (RNA_boolean_get(op->ptr, "only_active")) + filter |= ANIMFILTER_ACTIVE; + else + filter |= ANIMFILTER_SEL; + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* smooth keyframes */ + for (ale= anim_data.first; ale; ale= ale->next) { + FCurve *fcu= (FCurve *)ale->data; + FModifier *fcm; + + /* add F-Modifier of specified type to active F-Curve, and make it the active one */ + fcm= add_fmodifier(&fcu->modifiers, type); + if (fcm) + set_active_fmodifier(&fcu->modifiers, fcm); + else { // TODO: stop when this happens? + BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details."); + break; + } } + BLI_freelistN(&anim_data); /* validate keyframes after editing */ ANIM_editkeyframes_refresh(&ac); @@ -1786,6 +1796,7 @@ void GRAPH_OT_fmodifier_add (wmOperatorType *ot) /* id-props */ RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", ""); + RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve."); } /* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index b7d67c85ab9..b82055064f8 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -221,7 +221,7 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); /* F-Modifiers */ - WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "only_active", 0); /* transform system */ -- cgit v1.2.3 From 38ae41f94ea2045f71c9ba2a89778ea1e6ed93df Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 13:09:18 +0000 Subject: fix for buildinfo on mac's --- source/creator/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 0cc0d5d496b..a4c2bfa0008 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -24,6 +24,9 @@ # # ***** END GPL LICENSE BLOCK ***** +# So BUILDINFO and BLENDERPATH strings are automatically quoted +CMAKE_POLICY(SET CMP0005 NEW) + SETUP_LIBDIRS() INCLUDE_DIRECTORIES(../../intern/guardedalloc @@ -68,7 +71,6 @@ ENDIF(NOT WITH_SDL) IF(UNIX AND NOT APPLE) SET(BLENDERPATH ${CMAKE_INSTALL_PREFIX}/share/blender/${BLENDER_VERSION}) - CMAKE_POLICY(SET CMP0005 NEW) # blender_path in creator.c ADD_DEFINITIONS(-DBLENDERPATH="${BLENDERPATH}") ENDIF(UNIX AND NOT APPLE) -- cgit v1.2.3 From 69e47fcb0edfefea4c23befdd5c44886fa18557e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 14:26:00 +0000 Subject: WITH_CXX_GUARDEDALLOC was broken since BL_ArmatureObject become a PyObject --- source/gameengine/Converter/BL_ArmatureObject.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 3e917e08001..8e3d5734b73 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -134,13 +134,6 @@ protected: float m_obmat[4][4]; double m_lastapplyframe; - - -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ArmatureObject"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif }; /* Pose function specific to the game engine */ -- cgit v1.2.3 From 9f6566c0a57ae136a819a461c43092a998c69f77 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 16:27:12 +0000 Subject: removed double library entries without realizing I had the BGE disabled, these are needed. --- source/creator/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a4c2bfa0008..f260002feac 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -364,7 +364,7 @@ IF(UNIX) blender_ONL bf_python bf_gen_python - bf_ikplugin + bf_ikplugin bf_blenkernel bf_nodes bf_gpu @@ -379,12 +379,15 @@ IF(UNIX) bf_readblenfile blender_bop bf_kernel + bf_decimation bf_elbeem bf_IK bf_memutil bf_guardedalloc blender_CTR bf_moto + bf_windowmanager + bf_editors bf_blroutines bf_converter bf_dummy @@ -399,11 +402,18 @@ IF(UNIX) bf_oglrasterizer bf_expressions bf_scenegraph + bf_moto + bf_blroutines kx_network + bf_kernel bf_ngnetwork extern_bullet bf_loopbacknetwork - bf_ITASC + bf_ITASC + bf_common + bf_moto + bf_python + bf_gen_python extern_binreloc extern_glew extern_libopenjpeg -- cgit v1.2.3 From aa989c1e8343cb761665129d44e03a4fc4c7cd95 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Sep 2009 16:30:15 +0000 Subject: almost all event managers stored a pointer back to the logic manager, easier if this pointer is in the base class - SCA_EventManager --- source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_ActuatorEventManager.h | 2 -- source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_AlwaysEventManager.h | 2 -- source/gameengine/GameLogic/SCA_BasicEventManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_EventManager.cpp | 5 +++-- source/gameengine/GameLogic/SCA_EventManager.h | 4 +++- source/gameengine/GameLogic/SCA_JoystickManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_JoystickManager.h | 2 -- source/gameengine/GameLogic/SCA_KeyboardManager.cpp | 7 +++---- source/gameengine/GameLogic/SCA_KeyboardManager.h | 2 -- source/gameengine/GameLogic/SCA_MouseManager.cpp | 7 +++---- source/gameengine/GameLogic/SCA_MouseManager.h | 1 - source/gameengine/GameLogic/SCA_PropertyEventManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_PropertyEventManager.h | 2 -- source/gameengine/GameLogic/SCA_RandomEventManager.cpp | 3 +-- source/gameengine/GameLogic/SCA_RandomEventManager.h | 2 -- source/gameengine/GameLogic/SCA_TimeEventManager.cpp | 2 +- source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp | 2 +- source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h | 1 - source/gameengine/Ketsji/KX_RayEventManager.h | 3 +-- source/gameengine/Ketsji/KX_TouchEventManager.cpp | 3 +-- source/gameengine/Ketsji/KX_TouchEventManager.h | 1 - 23 files changed, 22 insertions(+), 44 deletions(-) diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp index a80b2af55c8..e4dfe4e0bff 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp @@ -36,8 +36,7 @@ SCA_ActuatorEventManager::SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(ACTUATOR_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, ACTUATOR_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h index f3884c87a75..8c86d0dd422 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h @@ -37,8 +37,6 @@ using namespace std; class SCA_ActuatorEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_ActuatorEventManager(); diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp index dd3b55abcc9..aee01606974 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp @@ -42,8 +42,7 @@ using namespace std; SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(ALWAYS_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, ALWAYS_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h index 9540e3b71f6..f7fb3b9714e 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h @@ -34,8 +34,6 @@ using namespace std; class SCA_AlwaysEventManager : public SCA_EventManager { - - class SCA_LogicManager* m_logicmgr; public: SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr); virtual void NextFrame(); diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp index 24cae439fb7..a2a7e535b5c 100644 --- a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp @@ -42,8 +42,7 @@ using namespace std; SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(BASIC_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, BASIC_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp index d1301541a0a..5b6f3c46022 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.cpp +++ b/source/gameengine/GameLogic/SCA_EventManager.cpp @@ -35,8 +35,9 @@ #endif -SCA_EventManager::SCA_EventManager(EVENT_MANAGER_TYPE mgrtype) - :m_mgrtype(mgrtype) +SCA_EventManager::SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype) + :m_logicmgr(logicmgr), + m_mgrtype(mgrtype) { } diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index f77b115ee03..debefcc45b0 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -38,6 +38,8 @@ class SCA_EventManager { protected: + class SCA_LogicManager* m_logicmgr; /* all event manager subclasses use this (other then TimeEventManager) */ + // use a set to speed-up insertion/removal //std::set m_sensors; SG_DList m_sensors; @@ -58,7 +60,7 @@ public: BASIC_EVENTMGR }; - SCA_EventManager(EVENT_MANAGER_TYPE mgrtype); + SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype); virtual ~SCA_EventManager(); virtual void RemoveSensor(class SCA_ISensor* sensor); diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index ff8f3b1c81f..480292774da 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -37,8 +37,7 @@ SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(JOY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, JOY_EVENTMGR) { int i; for (i=0; i it(m_sensors); for (it.begin();!it.end();++it) { - (*it)->Activate(m_logicmanager); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h index c5553a74aef..8155283a274 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.h +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h @@ -45,8 +45,6 @@ using namespace std; class SCA_KeyboardManager : public SCA_EventManager { class SCA_IInputDevice* m_inputDevice; - class SCA_LogicManager* m_logicmanager; - public: SCA_KeyboardManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* inputdev); diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp index d407647cec3..c752701e785 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.cpp +++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp @@ -48,9 +48,8 @@ SCA_MouseManager::SCA_MouseManager(SCA_LogicManager* logicmgr, SCA_IInputDevice* mousedev) - : SCA_EventManager(MOUSE_EVENTMGR), - m_mousedevice (mousedev), - m_logicmanager(logicmgr) + : SCA_EventManager(logicmgr, MOUSE_EVENTMGR), + m_mousedevice (mousedev) { m_xpos = 0; m_ypos = 0; @@ -93,7 +92,7 @@ void SCA_MouseManager::NextFrame() mousesensor->setX(mx); mousesensor->setY(my); - mousesensor->Activate(m_logicmanager); + mousesensor->Activate(m_logicmgr); } } } diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h index ef1533c636b..00bbab66aa6 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.h +++ b/source/gameengine/GameLogic/SCA_MouseManager.h @@ -47,7 +47,6 @@ class SCA_MouseManager : public SCA_EventManager { class SCA_IInputDevice* m_mousedevice; - class SCA_LogicManager* m_logicmanager; unsigned short m_xpos; // Cached location of the mouse pointer unsigned short m_ypos; diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp index 764465309df..e01ce74e0a9 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp @@ -35,8 +35,7 @@ SCA_PropertyEventManager::SCA_PropertyEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(PROPERTY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, PROPERTY_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/GameLogic/SCA_PropertyEventManager.h index a9692377df8..5a036abb8b7 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.h +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.h @@ -37,8 +37,6 @@ using namespace std; class SCA_PropertyEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_PropertyEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_PropertyEventManager(); diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp index 976597aa812..780f8d10857 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp @@ -42,8 +42,7 @@ using namespace std; #endif SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(RANDOM_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, RANDOM_EVENTMGR) { } diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/GameLogic/SCA_RandomEventManager.h index c8b511b87b7..81896709551 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.h +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.h @@ -39,8 +39,6 @@ using namespace std; class SCA_RandomEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_RandomEventManager(class SCA_LogicManager* logicmgr); diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp index 911ea772bef..1b49906b8de 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp @@ -43,7 +43,7 @@ #include "FloatValue.h" SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr) -: SCA_EventManager(TIME_EVENTMGR) +: SCA_EventManager(NULL, TIME_EVENTMGR) { } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index 738f64713b0..65f7d98253c 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -45,7 +45,7 @@ KX_NetworkEventManager::KX_NetworkEventManager(class SCA_LogicManager* logicmgr, class NG_NetworkDeviceInterface *ndi) : -SCA_EventManager(NETWORK_EVENTMGR), m_logicmgr(logicmgr), m_ndi(ndi) +SCA_EventManager(logicmgr, NETWORK_EVENTMGR), m_ndi(ndi) { //printf("KX_NetworkEventManager constructor\n"); } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h index ae88f1d4987..fd776640bcf 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h @@ -34,7 +34,6 @@ class KX_NetworkEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; class NG_NetworkDeviceInterface* m_ndi; public: diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h index 27c9be14d1f..030dae525e1 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_RayEventManager.h @@ -41,8 +41,7 @@ class KX_RayEventManager : public SCA_EventManager class SCA_LogicManager* m_logicmgr; public: KX_RayEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(RAY_EVENTMGR), - m_logicmgr(logicmgr) + : SCA_EventManager(logicmgr, RAY_EVENTMGR) {} virtual void NextFrame(); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 712a512995e..6b454f6a338 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -40,8 +40,7 @@ KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr, PHY_IPhysicsEnvironment* physEnv) - : SCA_EventManager(TOUCH_EVENTMGR), - m_logicmgr(logicmgr), + : SCA_EventManager(logicmgr, TOUCH_EVENTMGR), m_physEnv(physEnv) { //notm_scene->addTouchCallback(STATIC_RESPONSE, KX_TouchEventManager::collisionResponse, this); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index 6da37d615a4..e6414a2e285 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -43,7 +43,6 @@ class PHY_IPhysicsEnvironment; class KX_TouchEventManager : public SCA_EventManager { typedef std::pair NewCollision; - class SCA_LogicManager* m_logicmgr; PHY_IPhysicsEnvironment* m_physEnv; std::set m_newCollisions; -- cgit v1.2.3 From 72c4c9da7a4074f86f4ed59d87a6e50a98b9bb06 Mon Sep 17 00:00:00 2001 From: Kent Mein Date: Fri, 25 Sep 2009 18:47:43 +0000 Subject: Fixing up Makefiles, its not fully working but its closer... Kent --- intern/itasc/Makefile | 9 +++++---- intern/itasc/kdl/Makefile | 10 +++++----- intern/itasc/kdl/utilities/Makefile | 2 ++ source/Makefile | 2 ++ source/blender/ikplugin/intern/Makefile | 6 ++++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/intern/itasc/Makefile b/intern/itasc/Makefile index 6ac0d142b72..2272cf2c6ac 100644 --- a/intern/itasc/Makefile +++ b/intern/itasc/Makefile @@ -28,10 +28,13 @@ # iksolver main makefile. # +include nan_definitions.mk LIBNAME = itasc -DIR = $(OCGDIR)/intern/$(SOURCEDIR) - +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = kdl +include nan_subdirs.mk include nan_compile.mk CPPFLAGS += -I. @@ -48,6 +51,4 @@ ifeq ($(OS),darwin) ranlib $(NAN_ITASC)/lib/debug/libitasc.a endif ############################## -DIRS = kdl -SOURCEDIR = intern/$(LIBNAME) include nan_subdirs.mk diff --git a/intern/itasc/kdl/Makefile b/intern/itasc/kdl/Makefile index e34c991db38..9b152c27c7c 100644 --- a/intern/itasc/kdl/Makefile +++ b/intern/itasc/kdl/Makefile @@ -28,15 +28,15 @@ # iksolver main makefile. # +include nan_definitions.mk + LIBNAME = itasc DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = utilities +SOURCEDIR = intern/$(LIBNAME)/kdl +include nan_subdirs.mk include nan_compile.mk CPPFLAGS += -I. CPPFLAGS += -I../../../extern/Eigen2 - -############################## -DIRS = utilities -SOURCEDIR = intern/$(LIBNAME)/kdl -include nan_subdirs.mk diff --git a/intern/itasc/kdl/utilities/Makefile b/intern/itasc/kdl/utilities/Makefile index 6dedc24181e..4397a80cef5 100644 --- a/intern/itasc/kdl/utilities/Makefile +++ b/intern/itasc/kdl/utilities/Makefile @@ -28,6 +28,8 @@ # iksolver main makefile. # +include nan_definitions.mk + LIBNAME = itasc DIR = $(OCGDIR)/intern/$(LIBNAME) diff --git a/source/Makefile b/source/Makefile index dab037d1749..b0c15c2eba1 100644 --- a/source/Makefile +++ b/source/Makefile @@ -98,7 +98,9 @@ COMLIB += $(OCGDIR)/blender/nodes_tex/$(DEBUG_DIR)libnodes_tex.a COMLIB += $(OCGDIR)/blender/nodes/$(DEBUG_DIR)libnodes.a COMLIB += $(OCGDIR)/blender/imbuf/$(DEBUG_DIR)libimbuf.a COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a +COMLIB += $(OCGDIR)/blender/ikplugin/$(DEBUG_DIR)libikplugin.a COMLIB += $(NAN_IKSOLVER)/lib/$(DEBUG_DIR)libiksolver.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc.a COMLIB += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a COMLIB += $(NAN_SUPERLU)/lib/$(DEBUG_DIR)libsuperlu.a COMLIB += $(OCGDIR)/blender/avi/$(DEBUG_DIR)libavi.a diff --git a/source/blender/ikplugin/intern/Makefile b/source/blender/ikplugin/intern/Makefile index 9254b65b7b7..0c54e5d1264 100644 --- a/source/blender/ikplugin/intern/Makefile +++ b/source/blender/ikplugin/intern/Makefile @@ -36,8 +36,8 @@ CFLAGS += -I../../makesdna CFLAGS += -I../../blenkernel CFLAGS += -I../../blenlib CFLAGS += -I../../include -CFLAGS += -I../../../intern/itasc -CFLAGS += -I../../../extern/Eigen2 +CFLAGS += -I../../../../intern/itasc +CFLAGS += -I../../../../extern/Eigen2 CFLAGS += -I.. CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include @@ -46,4 +46,6 @@ CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../blenkernel CPPFLAGS += -I../../blenlib CPPFLAGS += -I../../include +CPPFLAGS += -I../../../../intern/itasc +CPPFLAGS += -I../../../../extern/Eigen2 CPPFLAGS += -I.. -- cgit v1.2.3 From da5ff2ca98ae275f6e9addbad52621415fd30160 Mon Sep 17 00:00:00 2001 From: "Guillermo S. Romero" Date: Fri, 25 Sep 2009 22:38:15 +0000 Subject: Add directives to support multi dir lib. --- intern/itasc/Makefile | 13 ++++++------- intern/itasc/kdl/Makefile | 5 +++-- intern/itasc/kdl/utilities/Makefile | 5 +++-- source/Makefile | 2 ++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/intern/itasc/Makefile b/intern/itasc/Makefile index 2272cf2c6ac..2be46a017df 100644 --- a/intern/itasc/Makefile +++ b/intern/itasc/Makefile @@ -40,15 +40,14 @@ include nan_compile.mk CPPFLAGS += -I. CPPFLAGS += -I../../extern/Eigen2 -install: all debug +install: $(ALL_OR_DEBUG) @[ -d $(NAN_ITASC) ] || mkdir $(NAN_ITASC) - @[ -d $(NAN_ITASC)/lib ] || mkdir $(NAN_ITASC)/lib - @[ -d $(NAN_ITASC)/lib/debug ] || mkdir $(NAN_ITASC)/lib/debug - @../tools/cpifdiff.sh $(DIR)/libitasc.a $(NAN_ITASC)/lib/ - @../tools/cpifdiff.sh $(DIR)/debug/libitasc.a $(NAN_ITASC)/lib/debug/ + @[ -d $(NAN_ITASC)/lib/$(DEBUG_DIR) ] || mkdir $(NAN_ITASC)/lib/$(DEBUG_DIR) + @../tools/cpifdiff.sh $(DIR)/$(DEBUG_DIR)libitasc.a $(DIR)/$(DEBUG_DIR)libitasc_kdl.a $(DIR)/$(DEBUG_DIR)libitasc_kdl_util.a $(NAN_ITASC)/lib/$(DEBUG_DIR) ifeq ($(OS),darwin) - ranlib $(NAN_ITASC)/lib/libitasc.a - ranlib $(NAN_ITASC)/lib/debug/libitasc.a + ranlib $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc.a + ranlib $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl.a + ranlib $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl_util.a endif ############################## include nan_subdirs.mk diff --git a/intern/itasc/kdl/Makefile b/intern/itasc/kdl/Makefile index 9b152c27c7c..058f93da4e1 100644 --- a/intern/itasc/kdl/Makefile +++ b/intern/itasc/kdl/Makefile @@ -30,8 +30,9 @@ include nan_definitions.mk -LIBNAME = itasc -DIR = $(OCGDIR)/intern/$(LIBNAME) +LIBNAME = itasc_kdl +# Yep, same dir than parent (itasc instead of $(LIBNAME)) +DIR = $(OCGDIR)/intern/itasc DIRS = utilities SOURCEDIR = intern/$(LIBNAME)/kdl diff --git a/intern/itasc/kdl/utilities/Makefile b/intern/itasc/kdl/utilities/Makefile index 4397a80cef5..8ee08089e10 100644 --- a/intern/itasc/kdl/utilities/Makefile +++ b/intern/itasc/kdl/utilities/Makefile @@ -30,8 +30,9 @@ include nan_definitions.mk -LIBNAME = itasc -DIR = $(OCGDIR)/intern/$(LIBNAME) +LIBNAME = itasc_kdl_util +# Same dir than parent (itasc instead of $(LIBNAME)) +DIR = $(OCGDIR)/intern/itasc include nan_compile.mk diff --git a/source/Makefile b/source/Makefile index b0c15c2eba1..5a071a10a9c 100644 --- a/source/Makefile +++ b/source/Makefile @@ -101,6 +101,8 @@ COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a COMLIB += $(OCGDIR)/blender/ikplugin/$(DEBUG_DIR)libikplugin.a COMLIB += $(NAN_IKSOLVER)/lib/$(DEBUG_DIR)libiksolver.a COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl.a +COMLIB += $(NAN_ITASC)/lib/$(DEBUG_DIR)libitasc_kdl_util.a COMLIB += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a COMLIB += $(NAN_SUPERLU)/lib/$(DEBUG_DIR)libsuperlu.a COMLIB += $(OCGDIR)/blender/avi/$(DEBUG_DIR)libavi.a -- cgit v1.2.3 From 903d8231d905f528d746410ca868fa6dd1f0714b Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sat, 26 Sep 2009 16:22:52 +0000 Subject: netrender: fix some bugs with job cancellation, remove credits system, add more status report on server, cleanup server error management --- release/io/netrender/balancing.py | 6 - release/io/netrender/master.py | 247 ++++++++++++++++++------------------ release/io/netrender/master_html.py | 8 +- release/io/netrender/model.py | 3 - release/io/netrender/operators.py | 4 +- release/io/netrender/slave.py | 6 +- 6 files changed, 129 insertions(+), 145 deletions(-) diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py index 372ea7d95b7..637dd5ff92e 100644 --- a/release/io/netrender/balancing.py +++ b/release/io/netrender/balancing.py @@ -61,12 +61,6 @@ class Balancer: # ========================== - -class RatingCredit(RatingRule): - def rate(self, job): - # more credit is better (sort at first in list) - return -job.credits * job.priority - class RatingUsage(RatingRule): def rate(self, job): # less usage is better diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index 1202b94840f..a3e186a9cfd 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -35,9 +35,14 @@ class MRenderSlave(netrender.model.RenderSlave): def seen(self): self.last_seen = time.time() + + def finishedFrame(self, frame_number): + self.job_frames.remove(frame_number) + if not self.job_frames: + self.job = None class MRenderJob(netrender.model.RenderJob): - def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []): + def __init__(self, job_id, name, files, chunks = 1, priority = 1, blacklist = []): super().__init__() self.id = job_id self.name = name @@ -46,7 +51,6 @@ class MRenderJob(netrender.model.RenderJob): self.chunks = chunks self.priority = priority self.usage = 0.0 - self.credits = credits self.blacklist = blacklist self.last_dispatched = time.time() @@ -79,14 +83,6 @@ class MRenderJob(netrender.model.RenderJob): def start(self): self.status = JOB_QUEUED - - def update(self): - if self.last_update == 0: - self.credits += (time.time() - self.last_dispatched) / 60 - else: - self.credits += (time.time() - self.last_update) / 60 - - self.last_update = time.time() def addLog(self, frames): log_name = "_".join(("%04d" % f for f in frames)) + ".log" @@ -110,7 +106,6 @@ class MRenderJob(netrender.model.RenderJob): frames = [] for f in self.frames: if f.status == QUEUED: - self.credits -= 1 # cost of one frame self.last_dispatched = time.time() frames.append(f) if len(frames) >= self.chunks: @@ -150,30 +145,24 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.end_headers() def do_HEAD(self): - print(self.path) if self.path == "/status": job_id = self.headers.get('job-id', "") job_frame = int(self.headers.get('job-frame', -1)) - if job_id: - print("status:", job_id, "\n") + job = self.server.getJobID(job_id) + if job: + frame = job[job_frame] - job = self.server.getJobByID(job_id) - if job: - if job_frame != -1: - frame = job[frame] - - if not frame: - # no such frame - self.send_heat(http.client.NO_CONTENT) - return + + if frame: + self.send_head(http.client.OK) else: - # no such job id + # no such frame self.send_head(http.client.NO_CONTENT) - return - - self.send_head() + else: + # no such job id + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -182,19 +171,17 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- def do_GET(self): - print(self.path) if self.path == "/version": self.send_head() - self.server.stats("", "New client connection") + self.server.stats("", "Version check") self.wfile.write(VERSION) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "/render": job_id = self.headers['job-id'] job_frame = int(self.headers['job-frame']) - print("render:", job_id, job_frame) - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: frame = job[job_frame] @@ -203,7 +190,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if frame.status in (QUEUED, DISPATCHED): self.send_head(http.client.ACCEPTED) elif frame.status == DONE: - self.server.stats("", "Sending result back to client") + self.server.stats("", "Sending result to client") f = open(job.save_path + "%04d" % job_frame + ".exr", 'rb') self.send_head() @@ -223,9 +210,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): elif self.path == "/log": job_id = self.headers['job-id'] job_frame = int(self.headers['job-frame']) - print("log:", job_id, job_frame) - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: frame = job[job_frame] @@ -234,7 +220,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if not frame.log_path or frame.status in (QUEUED, DISPATCHED): self.send_head(http.client.PROCESSING) else: - self.server.stats("", "Sending log back to client") + self.server.stats("", "Sending log to client") f = open(frame.log_path, 'rb') self.send_head() @@ -254,9 +240,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_frame = int(self.headers.get('job-frame', -1)) if job_id: - print("status:", job_id, "\n") - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: if job_frame != -1: frame = job[frame] @@ -279,21 +264,21 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): for job in self.server: message.append(job.serialize()) + + self.server.stats("", "Sending status") self.send_head() self.wfile.write(bytes(repr(message), encoding='utf8')) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "/job": - self.server.update() + self.server.balance() slave_id = self.headers['slave-id'] - print("slave-id", slave_id) - - slave = self.server.updateSlave(slave_id) + slave = self.server.getSeenSlave(slave_id) if slave: # only if slave id is valid - job, frames = self.server.getNewJob(slave_id) + job, frames = self.server.newDispatch(slave_id) if job and frames: for f in frames: @@ -310,9 +295,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.wfile.write(bytes(repr(message), encoding='utf8')) - self.server.stats("", "Sending job frame to render node") + self.server.stats("", "Sending job to slave") else: # no job available, return error code + slave.job = None + slave.job_frames = [] + self.send_head(http.client.ACCEPTED) else: # invalid slave id self.send_head(http.client.NO_CONTENT) @@ -320,21 +308,19 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): elif self.path == "/file": slave_id = self.headers['slave-id'] - slave = self.server.updateSlave(slave_id) + slave = self.server.getSeenSlave(slave_id) if slave: # only if slave id is valid job_id = self.headers['job-id'] job_file = self.headers['job-file'] - print("job:", job_id, "\n") - print("file:", job_file, "\n") - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: render_file = job.files_map.get(job_file, None) if render_file: - self.server.stats("", "Sending file to render node") + self.server.stats("", "Sending file to slave") f = open(render_file.filepath, 'rb') self.send_head() @@ -350,9 +336,11 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): else: # invalid slave id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/slave": + elif self.path == "/slaves": message = [] + self.server.stats("", "Sending slaves status") + for slave in self.server.slaves: message.append(slave.serialize()) @@ -370,12 +358,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- def do_POST(self): - print(self.path) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- if self.path == "/job": - print("posting job info") - self.server.stats("", "Receiving job") length = int(self.headers['content-length']) @@ -383,8 +368,6 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_id = self.server.nextJobID() - print(job_info.files) - job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist) for frame in job_info.frames: @@ -395,17 +378,30 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): headers={"job-id": job_id} if job.testStart(): + self.server.stats("", "New job, missing files") self.send_head(headers=headers) else: + self.server.stats("", "New job, started") self.send_head(http.client.ACCEPTED, headers=headers) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "/cancel": job_id = self.headers.get('job-id', "") - if job_id: - print("cancel:", job_id, "\n") - self.server.removeJob(job_id) - else: # cancel all jobs - self.server.clear() + + job = self.server.getJobID(job_id) + + if job: + self.server.stats("", "Cancelling job") + self.server.removeJob(job) + self.send_head() + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/clear": + # cancel all jobs + self.server.stats("", "Clearing jobs") + self.server.clear() self.send_head() # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -414,15 +410,25 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_frame = int(self.headers.get('job-frame', "-1")) all = bool(self.headers.get('reset-all', "False")) - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: if job_frame != -1: - job[job_frame].reset(all) + + frame = job[job_frame] + if frame: + self.server.stats("", "Reset job frame") + frame.reset(all) + self.send_head() + else: + # no such frame + self.send_head(http.client.NO_CONTENT) + else: + self.server.stats("", "Reset job") job.reset(all) + self.send_head() - self.send_head() else: # job not found self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -430,6 +436,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): length = int(self.headers['content-length']) job_frame_string = self.headers['job-frame'] + self.server.stats("", "New slave connected") + slave_info = netrender.model.RenderSlave.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) slave_id = self.server.addSlave(slave_info.name, self.client_address, slave_info.stats) @@ -439,16 +447,17 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): elif self.path == "/log": slave_id = self.headers['slave-id'] - slave = self.server.updateSlave(slave_id) + slave = self.server.getSeenSlave(slave_id) if slave: # only if slave id is valid length = int(self.headers['content-length']) log_info = netrender.model.LogFile.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) - job = self.server.getJobByID(log_info.job_id) + job = self.server.getJobID(log_info.job_id) if job: + self.server.stats("", "Log announcement") job.addLog(log_info.frames) self.send_head(http.client.OK) else: @@ -462,18 +471,16 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- def do_PUT(self): - print(self.path) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- if self.path == "/file": - print("writing blend file") self.server.stats("", "Receiving job") length = int(self.headers['content-length']) job_id = self.headers['job-id'] job_file = self.headers['job-file'] - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: @@ -501,8 +508,10 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): render_file.filepath = file_path # set the new path if job.testStart(): + self.server.stats("", "File upload, starting job") self.send_head(http.client.OK) else: + self.server.stats("", "File upload, file missings") self.send_head(http.client.ACCEPTED) else: # invalid file self.send_head(http.client.NO_CONTENT) @@ -510,17 +519,16 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "/render": - print("writing result file") self.server.stats("", "Receiving render result") slave_id = self.headers['slave-id'] - slave = self.server.updateSlave(slave_id) + slave = self.server.getSeenSlave(slave_id) if slave: # only if slave id is valid job_id = self.headers['job-id'] - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: job_frame = int(self.headers['job-frame']) @@ -528,43 +536,43 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_time = float(self.headers['job-time']) frame = job[job_frame] - - if job_result == DONE: - length = int(self.headers['content-length']) - buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb') - f.write(buf) - f.close() - - del buf - elif job_result == ERROR: - # blacklist slave on this job on error - job.blacklist.append(slave.id) - - slave.job_frames.remove(job_frame) - if not slave.job_frames: - slave.job = None - frame.status = job_result - frame.time = job_time - - job.testFinished() - - self.server.updateSlave(self.headers['slave-id']) - - self.send_head() + if frame: + if job_result == DONE: + length = int(self.headers['content-length']) + buf = self.rfile.read(length) + f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb') + f.write(buf) + f.close() + + del buf + elif job_result == ERROR: + # blacklist slave on this job on error + job.blacklist.append(slave.id) + + self.server.stats("", "Receiving result") + + slave.finishedFrame(job_frame) + + frame.status = job_result + frame.time = job_time + + job.testFinished() + + self.send_head() + else: # frame not found + self.send_head(http.client.NO_CONTENT) else: # job not found self.send_head(http.client.NO_CONTENT) else: # invalid slave id self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "/log": - print("writing log file") self.server.stats("", "Receiving log file") job_id = self.headers['job-id'] - job = self.server.getJobByID(job_id) + job = self.server.getJobID(job_id) if job: job_frame = int(self.headers['job-frame']) @@ -580,7 +588,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): del buf - self.server.updateSlave(self.headers['slave-id']) + self.server.getSeenSlave(self.headers['slave-id']) self.send_head() else: # frame not found @@ -600,10 +608,7 @@ class RenderMasterServer(http.server.HTTPServer): self.slave_timeout = 2 - self.first_usage = True - self.balancer = netrender.balancing.Balancer() - #self.balancer.addRule(netrender.balancing.RatingCredit()) self.balancer.addRule(netrender.balancing.RatingUsage()) self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves, limit = 0.9)) @@ -631,7 +636,7 @@ class RenderMasterServer(http.server.HTTPServer): def getSlave(self, slave_id): return self.slaves_map.get(slave_id, None) - def updateSlave(self, slave_id): + def getSeenSlave(self, slave_id): slave = self.getSlave(slave_id) if slave: slave.seen() @@ -655,18 +660,12 @@ class RenderMasterServer(http.server.HTTPServer): self.removeSlave(slave) def updateUsage(self): - m = 1.0 - - if not self.first_usage: - for job in self.jobs: - job.usage *= 0.5 - - m = 0.5 - else: - self.first_usage = False + blend = 0.5 + for job in self.jobs: + job.usage *= (1 - blend) if self.slaves: - slave_usage = m / self.countSlaves() + slave_usage = blend / self.countSlaves() for slave in self.slaves: if slave.job: @@ -679,9 +678,7 @@ class RenderMasterServer(http.server.HTTPServer): for job in removed: self.removeJob(job) - def update(self): - for job in self.jobs: - job.update() + def balance(self): self.balancer.balance(self.jobs) def countJobs(self, status = JOB_QUEUED): @@ -695,16 +692,14 @@ class RenderMasterServer(http.server.HTTPServer): def countSlaves(self): return len(self.slaves) - def removeJob(self, id): - job = self.jobs_map.pop(id) - - if job: - self.jobs.remove(job) - - for slave in self.slaves: - if slave.job == job: - slave.job = None - slave.job_frames = [] + def removeJob(self, job): + self.jobs.remove(job) + self.jobs_map.pop(job.id) + + for slave in self.slaves: + if slave.job == job: + slave.job = None + slave.job_frames = [] def addJob(self, job): self.jobs.append(job) @@ -717,14 +712,14 @@ class RenderMasterServer(http.server.HTTPServer): job.save() - def getJobByID(self, id): + def getJobID(self, id): return self.jobs_map.get(id, None) def __iter__(self): for job in self.jobs: yield job - def getNewJob(self, slave_id): + def newDispatch(self, slave_id): if self.jobs: for job in self.jobs: if not self.balancer.applyExceptions(job) and slave_id not in job.blacklist: diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py index 7513971e6cf..6a956a70e9f 100644 --- a/release/io/netrender/master_html.py +++ b/release/io/netrender/master_html.py @@ -55,7 +55,6 @@ def get(handler): headerTable( "name", "priority", - "credits", "usage", "wait", "length", @@ -66,14 +65,13 @@ def get(handler): "exception" ) - handler.server.update() + handler.server.balance() for job in handler.server.jobs: results = job.framesStatus() rowTable( link(job.name, "/html/job" + job.id), job.priority, - round(job.credits, 1), "%0.1f%%" % (job.usage * 100), "%is" % int(time.time() - job.last_dispatched), len(job), @@ -92,7 +90,7 @@ def get(handler): output("NetRender") - job = handler.server.getJobByID(job_id) + job = handler.server.getJobID(job_id) if job: output("

Frames

") @@ -119,7 +117,7 @@ def get(handler): job_id = match.groups()[0] frame_number = int(match.groups()[1]) - job = handler.server.getJobByID(job_id) + job = handler.server.getJobID(job_id) if job: frame = job[frame_number] diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 91a7c8a035f..be97f8d0a81 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -80,7 +80,6 @@ class RenderJob: self.frames = [] self.chunks = 0 self.priority = 0 - self.credits = 0 self.usage = 0.0 self.blacklist = [] self.last_dispatched = 0.0 @@ -145,7 +144,6 @@ class RenderJob: "chunks": self.chunks, "priority": self.priority, "usage": self.usage, - "credits": self.credits, "blacklist": self.blacklist, "last_dispatched": self.last_dispatched } @@ -163,7 +161,6 @@ class RenderJob: job.chunks = data["chunks"] job.priority = data["priority"] job.usage = data["usage"] - job.credits = data["credits"] job.blacklist = data["blacklist"] job.last_dispatched = data["last_dispatched"] diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index 498edd74529..4278231ab35 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -205,7 +205,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): conn = clientConnection(context.scene) if conn: - conn.request("GET", "/slave") + conn.request("GET", "/slaves") response = conn.getresponse() print( response.status, response.reason ) @@ -289,7 +289,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator): conn = clientConnection(context.scene) if conn: - conn.request("POST", "/cancel") + conn.request("POST", "/clear") response = conn.getresponse() print( response.status, response.reason ) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index 406b987c990..657e31001e0 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -32,8 +32,8 @@ def slave_Info(): slave.stats = sysname + " " + release + " " + machine + " " + processor return slave -def testCancel(conn, job_id): - conn.request("HEAD", "/status", headers={"job-id":job_id}) +def testCancel(conn, job_id, frame_number): + conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) response = conn.getresponse() # cancelled if job isn't found anymore @@ -152,7 +152,7 @@ def render_slave(engine, scene): stdout = bytes() run_t = current_t - if testCancel(conn, job.id): + if testCancel(conn, job.id, first_frame): cancelled = True if cancelled: -- cgit v1.2.3 From 128dba3329076980d9a7c1cfa326cc3b17f05152 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Sat, 26 Sep 2009 16:43:20 +0000 Subject: Assorted tiny UI tweaks --- release/ui/buttons_data_camera.py | 8 +- source/blender/editors/screen/screen_ops.c | 6 +- source/blender/editors/space_node/drawnode.c | 98 +++++++++++------------ source/blender/editors/space_view3d/view3d_edit.c | 4 +- source/blender/makesrna/intern/rna_image.c | 2 +- 5 files changed, 60 insertions(+), 58 deletions(-) diff --git a/release/ui/buttons_data_camera.py b/release/ui/buttons_data_camera.py index aa107d8dbdd..0ac9a88eb35 100644 --- a/release/ui/buttons_data_camera.py +++ b/release/ui/buttons_data_camera.py @@ -38,13 +38,13 @@ class DATA_PT_camera(DataButtonsPanel): layout.itemR(cam, "type", expand=True) - row = layout.row(align=True) + row = layout.row() if cam.type == 'PERSP': - row.itemR(cam, "lens_unit", text="") if cam.lens_unit == 'MILLIMETERS': row.itemR(cam, "lens", text="Angle") elif cam.lens_unit == 'DEGREES': row.itemR(cam, "angle") + row.itemR(cam, "lens_unit", text="") elif cam.type == 'ORTHO': row.itemR(cam, "ortho_scale") @@ -86,11 +86,13 @@ class DATA_PT_camera_display(DataButtonsPanel): col.itemR(cam, "show_name", text="Name") col = split.column() + col.itemR(cam, "draw_size", text="Size") + col.itemS() col.itemR(cam, "show_passepartout", text="Passepartout") sub = col.column() sub.active = cam.show_passepartout sub.itemR(cam, "passepartout_alpha", text="Alpha", slider=True) - col.itemR(cam, "draw_size", text="Size") + bpy.types.register(DATA_PT_context_camera) bpy.types.register(DATA_PT_camera) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 5f7be1fd2bc..ae3f74403f2 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1574,7 +1574,7 @@ static int screen_full_area_exec(bContext *C, wmOperator *op) static void SCREEN_OT_screen_full_area(wmOperatorType *ot) { - ot->name = "Toggle Make Area Fullscreen"; + ot->name = "Toggle Full Screen"; ot->idname = "SCREEN_OT_screen_full_area"; ot->exec= screen_full_area_exec; @@ -2097,7 +2097,7 @@ static int region_foursplit_exec(bContext *C, wmOperator *op) static void SCREEN_OT_region_foursplit(wmOperatorType *ot) { /* identifiers */ - ot->name= "Split Region in 4 Parts"; + ot->name= "Toggle Quad View"; ot->idname= "SCREEN_OT_region_foursplit"; /* api callbacks */ @@ -2347,7 +2347,7 @@ static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event) static void SCREEN_OT_animation_play(wmOperatorType *ot) { /* identifiers */ - ot->name= "Animation player"; + ot->name= "Play Animation"; ot->idname= "SCREEN_OT_animation_play"; /* api callbacks */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f42bf97bf1a..0de19b22f3f 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1119,15 +1119,15 @@ static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) } uiItemR(col, NULL, 0, ptr, "relative", 0); - row= uiLayoutRow(col, 1); + col= uiLayoutColumn(layout, 1); if (RNA_boolean_get(ptr, "relative")== 1) { - uiItemR(row, "X", 0, ptr, "factor_x", 0); - uiItemR(row, "Y", 0, ptr, "factor_y", 0); + uiItemR(col, "X", 0, ptr, "factor_x", 0); + uiItemR(col, "Y", 0, ptr, "factor_y", 0); } else { - uiItemR(row, "X", 0, ptr, "sizex", 0); - uiItemR(row, "Y", 0, ptr, "sizey", 0); + uiItemR(col, "X", 0, ptr, "sizex", 0); + uiItemR(col, "Y", 0, ptr, "sizey", 0); } } @@ -1140,10 +1140,8 @@ static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) col= uiLayoutColumn(layout, 1); uiItemL(col, "Center:", 0); - - row= uiLayoutRow(col, 1); - uiItemR(row, "X:", 0, ptr, "center_x", 0); - uiItemR(row, "Y", 0, ptr, "center_y", 0); + uiItemR(col, "X", 0, ptr, "center_x", 0); + uiItemR(col, "Y", 0, ptr, "center_y", 0); uiItemS(layout); @@ -1172,7 +1170,7 @@ static void node_composit_buts_defocus(uiLayout *layout, PointerRNA *ptr) { uiLayout *sub, *col; - col= uiLayoutColumn(layout, 1); + col= uiLayoutColumn(layout, 0); uiItemL(col, "Bokeh Type:", 0); uiItemR(col, "", 0, ptr, "bokeh", 0); uiItemR(col, NULL, 0, ptr, "angle", 0); @@ -1211,7 +1209,7 @@ static void node_composit_buts_glare(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, NULL, 0, ptr, "iterations", 0); if (RNA_enum_get(ptr, "glare_type")!= 0) - uiItemR(layout, NULL, 0, ptr, "color_modulation", 0); + uiItemR(layout, NULL, 0, ptr, "color_modulation", UI_ITEM_R_SLIDER); } uiItemR(layout, NULL, 0, ptr, "mix", 0); @@ -1222,7 +1220,7 @@ static void node_composit_buts_glare(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, NULL, 0, ptr, "angle_offset", 0); } if (RNA_enum_get(ptr, "glare_type")== 0 || RNA_enum_get(ptr, "glare_type")== 2) { - uiItemR(layout, NULL, 0, ptr, "fade", 0); + uiItemR(layout, NULL, 0, ptr, "fade", UI_ITEM_R_SLIDER); if (RNA_enum_get(ptr, "glare_type")== 0) uiItemR(layout, NULL, 0, ptr, "rotate_45", 0); @@ -1237,18 +1235,18 @@ static void node_composit_buts_tonemap(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col = uiLayoutColumn(layout, 1); + col = uiLayoutColumn(layout, 0); uiItemR(col, "", 0, ptr, "tonemap_type", 0); if (RNA_enum_get(ptr, "tonemap_type")== 0) { - uiItemR(col, NULL, 0, ptr, "key", 0); + uiItemR(col, NULL, 0, ptr, "key", UI_ITEM_R_SLIDER); uiItemR(col, NULL, 0, ptr, "offset", 0); uiItemR(col, NULL, 0, ptr, "gamma", 0); } else { uiItemR(col, NULL, 0, ptr, "intensity", 0); - uiItemR(col, NULL, 0, ptr, "contrast", 0); - uiItemR(col, NULL, 0, ptr, "adaptation", 0); - uiItemR(col, NULL, 0, ptr, "correction", 0); + uiItemR(col, NULL, 0, ptr, "contrast", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "adaptation", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "correction", UI_ITEM_R_SLIDER); } } @@ -1270,7 +1268,7 @@ static void node_composit_buts_vecblur(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col= uiLayoutColumn(layout, 1); + col= uiLayoutColumn(layout, 0); uiItemR(col, NULL, 0, ptr, "samples", 0); uiItemR(col, "Blur", 0, ptr, "factor", 0); @@ -1309,7 +1307,7 @@ static void node_composit_buts_splitviewer(uiLayout *layout, PointerRNA *ptr) { uiLayout *row, *col; - col= uiLayoutColumn(layout, 1); + col= uiLayoutColumn(layout, 0); row= uiLayoutRow(col, 0); uiItemR(row, NULL, 0, ptr, "axis", UI_ITEM_R_EXPAND); uiItemR(col, NULL, 0, ptr, "factor", 0); @@ -1351,7 +1349,7 @@ static void node_composit_buts_hue_sat(uiLayout *layout, PointerRNA *ptr) { uiLayout *col; - col =uiLayoutColumn(layout, 1); + col =uiLayoutColumn(layout, 0); uiItemR(col, NULL, 0, ptr, "hue", UI_ITEM_R_SLIDER); uiItemR(col, NULL, 0, ptr, "sat", UI_ITEM_R_SLIDER); uiItemR(col, NULL, 0, ptr, "val", UI_ITEM_R_SLIDER); @@ -1384,7 +1382,7 @@ static void node_composit_buts_color_spill(uiLayout *layout, PointerRNA *ptr) { uiLayout *row, *col; - col =uiLayoutColumn(layout, 1); + col =uiLayoutColumn(layout, 0); uiItemR(col, NULL, 0, ptr, "factor", 0); row= uiLayoutRow(col, 0); uiItemR(row, NULL, 0, ptr, "channel", UI_ITEM_R_EXPAND); @@ -1392,35 +1390,37 @@ static void node_composit_buts_color_spill(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); - bNode *node= ptr->data; - rctf *butr= &node->butr; - short dx=(butr->xmax-butr->xmin)/2; - NodeChroma *c= node->storage; - - uiBlockBeginAlign(block); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", - butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, - &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", - butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, - &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", - butr->xmin, butr->ymin+20, dx, 20, - &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", - butr->xmin+dx, butr->ymin+20, dx, 20, - &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); - - uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", - butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, - &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); - uiBlockEndAlign(block); - if(c->t2 > c->t1) - c->t2=c->t1; + uiLayout *col; + + col= uiLayoutColumn(layout, 0); + uiItemR(col, NULL, 0, ptr, "acceptance", 0); + uiItemR(col, NULL, 0, ptr, "cutoff", 0); + + col= uiLayoutColumn(layout, 1); + uiItemR(col, NULL, 0, ptr, "lift", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "gain", UI_ITEM_R_SLIDER); + uiItemR(col, NULL, 0, ptr, "shadow_adjust", UI_ITEM_R_SLIDER); + +// uiBlock *block= uiLayoutFreeBlock(layout); +// bNode *node= ptr->data; +// rctf *butr= &node->butr; +// short dx=(butr->xmax-butr->xmin)/2; +// NodeChroma *c= node->storage; + +// uiBlockBeginAlign(block); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Acceptance ", butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20, &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color"); +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Cutoff ", butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20, &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color"); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Lift ", butr->xmin, butr->ymin+20, dx, 20, &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift"); +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Gain ", butr->xmin+dx, butr->ymin+20, dx, 20, &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain"); +// +// uiDefButF(block, NUMSLI, B_NODE_EXEC, "Shadow Adjust ", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured"); +// uiBlockEndAlign(block); +// +// if(c->t2 > c->t1) +// c->t2=c->t1; } static void node_composit_buts_color_matte(uiLayout *layout, PointerRNA *ptr) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 640252287fe..c07d9108993 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1056,7 +1056,7 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. void VIEW3D_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name= "View home"; + ot->name= "View All"; ot->description = "View all objects in scene."; ot->idname= "VIEW3D_OT_view_all"; @@ -1195,7 +1195,7 @@ void VIEW3D_OT_view_center(wmOperatorType *ot) { /* identifiers */ - ot->name= "View center"; + ot->name= "View Selected"; ot->description = "Move the view to the selection center."; ot->idname= "VIEW3D_OT_view_center"; diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index db7a8afb4a4..4c2689d4f64 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -242,7 +242,7 @@ static void rna_def_image(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_field_order_items[]= { {0, "EVEN", 0, "Even", "Even Fields first"}, - {IMA_STD_FIELD, "Odd", 0, "Odd", "Odd Fields first"}, + {IMA_STD_FIELD, "ODD", 0, "Odd", "Odd Fields first"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "Image", "ID"); -- cgit v1.2.3 From 7af92d6eff8d690789503349991db475dde16972 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sat, 26 Sep 2009 19:50:59 +0000 Subject: netrender: split off job settings in their own panel. Add button to open up web interface in a browser. --- release/io/netrender/operators.py | 44 +++++++++++++++++++++++++++++++++------ release/io/netrender/ui.py | 34 +++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index 4278231ab35..42d1f6a0b86 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -1,6 +1,7 @@ import bpy import sys, os import http, http.client, http.server, urllib, socket +import webbrowser from netrender.utils import * import netrender.client as client @@ -369,13 +370,13 @@ class netclientscan(bpy.types.Operator): def execute(self, context): netsettings = context.scene.network_render - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - s.settimeout(30) - - s.bind(('', 8000)) - try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.settimeout(30) + + s.bind(('', 8000)) + buf, address = s.recvfrom(64) print("received:", buf) @@ -389,3 +390,34 @@ class netclientscan(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) + +@rnaOperator +class netclientweb(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientweb" + __label__ = "Net Render Client Web" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + + # open connection to make sure server exists + conn = clientConnection(context.scene) + + if conn: + conn.close() + + webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port)) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index 7ee0b64d150..ddaf0e6854a 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -48,9 +48,6 @@ class SCENE_PT_network_settings(RenderButtonsPanel): col = split.column() - if scene.network_render.mode == "RENDER_CLIENT": - col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") - col.itemR(scene.network_render, "mode") col.itemR(scene.network_render, "path") col.itemR(scene.network_render, "server_address") @@ -60,12 +57,33 @@ class SCENE_PT_network_settings(RenderButtonsPanel): col.itemR(scene.network_render, "server_broadcast") else: col.itemO("render.netclientscan", icon="ICON_FILE_REFRESH", text="") + +@rnaType +class SCENE_PT_network_job(RenderButtonsPanel): + __label__ = "Job Settings" + COMPAT_ENGINES = set(['NET_RENDER']) + + def poll(self, context): + scene = context.scene + return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" + + def draw(self, context): + layout = self.layout + scene = context.scene + rd = scene.render_data + + layout.active = True + + split = layout.split() + + col = split.column() - if scene.network_render.mode == "RENDER_CLIENT": - col.itemO("render.netclientsend", text="send job to server") - col.itemR(scene.network_render, "job_name") - col.itemR(scene.network_render, "priority") - col.itemR(scene.network_render, "chunks") + col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") + col.itemO("render.netclientsend", icon="ICON_FILE_BLEND", text="Send job") + col.itemO("render.netclientweb", icon="ICON_QUESTION", text="Open Master Monitor") + col.itemR(scene.network_render, "job_name") + col.itemR(scene.network_render, "priority") + col.itemR(scene.network_render, "chunks") @rnaType class SCENE_PT_network_slaves(RenderButtonsPanel): -- cgit v1.2.3 From 69995bb1b32a081dab987926e0c9f3b94cd63209 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sat, 26 Sep 2009 20:03:01 +0000 Subject: Sound: * Threading buxfix letting MSVC Debug builds crash because of corrupted std::lists * Adopted two property ranges * Changed the mixdown volume to set the device volume instead of the volume of every sound. I also removed the private redefinition of m_logicmgr in SCA_BasicEventManager, which was already defined protected in the parent class SCA_EventManager and thus caused a bug letting GE crash here because of an uninitialized pointer. --- intern/audaspace/OpenAL/AUD_OpenALDevice.cpp | 389 ++++++++++++--------- intern/audaspace/intern/AUD_C-API.cpp | 11 + intern/audaspace/intern/AUD_C-API.h | 8 + intern/audaspace/intern/AUD_SoftwareDevice.cpp | 194 ++++++---- source/blender/blenkernel/intern/sound.c | 6 +- source/blender/makesrna/intern/rna_scene.c | 4 +- .../gameengine/GameLogic/SCA_BasicEventManager.h | 2 - 7 files changed, 362 insertions(+), 252 deletions(-) diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp index b33afa2b955..aa9f425d6fb 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp @@ -127,101 +127,103 @@ void AUD_OpenALDevice::updateStreams() alcSuspendContext(m_context); - // for all sounds - AUD_HandleIterator it = m_playingSounds->begin(); - while(it != m_playingSounds->end()) { - sound = *it; - // increment the iterator to make sure it's valid, - // in case the sound gets deleted after stopping - ++it; - - // is it a streamed sound? - if(!sound->isBuffered) + // for all sounds + AUD_HandleIterator it = m_playingSounds->begin(); + while(it != m_playingSounds->end()) { - // check for buffer refilling - alGetSourcei(sound->source, AL_BUFFERS_PROCESSED, &info); + sound = *it; + // increment the iterator to make sure it's valid, + // in case the sound gets deleted after stopping + ++it; - if(info) + // is it a streamed sound? + if(!sound->isBuffered) { - specs = sound->reader->getSpecs(); + // check for buffer refilling + alGetSourcei(sound->source, AL_BUFFERS_PROCESSED, &info); - // for all empty buffers - while(info--) + if(info) { - // if there's still data to play back - if(!sound->data_end) - { - // read data - length = m_buffersize; - sound->reader->read(length, buffer); - - // read nothing? - if(length == 0) - { - sound->data_end = true; - break; - } - - // unqueue buffer - alSourceUnqueueBuffers(sound->source, 1, - &sound->buffers[sound->current]); - ALenum err; - if((err = alGetError()) != AL_NO_ERROR) - { - sound->data_end = true; - break; - } - - // fill with new data - alBufferData(sound->buffers[sound->current], - sound->format, - buffer, - length * AUD_SAMPLE_SIZE(specs), - specs.rate); + specs = sound->reader->getSpecs(); - if(alGetError() != AL_NO_ERROR) + // for all empty buffers + while(info--) + { + // if there's still data to play back + if(!sound->data_end) { - sound->data_end = true; - break; + // read data + length = m_buffersize; + sound->reader->read(length, buffer); + + // read nothing? + if(length == 0) + { + sound->data_end = true; + break; + } + + // unqueue buffer + alSourceUnqueueBuffers(sound->source, 1, + &sound->buffers[sound->current]); + ALenum err; + if((err = alGetError()) != AL_NO_ERROR) + { + sound->data_end = true; + break; + } + + // fill with new data + alBufferData(sound->buffers[sound->current], + sound->format, + buffer, + length * AUD_SAMPLE_SIZE(specs), + specs.rate); + + if(alGetError() != AL_NO_ERROR) + { + sound->data_end = true; + break; + } + + // and queue again + alSourceQueueBuffers(sound->source, 1, + &sound->buffers[sound->current]); + if(alGetError() != AL_NO_ERROR) + { + sound->data_end = true; + break; + } + + sound->current = (sound->current+1) % + AUD_OPENAL_CYCLE_BUFFERS; } - - // and queue again - alSourceQueueBuffers(sound->source, 1, - &sound->buffers[sound->current]); - if(alGetError() != AL_NO_ERROR) - { - sound->data_end = true; + else break; - } - - sound->current = (sound->current+1) % - AUD_OPENAL_CYCLE_BUFFERS; } - else - break; } } - } - // check if the sound has been stopped - alGetSourcei(sound->source, AL_SOURCE_STATE, &info); + // check if the sound has been stopped + alGetSourcei(sound->source, AL_SOURCE_STATE, &info); - if(info != AL_PLAYING) - { - // if it really stopped - if(sound->data_end) + if(info != AL_PLAYING) { - // pause or - if(sound->keep) - pause(sound); - // stop + // if it really stopped + if(sound->data_end) + { + // pause or + if(sound->keep) + pause(sound); + // stop + else + stop(sound); + } + // continue playing else - stop(sound); + alSourcePlay(sound->source); } - // continue playing - else - alSourcePlay(sound->source); } } @@ -516,60 +518,73 @@ bool AUD_OpenALDevice::getFormat(ALenum &format, AUD_Specs specs) AUD_Handle* AUD_OpenALDevice::play(AUD_IFactory* factory, bool keep) { - // check if it is a buffered factory - for(AUD_BFIterator i = m_bufferedFactories->begin(); - i != m_bufferedFactories->end(); i++) - { - if((*i)->factory == factory) - { - // create the handle - AUD_OpenALHandle* sound = new AUD_OpenALHandle; AUD_NEW("handle") - sound->keep = keep; - sound->current = -1; - sound->isBuffered = true; - sound->data_end = true; + lock(); - alcSuspendContext(m_context); + AUD_OpenALHandle* sound = NULL; - // OpenAL playback code - try + try + { + // check if it is a buffered factory + for(AUD_BFIterator i = m_bufferedFactories->begin(); + i != m_bufferedFactories->end(); i++) + { + if((*i)->factory == factory) { - alGenSources(1, &sound->source); - if(alGetError() != AL_NO_ERROR) - AUD_THROW(AUD_ERROR_OPENAL); + // create the handle + sound = new AUD_OpenALHandle; AUD_NEW("handle") + sound->keep = keep; + sound->current = -1; + sound->isBuffered = true; + sound->data_end = true; + + alcSuspendContext(m_context); + // OpenAL playback code try { - alSourcei(sound->source, AL_BUFFER, (*i)->buffer); + alGenSources(1, &sound->source); if(alGetError() != AL_NO_ERROR) AUD_THROW(AUD_ERROR_OPENAL); + + try + { + alSourcei(sound->source, AL_BUFFER, (*i)->buffer); + if(alGetError() != AL_NO_ERROR) + AUD_THROW(AUD_ERROR_OPENAL); + } + catch(AUD_Exception) + { + alDeleteSources(1, &sound->source); + throw; + } } catch(AUD_Exception) { - alDeleteSources(1, &sound->source); + delete sound; AUD_DELETE("handle") + alcProcessContext(m_context); throw; } - } - catch(AUD_Exception) - { - delete sound; AUD_DELETE("handle") - alcProcessContext(m_context); - unlock(); - throw; - } - // play sound - m_playingSounds->push_back(sound); + // play sound + m_playingSounds->push_back(sound); - alSourcei(sound->source, AL_SOURCE_RELATIVE, 1); - start(); + alSourcei(sound->source, AL_SOURCE_RELATIVE, 1); + start(); - alcProcessContext(m_context); - unlock(); - - return sound; + alcProcessContext(m_context); + } } } + catch(AUD_Exception) + { + unlock(); + throw; + } + + unlock(); + + if(sound) + return sound; AUD_IReader* reader = factory->createReader(); @@ -596,7 +611,7 @@ AUD_Handle* AUD_OpenALDevice::play(AUD_IFactory* factory, bool keep) } // create the handle - AUD_OpenALHandle* sound = new AUD_OpenALHandle; AUD_NEW("handle") + sound = new AUD_OpenALHandle; AUD_NEW("handle") sound->keep = keep; sound->reader = reader; sound->current = 0; @@ -683,8 +698,11 @@ AUD_Handle* AUD_OpenALDevice::play(AUD_IFactory* factory, bool keep) bool AUD_OpenALDevice::pause(AUD_Handle* handle) { - // only songs that are played can be paused + bool result = false; + lock(); + + // only songs that are played can be paused for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { @@ -693,16 +711,20 @@ bool AUD_OpenALDevice::pause(AUD_Handle* handle) m_pausedSounds->push_back(*i); alSourcePause((*i)->source); m_playingSounds->erase(i); - unlock(); - return true; + result = true; + break; } } + unlock(); - return false; + + return result; } bool AUD_OpenALDevice::resume(AUD_Handle* handle) { + bool result = false; + lock(); // only songs that are paused can be resumed @@ -714,19 +736,24 @@ bool AUD_OpenALDevice::resume(AUD_Handle* handle) m_playingSounds->push_back(*i); start(); m_pausedSounds->erase(i); - unlock(); - return true; + result = true; + break; } } + unlock(); - return false; + + return result; } bool AUD_OpenALDevice::stop(AUD_Handle* handle) { AUD_OpenALHandle* sound; + bool result = false; + lock(); + for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { @@ -741,51 +768,60 @@ bool AUD_OpenALDevice::stop(AUD_Handle* handle) } delete *i; AUD_DELETE("handle") m_playingSounds->erase(i); - unlock(); - return true; + result = true; + break; } } - for(AUD_HandleIterator i = m_pausedSounds->begin(); - i != m_pausedSounds->end(); i++) + if(!result) { - if(*i == handle) + for(AUD_HandleIterator i = m_pausedSounds->begin(); + i != m_pausedSounds->end(); i++) { - sound = *i; - alDeleteSources(1, &sound->source); - if(!sound->isBuffered) + if(*i == handle) { - delete sound->reader; AUD_DELETE("reader") - alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers); + sound = *i; + alDeleteSources(1, &sound->source); + if(!sound->isBuffered) + { + delete sound->reader; AUD_DELETE("reader") + alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers); + } + delete *i; AUD_DELETE("handle") + m_pausedSounds->erase(i); + result = true; + break; } - delete *i; AUD_DELETE("handle") - m_pausedSounds->erase(i); - unlock(); - return true; } } + unlock(); - return false; + + return result; } bool AUD_OpenALDevice::setKeep(AUD_Handle* handle, bool keep) { + bool result = false; + lock(); + if(isValid(handle)) { ((AUD_OpenALHandle*)handle)->keep = keep; - unlock(); - return true; + result = true; } + unlock(); - return false; + + return result; } bool AUD_OpenALDevice::sendMessage(AUD_Handle* handle, AUD_Message &message) { - lock(); - bool result = false; + lock(); + if(handle == 0) { for(AUD_HandleIterator i = m_playingSounds->begin(); @@ -800,12 +836,16 @@ bool AUD_OpenALDevice::sendMessage(AUD_Handle* handle, AUD_Message &message) else if(isValid(handle)) if(!((AUD_OpenALHandle*)handle)->isBuffered) result = ((AUD_OpenALHandle*)handle)->reader->notify(message); + unlock(); + return result; } bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position) { + bool result = false; + lock(); if(isValid(handle)) @@ -857,20 +897,19 @@ bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position) alSourceRewind(alhandle->source); } } - unlock(); - return true; + result = true; } unlock(); - return false; + return result; } float AUD_OpenALDevice::getPosition(AUD_Handle* handle) { - lock(); - float position = 0.0; + lock(); + if(isValid(handle)) { AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle; @@ -887,27 +926,35 @@ float AUD_OpenALDevice::getPosition(AUD_Handle* handle) AUD_Status AUD_OpenALDevice::getStatus(AUD_Handle* handle) { + AUD_Status status = AUD_STATUS_INVALID; + lock(); + for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { if(*i == handle) { - unlock(); - return AUD_STATUS_PLAYING; + status = AUD_STATUS_PLAYING; + break; } } - for(AUD_HandleIterator i = m_pausedSounds->begin(); - i != m_pausedSounds->end(); i++) + if(status == AUD_STATUS_INVALID) { - if(*i == handle) + for(AUD_HandleIterator i = m_pausedSounds->begin(); + i != m_pausedSounds->end(); i++) { - unlock(); - return AUD_STATUS_PAUSED; + if(*i == handle) + { + status = AUD_STATUS_PAUSED; + break; + } } } + unlock(); - return AUD_STATUS_INVALID; + + return status; } void AUD_OpenALDevice::lock() @@ -935,6 +982,7 @@ bool AUD_OpenALDevice::checkCapability(int capability) bool AUD_OpenALDevice::setCapability(int capability, void *value) { + bool result = false; switch(capability) { case AUD_CAPS_VOLUME: @@ -948,8 +996,7 @@ bool AUD_OpenALDevice::setCapability(int capability, void *value) { alSourcef(((AUD_OpenALHandle*)caps->handle)->source, AL_GAIN, caps->value); - unlock(); - return true; + result = true; } unlock(); } @@ -962,8 +1009,7 @@ bool AUD_OpenALDevice::setCapability(int capability, void *value) { alSourcef(((AUD_OpenALHandle*)caps->handle)->source, AL_PITCH, caps->value); - unlock(); - return true; + result = true; } unlock(); } @@ -981,11 +1027,13 @@ bool AUD_OpenALDevice::setCapability(int capability, void *value) { if((*i)->factory == factory) { - unlock(); - return true; + result = true; + break; } } unlock(); + if(result) + return result; AUD_IReader* reader = factory->createReader(); @@ -1104,11 +1152,13 @@ bool AUD_OpenALDevice::setCapability(int capability, void *value) } break; } - return false; + return result; } bool AUD_OpenALDevice::getCapability(int capability, void *value) { + bool result = false; + switch(capability) { case AUD_CAPS_VOLUME: @@ -1122,8 +1172,7 @@ bool AUD_OpenALDevice::getCapability(int capability, void *value) { alGetSourcef(((AUD_OpenALHandle*)caps->handle)->source, AL_GAIN, &caps->value); - unlock(); - return true; + result = true; } unlock(); } @@ -1136,14 +1185,14 @@ bool AUD_OpenALDevice::getCapability(int capability, void *value) { alGetSourcef(((AUD_OpenALHandle*)caps->handle)->source, AL_PITCH, &caps->value); - unlock(); - return true; + result = true; } unlock(); } break; } - return false; + + return result; } /******************************************************************************/ @@ -1233,6 +1282,8 @@ float AUD_OpenALDevice::getSetting(AUD_3DSetting setting) bool AUD_OpenALDevice::updateSource(AUD_Handle* handle, AUD_3DData &data) { + bool result = false; + lock(); if(isValid(handle)) @@ -1241,12 +1292,12 @@ bool AUD_OpenALDevice::updateSource(AUD_Handle* handle, AUD_3DData &data) alSourcefv(source, AL_POSITION, (ALfloat*)data.position); alSourcefv(source, AL_VELOCITY, (ALfloat*)data.velocity); alSourcefv(source, AL_DIRECTION, (ALfloat*)&(data.orientation[3])); - unlock(); - return true; + result = true; } unlock(); - return false; + + return result; } bool AUD_OpenALDevice::setSourceSetting(AUD_Handle* handle, diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index afa1568d6dc..bc9598d6c81 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -531,6 +531,17 @@ AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound) } } +int AUD_setDeviceVolume(AUD_Device* device, float volume) +{ + assert(device); + + try + { + return device->setCapability(AUD_CAPS_VOLUME, &volume); + } + catch(AUD_Exception) {} +} + int AUD_setDeviceSoundVolume(AUD_Device* device, AUD_Handle* handle, float volume) { diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index b02b465bff2..66a5a5147b3 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -299,6 +299,14 @@ extern int AUD_setSoundPitch(AUD_Handle* handle, float pitch); */ extern AUD_Device* AUD_openReadDevice(AUD_Specs specs); +/** + * Sets the main volume of a device. + * \param device The device. + * \param volume The new volume, must be between 0.0 and 1.0. + * \return Whether the action succeeded. + */ +extern int AUD_setDeviceVolume(AUD_Device* device, float volume); + /** * Plays back a sound file through a read device. * \param device The read device. diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index 174ff8c8979..42a90a6f15e 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -94,51 +94,53 @@ void AUD_SoftwareDevice::mix(sample_t* buffer, int length) { lock(); - AUD_SoftwareHandle* sound; - int len; - sample_t* buf; - int sample_size = AUD_SAMPLE_SIZE(m_specs); - std::list stopSounds; - - // for all sounds - AUD_HandleIterator it = m_playingSounds->begin(); - while(it != m_playingSounds->end()) { - sound = *it; - // increment the iterator to make sure it's valid, - // in case the sound gets deleted after stopping - ++it; + AUD_SoftwareHandle* sound; + int len; + sample_t* buf; + int sample_size = AUD_SAMPLE_SIZE(m_specs); + std::list stopSounds; + + // for all sounds + AUD_HandleIterator it = m_playingSounds->begin(); + while(it != m_playingSounds->end()) + { + sound = *it; + // increment the iterator to make sure it's valid, + // in case the sound gets deleted after stopping + ++it; - // get the buffer from the source - len = length; - sound->reader->read(len, buf); + // get the buffer from the source + len = length; + sound->reader->read(len, buf); - m_mixer->add(buf, sound->reader->getSpecs(), len, sound->volume); + m_mixer->add(buf, sound->reader->getSpecs(), len, sound->volume); - // in case the end of the sound is reached - if(len < length) - { - if(sound->keep) - pause(sound); - else - stopSounds.push_back(sound); + // in case the end of the sound is reached + if(len < length) + { + if(sound->keep) + pause(sound); + else + stopSounds.push_back(sound); + } } - } - // fill with silence - if(m_specs.format == AUD_FORMAT_U8) - memset(buffer, 0x80, length * sample_size); - else - memset(buffer, 0, length * sample_size); + // fill with silence + if(m_specs.format == AUD_FORMAT_U8) + memset(buffer, 0x80, length * sample_size); + else + memset(buffer, 0, length * sample_size); - // superpose - m_mixer->superpose(buffer, length, m_volume); + // superpose + m_mixer->superpose(buffer, length, m_volume); - while(!stopSounds.empty()) - { - sound = stopSounds.front(); - stopSounds.pop_front(); - stop(sound); + while(!stopSounds.empty()) + { + sound = stopSounds.front(); + stopSounds.pop_front(); + stop(sound); + } } unlock(); @@ -201,8 +203,11 @@ AUD_Handle* AUD_SoftwareDevice::play(AUD_IFactory* factory, bool keep) bool AUD_SoftwareDevice::pause(AUD_Handle* handle) { - // only songs that are played can be paused + bool result = false; + lock(); + + // only songs that are played can be paused for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { @@ -212,18 +217,23 @@ bool AUD_SoftwareDevice::pause(AUD_Handle* handle) m_playingSounds->erase(i); if(m_playingSounds->empty()) playing(m_playback = false); - unlock(); - return true; + result = true; + break; } } + unlock(); - return false; + + return result; } bool AUD_SoftwareDevice::resume(AUD_Handle* handle) { - // only songs that are paused can be resumed + bool result = false; + lock(); + + // only songs that are paused can be resumed for(AUD_HandleIterator i = m_pausedSounds->begin(); i != m_pausedSounds->end(); i++) { @@ -233,17 +243,22 @@ bool AUD_SoftwareDevice::resume(AUD_Handle* handle) m_pausedSounds->erase(i); if(!m_playback) playing(m_playback = true); - unlock(); - return true; + result = true; + break; } } + unlock(); - return false; + + return result; } bool AUD_SoftwareDevice::stop(AUD_Handle* handle) { + bool result = false; + lock(); + for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { @@ -254,37 +269,46 @@ bool AUD_SoftwareDevice::stop(AUD_Handle* handle) m_playingSounds->erase(i); if(m_playingSounds->empty()) playing(m_playback = false); - unlock(); - return true; + result = true; + break; } } - for(AUD_HandleIterator i = m_pausedSounds->begin(); - i != m_pausedSounds->end(); i++) + if(!result) { - if(*i == handle) + for(AUD_HandleIterator i = m_pausedSounds->begin(); + i != m_pausedSounds->end(); i++) { - delete (*i)->reader; AUD_DELETE("reader") - delete *i; AUD_DELETE("handle") - m_pausedSounds->erase(i); - unlock(); - return true; + if(*i == handle) + { + delete (*i)->reader; AUD_DELETE("reader") + delete *i; AUD_DELETE("handle") + m_pausedSounds->erase(i); + result = true; + break; + } } } + unlock(); - return false; + + return result; } bool AUD_SoftwareDevice::setKeep(AUD_Handle* handle, bool keep) { + bool result = false; + lock(); + if(isValid(handle)) { ((AUD_SoftwareHandle*)handle)->keep = keep; - unlock(); - return true; + result = true; } + unlock(); - return false; + + return result; } bool AUD_SoftwareDevice::sendMessage(AUD_Handle* handle, AUD_Message &message) @@ -312,16 +336,18 @@ bool AUD_SoftwareDevice::seek(AUD_Handle* handle, float position) { lock(); + bool result = false; + if(isValid(handle)) { AUD_IReader* reader = ((AUD_SoftwareHandle*)handle)->reader; reader->seek((int)(position * reader->getSpecs().rate)); - unlock(); - return true; + result = true; } unlock(); - return false; + + return result; } float AUD_SoftwareDevice::getPosition(AUD_Handle* handle) @@ -337,32 +363,41 @@ float AUD_SoftwareDevice::getPosition(AUD_Handle* handle) } unlock(); + return position; } AUD_Status AUD_SoftwareDevice::getStatus(AUD_Handle* handle) { + AUD_Status status = AUD_STATUS_INVALID; + lock(); + for(AUD_HandleIterator i = m_playingSounds->begin(); i != m_playingSounds->end(); i++) { if(*i == handle) { - unlock(); - return AUD_STATUS_PLAYING; + status = AUD_STATUS_PLAYING; + break; } } - for(AUD_HandleIterator i = m_pausedSounds->begin(); - i != m_pausedSounds->end(); i++) + if(status == AUD_STATUS_INVALID) { - if(*i == handle) + for(AUD_HandleIterator i = m_pausedSounds->begin(); + i != m_pausedSounds->end(); i++) { - unlock(); - return AUD_STATUS_PAUSED; + if(*i == handle) + { + status = AUD_STATUS_PAUSED; + break; + } } } + unlock(); - return AUD_STATUS_INVALID; + + return status; } void AUD_SoftwareDevice::lock() @@ -384,6 +419,8 @@ bool AUD_SoftwareDevice::checkCapability(int capability) bool AUD_SoftwareDevice::setCapability(int capability, void *value) { + bool result = false; + switch(capability) { case AUD_CAPS_VOLUME: @@ -407,18 +444,20 @@ bool AUD_SoftwareDevice::setCapability(int capability, void *value) handle->volume = 1.0; else if(handle->volume < 0.0) handle->volume = 0.0; - unlock(); - return true; + result = true; } unlock(); } break; } - return false; + + return result;; } bool AUD_SoftwareDevice::getCapability(int capability, void *value) { + bool result = false; + switch(capability) { case AUD_CAPS_VOLUME: @@ -429,16 +468,19 @@ bool AUD_SoftwareDevice::getCapability(int capability, void *value) case AUD_CAPS_SOURCE_VOLUME: { AUD_SourceCaps* caps = (AUD_SourceCaps*) value; + lock(); + if(isValid(caps->handle)) { caps->value = ((AUD_SoftwareHandle*)caps->handle)->volume; - unlock(); - return true; + result = true; } + unlock(); } break; } - return false; + + return result; } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index c6c4a776faf..6ac9b020f21 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -450,10 +450,11 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int e float fps = FPS; AUD_Sound *limiter, *delayer; int frameskip, s, e; - AUD_Handle* h; end++; + AUD_setDeviceVolume(mixdown, volume); + for(handle = scene->sound_handles.first; handle; handle = handle->next) { if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->handle) @@ -471,8 +472,7 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int e limiter = AUD_limitSound(handle->source->handle, frameskip / fps, e / fps); delayer = AUD_delaySound(limiter, s / fps); - h = AUD_playDevice(mixdown, delayer); - AUD_setDeviceSoundVolume(mixdown, h, volume); + AUD_playDevice(mixdown, delayer); AUD_unload(delayer); AUD_unload(limiter); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index cac639a64ed..f0b4fae69ee 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2123,13 +2123,13 @@ void RNA_def_scene(BlenderRNA *brna) prop= RNA_def_property(srna, "speed_of_sound", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "audio.speed_of_sound"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 0.01f, FLT_MAX); RNA_def_property_ui_text(prop, "Speed of Sound", "Speed of sound for doppler effect calculation."); RNA_def_property_update(prop, NC_SCENE, NULL); prop= RNA_def_property(srna, "doppler_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "audio.doppler_factor"); - RNA_def_property_range(prop, FLT_MIN, FLT_MAX); + RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_text(prop, "Doppler Factor", "Pitch factor for doppler effect calculation."); RNA_def_property_update(prop, NC_SCENE, NULL); diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.h b/source/gameengine/GameLogic/SCA_BasicEventManager.h index 1aae5f9be5c..3bd2df08c07 100644 --- a/source/gameengine/GameLogic/SCA_BasicEventManager.h +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.h @@ -39,8 +39,6 @@ using namespace std; class SCA_BasicEventManager : public SCA_EventManager { - class SCA_LogicManager* m_logicmgr; - public: SCA_BasicEventManager(class SCA_LogicManager* logicmgr); ~SCA_BasicEventManager(); -- cgit v1.2.3 From fbfa8d2f812095eef100b1fdd67ce766bf884844 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 27 Sep 2009 04:22:04 +0000 Subject: 2.5 - Assorted Animation UI/Editing Tweaks Main Feature: * It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.) * Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying. * Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region. --> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen... --> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors... Other tweaks: * Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon * Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though. * Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too. * Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures. --- source/blender/blenkernel/intern/anim_sys.c | 4 +- .../editors/animation/anim_channels_defines.c | 45 ++++++- .../blender/editors/animation/anim_channels_edit.c | 143 +++++++++++++++++++-- source/blender/editors/animation/anim_filter.c | 59 ++++++--- source/blender/editors/animation/keyframes_edit.c | 9 ++ source/blender/editors/armature/editarmature.c | 4 +- source/blender/editors/include/ED_keyframes_edit.h | 1 + source/blender/editors/space_action/action_edit.c | 72 ++++++----- source/blender/editors/space_graph/graph_draw.c | 11 +- source/blender/editors/space_graph/graph_edit.c | 25 +++- source/blender/editors/space_graph/graph_intern.h | 1 + source/blender/editors/space_graph/graph_utils.c | 30 +++++ source/blender/editors/space_nla/nla_buttons.c | 83 ++++++++---- source/blender/editors/space_nla/nla_channels.c | 47 ++++++- source/blender/makesdna/DNA_anim_types.h | 5 + source/blender/makesrna/intern/rna_animation.c | 11 +- .../blender/windowmanager/intern/wm_event_system.c | 2 +- 17 files changed, 440 insertions(+), 112 deletions(-) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index ca16c62436b..07b7b6dc30c 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -244,6 +244,8 @@ void BKE_animdata_make_local(AnimData *adt) /* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate */ static char *rna_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *newName, char *oldpath) { + + return oldpath; // FIXME!!! } @@ -264,7 +266,7 @@ static void fcurves_path_rename_fix (ID *owner_id, PointerRNA *modPtr, char *new /* driver targets */ for (dtar= driver->targets.first; dtar; dtar=dtar->next) { - dtat->rna_path= rna_path_rename_fix(owner_id, modPtr, newName, dtar->rna_path); + dtat->rna_path= rna_path_rename_fix(dtar->id, modPtr, newName, dtar->rna_path); } } } diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index c6ecad03be8..8f8700cc43b 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -762,7 +762,7 @@ static int acf_fillactd_setting_flag(int setting, short *neg) switch (setting) { case ACHANNEL_SETTING_SELECT: /* selected */ - return ACT_SELECTED; + return ADT_UI_SELECTED; case ACHANNEL_SETTING_EXPAND: /* expanded */ *neg= 1; @@ -777,13 +777,18 @@ static int acf_fillactd_setting_flag(int setting, short *neg) static void *acf_fillactd_setting_ptr(bAnimListElem *ale, int setting, short *type) { bAction *act= (bAction *)ale->data; + AnimData *adt= ale->adt; /* clear extra return data first */ *type= 0; switch (setting) { case ACHANNEL_SETTING_SELECT: /* selected */ - GET_ACF_FLAG_PTR(act->flag); + if (adt) { + GET_ACF_FLAG_PTR(adt->flag); + } + else + return 0; case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(act->flag); @@ -1001,6 +1006,9 @@ static int acf_dsmat_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1019,6 +1027,7 @@ static void *acf_dsmat_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(ma->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (ma->adt) @@ -1070,6 +1079,9 @@ static int acf_dslam_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1088,6 +1100,7 @@ static void *acf_dslam_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(la->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (la->adt) @@ -1139,6 +1152,9 @@ static int acf_dscam_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1157,6 +1173,7 @@ static void *acf_dscam_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(ca->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (ca->adt) @@ -1208,6 +1225,9 @@ static int acf_dscur_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1226,6 +1246,7 @@ static void *acf_dscur_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(cu->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (cu->adt) @@ -1277,6 +1298,9 @@ static int acf_dsskey_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1295,6 +1319,7 @@ static void *acf_dsskey_setting_ptr(bAnimListElem *ale, int setting, short *type case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(key->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (key->adt) @@ -1346,6 +1371,9 @@ static int acf_dswor_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1364,6 +1392,7 @@ static void *acf_dswor_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(wo->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (wo->adt) @@ -1415,6 +1444,9 @@ static int acf_dspart_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1433,6 +1465,7 @@ static void *acf_dspart_setting_ptr(bAnimListElem *ale, int setting, short *type case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(part->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (part->adt) @@ -1485,6 +1518,9 @@ static int acf_dsmball_setting_flag(int setting, short *neg) *neg= 1; return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + default: /* unsupported */ return 0; } @@ -1502,6 +1538,7 @@ static void *acf_dsmball_setting_ptr(bAnimListElem *ale, int setting, short *typ case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(mb->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (mb->adt) @@ -1553,6 +1590,9 @@ static int acf_dsarm_setting_flag(int setting, short *neg) case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ *neg= 1; return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; default: /* unsupported */ return 0; @@ -1571,6 +1611,7 @@ static void *acf_dsarm_setting_ptr(bAnimListElem *ale, int setting, short *type) case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(arm->flag); + case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ if (arm->adt) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4afecdb55c0..83f5fca5af5 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -91,6 +91,7 @@ /* -------------------------- Exposed API ----------------------------------- */ /* Set the given animation-channel as the active one for the active context */ +// TODO: extend for animdata types... void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type) { ListBase anim_data = {NULL, NULL}; @@ -130,11 +131,29 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); + } + } + break; } } /* set active flag */ - if (channel_data != NULL) { + if (channel_data) { switch (channel_type) { case ANIMTYPE_GROUP: { @@ -154,6 +173,23 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int nlt->flag |= NLATRACK_ACTIVE; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) + ale->adt->flag |= ADT_UI_ACTIVE; + } + break; } } @@ -174,7 +210,7 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short int filter; /* filter data */ - filter= ANIMFILTER_VISIBLE; + filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS; ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype); /* See if we should be selecting or deselecting */ @@ -189,12 +225,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel= ACHANNEL_SETFLAG_CLEAR; break; case ANIMTYPE_OBJECT: + #if 0 /* for now, do not take object selection into account, since it gets too annoying */ if (ale->flag & SELECT) sel= ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_FILLACTD: - if (ale->flag & ACT_SELECTED) - sel= ACHANNEL_SETFLAG_CLEAR; + #endif break; case ANIMTYPE_GROUP: if (ale->flag & AGRP_SELECTED) @@ -208,6 +242,22 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short if (ale->flag & NLATRACK_SELECTED) sel= ACHANNEL_SETFLAG_CLEAR; break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + sel= ACHANNEL_SETFLAG_CLEAR; + } + break; } } } @@ -220,23 +270,26 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short Scene *scene= (Scene *)ale->data; ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); + + if (scene->adt) { + ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED); + } } break; case ANIMTYPE_OBJECT: + #if 0 /* for now, do not take object selection into account, since it gets too annoying */ { Base *base= (Base *)ale->data; Object *ob= base->object; ACHANNEL_SET_FLAG(base, sel, SELECT); ACHANNEL_SET_FLAG(ob, sel, SELECT); - } - break; - case ANIMTYPE_FILLACTD: - { - bAction *act= (bAction *)ale->data; - ACHANNEL_SET_FLAG(act, sel, ACT_SELECTED); + if (ob->adt) { + ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED); + } } + #endif break; case ANIMTYPE_GROUP: { @@ -262,6 +315,25 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short nlt->flag &= ~NLATRACK_ACTIVE; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); + ale->adt->flag &= ~ADT_UI_ACTIVE; + } + } + break; } } @@ -1310,18 +1382,22 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh } /* action to take depends on what channel we've got */ + // WARNING: must keep this in sync with the equivalent function in nla_channels.c switch (ale->type) { case ANIMTYPE_SCENE: { Scene *sce= (Scene *)ale->data; + AnimData *adt= sce->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ sce->flag ^= SCE_DS_SELECTED; + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { sce->flag |= SCE_DS_SELECTED; + if (adt) adt->flag |= ADT_UI_SELECTED; } notifierFlags |= ND_ANIMCHAN_SELECT; @@ -1333,34 +1409,75 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh Scene *sce= (Scene *)ads->source; Base *base= (Base *)ale->data; Object *ob= base->object; + AnimData *adt= ob->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ base->flag ^= SELECT; ob->flag= base->flag; + + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { Base *b; - /* deleselect all */ + /* deselect all */ + // TODO: should this deselect all other types of channels too? for (b= sce->base.first; b; b= b->next) { b->flag &= ~SELECT; b->object->flag= b->flag; + if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); } /* select object now */ base->flag |= SELECT; ob->flag |= SELECT; + if (adt) adt->flag |= ADT_UI_SELECTED; } /* xxx should be ED_base_object_activate(), but we need context pointer for that... */ //set_active_base(base); + if ((adt) && (adt->flag & ADT_UI_SELECTED)) + adt->flag |= ADT_UI_ACTIVE; notifierFlags |= ND_ANIMCHAN_SELECT; } break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* sanity checking... */ + if (ale->adt) { + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + ale->adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + ale->adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + ale->adt->flag |= ADT_UI_ACTIVE; + } + notifierFlags |= ND_ANIMCHAN_SELECT; + } + break; + case ANIMTYPE_GROUP: { bActionGroup *agrp= (bActionGroup *)ale->data; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 38b702f81e0..74b93089bc0 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -413,7 +413,9 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) }\ } - +/* quick macro to test if an anim-channel representing an AnimData block is suitably active */ +#define ANIMCHANNEL_ACTIVEOK(ale) \ + ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) ) /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ @@ -980,10 +982,13 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* include material-expand widget? */ // hmm... do we need to store the index of this material in the array anywhere? if (filter_mode & ANIMFILTER_CHANNELS) { - ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(ma) { + ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } @@ -1037,11 +1042,14 @@ static int animdata_filter_dopesheet_particles (ListBase *anim_data, bDopeSheet /* add particle settings? */ if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) { - if ((filter_mode & ANIMFILTER_CHANNELS)){ - ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + if ((filter_mode & ANIMFILTER_CHANNELS)) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(psys->part) { + ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } @@ -1117,9 +1125,12 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad expanded= EXPANDED_DRVD(adt); /* include data-expand widget? */ - if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { - ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat); - if (ale) BLI_addtail(anim_data, ale); + if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(iat) { + ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat); + if (ale) BLI_addtail(anim_data, ale); + } } /* add object-data animation channels? */ @@ -1149,10 +1160,13 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) { /* check if filtering by selection */ if ANIMCHANNEL_SELOK((base->flag & SELECT)) { - ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(ob) { + ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } } @@ -1233,10 +1247,13 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B { /* action (keyframes) */ /* include shapekey-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(key) { + ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 9666cb115b1..65f7d845b29 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -461,6 +461,13 @@ static short snap_bezier_horizontal(BeztEditData *bed, BezTriple *bezt) return 0; } +static short snap_bezier_value(BeztEditData *bed, BezTriple *bezt) +{ + /* value to snap to is stored in the custom data -> first float value slot */ + if (bezt->f2 & SELECT) + bezt->vec[1][1]= bed->f1; + return 0; +} BeztEditFunc ANIM_editkeyframes_snap(short type) { @@ -476,6 +483,8 @@ BeztEditFunc ANIM_editkeyframes_snap(short type) return snap_bezier_nearestsec; case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */ return snap_bezier_horizontal; + case SNAP_KEYS_VALUE: /* snap to given value */ + return snap_bezier_value; default: /* just in case */ return snap_bezier_nearest; } diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 5c224fbd4db..5f8c503e854 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -1736,7 +1736,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *op) ED_armature_sync_selection(arm->edbo); - WM_event_add_notifier(C, NC_OBJECT, obedit); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, obedit); return OPERATOR_FINISHED; } @@ -3938,7 +3938,7 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op) ED_armature_sync_selection(arm->edbo); /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index b2bf05ea5ea..57a6c5fc773 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -73,6 +73,7 @@ typedef enum eEditKeyframes_Snap { SNAP_KEYS_NEARSEC, SNAP_KEYS_NEARMARKER, SNAP_KEYS_HORIZONTAL, + SNAP_KEYS_VALUE, } eEditKeyframes_Snap; /* mirroring tools */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 9e05c482ecb..865d072d938 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -88,6 +88,44 @@ #include "action_intern.h" +/* ************************************************************************** */ +/* ACTION MANAGEMENT */ + +/* ******************** New Action Operator *********************** */ + +static int act_new_exec(bContext *C, wmOperator *op) +{ + bAction *action; + + // XXX need to restore behaviour to copy old actions... + action= add_empty_action("Action"); + + /* combined with RNA property, this will assign & increase user, + so decrease here to compensate for that */ + action->id.us--; + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); + + return OPERATOR_FINISHED; +} + +void ACT_OT_new (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "New"; + ot->idname= "ACT_OT_new"; + ot->description= "Create new action."; + + /* api callbacks */ + ot->exec= act_new_exec; + // NOTE: this is used in the NLA too... + //ot->poll= ED_operator_action_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ************************************************************************** */ /* KEYFRAME-RANGE STUFF */ @@ -1331,38 +1369,4 @@ void ACT_OT_mirror (wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); } -/* ******************** New Action Operator *********************** */ - -static int act_new_exec(bContext *C, wmOperator *op) -{ - bAction *action; - - // XXX need to restore behaviour to copy old actions... - action= add_empty_action("Action"); - - /* combined with RNA property, this will assign & increase user, - so decrease here to compensate for that */ - action->id.us--; - - /* set notifier that keyframes have changed */ - WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - - return OPERATOR_FINISHED; -} - -void ACT_OT_new (wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "New"; - ot->idname= "ACT_OT_new"; - ot->description= "Create new action."; - - /* api callbacks */ - ot->exec= act_new_exec; - ot->poll= ED_operator_action_active; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - /* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 38430045bef..57e2208f089 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -858,9 +858,6 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri * - if the option to only show controls if the F-Curve is selected is enabled, we must obey this */ if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) { - /* enable blending to allow fading of curves */ - glEnable(GL_BLEND); - if (fcurve_needs_draw_fmodifier_controls(fcu, fcm)) { /* only draw controls if this is the active modifier */ if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) { @@ -874,7 +871,10 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri else if ( ((fcu->bezt) || (fcu->fpt)) && (fcu->totvert) ) { if (fcu->bezt) { /* only draw handles/vertices on keyframes */ - draw_fcurve_handles(sipo, ar, fcu); + glEnable(GL_BLEND); + draw_fcurve_handles(sipo, ar, fcu); + glDisable(GL_BLEND); + draw_fcurve_vertices(sipo, ar, fcu); } else { @@ -882,9 +882,6 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri draw_fcurve_samples(sipo, ar, fcu); } } - - /* restore settings */ - glDisable(GL_BLEND); } /* undo mapping of keyframes for drawing if scaled F-Curve */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 9e0d574ffa3..9814f16de16 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1296,8 +1296,7 @@ void GRAPH_OT_handle_type (wmOperatorType *ot) /* set of three euler-rotation F-Curves */ typedef struct tEulerFilter { ID *id; /* ID-block which owns the channels */ - FCurve *fcu1, *fcu2, *fcu3; /* x,y,z rotation curves */ - int i1, i2, i3; /* current index for each curve */ + FCurve (*fcurves)[3]; /* 3 Pointers to F-Curves */ } tEulerFilter; static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) @@ -1347,10 +1346,26 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) if ((euf) && (ale->id != euf->id)) { } + else { + /* just add to a new block */ + euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter"); + BLI_addtail(&eulers, euf); + + euf->id= ale->id; + euf->fcurves[fcu->array_index]= fcu; + } } + BLI_freelistN(&anim_data); - // XXX for now - return OPERATOR_CANCELLED; + /* step 2: go through each set of curves, processing the values at each keyframe + * - it is assumed that there must be a full set of keyframes at each keyframe position + */ + for (euf= eulers.first; euf; euf= euf->next) { + + } + BLI_freelistN(&eulers); + + return OPERATOR_FINISHED; } void GRAPH_OT_euler_filter (wmOperatorType *ot) @@ -1789,7 +1804,7 @@ void GRAPH_OT_fmodifier_add (wmOperatorType *ot) /* api callbacks */ ot->invoke= graph_fmodifier_add_invoke; ot->exec= graph_fmodifier_add_exec; - ot->poll= graphop_active_fcurve_poll; + ot->poll= graphop_selected_fcurve_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 2e8d0655d2d..83a565e485f 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -155,6 +155,7 @@ short fcurve_needs_draw_fmodifier_controls(struct FCurve *fcu, struct FModifier int graphop_visible_keyframes_poll(struct bContext *C); int graphop_editable_keyframes_poll(struct bContext *C); int graphop_active_fcurve_poll(struct bContext *C); +int graphop_selected_fcurve_poll(struct bContext *C); /* ***************************************** */ /* graph_ops.c */ diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index f00e7845549..19cffb5cde1 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -285,4 +285,34 @@ int graphop_active_fcurve_poll (bContext *C) return has_fcurve; } +/* has selected F-Curve that's editable */ +int graphop_selected_fcurve_poll (bContext *C) +{ + bAnimContext ac; + bAnimListElem *ale; + ListBase anim_data = {NULL, NULL}; + ScrArea *sa= CTX_wm_area(C); + int filter, items; + short found = 0; + + /* firstly, check if in Graph Editor */ + // TODO: also check for region? + if ((sa == NULL) || (sa->spacetype != SPACE_IPO)) + return 0; + + /* try to init Anim-Context stuff ourselves and check */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return 0; + + /* get the editable + selected F-Curves, and as long as we got some, we can return */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY); + items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + if (items == 0) + return 0; + + /* cleanup and return findings */ + BLI_freelistN(&anim_data); + return found; +} + /* ************************************************************** */ diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index a5ba63fd15d..b193b89d65a 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -114,34 +114,69 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA if (ANIM_animdata_get_context(C, &ac) == 0) return 0; - /* extract list of active channel(s), of which we should only take the first one (expecting it to be an NLA track) */ - filter= (ANIMFILTER_VISIBLE|ANIMFILTER_ACTIVE); + /* extract list of active channel(s), of which we should only take the first one + * - we need the channels flag to get the active AnimData block when there are no NLA Tracks + */ + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_ACTIVE|ANIMFILTER_CHANNELS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); for (ale= anim_data.first; ale; ale= ale->next) { - // TODO: need some way to select active animdata too... - if (ale->type == ANIMTYPE_NLATRACK) { - NlaTrack *nlt= (NlaTrack *)ale->data; - AnimData *adt= ale->adt; - - /* found it, now set the pointers */ - if (adt_ptr) { - /* AnimData pointer */ - RNA_pointer_create(ale->id, &RNA_AnimData, adt, adt_ptr); - } - if (nlt_ptr) { - /* NLA-Track pointer */ - RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr); - } - if (strip_ptr) { - /* NLA-Strip pointer */ - NlaStrip *strip= BKE_nlastrip_find_active(nlt); - RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr); + switch (ale->type) { + case ANIMTYPE_NLATRACK: /* NLA Track - The primary data type which should get caught */ + { + NlaTrack *nlt= (NlaTrack *)ale->data; + AnimData *adt= ale->adt; + + /* found it, now set the pointers */ + if (adt_ptr) { + /* AnimData pointer */ + RNA_pointer_create(ale->id, &RNA_AnimData, adt, adt_ptr); + } + if (nlt_ptr) { + /* NLA-Track pointer */ + RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr); + } + if (strip_ptr) { + /* NLA-Strip pointer */ + NlaStrip *strip= BKE_nlastrip_find_active(nlt); + RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr); + } + + found= 1; } - - found= 1; - break; + break; + + case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */ + case ANIMTYPE_OBJECT: + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* for these channels, we only do AnimData */ + if (ale->id && ale->adt) { + if (adt_ptr) { + /* AnimData pointer */ + RNA_pointer_create(ale->id, &RNA_AnimData, ale->adt, adt_ptr); + + /* set found status to -1, since setting to 1 would break the loop + * and potentially skip an active NLA-Track in some cases... + */ + found= -1; + } + } + } + break; } + + if (found > 0) + break; } /* free temp data */ @@ -211,7 +246,7 @@ static void nla_panel_animdata (const bContext *C, Panel *pa) /* Active Action Properties ------------------------------------- */ /* action */ row= uiLayoutRow(layout, 1); - uiTemplateID(row, (bContext *)C, &adt_ptr, "action", NULL /*"ACT_OT_new"*/, NULL, NULL /*"ACT_OT_unlink"*/); // XXX: need to make these operators + uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACT_OT_new", NULL, NULL /*"ACT_OT_unlink"*/); // XXX: need to make these operators /* extrapolation */ row= uiLayoutRow(layout, 1); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index ccf23266427..07dc3f0ad89 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -116,18 +116,22 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho } /* action to take depends on what channel we've got */ + // WARNING: must keep this in sync with the equivalent function in anim_channels_edit.c switch (ale->type) { case ANIMTYPE_SCENE: { Scene *sce= (Scene *)ale->data; + AnimData *adt= sce->adt; /* set selection status */ if (selectmode == SELECT_INVERT) { /* swap select */ sce->flag ^= SCE_DS_SELECTED; + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { sce->flag |= SCE_DS_SELECTED; + if (adt) adt->flag |= ADT_UI_SELECTED; } notifierFlags |= ND_ANIMCHAN_SELECT; @@ -139,6 +143,7 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho Scene *sce= (Scene *)ads->source; Base *base= (Base *)ale->data; Object *ob= base->object; + AnimData *adt= ob->adt; if (nlaedit_is_tweakmode_on(ac) == 0) { /* set selection status */ @@ -146,23 +151,30 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho /* swap select */ base->flag ^= SELECT; ob->flag= base->flag; + + if (adt) adt->flag ^= ADT_UI_SELECTED; } else { Base *b; - /* deleselect all */ + /* deselect all */ + // TODO: should this deselect all other types of channels too? for (b= sce->base.first; b; b= b->next) { b->flag &= ~SELECT; b->object->flag= b->flag; + if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); } /* select object now */ base->flag |= SELECT; ob->flag |= SELECT; + if (adt) adt->flag |= ADT_UI_SELECTED; } /* xxx should be ED_base_object_activate(), but we need context pointer for that... */ //set_active_base(base); + if ((adt) && (adt->flag & ADT_UI_SELECTED)) + adt->flag |= ADT_UI_ACTIVE; /* notifiers - channel was selected */ notifierFlags |= ND_ANIMCHAN_SELECT; @@ -170,6 +182,39 @@ static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sho } break; + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + { + /* sanity checking... */ + if (ale->adt) { + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + ale->adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + ale->adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + ale->adt->flag |= ADT_UI_ACTIVE; + } + + notifierFlags |= ND_ANIMCHAN_SELECT; + } + break; + case ANIMTYPE_NLATRACK: { NlaTrack *nlt= (NlaTrack *)ale->data; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index f75ed273164..c1e9ed4be40 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -763,6 +763,11 @@ typedef enum eAnimData_Flag { /* don't execute drivers */ ADT_DRIVERS_DISABLED = (1<<11), + /* AnimData block is selected in UI */ + ADT_UI_SELECTED = (1<<14), + /* AnimData block is active in UI */ + ADT_UI_ACTIVE = (1<<15), + /* F-Curves from this AnimData block are not visible in the Graph Editor */ ADT_CURVES_NOT_VISIBLE = (1<<16), } eAnimData_Flag; diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index a8d3a6edaae..4b2c11c2e0d 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -57,6 +57,12 @@ static int rna_AnimData_action_editable(PointerRNA *ptr) return 1; } +static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) +{ + AnimData *adt= (AnimData*)(ptr->data); + adt->action= value.data; +} + static void rna_ksPath_RnaPath_get(PointerRNA *ptr, char *value) { KS_Path *ksp= (KS_Path *)ptr->data; @@ -202,8 +208,11 @@ void rna_def_animdata(BlenderRNA *brna) /* Active Action */ prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock."); + RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); /* this flag as well as the dynamic test must be defined for this to be editable... */ RNA_def_property_editable_func(prop, "rna_AnimData_action_editable"); + RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock."); + /* Active Action Settings */ prop= RNA_def_property(srna, "action_extrapolation", PROP_ENUM, PROP_NONE); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index af1339323f3..846309f1265 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -239,7 +239,7 @@ void wm_event_do_notifiers(bContext *C) if(G.rendering==0) { // XXX make lock in future, or separated derivedmesh users in scene - /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual, + /* update all objects, drivers, matrices, displists, etc. Flags set by depgraph or manual, no layer check here, gets correct flushed */ /* sets first, we allow per definition current scene to have dependencies on sets */ if(scene->set) { -- cgit v1.2.3 From 8a6d6a33f8542e8940119a6435969ac119e68229 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 27 Sep 2009 06:14:42 +0000 Subject: Animation Editors - Moved the code for drawing the filtering toggles into a single function. --- source/blender/editors/animation/anim_draw.c | 50 ++++++++++++++++++++++ source/blender/editors/include/ED_anim_api.h | 10 ++++- .../blender/editors/space_action/action_header.c | 19 +------- source/blender/editors/space_graph/graph_header.c | 25 +---------- source/blender/editors/space_graph/graph_utils.c | 1 - source/blender/editors/space_nla/nla_header.c | 26 +---------- source/blender/makesdna/DNA_action_types.h | 2 +- 7 files changed, 62 insertions(+), 71 deletions(-) diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 6388106fdb5..507bf03e7ef 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -55,6 +55,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_edit.h" +#include "ED_types.h" #include "ED_util.h" #include "WM_api.h" @@ -316,3 +317,52 @@ void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, s } /* *************************************************** */ +/* ANIMATION EDITOR UI-WIDGETS */ + +/* ui button event */ +#define B_REDR 1 + +/* standard header buttons for Animation Editors */ +short ANIM_headerUI_standard_buttons (const bContext *C, bDopeSheet *ads, uiBlock *block, short xco, short yco) +{ + ScrArea *sa= CTX_wm_area(C); + short nlaActive= ((sa) && (sa->spacetype==SPACE_NLA)); + + /* check if the DopeSheet data exists, just in case... */ + if (ads) { + /* more 'generic' filtering options */ + if (nlaActive) uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); + if (nlaActive) uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data"); + if (nlaActive) uiBlockEndAlign(block); + xco += 5; + + /* datatype based */ + // TODO: only show the datablocks which exist + uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display World Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Material Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Lamp Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Camera Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Curve Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display MetaBall Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Armature Data"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Particle Data"); + uiBlockEndAlign(block); + xco += 30; + } + else { + // XXX this case shouldn't happen at all... for now, just pad out same amount of space + printf("ERROR: dopesheet data not available when drawing Animation Editor header \n"); + xco += 11*XIC + 30; + } + + // TODO: include auto-snapping menu here too... + + /* return the width of the buttons */ + return xco; +} + +/* *************************************************** */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 7e7aba85363..d9439956569 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -42,11 +42,14 @@ struct View2D; struct Scene; struct Object; +struct bDopeSheet; + struct bActionGroup; struct FCurve; struct FModifier; struct uiBlock; +struct uiLayout; /* ************************************************ */ /* ANIMATION CHANNEL FILTERING */ @@ -394,11 +397,14 @@ void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag); /* main call to draw preview range curtains */ void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d); +/* ------------- Preview Range Drawing -------------- */ + +/* standard header buttons for Animation Editors */ +short ANIM_headerUI_standard_buttons(const struct bContext *C, struct bDopeSheet *ads, struct uiBlock *block, short xco, short yco); + /* ************************************************* */ /* F-MODIFIER TOOLS */ -struct uiLayout; - /* draw a given F-Modifier for some layout/UI-Block */ void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, ListBase *modifiers, struct FModifier *fcm); diff --git a/source/blender/editors/space_action/action_header.c b/source/blender/editors/space_action/action_header.c index f602345baea..25a5123d1b5 100644 --- a/source/blender/editors/space_action/action_header.c +++ b/source/blender/editors/space_action/action_header.c @@ -336,24 +336,7 @@ void action_header_buttons(const bContext *C, ARegion *ar) /* FILTERING OPTIONS */ xco -= 10; - //uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Only display selected Objects"); - //uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Armature/Bone"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 30; + xco= ANIM_headerUI_standard_buttons(C, &saction->ads, block, xco, yco); } else if (saction->mode == SACTCONT_ACTION) { uiLayout *layout; diff --git a/source/blender/editors/space_graph/graph_header.c b/source/blender/editors/space_graph/graph_header.c index 79d38d9c252..98d58c92da4 100644 --- a/source/blender/editors/space_graph/graph_header.c +++ b/source/blender/editors/space_graph/graph_header.c @@ -298,30 +298,7 @@ void graph_header_buttons(const bContext *C, ARegion *ar) xco+= 120; /* filtering buttons */ - if (sipo->ads) { - //uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); - //uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Armature/Bone data"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(sipo->ads->filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 30; - } - else { - // XXX this case shouldn't happen at all... for now, just pad out same amount of space - xco += 10*XIC + 30; - } + xco= ANIM_headerUI_standard_buttons(C, sipo->ads, block, xco, yco); /* auto-snap selector */ if (sipo->flag & SIPO_DRAWTIME) { diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index 19cffb5cde1..25087441b6a 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -289,7 +289,6 @@ int graphop_active_fcurve_poll (bContext *C) int graphop_selected_fcurve_poll (bContext *C) { bAnimContext ac; - bAnimListElem *ale; ListBase anim_data = {NULL, NULL}; ScrArea *sa= CTX_wm_area(C); int filter, items; diff --git a/source/blender/editors/space_nla/nla_header.c b/source/blender/editors/space_nla/nla_header.c index 0d3bf2cb6b1..4eb9fac5cb8 100644 --- a/source/blender/editors/space_nla/nla_header.c +++ b/source/blender/editors/space_nla/nla_header.c @@ -246,31 +246,7 @@ void nla_header_buttons(const bContext *C, ARegion *ar) uiBlockSetEmboss(block, UI_EMBOSS); /* filtering buttons */ - if (snla->ads) { - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data"); - uiBlockEndAlign(block); - xco += 5; - - uiBlockBeginAlign(block); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display World Animation"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Materials"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Lamps"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Curves"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display MetaBalls"); - uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Particles"); - uiBlockEndAlign(block); - xco += 15; - } - else { - // XXX this case shouldn't happen at all... for now, just pad out same amount of space - xco += 10*XIC + 15; - } - xco += (XIC + 8); + xco= ANIM_headerUI_standard_buttons(C, snla->ads, block, xco, yco); /* auto-snap selector */ if (snla->flag & SNLA_DRAWTIME) { diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 43ef9f28828..2ed08150f3e 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -433,7 +433,7 @@ typedef enum DOPESHEET_FILTERFLAG { ADS_FILTER_NLA_NOACT = (1<<20), /* if the AnimData block has no NLA data, don't include to just show Action-line */ /* combination filters (some only used at runtime) */ - ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR|ADS_FILTER_NOPART), + ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR|ADS_FILTER_NOPART|ADS_FILTER_NOARM), } DOPESHEET_FILTERFLAG; /* DopeSheet general flags */ -- cgit v1.2.3 From bd7dc7788401acf74f971a4830a597cab6a0bc45 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 27 Sep 2009 06:27:45 +0000 Subject: Bugfix: Shapekey NLA Tracks were shown mixed with the ones for Objects --- source/blender/editors/animation/anim_filter.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 74b93089bc0..13b050e4497 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1226,8 +1226,21 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B ANIMDATA_FILTER_CASES(key, { /* AnimData blocks - do nothing... */ }, { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); + /* include shapekey-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(key) { + ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + } + + /* add NLA tracks - only if expanded or so */ + if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) + items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); }, { /* drivers */ /* include shapekey-expand widget? */ -- cgit v1.2.3 From 43631327887d3000be0743be8ac632f25401078f Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sun, 27 Sep 2009 09:19:29 +0000 Subject: Added Image.get_abs_filename() and updated scripts to use it. This removes the necessity of bpy.sys.expandpath(). Added missing Object.dupli_list. --- release/io/export_fbx.py | 4 ++-- release/io/export_obj.py | 7 ++++--- release/io/export_x3d.py | 2 +- release/io/import_3ds.py | 2 +- source/blender/makesrna/intern/rna_image_api.c | 25 ++++++++++++++++++++++--- source/blender/makesrna/intern/rna_object.c | 5 +++++ 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py index 3515170528f..aa65473b8d6 100644 --- a/release/io/export_fbx.py +++ b/release/io/export_fbx.py @@ -94,6 +94,7 @@ def copy_file(source, dest): file.close() +# XXX not used anymore, images are copied one at a time def copy_images(dest_dir, textures): if not dest_dir.endswith(os.sep): dest_dir += os.sep @@ -1285,10 +1286,9 @@ def write(filename, batch_objects = None, \ base = os.path.basename(rel) if EXP_IMAGE_COPY: - src = bpy.sys.expandpath(image.filename) absp = image.get_export_path(basepath, False) if not os.path.exists(absp): - shutil.copy(src, absp) + shutil.copy(image.get_abs_filename(), absp) return (rel, base) diff --git a/release/io/export_obj.py b/release/io/export_obj.py index bd323b6586a..e2ac78798bd 100644 --- a/release/io/export_obj.py +++ b/release/io/export_obj.py @@ -48,6 +48,7 @@ will be exported as mesh data. # import math and other in functions that use them for the sake of fast Blender startup # import math import os +import time import bpy import Mathutils @@ -98,7 +99,7 @@ def write_mtl(scene, filename, copy_images): if copy_images: abspath = image.get_export_path(dest_dir, False) if not os.path.exists(abs_path): - shutil.copy(bpy.sys.expandpath(image.filename), abs_path) + shutil.copy(image.get_abs_filename(), abs_path) return rel @@ -370,7 +371,7 @@ def write(filename, objects, scene, print('OBJ Export path: "%s"' % filename) temp_mesh_name = '~tmp-mesh' - time1 = bpy.sys.time() + time1 = time.clock() # time1 = sys.time() # scn = Scene.GetCurrent() @@ -816,7 +817,7 @@ def write(filename, objects, scene, # 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" % (time.clock() - time1)) # print "OBJ Export time: %.2f" % (sys.time() - time1) def do_export(filename, context, diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py index 3661d78a343..f23ccf8d2dc 100644 --- a/release/io/export_x3d.py +++ b/release/io/export_x3d.py @@ -779,7 +779,7 @@ class x3d_class: pic = tex.image # using .expandpath just in case, os.path may not expect // - basename = os.path.basename(bpy.sys.expandpath(pic.filename)) + basename = os.path.basename(pic.get_abs_filename()) pic = alltextures[i].image # pic = alltextures[i].getImage() diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py index d57911df83c..99825471764 100644 --- a/release/io/import_3ds.py +++ b/release/io/import_3ds.py @@ -939,7 +939,7 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, # if BPyMessages.Error_NoFile(filename): # return - print('\n\nImporting 3DS: "%s"' % (bpy.sys.expandpath(filename))) + print('\n\nImporting 3DS: "%s"' % (filename)) # print('\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename))) time1 = time.clock() diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 25c764b8823..2bb7905fc03 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -34,12 +34,14 @@ #include "RNA_define.h" #include "RNA_types.h" -#include "DNA_object_types.h" - #ifdef RNA_RUNTIME -#include "BKE_utildefines.h" #include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" + +#include "DNA_image_types.h" +#include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -61,6 +63,17 @@ static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel) return path; } +char *rna_Image_get_abs_filename(Image *image, bContext *C) +{ + char *filename= MEM_callocN(FILE_MAX, "Image.get_abs_filename()"); + + BLI_strncpy(filename, image->name, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(filename, CTX_data_main(C)->name); + BLI_convertstringframe(filename, CTX_data_scene(C)->r.cfra); + + return filename; +} + #else void RNA_api_image(StructRNA *srna) @@ -76,6 +89,12 @@ void RNA_api_image(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_string(func, "path", "", 0, "", "Absolute export path."); RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "get_abs_filename", "rna_Image_get_abs_filename"); + RNA_def_function_ui_description(func, "Get absolute filename."); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm= RNA_def_string_file_path(func, "abs_filename", NULL, 0, "", "Image/movie absolute filename."); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 76d9e077a18..5c665c0d730 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1414,6 +1414,11 @@ 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|PROP_UNIT_TIME); -- cgit v1.2.3 From 6e0c1cd4e5acaa91adbfd2137709a6803647cde7 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 27 Sep 2009 09:38:13 +0000 Subject: RNA + Animation: * Added missing RNA wrapping for Scene -> AnimData * Fixed bug (with temp-fix) where sequence strips with no names couldn't be animated properly. Currently, this will just use the index of the strip, although that is likely to be mutable (adding/removing strips will change it). * Removed some old unused code from action.c --- source/blender/blenkernel/intern/action.c | 132 ------------------------ source/blender/editors/space_graph/graph_edit.c | 2 + source/blender/makesrna/intern/rna_armature.c | 1 + source/blender/makesrna/intern/rna_scene.c | 3 + source/blender/makesrna/intern/rna_sequence.c | 10 +- 5 files changed, 15 insertions(+), 133 deletions(-) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 4cfd35a494d..b8dc9fd049d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1181,138 +1181,6 @@ static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset); } -typedef struct NlaIpoChannel { - struct NlaIpoChannel *next, *prev; - float val; - void *poin; - int type; -} NlaIpoChannel; - -static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime) -{ - bActionChannel *achan= get_action_channel(act, name); - IpoCurve *icu; - NlaIpoChannel *nic; - - if(achan==NULL) return; - - if(achan->ipo) { - calc_ipo(achan->ipo, ctime); - - for(icu= achan->ipo->curve.first; icu; icu= icu->next) { - /* skip IPO_BITS, is for layers and cannot be blended */ - if(icu->vartype != IPO_BITS) { - nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel"); - BLI_addtail(lb, nic); - nic->val= icu->curval; - nic->poin= get_ipo_poin(id, icu, &nic->type); - } - } - } - - /* constraint channels only for objects */ - if(GS(id->name)==ID_OB) { - Object *ob= (Object *)id; - bConstraint *con; - bConstraintChannel *conchan; - - for (con=ob->constraints.first; con; con=con->next) { - conchan = get_constraint_channel(&achan->constraintChannels, con->name); - - if(conchan && conchan->ipo) { - calc_ipo(conchan->ipo, ctime); - - icu= conchan->ipo->curve.first; // only one ipo now - if(icu) { - nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel constr"); - BLI_addtail(lb, nic); - nic->val= icu->curval; - nic->poin= &con->enforce; - nic->type= IPO_FLOAT; - } - } - } - } -} - -static NlaIpoChannel *find_nla_ipochannel(ListBase *lb, void *poin) -{ - NlaIpoChannel *nic; - - if(poin) { - for(nic= lb->first; nic; nic= nic->next) { - if(nic->poin==poin) - return nic; - } - } - return NULL; -} - - -static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int mode) -{ - NlaIpoChannel *snic, *dnic, *next; - float dstweight; - - switch (mode){ - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; - } - - for(snic= src->first; snic; snic= next) { - next= snic->next; - - dnic= find_nla_ipochannel(dst, snic->poin); - if(dnic==NULL) { - /* remove from src list, and insert in dest */ - BLI_remlink(src, snic); - BLI_addtail(dst, snic); - } - else { - /* we do the blend */ - dnic->val= dstweight*dnic->val + srcweight*snic->val; - } - } -} - -static int execute_ipochannels(ListBase *lb) -{ - NlaIpoChannel *nic; - int count = 0; - - for(nic= lb->first; nic; nic= nic->next) { - if(nic->poin) { - write_ipo_poin(nic->poin, nic->type, nic->val); - count++; - } - } - return count; -} - -/* nla timing */ - -/* this now only used for repeating cycles, to enable fields and blur. */ -/* the whole time control in blender needs serious thinking... */ -static float nla_time(Scene *scene, float cfra, float unit) -{ - extern float bluroffs; // bad construct, borrowed from object.c for now - extern float fieldoffs; - - /* motion blur & fields */ - cfra+= unit*(bluroffs+fieldoffs); - - /* global time */ - cfra*= scene->r.framelen; - - return cfra; -} - /* added "sizecorr" here, to allow armatures to be scaled and still have striding. Only works for uniform scaling. In general I'd advise against scaling armatures ever though! (ton) */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 9814f16de16..8c739d68cea 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1344,6 +1344,8 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) * - first check if id-blocks are compatible */ if ((euf) && (ale->id != euf->id)) { + /* if the paths match, add this curve to the set of curves */ + // NOTE: simple string compare for now... could be a bit more fancy... } else { diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index c89ed48d44a..5dbfdd3e6f1 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -592,6 +592,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_ARMATURE_DATA); RNA_def_struct_sdna(srna, "bArmature"); + /* Animation Data */ rna_def_animdata_common(srna); /* Collections */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index f0b4fae69ee..1d8ebdce369 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2041,6 +2041,9 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stamp Note", "User define note for the render stamping."); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + /* Animation Data (for Scene) */ + rna_def_animdata_common(srna); + /* Nodes (Compositing) */ prop= RNA_def_property(srna, "nodetree", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Node Tree", "Compositing node tree."); diff --git a/source/blender/makesrna/intern/rna_sequence.c b/source/blender/makesrna/intern/rna_sequence.c index 51e81d6dd3a..9404fb775c3 100644 --- a/source/blender/makesrna/intern/rna_sequence.c +++ b/source/blender/makesrna/intern/rna_sequence.c @@ -228,7 +228,15 @@ static char *rna_Sequence_path(PointerRNA *ptr) /* sequencer data comes from scene... * TODO: would be nice to make SequenceEditor data a datablock of its own (for shorter paths) */ - return BLI_sprintfN("sequence_editor.sequences[\"%s\"]", seq->name+2); + if (seq->name+2) + return BLI_sprintfN("sequence_editor.sequences[\"%s\"]", seq->name+2); + else { + /* compromise for the frequent sitation when strips don't have names... */ + Scene *sce= (Scene*)ptr->id.data; + Editing *ed= seq_give_editing(sce, FALSE); + + return BLI_sprintfN("sequence_editor.sequences[%d]", BLI_findindex(&ed->seqbase, seq)); + } } static PointerRNA rna_SequenceEdtior_meta_stack_get(CollectionPropertyIterator *iter) -- cgit v1.2.3 From 2fef3dbaa3512f6561155402c46bf3ff8c955980 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 27 Sep 2009 11:00:35 +0000 Subject: 2.5 Layout Files: * Some Code and Whitespace Cleanup. --- release/io/engine_render_pov.py | 38 ++++++++------------------ release/io/netrender/ui.py | 2 ++ release/ui/buttons_data_armature.py | 3 +-- release/ui/buttons_data_bone.py | 2 +- release/ui/buttons_data_camera.py | 5 ++-- release/ui/buttons_data_curve.py | 1 - release/ui/buttons_data_lamp.py | 9 +++---- release/ui/buttons_data_lattice.py | 2 +- release/ui/buttons_data_mesh.py | 2 +- release/ui/buttons_data_metaball.py | 8 +----- release/ui/buttons_data_text.py | 2 -- release/ui/buttons_game.py | 4 --- release/ui/buttons_material.py | 40 ++++++++++++---------------- release/ui/buttons_object_constraint.py | 3 +-- release/ui/buttons_physics_cloth.py | 6 ++--- release/ui/buttons_physics_field.py | 2 -- release/ui/buttons_physics_fluid.py | 9 +++---- release/ui/buttons_physics_smoke.py | 5 +--- release/ui/buttons_physics_softbody.py | 10 +++---- release/ui/buttons_scene.py | 1 - release/ui/buttons_texture.py | 7 ++--- release/ui/buttons_world.py | 7 +++-- release/ui/space_sequencer.py | 4 +-- release/ui/space_view3d_toolbar.py | 19 +++++-------- source/blender/editors/space_node/drawnode.c | 11 ++++---- 25 files changed, 70 insertions(+), 132 deletions(-) diff --git a/release/io/engine_render_pov.py b/release/io/engine_render_pov.py index 1c5026c84c0..f0247ce532a 100644 --- a/release/io/engine_render_pov.py +++ b/release/io/engine_render_pov.py @@ -110,8 +110,7 @@ def write_pov(filename, scene=None, info_callback = None): file.write('\tdiffuse 0.8\n') file.write('\tspecular 0.2\n') - - + # This is written into the object ''' if material and material.transparency_method=='RAYTRACE': @@ -143,9 +142,7 @@ def write_pov(filename, scene=None, info_callback = None): file.write('\trotate <%.6f, %.6f, %.6f>\n' % tuple([degrees(e) for e in matrix.rotationPart().toEuler()])) file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2])) file.write('}\n') - - - + def exportLamps(lamps): # Get all lamps for ob in lamps: @@ -186,9 +183,7 @@ def write_pov(filename, scene=None, info_callback = None): else: size_y = lamp.size_y samples_y = lamp.shadow_ray_samples_y - - - + file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y)) if lamp.shadow_ray_sampling_method == 'CONSTANT_JITTERED': if lamp.jitter: @@ -264,10 +259,7 @@ def write_pov(filename, scene=None, info_callback = None): writeMatrix(ob.matrix) file.write('}\n') - - - - + def exportMeshs(sel): ob_num = 0 @@ -475,8 +467,7 @@ def write_pov(filename, scene=None, info_callback = None): file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count - - + file.write('\n }\n') # normal_indices indicies @@ -589,7 +580,6 @@ def write_pov(filename, scene=None, info_callback = None): file.close() - def write_pov_ini(filename_ini, filename_pov, filename_image): scene = bpy.data.scenes[0] render = scene.render_data @@ -775,9 +765,7 @@ class PovrayRender(bpy.types.RenderEngine): # compute resolution x= int(r.resolution_x*r.resolution_percentage*0.01) y= int(r.resolution_y*r.resolution_percentage*0.01) - - - + # Wait for the file to be created while not os.path.exists(self.temp_file_out): if self.test_break(): @@ -876,12 +864,13 @@ class SCENE_PT_povray_radiosity(RenderButtonsPanel): COMPAT_ENGINES = set(['POVRAY_RENDER']) def draw_header(self, context): - layout = self.layout scene = context.scene - layout.itemR(scene, "pov_radio_enable", text="") + + self.layout.itemR(scene, "pov_radio_enable", text="") def draw(self, context): layout = self.layout + scene = context.scene rd = scene.render_data @@ -890,7 +879,6 @@ class SCENE_PT_povray_radiosity(RenderButtonsPanel): split = layout.split() col = split.column() - col.itemR(scene, "pov_radio_count", text="Rays") col.itemR(scene, "pov_radio_recursion_limit", text="Recursions") col = split.column() @@ -905,15 +893,12 @@ class SCENE_PT_povray_radiosity(RenderButtonsPanel): col.itemR(scene, "pov_radio_adc_bailout", slider=True) col.itemR(scene, "pov_radio_gray_threshold", slider=True) col.itemR(scene, "pov_radio_low_error_factor", slider=True) - - - + col = split.column() col.itemR(scene, "pov_radio_brightness") col.itemR(scene, "pov_radio_minimum_reuse", text="Min Reuse") col.itemR(scene, "pov_radio_nearest_count") - - + split = layout.split() col = split.column() @@ -923,6 +908,5 @@ class SCENE_PT_povray_radiosity(RenderButtonsPanel): col = split.column() col.itemR(scene, "pov_radio_always_sample") - bpy.types.register(SCENE_PT_povray_radiosity) diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index ddaf0e6854a..7681d4865e9 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -39,6 +39,7 @@ class SCENE_PT_network_settings(RenderButtonsPanel): def draw(self, context): layout = self.layout + scene = context.scene rd = scene.render_data @@ -69,6 +70,7 @@ class SCENE_PT_network_job(RenderButtonsPanel): def draw(self, context): layout = self.layout + scene = context.scene rd = scene.render_data diff --git a/release/ui/buttons_data_armature.py b/release/ui/buttons_data_armature.py index 413deee362b..9344294ff9e 100644 --- a/release/ui/buttons_data_armature.py +++ b/release/ui/buttons_data_armature.py @@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.armature) + return context.armature class DATA_PT_context_arm(DataButtonsPanel): __show_header__ = False @@ -128,7 +128,6 @@ class DATA_PT_paths(DataButtonsPanel): split = layout.split() col = split.column() - sub = col.column(align=True) if (arm.paths_type == 'CURRENT_FRAME'): sub.itemR(arm, "path_before_current", text="Before") diff --git a/release/ui/buttons_data_bone.py b/release/ui/buttons_data_bone.py index dae969a7e5f..50ece679e27 100644 --- a/release/ui/buttons_data_bone.py +++ b/release/ui/buttons_data_bone.py @@ -240,7 +240,6 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel): #row = split.row() #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True) #row.active = pchan.ik_lin_control - class BONE_PT_deform(BoneButtonsPanel): __label__ = "Deform" @@ -307,6 +306,7 @@ class BONE_PT_iksolver_itasc(BoneButtonsPanel): def draw(self, context): layout = self.layout + ob = context.object itasc = ob.pose.ik_param diff --git a/release/ui/buttons_data_camera.py b/release/ui/buttons_data_camera.py index 0ac9a88eb35..19d7dfef852 100644 --- a/release/ui/buttons_data_camera.py +++ b/release/ui/buttons_data_camera.py @@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.camera) + return context.camera class DATA_PT_context_camera(DataButtonsPanel): __show_header__ = False @@ -92,8 +92,7 @@ class DATA_PT_camera_display(DataButtonsPanel): sub = col.column() sub.active = cam.show_passepartout sub.itemR(cam, "passepartout_alpha", text="Alpha", slider=True) - - + bpy.types.register(DATA_PT_context_camera) bpy.types.register(DATA_PT_camera) bpy.types.register(DATA_PT_camera_display) diff --git a/release/ui/buttons_data_curve.py b/release/ui/buttons_data_curve.py index 70904239d86..c715cfb5d93 100644 --- a/release/ui/buttons_data_curve.py +++ b/release/ui/buttons_data_curve.py @@ -120,7 +120,6 @@ class DATA_PT_geometry_curve(DataButtonsPanel): col.itemL(text="Bevel Object:") col.itemR(curve, "bevel_object", text="") - class DATA_PT_pathanim(DataButtonsPanelCurve): __label__ = "Path Animation" diff --git a/release/ui/buttons_data_lamp.py b/release/ui/buttons_data_lamp.py index 0dbda46bccf..86ca5beb9b5 100644 --- a/release/ui/buttons_data_lamp.py +++ b/release/ui/buttons_data_lamp.py @@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.lamp) + return context.lamp class DATA_PT_preview(DataButtonsPanel): __label__ = "Preview" @@ -87,8 +87,7 @@ class DATA_PT_sunsky(DataButtonsPanel): lamp = context.lamp.sky layout.itemR(lamp, "sky") - - + row = layout.row() row.active = lamp.sky or lamp.atmosphere row.itemR(lamp, "atmosphere_turbidity", text="Turbidity") @@ -198,7 +197,7 @@ class DATA_PT_shadow(DataButtonsPanel): sub.itemR(lamp, "dither") sub.itemR(lamp, "jitter") - if lamp.shadow_method == 'BUFFER_SHADOW': + elif lamp.shadow_method == 'BUFFER_SHADOW': col = layout.column() col.itemL(text="Buffer Type:") col.row().itemR(lamp, "shadow_buffer_type", expand=True) @@ -258,8 +257,6 @@ class DATA_PT_area(DataButtonsPanel): elif (lamp.shape == 'RECTANGLE'): sub.itemR(lamp, "size", text="Size X") sub.itemR(lamp, "size_y", text="Size Y") - - col = split.column() class DATA_PT_spot(DataButtonsPanel): __label__ = "Spot Shape" diff --git a/release/ui/buttons_data_lattice.py b/release/ui/buttons_data_lattice.py index 895c1a65bea..bc977860330 100644 --- a/release/ui/buttons_data_lattice.py +++ b/release/ui/buttons_data_lattice.py @@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.lattice) + return context.lattice class DATA_PT_context_lattice(DataButtonsPanel): __show_header__ = False diff --git a/release/ui/buttons_data_mesh.py b/release/ui/buttons_data_mesh.py index a93d7b66397..780ae3ac8f9 100644 --- a/release/ui/buttons_data_mesh.py +++ b/release/ui/buttons_data_mesh.py @@ -7,7 +7,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.mesh) + return context.mesh class DATA_PT_context_mesh(DataButtonsPanel): __show_header__ = False diff --git a/release/ui/buttons_data_metaball.py b/release/ui/buttons_data_metaball.py index 88c0066c67f..757546fdf8a 100644 --- a/release/ui/buttons_data_metaball.py +++ b/release/ui/buttons_data_metaball.py @@ -6,7 +6,7 @@ class DataButtonsPanel(bpy.types.Panel): __context__ = "data" def poll(self, context): - return (context.meta_ball) + return context.meta_ball class DATA_PT_context_metaball(DataButtonsPanel): __show_header__ = False @@ -74,11 +74,9 @@ class DATA_PT_metaball_element(DataButtonsPanel): col.itemR(metaelem, "hide", text="Hide") if metaelem.type == 'BALL': - col = split.column(align=True) elif metaelem.type == 'CUBE': - col = split.column(align=True) col.itemL(text="Size:") col.itemR(metaelem, "size_x", text="X") @@ -86,26 +84,22 @@ class DATA_PT_metaball_element(DataButtonsPanel): col.itemR(metaelem, "size_z", text="Z") elif metaelem.type == 'TUBE': - col = split.column(align=True) col.itemL(text="Size:") col.itemR(metaelem, "size_x", text="X") elif metaelem.type == 'PLANE': - col = split.column(align=True) col.itemL(text="Size:") col.itemR(metaelem, "size_x", text="X") col.itemR(metaelem, "size_y", text="Y") elif metaelem.type == 'ELLIPSOID': - col = split.column(align=True) col.itemL(text="Size:") col.itemR(metaelem, "size_x", text="X") col.itemR(metaelem, "size_y", text="Y") col.itemR(metaelem, "size_z", text="Z") - bpy.types.register(DATA_PT_context_metaball) bpy.types.register(DATA_PT_metaball) diff --git a/release/ui/buttons_data_text.py b/release/ui/buttons_data_text.py index 2959f60a5f5..0d46d5f8a0d 100644 --- a/release/ui/buttons_data_text.py +++ b/release/ui/buttons_data_text.py @@ -125,7 +125,6 @@ class DATA_PT_font(DataButtonsPanel): col.itemL(text="Underline:") col.itemR(text, "ul_position", text="Position") col.itemR(text, "ul_height", text="Thickness") - class DATA_PT_paragraph(DataButtonsPanel): __label__ = "Paragraph" @@ -151,7 +150,6 @@ class DATA_PT_paragraph(DataButtonsPanel): col.itemR(text, "offset_x", text="X") col.itemR(text, "offset_y", text="Y") - class DATA_PT_textboxes(DataButtonsPanel): __label__ = "Text Boxes" diff --git a/release/ui/buttons_game.py b/release/ui/buttons_game.py index f3461d3e370..5f5d4f916d0 100644 --- a/release/ui/buttons_game.py +++ b/release/ui/buttons_game.py @@ -26,7 +26,6 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel): #if game.physics_type == 'DYNAMIC': if game.physics_type in ('DYNAMIC', 'RIGID_BODY'): - split = layout.split() col = split.column() @@ -88,7 +87,6 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel): col.itemR(game, "lock_z_rot_axis", text="Z") elif game.physics_type == 'SOFT_BODY': - col = layout.column() col.itemR(game, "actor") col.itemR(game, "ghost") @@ -124,14 +122,12 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel): sub.itemR(soft, "cluster_iterations", text="Iterations") elif game.physics_type == 'STATIC': - col = layout.column() col.itemR(game, "actor") col.itemR(game, "ghost") col.itemR(ob, "restrict_render", text="Invisible") elif game.physics_type in ('SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'): - layout.itemR(ob, "restrict_render", text="Invisible") class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel): diff --git a/release/ui/buttons_material.py b/release/ui/buttons_material.py index 8b58c2b8953..448cb36e130 100644 --- a/release/ui/buttons_material.py +++ b/release/ui/buttons_material.py @@ -356,8 +356,8 @@ class MATERIAL_PT_sss(MaterialButtonsPanel): return mat and (mat.type in ('SURFACE', 'WIRE')) and (engine in self.COMPAT_ENGINES) def draw_header(self, context): - sss = context.material.subsurface_scattering mat = context.material + sss = mat.subsurface_scattering self.layout.active = (not mat.shadeless) self.layout.itemR(sss, "enabled", text="") @@ -366,7 +366,7 @@ class MATERIAL_PT_sss(MaterialButtonsPanel): layout = self.layout mat = context.material - sss = context.material.subsurface_scattering + sss = mat.subsurface_scattering layout.active = sss.enabled @@ -409,7 +409,7 @@ class MATERIAL_PT_mirror(MaterialButtonsPanel): layout = self.layout mat = context.material - raym = context.material.raytrace_mirror + raym = mat.raytrace_mirror layout.active = raym.enabled @@ -457,13 +457,14 @@ class MATERIAL_PT_transp(MaterialButtonsPanel): def draw_header(self, context): mat = context.material + self.layout.itemR(mat, "transparency", text="") def draw(self, context): layout = self.layout mat = context.material - rayt = context.material.raytrace_transparency + rayt = mat.raytrace_transparency row = layout.row() row.active = mat.transparency and (not mat.shadeless) @@ -561,11 +562,9 @@ class MATERIAL_PT_flare(MaterialButtonsPanel): return mat and (mat.type == 'HALO') and (engine in self.COMPAT_ENGINES) def draw_header(self, context): - layout = self.layout - - mat = context.material - halo = mat.halo - layout.itemR(halo, "flare_mode", text="") + halo = context.material.halo + + self.layout.itemR(halo, "flare_mode", text="") def draw(self, context): layout = self.layout @@ -619,7 +618,6 @@ class MATERIAL_PT_volume_shading(VolumeButtonsPanel): def draw(self, context): layout = self.layout - mat = context.material vol = context.material.volume row = layout.row() @@ -658,10 +656,10 @@ class MATERIAL_PT_volume_scattering(VolumeButtonsPanel): elif vol.scattering_mode in ('MULTIPLE_SCATTERING', 'SINGLE_PLUS_MULTIPLE_SCATTERING'): col.itemR(vol, "cache_resolution") - col = col.column(align=True) - col.itemR(vol, "ms_diffusion") - col.itemR(vol, "ms_spread") - col.itemR(vol, "ms_intensity") + sub = col.column(align=True) + sub.itemR(vol, "ms_diffusion") + sub.itemR(vol, "ms_spread") + sub.itemR(vol, "ms_intensity") col = split.column() # col.itemL(text="Anisotropic Scattering:") @@ -677,11 +675,8 @@ class MATERIAL_PT_volume_transp(VolumeButtonsPanel): layout = self.layout mat = context.material - rayt = context.material.raytrace_transparency - row= layout.row() - row.itemR(mat, "transparency_method", expand=True) - row.active = mat.transparency and (not mat.shadeless) + layout.itemR(mat, "transparency_method", expand=True) class MATERIAL_PT_volume_integration(VolumeButtonsPanel): __label__ = "Integration" @@ -690,8 +685,7 @@ class MATERIAL_PT_volume_integration(VolumeButtonsPanel): def draw(self, context): layout = self.layout - - mat = context.material + vol = context.material.volume split = layout.split() @@ -699,9 +693,9 @@ class MATERIAL_PT_volume_integration(VolumeButtonsPanel): col = split.column() col.itemL(text="Step Calculation:") col.itemR(vol, "step_calculation", text="") - col = col.column(align=True) - col.itemR(vol, "step_size") - col.itemR(vol, "shading_step_size") + sub = col.column(align=True) + sub.itemR(vol, "step_size") + sub.itemR(vol, "shading_step_size") col = split.column() col.itemL() diff --git a/release/ui/buttons_object_constraint.py b/release/ui/buttons_object_constraint.py index ca5c86fddd7..e089cff264f 100644 --- a/release/ui/buttons_object_constraint.py +++ b/release/ui/buttons_object_constraint.py @@ -68,8 +68,7 @@ class ConstraintButtonsPanel(bpy.types.Panel): col = split.column() col.itemR(con, "iterations") col.itemR(con, "chain_length") - - + def CHILD_OF(self, context, layout, con): self.target_template(layout, con) diff --git a/release/ui/buttons_physics_cloth.py b/release/ui/buttons_physics_cloth.py index 5cdca3c2c74..f6493951a34 100644 --- a/release/ui/buttons_physics_cloth.py +++ b/release/ui/buttons_physics_cloth.py @@ -89,7 +89,7 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.cloth) + return context.cloth def draw(self, context): md = context.cloth @@ -100,7 +100,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.cloth) + return context.cloth def draw_header(self, context): cloth = context.cloth.collision_settings @@ -135,7 +135,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.cloth != None) + return context.cloth def draw_header(self, context): cloth = context.cloth.settings diff --git a/release/ui/buttons_physics_field.py b/release/ui/buttons_physics_field.py index f6b50844fc8..7d14690856a 100644 --- a/release/ui/buttons_physics_field.py +++ b/release/ui/buttons_physics_field.py @@ -103,7 +103,6 @@ class PHYSICS_PT_field(PhysicButtonsPanel): sub.itemR(field, "maximum_distance", text="Distance") if field.falloff_type == 'CONE': - layout.itemS() split = layout.split(percentage=0.35) @@ -125,7 +124,6 @@ class PHYSICS_PT_field(PhysicButtonsPanel): sub.itemR(field, "radial_maximum", text="Angle") elif field.falloff_type == 'TUBE': - layout.itemS() split = layout.split(percentage=0.35) diff --git a/release/ui/buttons_physics_fluid.py b/release/ui/buttons_physics_fluid.py index 6f7a97ff793..e178a831ddd 100644 --- a/release/ui/buttons_physics_fluid.py +++ b/release/ui/buttons_physics_fluid.py @@ -174,8 +174,7 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel): def poll(self, context): md = context.fluid - if md: - return (md.settings.type == 'DOMAIN') + return md and (md.settings.type == 'DOMAIN') def draw(self, context): layout = self.layout @@ -213,8 +212,7 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel): def poll(self, context): md = context.fluid - if md: - return (md.settings.type == 'DOMAIN') + return md and (md.settings.type == 'DOMAIN') def draw(self, context): layout = self.layout @@ -242,8 +240,7 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel): def poll(self, context): md = context.fluid - if md: - return (md.settings.type == 'DOMAIN') + return md and (md.settings.type == 'DOMAIN') def draw(self, context): layout = self.layout diff --git a/release/ui/buttons_physics_smoke.py b/release/ui/buttons_physics_smoke.py index 6aee152e92a..1541b0bae14 100644 --- a/release/ui/buttons_physics_smoke.py +++ b/release/ui/buttons_physics_smoke.py @@ -90,10 +90,7 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel): def poll(self, context): md = context.smoke - if md: - return (md.smoke_type == 'TYPE_DOMAIN') - - return False + return md and (md.smoke_type == 'TYPE_DOMAIN') def draw(self, context): layout = self.layout diff --git a/release/ui/buttons_physics_softbody.py b/release/ui/buttons_physics_softbody.py index 703977a056f..3bdbb1b8b90 100644 --- a/release/ui/buttons_physics_softbody.py +++ b/release/ui/buttons_physics_softbody.py @@ -63,7 +63,7 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.soft_body) + return context.soft_body def draw(self, context): md = context.soft_body @@ -74,7 +74,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.soft_body) + return context.soft_body def draw_header(self, context): softbody = context.soft_body.settings @@ -115,7 +115,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.soft_body) + return context.soft_body def draw_header(self, context): softbody = context.soft_body.settings @@ -163,7 +163,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.soft_body) + return context.soft_body def draw_header(self, context): softbody = context.soft_body.settings @@ -194,7 +194,7 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.soft_body) + return context.soft_body def draw(self, context): layout = self.layout diff --git a/release/ui/buttons_scene.py b/release/ui/buttons_scene.py index 6f283bb5d5b..8bb172e8cd1 100644 --- a/release/ui/buttons_scene.py +++ b/release/ui/buttons_scene.py @@ -452,7 +452,6 @@ class SCENE_PT_unit(RenderButtonsPanel): row.itemR(unit, "scale_length", text="Scale") row.itemR(unit, "use_separate") - bpy.types.register(SCENE_PT_render) bpy.types.register(SCENE_PT_layers) bpy.types.register(SCENE_PT_dimensions) diff --git a/release/ui/buttons_texture.py b/release/ui/buttons_texture.py index c595e2b1cc2..c95fa266aaa 100644 --- a/release/ui/buttons_texture.py +++ b/release/ui/buttons_texture.py @@ -253,7 +253,6 @@ class TEXTURE_PT_influence(TextureSlotPanel): col.itemL(text=" ") factor_but(col, tex.map_alpha, "map_coloremission", "coloremission_factor", "Emission Color") factor_but(col, tex.map_colorabsorption, "map_colorabsorption", "colorabsorption_factor", "Absorption Color") - elif la: row = layout.row() @@ -617,9 +616,8 @@ class TEXTURE_PT_distortednoise(TextureTypePanel): flow.itemR(tex, "nabla") class TEXTURE_PT_voxeldata(TextureButtonsPanel): - __idname__= "TEXTURE_PT_voxeldata" __label__ = "Voxel Data" - + def poll(self, context): tex = context.texture return (tex and tex.type == 'VOXEL_DATA') @@ -647,9 +645,8 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel): layout.itemR(vd, "intensity") class TEXTURE_PT_pointdensity(TextureButtonsPanel): - __idname__= "TEXTURE_PT_pointdensity" __label__ = "Point Density" - + def poll(self, context): tex = context.texture return (tex and tex.type == 'POINT_DENSITY') diff --git a/release/ui/buttons_world.py b/release/ui/buttons_world.py index b02673d126f..3134c0ce46b 100644 --- a/release/ui/buttons_world.py +++ b/release/ui/buttons_world.py @@ -169,10 +169,9 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel): col.itemR(ao, "energy") col = split.column() - colsub = col.split(percentage=0.3) - colsub.itemL(text="Color:") - colsub.itemR(ao, "color", text="") - + sub = col.split(percentage=0.3) + sub.itemL(text="Color:") + sub.itemR(ao, "color", text="") bpy.types.register(WORLD_PT_context_world) bpy.types.register(WORLD_PT_preview) diff --git a/release/ui/space_sequencer.py b/release/ui/space_sequencer.py index daae4a83ec4..a804998cdaa 100644 --- a/release/ui/space_sequencer.py +++ b/release/ui/space_sequencer.py @@ -555,11 +555,9 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel): return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META') def draw_header(self, context): - layout = self.layout - strip = act_strip(context) - layout.itemR(strip, "use_proxy", text="") + self.layout.itemR(strip, "use_proxy", text="") def draw(self, context): layout = self.layout diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 239a727d2a2..4c1b54ea8e6 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -173,9 +173,7 @@ class VIEW3D_PT_tools_textedit(View3DPanel): def draw(self, context): layout = self.layout - - - + col = layout.column(align=True) col.itemL(text="Text Edit:") col.itemO("font.text_copy", text="Copy") @@ -201,9 +199,7 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel): def draw(self, context): layout = self.layout - - - + col = layout.column(align=True) col.itemL(text="Transform:") col.itemO("tfm.translate") @@ -366,7 +362,6 @@ class VIEW3D_PT_tools_brush(PaintPanel): col.itemR(brush, "strength", slider=True) if settings.tool == 'ADD': - col = layout.column() col.itemR(settings, "add_interpolate") sub = col.column(align=True) @@ -409,8 +404,6 @@ class VIEW3D_PT_tools_brush(PaintPanel): col.itemR(brush, "persistent") col.itemO("sculpt.set_persistent_base") - - # Texture Paint Mode # elif context.texture_paint_object and brush: @@ -625,10 +618,10 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel): def poll(self, context): return context.tool_settings.image_paint.tool != 'SMEAR' - def draw_header(self, context): - layout = self.layout - ipaint = context.tool_settings.image_paint - layout.itemR(ipaint, "use_projection", text="") + def draw_header(self, context): + ipaint = context.tool_settings.image_paint + + self.layout.itemR(ipaint, "use_projection", text="") def draw(self, context): layout = self.layout diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 0de19b22f3f..b8da42079c4 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -243,12 +243,12 @@ static void node_buts_rgb(uiLayout *layout, PointerRNA *ptr) } static void node_buts_mix_rgb(uiLayout *layout, PointerRNA *ptr) -{ - bNodeTree *ntree= (bNodeTree*)ptr->id.data; +{ uiLayout *row; - row= uiLayoutRow(layout, 1); + bNodeTree *ntree= (bNodeTree*)ptr->id.data; + row= uiLayoutRow(layout, 1); uiItemR(row, "", 0, ptr, "blend_type", 0); if(ntree->type == NTREE_COMPOSIT) uiItemR(row, "", ICON_IMAGE_RGB_ALPHA, ptr, "alpha", 0); @@ -1107,7 +1107,7 @@ static void node_blur_update_sizey_cb(bContext *C, void *node, void *poin2) } static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) { - uiLayout *row, *col; + uiLayout *col; col= uiLayoutColumn(layout, 0); @@ -1124,7 +1124,6 @@ static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) uiItemR(col, "X", 0, ptr, "factor_x", 0); uiItemR(col, "Y", 0, ptr, "factor_y", 0); } - else { uiItemR(col, "X", 0, ptr, "sizex", 0); uiItemR(col, "Y", 0, ptr, "sizey", 0); @@ -1133,7 +1132,7 @@ static void node_composit_buts_blur(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_dblur(uiLayout *layout, PointerRNA *ptr) { - uiLayout *row, *col; + uiLayout *col; uiItemR(layout, NULL, 0, ptr, "iterations", 0); uiItemR(layout, NULL, 0, ptr, "wrap", 0); -- cgit v1.2.3 From 0cbc87b42816711469cb63825ee826a837cc364a Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Sun, 27 Sep 2009 16:20:42 +0000 Subject: Speed optimization in itasc when with armature with many bones and few targets. Thanks to Brecht who pointed out a simple but efficient optimization in SVD decomposition. --- intern/itasc/WDLSSolver.cpp | 26 +++++++++++++++++++++----- intern/itasc/WDLSSolver.hpp | 3 ++- intern/itasc/WSDLSSolver.cpp | 26 +++++++++++++++++++++----- intern/itasc/WSDLSSolver.hpp | 3 ++- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/intern/itasc/WDLSSolver.cpp b/intern/itasc/WDLSSolver.cpp index e8bfc95e5dd..1d0efde54c9 100644 --- a/intern/itasc/WDLSSolver.cpp +++ b/intern/itasc/WDLSSolver.cpp @@ -24,12 +24,22 @@ bool WDLSSolver::init(unsigned int nq, unsigned int nc, const std::vector& m_ns = std::min(nc,nq); m_AWq = e_zero_matrix(nc,nq); m_WyAWq = e_zero_matrix(nc,nq); - m_U = e_zero_matrix(nc,nq); + m_WyAWqt = e_zero_matrix(nq,nc); m_S = e_zero_vector(std::max(nc,nq)); - m_temp = e_zero_vector(nq); - m_V = e_zero_matrix(nq,nq); - m_WqV = e_zero_matrix(nq,nq); m_Wy_ydot = e_zero_vector(nc); + if (nq > nc) { + m_transpose = true; + m_temp = e_zero_vector(nc); + m_U = e_zero_matrix(nc,nc); + m_V = e_zero_matrix(nq,nc); + m_WqV = e_zero_matrix(nq,nc); + } else { + m_transpose = false; + m_temp = e_zero_vector(nq); + m_U = e_zero_matrix(nc,nq); + m_V = e_zero_matrix(nq,nq); + m_WqV = e_zero_matrix(nq,nq); + } return true; } @@ -42,7 +52,13 @@ bool WDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& yd m_WyAWq.row(i) = Wy(i)*m_AWq.row(i); // Compute the SVD of the weighted jacobian - int ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp); + int ret; + if (m_transpose) { + m_WyAWqt = m_WyAWq.transpose(); + ret = KDL::svd_eigen_HH(m_WyAWqt,m_V,m_S,m_U,m_temp); + } else { + ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp); + } if(ret<0) return false; diff --git a/intern/itasc/WDLSSolver.hpp b/intern/itasc/WDLSSolver.hpp index 4418e73675c..b56ad1ab2b8 100644 --- a/intern/itasc/WDLSSolver.hpp +++ b/intern/itasc/WDLSSolver.hpp @@ -14,12 +14,13 @@ namespace iTaSC { class WDLSSolver: public iTaSC::Solver { private: - e_matrix m_AWq,m_WyAWq,m_U,m_V,m_WqV; + e_matrix m_AWq,m_WyAWq,m_WyAWqt,m_U,m_V,m_WqV; e_vector m_S,m_temp,m_Wy_ydot; double m_lambda; double m_epsilon; double m_qmax; int m_ns; + bool m_transpose; public: WDLSSolver(); virtual ~WDLSSolver(); diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp index 971fb7f482e..9f7ebed960a 100644 --- a/intern/itasc/WSDLSSolver.cpp +++ b/intern/itasc/WSDLSSolver.cpp @@ -31,13 +31,23 @@ bool WSDLSSolver::init(unsigned int _nq, unsigned int _nc, const std::vector m_nc) { + m_transpose = true; + m_temp = e_zero_vector(m_nc); + m_U = e_zero_matrix(m_nc,m_nc); + m_V = e_zero_matrix(m_nq,m_nc); + m_WqV = e_zero_matrix(m_nq,m_nc); + } else { + m_transpose = false; + m_temp = e_zero_vector(m_nq); + m_U = e_zero_matrix(m_nc,m_nq); + m_V = e_zero_matrix(m_nq,m_nq); + m_WqV = e_zero_matrix(m_nq,m_nq); + } return true; } @@ -52,7 +62,13 @@ bool WSDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& y m_WyAWq.row(i) = Wy(i)*m_AWq.row(i); // Compute the SVD of the weighted jacobian - int ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp); + int ret; + if (m_transpose) { + m_WyAWqt = m_WyAWq.transpose(); + ret = KDL::svd_eigen_HH(m_WyAWqt,m_V,m_S,m_U,m_temp); + } else { + ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp); + } if(ret<0) return false; diff --git a/intern/itasc/WSDLSSolver.hpp b/intern/itasc/WSDLSSolver.hpp index 1341cf2af66..0b17f26ef47 100644 --- a/intern/itasc/WSDLSSolver.hpp +++ b/intern/itasc/WSDLSSolver.hpp @@ -14,11 +14,12 @@ namespace iTaSC { class WSDLSSolver: public iTaSC::Solver { private: - e_matrix m_AWq,m_WyAWq,m_U,m_V,m_WqV; + e_matrix m_AWq,m_WyAWq,m_WyAWqt,m_U,m_V,m_WqV; e_vector m_S,m_temp,m_Wy_ydot; std::vector m_ytask; e_scalar m_qmax; unsigned int m_ns, m_nc, m_nq; + bool m_transpose; public: WSDLSSolver(); virtual ~WSDLSSolver(); -- cgit v1.2.3 From 2d797f35d804fd86ef079b30f2c83a81a8e38cd5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 28 Sep 2009 03:19:52 +0000 Subject: - removed 2.4x release/scripts - moved release/io and release/ui into release/scripts/io, ui - updated scons, cmake, make When porting 2.4x scripts back, use a command like this so as not to loose the commit history... svn cp https://svn.blender.org/svnroot/bf-blender/branches/blender2.4/release/scripts/raw_import.py release/scripts/io/import_raw.py --- SConstruct | 4 +- release/Makefile | 3 - release/io/engine_render_pov.py | 912 --- release/io/export_3ds.py | 1128 ---- release/io/export_fbx.py | 3457 ----------- release/io/export_obj.py | 993 ---- release/io/export_ply.py | 279 - release/io/export_x3d.py | 1239 ---- release/io/import_3ds.py | 1166 ---- release/io/import_obj.py | 1633 ----- release/io/netrender/__init__.py | 19 - release/io/netrender/balancing.py | 94 - release/io/netrender/client.py | 203 - release/io/netrender/master.py | 752 --- release/io/netrender/master_html.py | 142 - release/io/netrender/model.py | 198 - release/io/netrender/operators.py | 423 -- release/io/netrender/slave.py | 207 - release/io/netrender/ui.py | 321 - release/io/netrender/utils.py | 86 - release/scripts/3ds_export.py | 1019 ---- release/scripts/3ds_import.py | 1007 ---- release/scripts/Axiscopy.py | 125 - release/scripts/DirectX8Exporter.py | 1196 ---- release/scripts/DirectX8Importer.py | 238 - release/scripts/IDPropBrowser.py | 523 -- release/scripts/ac3d_export.py | 828 --- release/scripts/ac3d_import.py | 783 --- release/scripts/add_mesh_empty.py | 13 - release/scripts/add_mesh_torus.py | 69 - release/scripts/animation_bake_constraints.py | 792 --- release/scripts/animation_clean.py | 192 - release/scripts/animation_trajectory.py | 575 -- release/scripts/armature_symmetry.py | 325 - release/scripts/bevel_center.py | 474 -- release/scripts/blenderLipSynchro.py | 729 --- release/scripts/bpydata/KUlang.txt | 121 - release/scripts/bpydata/config/readme.txt | 6 - release/scripts/bpydata/readme.txt | 9 - release/scripts/bpymodules/BPyAddMesh.py | 159 - release/scripts/bpymodules/BPyArmature.py | 152 - release/scripts/bpymodules/BPyBlender.py | 36 - release/scripts/bpymodules/BPyCurve.py | 79 - release/scripts/bpymodules/BPyImage.py | 318 - release/scripts/bpymodules/BPyMathutils.py | 228 - release/scripts/bpymodules/BPyMesh.py | 1326 ----- release/scripts/bpymodules/BPyMesh_redux.py | 652 -- release/scripts/bpymodules/BPyMessages.py | 61 - release/scripts/bpymodules/BPyNMesh.py | 48 - release/scripts/bpymodules/BPyObject.py | 108 - release/scripts/bpymodules/BPyRegistry.py | 267 - release/scripts/bpymodules/BPyRender.py | 633 -- release/scripts/bpymodules/BPySys.py | 74 - release/scripts/bpymodules/BPyTextPlugin.py | 814 --- release/scripts/bpymodules/BPyWindow.py | 206 - release/scripts/bpymodules/blend2renderinfo.py | 95 - release/scripts/bpymodules/defaultdoodads.py | 941 --- release/scripts/bpymodules/dxfColorMap.py | 282 - release/scripts/bpymodules/dxfLibrary.py | 880 --- release/scripts/bpymodules/dxfReader.py | 381 -- release/scripts/bpymodules/mesh_gradient.py | 229 - release/scripts/bpymodules/meshtools.py | 355 -- release/scripts/bpymodules/paths_ai2obj.py | 506 -- release/scripts/bpymodules/paths_eps2obj.py | 452 -- release/scripts/bpymodules/paths_gimp2obj.py | 363 -- release/scripts/bpymodules/paths_svg2obj.py | 1651 ------ release/scripts/bvh_import.py | 757 --- release/scripts/c3d_import.py | 1244 ---- release/scripts/camera_changer.py | 121 - release/scripts/config.py | 801 --- release/scripts/console.py | 861 --- release/scripts/discombobulator.py | 1526 ----- release/scripts/envelope_symmetry.py | 174 - release/scripts/export-iv-0.1.py | 304 - release/scripts/export_dxf.py | 3041 ---------- release/scripts/export_fbx.py | 3084 ---------- release/scripts/export_lightwave_motion.py | 157 - release/scripts/export_m3g.py | 3074 ---------- release/scripts/export_map.py | 454 -- release/scripts/export_mdd.py | 168 - release/scripts/export_obj.py | 933 --- release/scripts/faceselect_same_weights.py | 111 - release/scripts/flt_defaultp.py | 1 - release/scripts/flt_dofedit.py | 835 --- release/scripts/flt_export.py | 1697 ------ release/scripts/flt_filewalker.py | 286 - release/scripts/flt_import.py | 2534 -------- release/scripts/flt_lodedit.py | 502 -- release/scripts/flt_palettemanager.py | 505 -- release/scripts/flt_properties.py | 630 -- release/scripts/flt_toolbar.py | 809 --- release/scripts/help_bpy_api.py | 47 - release/scripts/help_browser.py | 814 --- release/scripts/hotkeys.py | 944 --- release/scripts/image_2d_cutout.py | 559 -- release/scripts/image_auto_layout.py | 455 -- release/scripts/image_billboard.py | 269 - release/scripts/image_edit.py | 158 - release/scripts/import_dxf.py | 6225 -------------------- release/scripts/import_edl.py | 961 --- release/scripts/import_lightwave_motion.py | 244 - release/scripts/import_mdd.py | 158 - release/scripts/import_obj.py | 1234 ---- release/scripts/import_web3d.py | 2594 -------- release/scripts/io/engine_render_pov.py | 912 +++ release/scripts/io/export_3ds.py | 1128 ++++ release/scripts/io/export_fbx.py | 3457 +++++++++++ release/scripts/io/export_obj.py | 993 ++++ release/scripts/io/export_ply.py | 279 + release/scripts/io/export_x3d.py | 1239 ++++ release/scripts/io/import_3ds.py | 1166 ++++ release/scripts/io/import_obj.py | 1633 +++++ release/scripts/io/netrender/__init__.py | 19 + release/scripts/io/netrender/balancing.py | 94 + release/scripts/io/netrender/client.py | 203 + release/scripts/io/netrender/master.py | 752 +++ release/scripts/io/netrender/master_html.py | 142 + release/scripts/io/netrender/model.py | 198 + release/scripts/io/netrender/operators.py | 423 ++ release/scripts/io/netrender/slave.py | 207 + release/scripts/io/netrender/ui.py | 321 + release/scripts/io/netrender/utils.py | 86 + release/scripts/lightwave_export.py | 707 --- release/scripts/lightwave_import.py | 1705 ------ release/scripts/md2_export.py | 1271 ---- release/scripts/md2_import.py | 600 -- release/scripts/mesh_boneweight_copy.py | 287 - release/scripts/mesh_cleanup.py | 456 -- release/scripts/mesh_edges2curves.py | 166 - release/scripts/mesh_mirror_tool.py | 352 -- release/scripts/mesh_poly_reduce.py | 143 - release/scripts/mesh_poly_reduce_grid.py | 351 -- release/scripts/mesh_skin.py | 639 -- release/scripts/mesh_solidify.py | 345 -- release/scripts/mesh_unfolder.py | 1582 ----- release/scripts/mesh_wire.py | 290 - release/scripts/ms3d_import.py | 487 -- release/scripts/ms3d_import_ascii.py | 479 -- release/scripts/obdatacopier.py | 215 - release/scripts/object_active_to_other.py | 58 - release/scripts/object_apply_def.py | 178 - release/scripts/object_batch_name_edit.py | 274 - release/scripts/object_cookie_cutter.py | 667 --- release/scripts/object_drop.py | 253 - release/scripts/object_find.py | 222 - release/scripts/object_random_loc_sz_rot.py | 129 - release/scripts/object_sel2dupgroup.py | 84 - release/scripts/object_timeofs_follow_act.py | 107 - release/scripts/off_export.py | 106 - release/scripts/off_import.py | 177 - release/scripts/paths_import.py | 96 - release/scripts/ply_import.py | 354 -- release/scripts/raw_export.py | 100 - release/scripts/raw_import.py | 120 - release/scripts/renameobjectbyblock.py | 178 - release/scripts/render_save_layers.py | 120 - release/scripts/rvk1_torvk2.py | 341 -- release/scripts/save_theme.py | 143 - release/scripts/scripttemplate_background_job.py | 124 - release/scripts/scripttemplate_camera_object.py | 104 - release/scripts/scripttemplate_gamelogic.py | 97 - release/scripts/scripttemplate_gamelogic_basic.py | 33 - release/scripts/scripttemplate_gamelogic_module.py | 45 - release/scripts/scripttemplate_ipo_gen.py | 92 - release/scripts/scripttemplate_mesh_edit.py | 98 - release/scripts/scripttemplate_metaball_create.py | 76 - release/scripts/scripttemplate_object_edit.py | 81 - release/scripts/scripttemplate_pyconstraint.py | 114 - release/scripts/scripttemplate_text_plugin.py | 69 - release/scripts/slp_import.py | 116 - release/scripts/sysinfo.py | 287 - release/scripts/textplugin_convert_ge.py | 863 --- release/scripts/textplugin_functiondocs.py | 64 - release/scripts/textplugin_imports.py | 91 - release/scripts/textplugin_membersuggest.py | 90 - release/scripts/textplugin_outliner.py | 142 - release/scripts/textplugin_suggest.py | 94 - release/scripts/textplugin_templates.py | 123 - release/scripts/ui/bpy_ops.py | 141 + release/scripts/ui/buttons_data_armature.py | 186 + release/scripts/ui/buttons_data_bone.py | 353 ++ release/scripts/ui/buttons_data_camera.py | 98 + release/scripts/ui/buttons_data_curve.py | 227 + release/scripts/ui/buttons_data_empty.py | 23 + release/scripts/ui/buttons_data_lamp.py | 310 + release/scripts/ui/buttons_data_lattice.py | 56 + release/scripts/ui/buttons_data_mesh.py | 203 + release/scripts/ui/buttons_data_metaball.py | 106 + release/scripts/ui/buttons_data_modifier.py | 449 ++ release/scripts/ui/buttons_data_text.py | 179 + release/scripts/ui/buttons_game.py | 416 ++ release/scripts/ui/buttons_material.py | 708 +++ release/scripts/ui/buttons_object.py | 185 + release/scripts/ui/buttons_object_constraint.py | 561 ++ release/scripts/ui/buttons_particle.py | 961 +++ release/scripts/ui/buttons_physics_cloth.py | 172 + release/scripts/ui/buttons_physics_field.py | 226 + release/scripts/ui/buttons_physics_fluid.py | 257 + release/scripts/ui/buttons_physics_smoke.py | 179 + release/scripts/ui/buttons_physics_softbody.py | 231 + release/scripts/ui/buttons_scene.py | 465 ++ release/scripts/ui/buttons_texture.py | 758 +++ release/scripts/ui/buttons_world.py | 181 + release/scripts/ui/space_buttons.py | 36 + release/scripts/ui/space_console.py | 451 ++ release/scripts/ui/space_filebrowser.py | 42 + release/scripts/ui/space_image.py | 503 ++ release/scripts/ui/space_info.py | 292 + release/scripts/ui/space_logic.py | 29 + release/scripts/ui/space_node.py | 118 + release/scripts/ui/space_outliner.py | 52 + release/scripts/ui/space_sequencer.py | 600 ++ release/scripts/ui/space_text.py | 245 + release/scripts/ui/space_time.py | 151 + release/scripts/ui/space_userpref.py | 405 ++ release/scripts/ui/space_view3d.py | 1362 +++++ release/scripts/ui/space_view3d_toolbar.py | 746 +++ release/scripts/unweld.py | 247 - release/scripts/uv_export.py | 498 -- release/scripts/uv_seams_from_islands.py | 101 - release/scripts/uvcalc_follow_active_coords.py | 254 - release/scripts/uvcalc_lightmap.py | 599 -- release/scripts/uvcalc_quad_clickproj.py | 271 - release/scripts/uvcalc_smart_project.py | 1132 ---- release/scripts/uvcopy.py | 112 - release/scripts/vertexpaint_from_material.py | 99 - release/scripts/vertexpaint_gradient.py | 46 - release/scripts/vertexpaint_selfshadow_ao.py | 186 - release/scripts/vrml97_export.py | 1300 ---- release/scripts/weightpaint_average.py | 121 - release/scripts/weightpaint_clean.py | 121 - release/scripts/weightpaint_copy.py | 101 - release/scripts/weightpaint_envelope_assign.py | 240 - release/scripts/weightpaint_gradient.py | 59 - release/scripts/weightpaint_grow_shrink.py | 131 - release/scripts/weightpaint_invert.py | 95 - release/scripts/weightpaint_normalize.py | 170 - release/scripts/widgetwizard.py | 917 --- release/scripts/wizard_bolt_factory.py | 2811 --------- release/scripts/wizard_curve2tree.py | 4048 ------------- release/scripts/wizard_landscape_ant.py | 2148 ------- release/scripts/x3d_export.py | 1051 ---- release/scripts/xsi_export.py | 1227 ---- release/ui/bpy_ops.py | 141 - release/ui/buttons_data_armature.py | 186 - release/ui/buttons_data_bone.py | 353 -- release/ui/buttons_data_camera.py | 98 - release/ui/buttons_data_curve.py | 227 - release/ui/buttons_data_empty.py | 23 - release/ui/buttons_data_lamp.py | 310 - release/ui/buttons_data_lattice.py | 56 - release/ui/buttons_data_mesh.py | 203 - release/ui/buttons_data_metaball.py | 106 - release/ui/buttons_data_modifier.py | 449 -- release/ui/buttons_data_text.py | 179 - release/ui/buttons_game.py | 416 -- release/ui/buttons_material.py | 708 --- release/ui/buttons_object.py | 185 - release/ui/buttons_object_constraint.py | 561 -- release/ui/buttons_particle.py | 961 --- release/ui/buttons_physics_cloth.py | 172 - release/ui/buttons_physics_field.py | 226 - release/ui/buttons_physics_fluid.py | 257 - release/ui/buttons_physics_smoke.py | 179 - release/ui/buttons_physics_softbody.py | 231 - release/ui/buttons_scene.py | 465 -- release/ui/buttons_texture.py | 758 --- release/ui/buttons_world.py | 181 - release/ui/space_buttons.py | 36 - release/ui/space_console.py | 451 -- release/ui/space_filebrowser.py | 42 - release/ui/space_image.py | 503 -- release/ui/space_info.py | 292 - release/ui/space_logic.py | 29 - release/ui/space_node.py | 118 - release/ui/space_outliner.py | 52 - release/ui/space_sequencer.py | 600 -- release/ui/space_text.py | 245 - release/ui/space_time.py | 151 - release/ui/space_userpref.py | 405 -- release/ui/space_view3d.py | 1362 ----- release/ui/space_view3d_toolbar.py | 746 --- source/blender/blenloader/BLO_readfile.h | 2 +- source/blender/python/intern/bpy_interface.c | 2 +- source/creator/CMakeLists.txt | 11 +- source/darwin/Makefile | 2 - 286 files changed, 25922 insertions(+), 120193 deletions(-) delete mode 100644 release/io/engine_render_pov.py delete mode 100644 release/io/export_3ds.py delete mode 100644 release/io/export_fbx.py delete mode 100644 release/io/export_obj.py delete mode 100644 release/io/export_ply.py delete mode 100644 release/io/export_x3d.py delete mode 100644 release/io/import_3ds.py delete mode 100644 release/io/import_obj.py delete mode 100644 release/io/netrender/__init__.py delete mode 100644 release/io/netrender/balancing.py delete mode 100644 release/io/netrender/client.py delete mode 100644 release/io/netrender/master.py delete mode 100644 release/io/netrender/master_html.py delete mode 100644 release/io/netrender/model.py delete mode 100644 release/io/netrender/operators.py delete mode 100644 release/io/netrender/slave.py delete mode 100644 release/io/netrender/ui.py delete mode 100644 release/io/netrender/utils.py delete mode 100644 release/scripts/3ds_export.py delete mode 100644 release/scripts/3ds_import.py delete mode 100644 release/scripts/Axiscopy.py delete mode 100644 release/scripts/DirectX8Exporter.py delete mode 100644 release/scripts/DirectX8Importer.py delete mode 100644 release/scripts/IDPropBrowser.py delete mode 100644 release/scripts/ac3d_export.py delete mode 100644 release/scripts/ac3d_import.py delete mode 100644 release/scripts/add_mesh_empty.py delete mode 100644 release/scripts/add_mesh_torus.py delete mode 100644 release/scripts/animation_bake_constraints.py delete mode 100644 release/scripts/animation_clean.py delete mode 100644 release/scripts/animation_trajectory.py delete mode 100644 release/scripts/armature_symmetry.py delete mode 100644 release/scripts/bevel_center.py delete mode 100644 release/scripts/blenderLipSynchro.py delete mode 100644 release/scripts/bpydata/KUlang.txt delete mode 100644 release/scripts/bpydata/config/readme.txt delete mode 100644 release/scripts/bpydata/readme.txt delete mode 100644 release/scripts/bpymodules/BPyAddMesh.py delete mode 100644 release/scripts/bpymodules/BPyArmature.py delete mode 100644 release/scripts/bpymodules/BPyBlender.py delete mode 100644 release/scripts/bpymodules/BPyCurve.py delete mode 100644 release/scripts/bpymodules/BPyImage.py delete mode 100644 release/scripts/bpymodules/BPyMathutils.py delete mode 100644 release/scripts/bpymodules/BPyMesh.py delete mode 100644 release/scripts/bpymodules/BPyMesh_redux.py delete mode 100644 release/scripts/bpymodules/BPyMessages.py delete mode 100644 release/scripts/bpymodules/BPyNMesh.py delete mode 100644 release/scripts/bpymodules/BPyObject.py delete mode 100644 release/scripts/bpymodules/BPyRegistry.py delete mode 100644 release/scripts/bpymodules/BPyRender.py delete mode 100644 release/scripts/bpymodules/BPySys.py delete mode 100644 release/scripts/bpymodules/BPyTextPlugin.py delete mode 100644 release/scripts/bpymodules/BPyWindow.py delete mode 100644 release/scripts/bpymodules/blend2renderinfo.py delete mode 100644 release/scripts/bpymodules/defaultdoodads.py delete mode 100644 release/scripts/bpymodules/dxfColorMap.py delete mode 100644 release/scripts/bpymodules/dxfLibrary.py delete mode 100644 release/scripts/bpymodules/dxfReader.py delete mode 100644 release/scripts/bpymodules/mesh_gradient.py delete mode 100644 release/scripts/bpymodules/meshtools.py delete mode 100644 release/scripts/bpymodules/paths_ai2obj.py delete mode 100644 release/scripts/bpymodules/paths_eps2obj.py delete mode 100644 release/scripts/bpymodules/paths_gimp2obj.py delete mode 100644 release/scripts/bpymodules/paths_svg2obj.py delete mode 100644 release/scripts/bvh_import.py delete mode 100644 release/scripts/c3d_import.py delete mode 100644 release/scripts/camera_changer.py delete mode 100644 release/scripts/config.py delete mode 100644 release/scripts/console.py delete mode 100644 release/scripts/discombobulator.py delete mode 100644 release/scripts/envelope_symmetry.py delete mode 100644 release/scripts/export-iv-0.1.py delete mode 100644 release/scripts/export_dxf.py delete mode 100644 release/scripts/export_fbx.py delete mode 100644 release/scripts/export_lightwave_motion.py delete mode 100644 release/scripts/export_m3g.py delete mode 100644 release/scripts/export_map.py delete mode 100644 release/scripts/export_mdd.py delete mode 100644 release/scripts/export_obj.py delete mode 100644 release/scripts/faceselect_same_weights.py delete mode 100644 release/scripts/flt_defaultp.py delete mode 100644 release/scripts/flt_dofedit.py delete mode 100644 release/scripts/flt_export.py delete mode 100644 release/scripts/flt_filewalker.py delete mode 100644 release/scripts/flt_import.py delete mode 100644 release/scripts/flt_lodedit.py delete mode 100644 release/scripts/flt_palettemanager.py delete mode 100644 release/scripts/flt_properties.py delete mode 100644 release/scripts/flt_toolbar.py delete mode 100644 release/scripts/help_bpy_api.py delete mode 100644 release/scripts/help_browser.py delete mode 100644 release/scripts/hotkeys.py delete mode 100644 release/scripts/image_2d_cutout.py delete mode 100644 release/scripts/image_auto_layout.py delete mode 100644 release/scripts/image_billboard.py delete mode 100644 release/scripts/image_edit.py delete mode 100644 release/scripts/import_dxf.py delete mode 100644 release/scripts/import_edl.py delete mode 100644 release/scripts/import_lightwave_motion.py delete mode 100644 release/scripts/import_mdd.py delete mode 100644 release/scripts/import_obj.py delete mode 100644 release/scripts/import_web3d.py create mode 100644 release/scripts/io/engine_render_pov.py create mode 100644 release/scripts/io/export_3ds.py create mode 100644 release/scripts/io/export_fbx.py create mode 100644 release/scripts/io/export_obj.py create mode 100644 release/scripts/io/export_ply.py create mode 100644 release/scripts/io/export_x3d.py create mode 100644 release/scripts/io/import_3ds.py create mode 100644 release/scripts/io/import_obj.py create mode 100644 release/scripts/io/netrender/__init__.py create mode 100644 release/scripts/io/netrender/balancing.py create mode 100644 release/scripts/io/netrender/client.py create mode 100644 release/scripts/io/netrender/master.py create mode 100644 release/scripts/io/netrender/master_html.py create mode 100644 release/scripts/io/netrender/model.py create mode 100644 release/scripts/io/netrender/operators.py create mode 100644 release/scripts/io/netrender/slave.py create mode 100644 release/scripts/io/netrender/ui.py create mode 100644 release/scripts/io/netrender/utils.py delete mode 100644 release/scripts/lightwave_export.py delete mode 100644 release/scripts/lightwave_import.py delete mode 100644 release/scripts/md2_export.py delete mode 100644 release/scripts/md2_import.py delete mode 100644 release/scripts/mesh_boneweight_copy.py delete mode 100644 release/scripts/mesh_cleanup.py delete mode 100644 release/scripts/mesh_edges2curves.py delete mode 100644 release/scripts/mesh_mirror_tool.py delete mode 100644 release/scripts/mesh_poly_reduce.py delete mode 100644 release/scripts/mesh_poly_reduce_grid.py delete mode 100644 release/scripts/mesh_skin.py delete mode 100644 release/scripts/mesh_solidify.py delete mode 100644 release/scripts/mesh_unfolder.py delete mode 100644 release/scripts/mesh_wire.py delete mode 100644 release/scripts/ms3d_import.py delete mode 100644 release/scripts/ms3d_import_ascii.py delete mode 100644 release/scripts/obdatacopier.py delete mode 100644 release/scripts/object_active_to_other.py delete mode 100644 release/scripts/object_apply_def.py delete mode 100644 release/scripts/object_batch_name_edit.py delete mode 100644 release/scripts/object_cookie_cutter.py delete mode 100644 release/scripts/object_drop.py delete mode 100644 release/scripts/object_find.py delete mode 100644 release/scripts/object_random_loc_sz_rot.py delete mode 100644 release/scripts/object_sel2dupgroup.py delete mode 100644 release/scripts/object_timeofs_follow_act.py delete mode 100644 release/scripts/off_export.py delete mode 100644 release/scripts/off_import.py delete mode 100644 release/scripts/paths_import.py delete mode 100644 release/scripts/ply_import.py delete mode 100644 release/scripts/raw_export.py delete mode 100644 release/scripts/raw_import.py delete mode 100644 release/scripts/renameobjectbyblock.py delete mode 100644 release/scripts/render_save_layers.py delete mode 100644 release/scripts/rvk1_torvk2.py delete mode 100644 release/scripts/save_theme.py delete mode 100644 release/scripts/scripttemplate_background_job.py delete mode 100644 release/scripts/scripttemplate_camera_object.py delete mode 100644 release/scripts/scripttemplate_gamelogic.py delete mode 100644 release/scripts/scripttemplate_gamelogic_basic.py delete mode 100644 release/scripts/scripttemplate_gamelogic_module.py delete mode 100644 release/scripts/scripttemplate_ipo_gen.py delete mode 100644 release/scripts/scripttemplate_mesh_edit.py delete mode 100644 release/scripts/scripttemplate_metaball_create.py delete mode 100644 release/scripts/scripttemplate_object_edit.py delete mode 100644 release/scripts/scripttemplate_pyconstraint.py delete mode 100644 release/scripts/scripttemplate_text_plugin.py delete mode 100644 release/scripts/slp_import.py delete mode 100644 release/scripts/sysinfo.py delete mode 100644 release/scripts/textplugin_convert_ge.py delete mode 100644 release/scripts/textplugin_functiondocs.py delete mode 100644 release/scripts/textplugin_imports.py delete mode 100644 release/scripts/textplugin_membersuggest.py delete mode 100644 release/scripts/textplugin_outliner.py delete mode 100644 release/scripts/textplugin_suggest.py delete mode 100644 release/scripts/textplugin_templates.py create mode 100644 release/scripts/ui/bpy_ops.py create mode 100644 release/scripts/ui/buttons_data_armature.py create mode 100644 release/scripts/ui/buttons_data_bone.py create mode 100644 release/scripts/ui/buttons_data_camera.py create mode 100644 release/scripts/ui/buttons_data_curve.py create mode 100644 release/scripts/ui/buttons_data_empty.py create mode 100644 release/scripts/ui/buttons_data_lamp.py create mode 100644 release/scripts/ui/buttons_data_lattice.py create mode 100644 release/scripts/ui/buttons_data_mesh.py create mode 100644 release/scripts/ui/buttons_data_metaball.py create mode 100644 release/scripts/ui/buttons_data_modifier.py create mode 100644 release/scripts/ui/buttons_data_text.py create mode 100644 release/scripts/ui/buttons_game.py create mode 100644 release/scripts/ui/buttons_material.py create mode 100644 release/scripts/ui/buttons_object.py create mode 100644 release/scripts/ui/buttons_object_constraint.py create mode 100644 release/scripts/ui/buttons_particle.py create mode 100644 release/scripts/ui/buttons_physics_cloth.py create mode 100644 release/scripts/ui/buttons_physics_field.py create mode 100644 release/scripts/ui/buttons_physics_fluid.py create mode 100644 release/scripts/ui/buttons_physics_smoke.py create mode 100644 release/scripts/ui/buttons_physics_softbody.py create mode 100644 release/scripts/ui/buttons_scene.py create mode 100644 release/scripts/ui/buttons_texture.py create mode 100644 release/scripts/ui/buttons_world.py create mode 100644 release/scripts/ui/space_buttons.py create mode 100644 release/scripts/ui/space_console.py create mode 100644 release/scripts/ui/space_filebrowser.py create mode 100644 release/scripts/ui/space_image.py create mode 100644 release/scripts/ui/space_info.py create mode 100644 release/scripts/ui/space_logic.py create mode 100644 release/scripts/ui/space_node.py create mode 100644 release/scripts/ui/space_outliner.py create mode 100644 release/scripts/ui/space_sequencer.py create mode 100644 release/scripts/ui/space_text.py create mode 100644 release/scripts/ui/space_time.py create mode 100644 release/scripts/ui/space_userpref.py create mode 100644 release/scripts/ui/space_view3d.py create mode 100644 release/scripts/ui/space_view3d_toolbar.py delete mode 100644 release/scripts/unweld.py delete mode 100644 release/scripts/uv_export.py delete mode 100644 release/scripts/uv_seams_from_islands.py delete mode 100644 release/scripts/uvcalc_follow_active_coords.py delete mode 100644 release/scripts/uvcalc_lightmap.py delete mode 100644 release/scripts/uvcalc_quad_clickproj.py delete mode 100644 release/scripts/uvcalc_smart_project.py delete mode 100644 release/scripts/uvcopy.py delete mode 100644 release/scripts/vertexpaint_from_material.py delete mode 100644 release/scripts/vertexpaint_gradient.py delete mode 100644 release/scripts/vertexpaint_selfshadow_ao.py delete mode 100644 release/scripts/vrml97_export.py delete mode 100644 release/scripts/weightpaint_average.py delete mode 100644 release/scripts/weightpaint_clean.py delete mode 100644 release/scripts/weightpaint_copy.py delete mode 100644 release/scripts/weightpaint_envelope_assign.py delete mode 100644 release/scripts/weightpaint_gradient.py delete mode 100644 release/scripts/weightpaint_grow_shrink.py delete mode 100644 release/scripts/weightpaint_invert.py delete mode 100644 release/scripts/weightpaint_normalize.py delete mode 100644 release/scripts/widgetwizard.py delete mode 100644 release/scripts/wizard_bolt_factory.py delete mode 100644 release/scripts/wizard_curve2tree.py delete mode 100644 release/scripts/wizard_landscape_ant.py delete mode 100644 release/scripts/x3d_export.py delete mode 100644 release/scripts/xsi_export.py delete mode 100644 release/ui/bpy_ops.py delete mode 100644 release/ui/buttons_data_armature.py delete mode 100644 release/ui/buttons_data_bone.py delete mode 100644 release/ui/buttons_data_camera.py delete mode 100644 release/ui/buttons_data_curve.py delete mode 100644 release/ui/buttons_data_empty.py delete mode 100644 release/ui/buttons_data_lamp.py delete mode 100644 release/ui/buttons_data_lattice.py delete mode 100644 release/ui/buttons_data_mesh.py delete mode 100644 release/ui/buttons_data_metaball.py delete mode 100644 release/ui/buttons_data_modifier.py delete mode 100644 release/ui/buttons_data_text.py delete mode 100644 release/ui/buttons_game.py delete mode 100644 release/ui/buttons_material.py delete mode 100644 release/ui/buttons_object.py delete mode 100644 release/ui/buttons_object_constraint.py delete mode 100644 release/ui/buttons_particle.py delete mode 100644 release/ui/buttons_physics_cloth.py delete mode 100644 release/ui/buttons_physics_field.py delete mode 100644 release/ui/buttons_physics_fluid.py delete mode 100644 release/ui/buttons_physics_smoke.py delete mode 100644 release/ui/buttons_physics_softbody.py delete mode 100644 release/ui/buttons_scene.py delete mode 100644 release/ui/buttons_texture.py delete mode 100644 release/ui/buttons_world.py delete mode 100644 release/ui/space_buttons.py delete mode 100644 release/ui/space_console.py delete mode 100644 release/ui/space_filebrowser.py delete mode 100644 release/ui/space_image.py delete mode 100644 release/ui/space_info.py delete mode 100644 release/ui/space_logic.py delete mode 100644 release/ui/space_node.py delete mode 100644 release/ui/space_outliner.py delete mode 100644 release/ui/space_sequencer.py delete mode 100644 release/ui/space_text.py delete mode 100644 release/ui/space_time.py delete mode 100644 release/ui/space_userpref.py delete mode 100644 release/ui/space_view3d.py delete mode 100644 release/ui/space_view3d_toolbar.py diff --git a/SConstruct b/SConstruct index 7e3d23970cb..5c4af916327 100644 --- a/SConstruct +++ b/SConstruct @@ -476,8 +476,8 @@ if env['OURPLATFORM']!='darwin': dotblenderinstall.append(env.Install(dir=td, source=srcfile)) if env['WITH_BF_PYTHON']: - #-- .blender/scripts, .blender/ui, .blender/io - scriptpaths=['release/scripts', 'release/ui', 'release/io'] + #-- .blender/scripts + scriptpaths=['release/scripts'] for scriptpath in scriptpaths: for dp, dn, df in os.walk(scriptpath): if '.svn' in dn: diff --git a/release/Makefile b/release/Makefile index 94bb902646d..9fe83ef3494 100644 --- a/release/Makefile +++ b/release/Makefile @@ -153,9 +153,6 @@ endif @echo "----> Copy python infrastructure" @[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts - - @echo "----> Copy python UI files" - @[ ! -d ui ] || cp -r ui $(CONFDIR)/ui ifeq ($(OS),darwin) @echo "----> Copy python modules" diff --git a/release/io/engine_render_pov.py b/release/io/engine_render_pov.py deleted file mode 100644 index f0247ce532a..00000000000 --- a/release/io/engine_render_pov.py +++ /dev/null @@ -1,912 +0,0 @@ -import bpy - -from math import atan, pi, degrees -import subprocess -import os -import sys -import time - -import platform as pltfrm - -if pltfrm.architecture()[0] == '64bit': - bitness = 64 -else: - bitness = 32 - -def write_pov(filename, scene=None, info_callback = None): - file = open(filename, 'w') - - # Only for testing - if not scene: - scene = bpy.data.scenes[0] - - render = scene.render_data - world = scene.world - - # --- taken from fbx exporter - ## This was used to make V, but faster not to do all that - ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' - ##v = range(255) - ##for c in valid: v.remove(ord(c)) - 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,42,43,46,47,58,59,60,61,62,63,64,92,94,96,124,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]) - def cleanName(name): - for ch in invalid: name = name.replace(ch, '_') - return name - del v - - # --- done with clean name. - - def uniqueName(name, nameSeq): - - if name not in nameSeq: - return name - - name_orig = name - i = 1 - while name in nameSeq: - name = '%s_%.3d' % (name_orig, i) - i+=1 - - return name - - - def writeMatrix(matrix): - file.write('\tmatrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n' %\ - (matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2], matrix[3][0], matrix[3][1], matrix[3][2]) ) - - def writeObjectMaterial(material): - if material and material.transparency_method=='RAYTRACE': - file.write('\tinterior { ior %.6f }\n' % material.raytrace_transparency.ior) - - # Other interior args - # fade_distance 2 - # fade_power [Value] - # fade_color - - # dispersion - # dispersion_samples - - materialNames = {} - DEF_MAT_NAME = 'Default' - def writeMaterial(material): - # Assumes only called once on each material - - if material: - name_orig = material.name - else: - name_orig = DEF_MAT_NAME - - name = materialNames[name_orig] = uniqueName(cleanName(name_orig), materialNames) - - file.write('#declare %s = finish {\n' % name) - - if material: - file.write('\tdiffuse %.3g\n' % material.diffuse_intensity) - file.write('\tspecular %.3g\n' % material.specular_intensity) - - file.write('\tambient %.3g\n' % material.ambient) - #file.write('\tambient rgb <%.3g, %.3g, %.3g>\n' % tuple([c*material.ambient for c in world.ambient_color])) # povray blends the global value - - # map hardness between 0.0 and 1.0 - roughness = ((1.0 - ((material.specular_hardness-1.0)/510.0))) - # scale from 0.0 to 0.1 - roughness *= 0.1 - # add a small value because 0.0 is invalid - roughness += (1/511.0) - - file.write('\troughness %.3g\n' % roughness) - - # 'phong 70.0 ' - - if material.raytrace_mirror.enabled: - raytrace_mirror= material.raytrace_mirror - if raytrace_mirror.reflect_factor: - file.write('\treflection {\n') - file.write('\t\trgb <%.3g, %.3g, %.3g>' % tuple(material.mirror_color)) - file.write('\t\tfresnel 1 falloff %.3g exponent %.3g metallic %.3g} ' % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor, raytrace_mirror.reflect_factor)) - - else: - file.write('\tdiffuse 0.8\n') - file.write('\tspecular 0.2\n') - - - # This is written into the object - ''' - if material and material.transparency_method=='RAYTRACE': - 'interior { ior %.3g} ' % material.raytrace_transparency.ior - ''' - - #file.write('\t\t\tcrand 1.0\n') # Sand granyness - #file.write('\t\t\tmetallic %.6f\n' % material.spec) - #file.write('\t\t\tphong %.6f\n' % material.spec) - #file.write('\t\t\tphong_size %.6f\n' % material.spec) - #file.write('\t\t\tbrilliance %.6f ' % (material.specular_hardness/256.0) # Like hardness - - file.write('}\n') - - def exportCamera(): - camera = scene.camera - matrix = camera.matrix - - # compute resolution - Qsize=float(render.resolution_x)/float(render.resolution_y) - - file.write('camera {\n') - file.write('\tlocation <0, 0, 0>\n') - file.write('\tlook_at <0, 0, -1>\n') - file.write('\tright <%s, 0, 0>\n' % -Qsize) - file.write('\tup <0, 1, 0>\n') - file.write('\tangle %f \n' % (360.0*atan(16.0/camera.data.lens)/pi)) - - file.write('\trotate <%.6f, %.6f, %.6f>\n' % tuple([degrees(e) for e in matrix.rotationPart().toEuler()])) - file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2])) - file.write('}\n') - - def exportLamps(lamps): - # Get all lamps - for ob in lamps: - lamp = ob.data - - matrix = ob.matrix - - color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy - - file.write('light_source {\n') - file.write('\t< 0,0,0 >\n') - file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color) - - if lamp.type == 'POINT': # Point Lamp - pass - elif lamp.type == 'SPOT': # Spot - file.write('\tspotlight\n') - - # Falloff is the main radius from the centre line - file.write('\tfalloff %.2f\n' % (lamp.spot_size/2.0) ) # 1 TO 179 FOR BOTH - file.write('\tradius %.6f\n' % ((lamp.spot_size/2.0) * (1-lamp.spot_blend)) ) - - # Blender does not have a tightness equivilent, 0 is most like blender default. - file.write('\ttightness 0\n') # 0:10f - - file.write('\tpoint_at <0, 0, -1>\n') - elif lamp.type == 'SUN': - file.write('\tparallel\n') - file.write('\tpoint_at <0, 0, -1>\n') # *must* be after 'parallel' - - elif lamp.type == 'AREA': - - size_x = lamp.size - samples_x = lamp.shadow_ray_samples_x - if lamp.shape == 'SQUARE': - size_y = size_x - samples_y = samples_x - else: - size_y = lamp.size_y - samples_y = lamp.shadow_ray_samples_y - - file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y)) - if lamp.shadow_ray_sampling_method == 'CONSTANT_JITTERED': - if lamp.jitter: - file.write('\tjitter\n') - else: - file.write('\tadaptive 1\n') - file.write('\tjitter\n') - - if lamp.shadow_method == 'NOSHADOW': - file.write('\tshadowless\n') - - file.write('\tfade_distance %.6f\n' % lamp.distance) - file.write('\tfade_power %d\n' % 1) # Could use blenders lamp quad? - writeMatrix(matrix) - - file.write('}\n') - - def exportMeta(metas): - - # TODO - blenders 'motherball' naming is not supported. - - for ob in metas: - meta = ob.data - - file.write('blob {\n') - file.write('\t\tthreshold %.4g\n' % meta.threshold) - - try: - material= meta.materials[0] # lame! - blender cant do enything else. - except: - material= None - - for elem in meta.elements: - - if elem.type not in ('BALL', 'ELLIPSOID'): - continue # Not supported - - loc = elem.location - - stiffness= elem.stiffness - if elem.negative: - stiffness = -stiffness - - if elem.type == 'BALL': - - file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x, loc.y, loc.z, elem.radius, stiffness)) - - # After this wecould do something simple like... - # "pigment {Blue} }" - # except we'll write the color - - elif elem.type == 'ELLIPSOID': - # location is modified by scale - file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x/elem.size_x, loc.y/elem.size_y, loc.z/elem.size_z, elem.radius, stiffness)) - file.write( 'scale <%.6g, %.6g, %.6g> ' % (elem.size_x, elem.size_y, elem.size_z)) - - if material: - diffuse_color = material.diffuse_color - - if material.transparency and material.transparency_method=='RAYTRACE': trans = 1-material.raytrace_transparency.filter - else: trans = 0.0 - - file.write( - 'pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s} }\n' % \ - (diffuse_color[0], diffuse_color[1], diffuse_color[2], 1-material.alpha, trans, materialNames[material.name]) - ) - - else: - file.write('pigment {rgb<1 1 1>} finish {%s} }\n' % DEF_MAT_NAME) # Write the finish last. - - writeObjectMaterial(material) - - writeMatrix(ob.matrix) - - file.write('}\n') - - def exportMeshs(sel): - - ob_num = 0 - - for ob in sel: - ob_num+= 1 - - if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META'): - continue - - me = ob.data - me_materials= me.materials - - me = ob.create_mesh(True, 'RENDER') - - if not me: - continue - - if info_callback: - info_callback('Object %2.d of %2.d (%s)' % (ob_num, len(sel), ob.name)) - - #if ob.type!='MESH': - # continue - # me = ob.data - - matrix = ob.matrix - try: uv_layer = me.active_uv_texture.data - except:uv_layer = None - - try: vcol_layer = me.active_vertex_color.data - except:vcol_layer = None - - faces_verts = [f.verts for f in me.faces] - faces_normals = [tuple(f.normal) for f in me.faces] - verts_normals = [tuple(v.normal) for v in me.verts] - - # quads incur an extra face - quadCount = len([f for f in faces_verts if len(f)==4]) - - file.write('mesh2 {\n') - file.write('\tvertex_vectors {\n') - file.write('\t\t%s' % (len(me.verts))) # vert count - for v in me.verts: - file.write(',\n\t\t<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count - file.write('\n }\n') - - - # Build unique Normal list - uniqueNormals = {} - for fi, f in enumerate(me.faces): - fv = faces_verts[fi] - # [-1] is a dummy index, use a list so we can modify in place - if f.smooth: # Use vertex normals - for v in fv: - key = verts_normals[v] - uniqueNormals[key] = [-1] - else: # Use face normal - key = faces_normals[fi] - uniqueNormals[key] = [-1] - - file.write('\tnormal_vectors {\n') - file.write('\t\t%d' % len(uniqueNormals)) # vert count - idx = 0 - for no, index in uniqueNormals.items(): - file.write(',\n\t\t<%.6f, %.6f, %.6f>' % no) # vert count - index[0] = idx - idx +=1 - file.write('\n }\n') - - - # Vertex colours - vertCols = {} # Use for material colours also. - - if uv_layer: - # Generate unique UV's - uniqueUVs = {} - - for fi, uv in enumerate(uv_layer): - - if len(faces_verts[fi])==4: - uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4 - else: - uvs = uv.uv1, uv.uv2, uv.uv3 - - for uv in uvs: - uniqueUVs[tuple(uv)] = [-1] - - file.write('\tuv_vectors {\n') - #print unique_uvs - file.write('\t\t%s' % (len(uniqueUVs))) # vert count - idx = 0 - for uv, index in uniqueUVs.items(): - file.write(',\n\t\t<%.6f, %.6f>' % uv) - index[0] = idx - idx +=1 - ''' - else: - # Just add 1 dummy vector, no real UV's - file.write('\t\t1') # vert count - file.write(',\n\t\t<0.0, 0.0>') - ''' - file.write('\n }\n') - - - if me.vertex_colors: - - for fi, f in enumerate(me.faces): - material_index = f.material_index - material = me_materials[material_index] - - if material and material.vertex_color_paint: - - col = vcol_layer[fi] - - if len(faces_verts[fi])==4: - cols = col.color1, col.color2, col.color3, col.color4 - else: - cols = col.color1, col.color2, col.color3 - - for col in cols: - key = col[0], col[1], col[2], material_index # Material index! - vertCols[key] = [-1] - - else: - if material: - diffuse_color = tuple(material.diffuse_color) - key = diffuse_color[0], diffuse_color[1], diffuse_color[2], material_index - vertCols[key] = [-1] - - - else: - # No vertex colours, so write material colours as vertex colours - for i, material in enumerate(me_materials): - - if material: - diffuse_color = tuple(material.diffuse_color) - key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat - vertCols[key] = [-1] - - - # Vert Colours - file.write('\ttexture_list {\n') - file.write('\t\t%s' % (len(vertCols))) # vert count - idx=0 - for col, index in vertCols.items(): - - if me_materials: - material = me_materials[col[3]] - material_finish = materialNames[material.name] - - if material.transparency and material.transparency_method=='RAYTRACE': trans = 1-material.raytrace_transparency.filter - else: trans = 0.0 - - else: - material_finish = DEF_MAT_NAME # not working properly, - trans = 0.0 - - #print material.apl - file.write( ',\n\t\ttexture { pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s}}' % - (col[0], col[1], col[2], 1-material.alpha, trans, material_finish) ) - - index[0] = idx - idx+=1 - - file.write( '\n }\n' ) - - # Face indicies - file.write('\tface_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, f in enumerate(me.faces): - fv = faces_verts[fi] - material_index= f.material_index - if len(fv) == 4: indicies = (0,1,2), (0,2,3) - else: indicies = ((0,1,2),) - - if vcol_layer: - col = vcol_layer[fi] - - if len(fv) == 4: - cols = col.color1, col.color2, col.color3, col.color4 - else: - cols = col.color1, col.color2, col.color3 - - - if not me_materials or me_materials[material_index] == None: # No materials - for i1, i2, i3 in indicies: - file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count - else: - material = me_materials[material_index] - for i1, i2, i3 in indicies: - if me.vertex_colors and material.vertex_color_paint: - # Colour per vertex - vertex colour - - col1 = cols[i1] - col2 = cols[i2] - col3 = cols[i3] - - ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0] - ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0] - ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0] - else: - # Colour per material - flat material colour - diffuse_color= material.diffuse_color - ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0] - - file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count - - - file.write('\n }\n') - - # normal_indices indicies - file.write('\tnormal_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, fv in enumerate(faces_verts): - - if len(fv) == 4: indicies = (0,1,2), (0,2,3) - else: indicies = ((0,1,2),) - - for i1, i2, i3 in indicies: - if f.smooth: - file.write(',\n\t\t<%d,%d,%d>' %\ - (uniqueNormals[verts_normals[fv[i1]]][0],\ - uniqueNormals[verts_normals[fv[i2]]][0],\ - uniqueNormals[verts_normals[fv[i3]]][0])) # vert count - else: - idx = uniqueNormals[faces_normals[fi]][0] - file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count - - file.write('\n }\n') - - if uv_layer: - file.write('\tuv_indices {\n') - file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count - for fi, fv in enumerate(faces_verts): - - if len(fv) == 4: indicies = (0,1,2), (0,2,3) - else: indicies = ((0,1,2),) - - uv = uv_layer[fi] - if len(faces_verts[fi])==4: - uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4) - else: - uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3) - - for i1, i2, i3 in indicies: - file.write(',\n\t\t<%d,%d,%d>' %\ - (uniqueUVs[uvs[i1]][0],\ - uniqueUVs[uvs[i2]][0],\ - uniqueUVs[uvs[i2]][0])) # vert count - file.write('\n }\n') - - if me.materials: - material = me.materials[0] # dodgy - writeObjectMaterial(material) - - writeMatrix(matrix) - file.write('}\n') - - bpy.data.remove_mesh(me) - - def exportWorld(world): - if not world: - return - - mist = world.mist - - if mist.enabled: - file.write('fog {\n') - file.write('\tdistance %.6f\n' % mist.depth) - file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1-mist.intensity,))) - #file.write('\tfog_offset %.6f\n' % mist.start) - #file.write('\tfog_alt 5\n') - #file.write('\tturbulence 0.2\n') - #file.write('\tturb_depth 0.3\n') - file.write('\tfog_type 1\n') - file.write('}\n') - - def exportGlobalSettings(scene): - - file.write('global_settings {\n') - - if scene.pov_radio_enable: - file.write('\tradiosity {\n') - file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout) - file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample) - file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness) - file.write("\t\tcount %d\n" % scene.pov_radio_count) - file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound) - file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold) - file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor) - file.write("\t\tmedia %d\n" % scene.pov_radio_media) - file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse) - file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count) - file.write("\t\tnormal %d\n" % scene.pov_radio_normal) - file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit) - file.write('\t}\n') - - if world: - file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color)) - - file.write('}\n') - - - # Convert all materials to strings we can access directly per vertex. - writeMaterial(None) # default material - - for material in bpy.data.materials: - writeMaterial(material) - - exportCamera() - #exportMaterials() - sel = scene.objects - exportLamps([l for l in sel if l.type == 'LAMP']) - exportMeta([l for l in sel if l.type == 'META']) - exportMeshs(sel) - exportWorld(scene.world) - exportGlobalSettings(scene) - - file.close() - -def write_pov_ini(filename_ini, filename_pov, filename_image): - scene = bpy.data.scenes[0] - render = scene.render_data - - x= int(render.resolution_x*render.resolution_percentage*0.01) - y= int(render.resolution_y*render.resolution_percentage*0.01) - - file = open(filename_ini, 'w') - - file.write('Input_File_Name="%s"\n' % filename_pov) - file.write('Output_File_Name="%s"\n' % filename_image) - - file.write('Width=%d\n' % x) - file.write('Height=%d\n' % y) - - # Needed for border render. - ''' - file.write('Start_Column=%d\n' % part.x) - file.write('End_Column=%d\n' % (part.x+part.w)) - - file.write('Start_Row=%d\n' % (part.y)) - file.write('End_Row=%d\n' % (part.y+part.h)) - ''' - - file.write('Display=0\n') - file.write('Pause_When_Done=0\n') - file.write('Output_File_Type=T\n') # TGA, best progressive loading - file.write('Output_Alpha=1\n') - - if render.antialiasing: - aa_mapping = {'OVERSAMPLE_5':2, 'OVERSAMPLE_8':3, 'OVERSAMPLE_11':4, 'OVERSAMPLE_16':5} # method 1 assumed - file.write('Antialias=1\n') - file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples]) - else: - file.write('Antialias=0\n') - - file.close() - -# Radiosity panel, use in the scene for now. -FloatProperty= bpy.types.Scene.FloatProperty -IntProperty= bpy.types.Scene.IntProperty -BoolProperty= bpy.types.Scene.BoolProperty - -# Not a real pov option, just to know if we should write -BoolProperty( attr="pov_radio_enable", - name="Enable Radiosity", - description="Enable povrays radiosity calculation.", - default= False) -BoolProperty( attr="pov_radio_display_advanced", - name="Advanced Options", - description="Show advanced options.", - default= False) - -# Real pov options -FloatProperty( attr="pov_radio_adc_bailout", - name="ADC Bailout", - description="The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results.", - min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default= 0.01) - -BoolProperty( attr="pov_radio_always_sample", - name="Always Sample", - description="Only use the data from the pretrace step and not gather any new samples during the final radiosity pass..", - default= True) - -FloatProperty( attr="pov_radio_brightness", - name="Brightness", - description="Ammount objects are brightened before being returned upwards to the rest of the system.", - min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default= 1.0) - -IntProperty( attr="pov_radio_count", - name="Ray Count", - description="number of rays that are sent out whenever a new radiosity value has to be calculated.", - min=1, max=1600, default= 35) - -FloatProperty( attr="pov_radio_error_bound", - name="Error Bound", - description="one of the two main speed/quality tuning values, lower values are more accurate.", - min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default= 1.8) - -FloatProperty( attr="pov_radio_gray_threshold", - name="Gray Threshold", - description="one of the two main speed/quality tuning values, lower values are more accurate.", - min=0.0, max=1.0, soft_min=0, soft_max=1, default= 0.0) - -FloatProperty( attr="pov_radio_low_error_factor", - name="Low Error Factor", - description="If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting.", - min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default= 0.5) - -# max_sample - not available yet -BoolProperty( attr="pov_radio_media", - name="Media", - description="Radiosity estimation can be affected by media.", - default= False) - -FloatProperty( attr="pov_radio_minimum_reuse", - name="Minimum Reuse", - description="Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors).", - min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default= 0.015) - -IntProperty( attr="pov_radio_nearest_count", - name="Nearest Count", - description="Number of old ambient values blended together to create a new interpolated value.", - min=1, max=20, default= 5) - -BoolProperty( attr="pov_radio_normal", - name="Normals", - description="Radiosity estimation can be affected by normals.", - default= False) - -IntProperty( attr="pov_radio_recursion_limit", - name="Recursion Limit", - description="how many recursion levels are used to calculate the diffuse inter-reflection.", - min=1, max=20, default= 3) - - -class PovrayRender(bpy.types.RenderEngine): - __idname__ = 'POVRAY_RENDER' - __label__ = "Povray" - DELAY = 0.02 - - def _export(self, scene): - import tempfile - - self.temp_file_in = tempfile.mktemp(suffix='.pov') - self.temp_file_out = tempfile.mktemp(suffix='.tga') - self.temp_file_ini = tempfile.mktemp(suffix='.ini') - ''' - self.temp_file_in = '/test.pov' - self.temp_file_out = '/test.tga' - self.temp_file_ini = '/test.ini' - ''' - - def info_callback(txt): - self.update_stats("", "POVRAY: " + txt) - - write_pov(self.temp_file_in, scene, info_callback) - - def _render(self): - - try: os.remove(self.temp_file_out) # so as not to load the old file - except: pass - - write_pov_ini(self.temp_file_ini, self.temp_file_in, self.temp_file_out) - - print ("***-STARTING-***") - - pov_binary = "povray" - - if sys.platform=='win32': - import winreg - regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\POV-Ray\\v3.6\\Windows') - - if bitness == 64: - pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine64' - else: - pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine' - - if 1: - self.process = subprocess.Popen([pov_binary, self.temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE - else: - # This works too but means we have to wait until its done - os.system('%s %s' % (pov_binary, self.temp_file_ini)) - - print ("***-DONE-***") - - def _cleanup(self): - for f in (self.temp_file_in, self.temp_file_ini, self.temp_file_out): - try: os.remove(f) - except: pass - - self.update_stats("", "") - - def render(self, scene): - - self.update_stats("", "POVRAY: Exporting data from Blender") - self._export(scene) - self.update_stats("", "POVRAY: Parsing File") - self._render() - - r = scene.render_data - - # compute resolution - x= int(r.resolution_x*r.resolution_percentage*0.01) - y= int(r.resolution_y*r.resolution_percentage*0.01) - - # Wait for the file to be created - while not os.path.exists(self.temp_file_out): - if self.test_break(): - try: self.process.terminate() - except: pass - break - - if self.process.poll() != None: - self.update_stats("", "POVRAY: Failed") - break - - time.sleep(self.DELAY) - - if os.path.exists(self.temp_file_out): - - self.update_stats("", "POVRAY: Rendering") - - prev_size = -1 - - def update_image(): - result = self.begin_result(0, 0, x, y) - lay = result.layers[0] - # possible the image wont load early on. - try: lay.load_from_file(self.temp_file_out) - except: pass - self.end_result(result) - - # Update while povray renders - while True: - - # test if povray exists - if self.process.poll() != None: - update_image(); - break - - # user exit - if self.test_break(): - try: self.process.terminate() - except: pass - - break - - # Would be nice to redirect the output - # stdout_value, stderr_value = self.process.communicate() # locks - - - # check if the file updated - new_size = os.path.getsize(self.temp_file_out) - - if new_size != prev_size: - update_image() - prev_size = new_size - - time.sleep(self.DELAY) - - self._cleanup() - -bpy.types.register(PovrayRender) - -# Use some of the existing buttons. -import buttons_scene -buttons_scene.SCENE_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_scene.SCENE_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_scene.SCENE_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_scene.SCENE_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER') -del buttons_scene - -# Use only a subset of the world panels -import buttons_world -buttons_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER') -buttons_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER') -del buttons_world - -# Example of wrapping every class 'as is' -import buttons_material -for member in dir(buttons_material): - subclass = getattr(buttons_material, member) - try: subclass.COMPAT_ENGINES.add('POVRAY_RENDER') - except: pass -del buttons_material - -class RenderButtonsPanel(bpy.types.Panel): - __space_type__ = 'PROPERTIES' - __region_type__ = 'WINDOW' - __context__ = "scene" - # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - def poll(self, context): - rd = context.scene.render_data - return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) - -class SCENE_PT_povray_radiosity(RenderButtonsPanel): - __label__ = "Radiosity" - COMPAT_ENGINES = set(['POVRAY_RENDER']) - - def draw_header(self, context): - scene = context.scene - - self.layout.itemR(scene, "pov_radio_enable", text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render_data - - layout.active = scene.pov_radio_enable - - split = layout.split() - - col = split.column() - col.itemR(scene, "pov_radio_count", text="Rays") - col.itemR(scene, "pov_radio_recursion_limit", text="Recursions") - col = split.column() - col.itemR(scene, "pov_radio_error_bound", text="Error") - - layout.itemR(scene, "pov_radio_display_advanced") - - if scene.pov_radio_display_advanced: - split = layout.split() - - col = split.column() - col.itemR(scene, "pov_radio_adc_bailout", slider=True) - col.itemR(scene, "pov_radio_gray_threshold", slider=True) - col.itemR(scene, "pov_radio_low_error_factor", slider=True) - - col = split.column() - col.itemR(scene, "pov_radio_brightness") - col.itemR(scene, "pov_radio_minimum_reuse", text="Min Reuse") - col.itemR(scene, "pov_radio_nearest_count") - - split = layout.split() - - col = split.column() - col.itemL(text="Estimation Influence:") - col.itemR(scene, "pov_radio_media") - col.itemR(scene, "pov_radio_normal") - - col = split.column() - col.itemR(scene, "pov_radio_always_sample") - -bpy.types.register(SCENE_PT_povray_radiosity) diff --git a/release/io/export_3ds.py b/release/io/export_3ds.py deleted file mode 100644 index 19c12146769..00000000000 --- a/release/io/export_3ds.py +++ /dev/null @@ -1,1128 +0,0 @@ -#!BPY -# coding: utf-8 -""" -Name: '3D Studio (.3ds)...' -Blender: 243 -Group: 'Export' -Tooltip: 'Export to 3DS file format (.3ds).' -""" - -__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] -__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") -__version__ = "0.90a" -__bpydoc__ = """\ - -3ds Exporter - -This script Exports a 3ds file. - -Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information -from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Bob Holcomb -# -# 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 ***** -# -------------------------------------------------------------------------- - - -###################################################### -# Importing modules -###################################################### - -import struct -import os -import time - -import bpy - -# import Blender -# from BPyMesh import getMeshFromObject -# from BPyObject import getDerivedObjects -# try: -# import struct -# except: -# struct = None - -# also used by X3D exporter -# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() -def create_derived_objects(ob): - if ob.parent and ob.parent.dupli_type != 'NONE': - return False, None - - if ob.dupli_type != 'NONE': - ob.create_dupli_list() - return True, [(dob.object, dob.matrix) for dob in ob.dupli_list] - else: - return False, [(ob, ob.matrix)] - -# also used by X3D exporter -def free_derived_objects(ob): - ob.free_dupli_list() - -# So 3ds max can open files, limit names to 12 in length -# this is verry annoying for filenames! -name_unique = [] -name_mapping = {} -def sane_name(name): - name_fixed = name_mapping.get(name) - if name_fixed != None: - return name_fixed - - if len(name) > 12: - new_name = name[:12] - else: - new_name = name - - i = 0 - - while new_name in name_unique: - new_name = new_name[:-4] + '.%.3d' % i - i+=1 - - name_unique.append(new_name) - name_mapping[name] = new_name - return new_name - -###################################################### -# Data Structures -###################################################### - -#Some of the chunks that we will export -#----- Primary Chunk, at the beginning of each file -PRIMARY= int("0x4D4D",16) - -#------ Main Chunks -OBJECTINFO = int("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information -VERSION = int("0x0002",16); #This gives the version of the .3ds file -KFDATA = int("0xB000",16); #This is the header for all of the key frame info - -#------ sub defines of OBJECTINFO -MATERIAL=45055 #0xAFFF // This stored the texture info -OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... - -#>------ sub defines of MATERIAL -MATNAME = int("0xA000",16); # This holds the material name -MATAMBIENT = int("0xA010",16); # Ambient color of the object/material -MATDIFFUSE = int("0xA020",16); # This holds the color of the object/material -MATSPECULAR = int("0xA030",16); # SPecular color of the object/material -MATSHINESS = int("0xA040",16); # ?? -MATMAP = int("0xA200",16); # This is a header for a new material -MATMAPFILE = int("0xA300",16); # This holds the file name of the texture - -RGB1= int("0x0011",16) -RGB2= int("0x0012",16) - -#>------ sub defines of OBJECT -OBJECT_MESH = int("0x4100",16); # This lets us know that we are reading a new object -OBJECT_LIGHT = int("0x4600",16); # This lets un know we are reading a light object -OBJECT_CAMERA= int("0x4700",16); # This lets un know we are reading a camera object - -#>------ sub defines of CAMERA -OBJECT_CAM_RANGES= int("0x4720",16); # The camera range values - -#>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = int("0x4110",16); # The objects vertices -OBJECT_FACES = int("0x4120",16); # The objects faces -OBJECT_MATERIAL = int("0x4130",16); # This is found if the object has a material, either texture map or color -OBJECT_UV = int("0x4140",16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = int("0x4160",16); # The Object Matrix - -#>------ sub defines of KFDATA -KFDATA_KFHDR = int("0xB00A",16); -KFDATA_KFSEG = int("0xB008",16); -KFDATA_KFCURTIME = int("0xB009",16); -KFDATA_OBJECT_NODE_TAG = int("0xB002",16); - -#>------ sub defines of OBJECT_NODE_TAG -OBJECT_NODE_ID = int("0xB030",16); -OBJECT_NODE_HDR = int("0xB010",16); -OBJECT_PIVOT = int("0xB013",16); -OBJECT_INSTANCE_NAME = int("0xB011",16); -POS_TRACK_TAG = int("0xB020",16); -ROT_TRACK_TAG = int("0xB021",16); -SCL_TRACK_TAG = int("0xB022",16); - -def uv_key(uv): - return round(uv[0], 6), round(uv[1], 6) -# return round(uv.x, 6), round(uv.y, 6) - -# size defines: -SZ_SHORT = 2 -SZ_INT = 4 -SZ_FLOAT = 4 - -class _3ds_short(object): - '''Class representing a short (2-byte integer) for a 3ds file. - *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' - __slots__ = 'value' - def __init__(self, val=0): - self.value=val - - def get_size(self): - return SZ_SHORT - - def write(self,file): - file.write(struct.pack("= mat_ls_len: - mat_index = f.mat = 0 - mat = mat_ls[mat_index] - if mat: mat_name = mat.name - else: mat_name = None - # else there alredy set to none - - img = uf.image -# img = f.image - if img: img_name = img.name - else: img_name = None - - materialDict.setdefault((mat_name, img_name), (mat, img) ) - - - else: - for mat in mat_ls: - if mat: # material may be None so check its not. - materialDict.setdefault((mat.name, None), (mat, None) ) - - # Why 0 Why! - for f in data.faces: - if f.material_index >= mat_ls_len: -# if f.mat >= mat_ls_len: - f.material_index = 0 - # f.mat = 0 - - if free: - free_derived_objects(ob) - - - # Make material chunks for all materials used in the meshes: - for mat_and_image in materialDict.values(): - object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) - - # Give all objects a unique ID and build a dictionary from object name to object id: - """ - name_to_id = {} - for ob, data in mesh_objects: - name_to_id[ob.name]= len(name_to_id) - #for ob in empty_objects: - # name_to_id[ob.name]= len(name_to_id) - """ - - # Create object chunks for all meshes: - i = 0 - for ob, blender_mesh in mesh_objects: - # create a new object chunk - object_chunk = _3ds_chunk(OBJECT) - - # set the object name - object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) - - # make a mesh chunk out of the mesh: - object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) - object_info.add_subchunk(object_chunk) - - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - # make a kf object node for the object: - kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) - ''' -# if not blender_mesh.users: - bpy.data.remove_mesh(blender_mesh) -# blender_mesh.verts = None - - i+=i - - # Create chunks for all empties: - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - for ob in empty_objects: - # Empties only require a kf object node: - kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) - pass - ''' - - # Add main object info chunk to primary chunk: - primary.add_subchunk(object_info) - - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - # Add main keyframe data chunk to primary chunk: - primary.add_subchunk(kfdata) - ''' - - # At this point, the chunk hierarchy is completely built. - - # Check the size: - primary.get_size() - # Open the file for writing: - file = open( filename, 'wb' ) - - # Recursively write the chunks to file: - primary.write(file) - - # Close the file: - file.close() - - # Debugging only: report the exporting time: -# Blender.Window.WaitCursor(0) - print("3ds export time: %.2f" % (time.clock() - time1)) -# print("3ds export time: %.2f" % (Blender.sys.time() - time1)) - - # Debugging only: dump the chunk hierarchy: - #primary.dump() - - -# if __name__=='__main__': -# if struct: -# Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) -# else: -# Blender.Draw.PupMenu("Error%t|This script requires a full python installation") -# # save_3ds('/test_b.3ds') - -class EXPORT_OT_3ds(bpy.types.Operator): - ''' - 3DS Exporter - ''' - __idname__ = "export.3ds" - __label__ = 'Export 3DS' - - # 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 3DS file", maxlen= 1024, default= ""), - ] - - def execute(self, context): - save_3ds(self.filename, context) - 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_3ds) diff --git a/release/io/export_fbx.py b/release/io/export_fbx.py deleted file mode 100644 index aa65473b8d6..00000000000 --- a/release/io/export_fbx.py +++ /dev/null @@ -1,3457 +0,0 @@ -#!BPY -""" -Name: 'Autodesk FBX (.fbx)...' -Blender: 249 -Group: 'Export' -Tooltip: 'Selection to an ASCII Autodesk FBX ' -""" -__author__ = "Campbell Barton" -__url__ = ['www.blender.org', 'blenderartists.org'] -__version__ = "1.2" - -__bpydoc__ = """\ -This script is an exporter to the FBX file format. - -http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx -""" -# -------------------------------------------------------------------------- -# FBX Export v0.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 os -import time -import math # math.pi -import shutil # for file copying - -# try: -# import time -# # import os # only needed for batch export, nbot used yet -# except: -# time = None # use this to check if they have python modules installed - -# for python 2.3 support -try: - set() -except: - try: - from sets import Set as set - except: - set = None # so it complains you dont have a ! - -# # os is only needed for batch 'own dir' option -# try: -# import os -# except: -# os = None - -# import Blender -import bpy -import Mathutils -# from Blender.Mathutils import Matrix, Vector, RotationMatrix - -# import BPyObject -# import BPyMesh -# import BPySys -# import BPyMessages - -## This was used to make V, but faster not to do all that -##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' -##v = range(255) -##for c in valid: v.remove(ord(c)) -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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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]) -def cleanName(name): - for ch in invalid: name = name.replace(ch, '_') - return name -# del v, i - - -def copy_file(source, dest): - file = open(source, 'rb') - data = file.read() - file.close() - - file = open(dest, 'wb') - file.write(data) - file.close() - - -# XXX not used anymore, images are copied one at a time -def copy_images(dest_dir, textures): - if not dest_dir.endswith(os.sep): - dest_dir += os.sep - - image_paths = set() - for tex in textures: - image_paths.add(Blender.sys.expandpath(tex.filename)) - - # Now copy images - copyCount = 0 - for image_path in image_paths: - if Blender.sys.exists(image_path): - # Make a name for the target path. - dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] - if not Blender.sys.exists(dest_image_path): # Image isnt alredy there - print('\tCopying "%s" > "%s"' % (image_path, dest_image_path)) - try: - copy_file(image_path, dest_image_path) - copyCount+=1 - except: - print('\t\tWarning, file failed to copy, skipping.') - - print('\tCopied %d images' % copyCount) - -# I guess FBX uses degrees instead of radians (Arystan). -# Call this function just before writing to FBX. -def eulerRadToDeg(eul): - ret = Mathutils.Euler() - - ret.x = 180 / math.pi * eul[0] - ret.y = 180 / math.pi * eul[1] - ret.z = 180 / math.pi * eul[2] - - return ret - -mtx4_identity = Mathutils.Matrix() - -# testing -mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'x') # used -#mtx_x90n = RotationMatrix(-90, 3, 'x') -#mtx_y90 = RotationMatrix( 90, 3, 'y') -#mtx_y90n = RotationMatrix(-90, 3, 'y') -#mtx_z90 = RotationMatrix( 90, 3, 'z') -#mtx_z90n = RotationMatrix(-90, 3, 'z') - -#mtx4_x90 = RotationMatrix( 90, 4, 'x') -mtx4_x90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'x') # used -#mtx4_y90 = RotationMatrix( 90, 4, 'y') -mtx4_y90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'y') # used -mtx4_z90 = Mathutils.RotationMatrix( math.pi/2, 4, 'z') # used -mtx4_z90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'z') # used - -# def strip_path(p): -# return p.split('\\')[-1].split('/')[-1] - -# Used to add the scene name into the filename without using odd chars -sane_name_mapping_ob = {} -sane_name_mapping_mat = {} -sane_name_mapping_tex = {} -sane_name_mapping_take = {} -sane_name_mapping_group = {} - -# Make sure reserved names are not used -sane_name_mapping_ob['Scene'] = 'Scene_' -sane_name_mapping_ob['blend_root'] = 'blend_root_' - -def increment_string(t): - name = t - num = '' - while name and name[-1].isdigit(): - num = name[-1] + num - name = name[:-1] - if num: return '%s%d' % (name, int(num)+1) - else: return name + '_0' - - - -# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. -def sane_name(data, dct): - #if not data: return None - - if type(data)==tuple: # materials are paired up with images - data, other = data - use_other = True - else: - other = None - use_other = False - - if data: name = data.name - else: name = None - orig_name = name - - if other: - orig_name_other = other.name - name = '%s #%s' % (name, orig_name_other) - else: - orig_name_other = None - - # dont cache, only ever call once for each data type now, - # so as to avoid namespace collision between types - like with objects <-> bones - #try: return dct[name] - #except: pass - - if not name: - name = 'unnamed' # blank string, ASKING FOR TROUBLE! - else: - #name = BPySys.cleanName(name) - name = cleanName(name) # use our own - - while name in iter(dct.values()): name = increment_string(name) - - if use_other: # even if other is None - orig_name_other will be a string or None - dct[orig_name, orig_name_other] = name - else: - dct[orig_name] = name - - return name - -def sane_obname(data): return sane_name(data, sane_name_mapping_ob) -def sane_matname(data): return sane_name(data, sane_name_mapping_mat) -def sane_texname(data): return sane_name(data, sane_name_mapping_tex) -def sane_takename(data): return sane_name(data, sane_name_mapping_take) -def sane_groupname(data): return sane_name(data, sane_name_mapping_group) - -# def derived_paths(fname_orig, basepath, FORCE_CWD=False): -# ''' -# fname_orig - blender path, can be relative -# basepath - fname_rel will be relative to this -# FORCE_CWD - dont use the basepath, just add a ./ to the filename. -# use when we know the file will be in the basepath. -# ''' -# fname = bpy.sys.expandpath(fname_orig) -# # fname = Blender.sys.expandpath(fname_orig) -# fname_strip = os.path.basename(fname) -# # fname_strip = strip_path(fname) -# if FORCE_CWD: -# fname_rel = '.' + os.sep + fname_strip -# else: -# fname_rel = bpy.sys.relpath(fname, basepath) -# # fname_rel = Blender.sys.relpath(fname, basepath) -# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] -# return fname, fname_strip, fname_rel - - -def mat4x4str(mat): - return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) - -# XXX not used -# duplicated in OBJ exporter -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 - -# ob must be OB_MESH -def BPyMesh_meshWeight2List(ob): - ''' Takes a mesh and return its group names and a list of lists, one list per vertex. - aligning the each vert list with the group names, each list contains float value for the weight. - These 2 lists can be modified and then used with list2MeshWeight to apply the changes. - ''' - - me = ob.data - - # Clear the vert group. - groupNames= [g.name for g in ob.vertex_groups] - len_groupNames= len(groupNames) - - if not len_groupNames: - # no verts? return a vert aligned empty list - return [[] for i in range(len(me.verts))], [] - else: - vWeightList= [[0.0]*len_groupNames for i in range(len(me.verts))] - - for i, v in enumerate(me.verts): - for g in v.groups: - vWeightList[i][g.group] = g.weight - - return groupNames, vWeightList - -def meshNormalizedWeights(me): - try: # account for old bad BPyMesh - groupNames, vWeightList = BPyMesh_meshWeight2List(me) -# groupNames, vWeightList = BPyMesh.meshWeight2List(me) - except: - return [],[] - - if not groupNames: - return [],[] - - for i, vWeights in enumerate(vWeightList): - tot = 0.0 - for w in vWeights: - tot+=w - - if tot: - for j, w in enumerate(vWeights): - vWeights[j] = w/tot - - return groupNames, vWeightList - -header_comment = \ -'''; FBX 6.1.0 project file -; Created by Blender FBX Exporter -; for support mail: ideasman42@gmail.com -; ---------------------------------------------------- - -''' - -# This func can be called with just the filename -def write(filename, batch_objects = None, \ - context = None, - EXP_OBS_SELECTED = True, - EXP_MESH = True, - EXP_MESH_APPLY_MOD = True, -# EXP_MESH_HQ_NORMALS = False, - EXP_ARMATURE = True, - EXP_LAMP = True, - EXP_CAMERA = True, - EXP_EMPTY = True, - EXP_IMAGE_COPY = False, - GLOBAL_MATRIX = Mathutils.Matrix(), - ANIM_ENABLE = True, - ANIM_OPTIMIZE = True, - ANIM_OPTIMIZE_PRECISSION = 6, - ANIM_ACTION_ALL = False, - BATCH_ENABLE = False, - BATCH_GROUP = True, - BATCH_FILE_PREFIX = '', - BATCH_OWN_DIR = False - ): - - # ----------------- Batch support! - if BATCH_ENABLE: - if os == None: BATCH_OWN_DIR = False - - fbxpath = filename - - # get the path component of filename - tmp_exists = bpy.sys.exists(fbxpath) -# tmp_exists = Blender.sys.exists(fbxpath) - - if tmp_exists != 2: # a file, we want a path - fbxpath = os.path.dirname(fbxpath) -# while fbxpath and fbxpath[-1] not in ('/', '\\'): -# fbxpath = fbxpath[:-1] - if not fbxpath: -# if not filename: - # XXX - print('Error%t|Directory does not exist!') -# Draw.PupMenu('Error%t|Directory does not exist!') - return - - tmp_exists = bpy.sys.exists(fbxpath) -# tmp_exists = Blender.sys.exists(fbxpath) - - if tmp_exists != 2: - # XXX - print('Error%t|Directory does not exist!') -# Draw.PupMenu('Error%t|Directory does not exist!') - return - - if not fbxpath.endswith(os.sep): - fbxpath += os.sep - del tmp_exists - - - if BATCH_GROUP: - data_seq = bpy.data.groups - else: - data_seq = bpy.data.scenes - - # call this function within a loop with BATCH_ENABLE == False - orig_sce = context.scene -# orig_sce = bpy.data.scenes.active - - - new_fbxpath = fbxpath # own dir option modifies, we need to keep an original - for data in data_seq: # scene or group - newname = BATCH_FILE_PREFIX + cleanName(data.name) -# newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) - - - if BATCH_OWN_DIR: - new_fbxpath = fbxpath + newname + os.sep - # path may alredy exist - # TODO - might exist but be a file. unlikely but should probably account for it. - - if bpy.sys.exists(new_fbxpath) == 0: -# if Blender.sys.exists(new_fbxpath) == 0: - os.mkdir(new_fbxpath) - - - filename = new_fbxpath + newname + '.fbx' - - print('\nBatch exporting %s as...\n\t"%s"' % (data, filename)) - - # XXX don't know what to do with this, probably do the same? (Arystan) - if BATCH_GROUP: #group - # group, so objects update properly, add a dummy scene. - sce = bpy.data.scenes.new() - sce.Layers = (1<<20) -1 - bpy.data.scenes.active = sce - for ob_base in data.objects: - sce.objects.link(ob_base) - - sce.update(1) - - # TODO - BUMMER! Armatures not in the group wont animate the mesh - - else:# scene - - - data_seq.active = data - - - # Call self with modified args - # Dont pass batch options since we alredy usedt them - write(filename, data.objects, - context, - False, - EXP_MESH, - EXP_MESH_APPLY_MOD, -# EXP_MESH_HQ_NORMALS, - EXP_ARMATURE, - EXP_LAMP, - EXP_CAMERA, - EXP_EMPTY, - EXP_IMAGE_COPY, - GLOBAL_MATRIX, - ANIM_ENABLE, - ANIM_OPTIMIZE, - ANIM_OPTIMIZE_PRECISSION, - ANIM_ACTION_ALL - ) - - if BATCH_GROUP: - # remove temp group scene - bpy.data.remove_scene(sce) -# bpy.data.scenes.unlink(sce) - - bpy.data.scenes.active = orig_sce - - return # so the script wont run after we have batch exported. - - # end batch support - - # Use this for working out paths relative to the export location - basepath = os.path.dirname(filename) or '.' - basepath += os.sep -# basepath = Blender.sys.dirname(filename) - - # ---------------------------------------------- - # storage classes - class my_bone_class: - __slots__ =(\ - 'blenName',\ - 'blenBone',\ - 'blenMeshes',\ - 'restMatrix',\ - 'parent',\ - 'blenName',\ - 'fbxName',\ - 'fbxArm',\ - '__pose_bone',\ - '__anim_poselist') - - def __init__(self, blenBone, fbxArm): - - # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace - self.fbxName = sane_obname(blenBone) - - self.blenName = blenBone.name - self.blenBone = blenBone - self.blenMeshes = {} # fbxMeshObName : mesh - self.fbxArm = fbxArm - self.restMatrix = blenBone.armature_matrix -# self.restMatrix = blenBone.matrix['ARMATURESPACE'] - - # not used yet - # self.restMatrixInv = self.restMatrix.copy().invert() - # self.restMatrixLocal = None # set later, need parent matrix - - self.parent = None - - # not public - pose = fbxArm.blenObject.pose -# pose = fbxArm.blenObject.getPose() - self.__pose_bone = pose.pose_channels[self.blenName] -# self.__pose_bone = pose.bones[self.blenName] - - # store a list if matricies here, (poseMatrix, head, tail) - # {frame:posematrix, frame:posematrix, ...} - self.__anim_poselist = {} - - ''' - def calcRestMatrixLocal(self): - if self.parent: - self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() - else: - self.restMatrixLocal = self.restMatrix.copy() - ''' - def setPoseFrame(self, f): - # cache pose info here, frame must be set beforehand - - # Didnt end up needing head or tail, if we do - here it is. - ''' - self.__anim_poselist[f] = (\ - self.__pose_bone.poseMatrix.copy(),\ - self.__pose_bone.head.copy(),\ - self.__pose_bone.tail.copy() ) - ''' - - self.__anim_poselist[f] = self.__pose_bone.pose_matrix.copy() -# self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() - - # get pose from frame. - def getPoseMatrix(self, f):# ---------------------------------------------- - return self.__anim_poselist[f] - ''' - def getPoseHead(self, f): - #return self.__pose_bone.head.copy() - return self.__anim_poselist[f][1].copy() - def getPoseTail(self, f): - #return self.__pose_bone.tail.copy() - return self.__anim_poselist[f][2].copy() - ''' - # end - - def getAnimParRelMatrix(self, frame): - #arm_mat = self.fbxArm.matrixWorld - #arm_mat = self.fbxArm.parRelMatrix() - if not self.parent: - #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore - return mtx4_z90 * self.getPoseMatrix(frame) - else: - #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() - return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() - - # we need thes because cameras and lights modified rotations - def getAnimParRelMatrixRot(self, frame): - return self.getAnimParRelMatrix(frame) - - def flushAnimData(self): - self.__anim_poselist.clear() - - - class my_object_generic: - # Other settings can be applied for each type - mesh, armature etc. - def __init__(self, ob, matrixWorld = None): - self.fbxName = sane_obname(ob) - self.blenObject = ob - self.fbxGroupNames = [] - self.fbxParent = None # set later on IF the parent is in the selection. - if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX - else: self.matrixWorld = ob.matrix * GLOBAL_MATRIX -# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX - self.__anim_poselist = {} # we should only access this - - def parRelMatrix(self): - if self.fbxParent: - return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() - else: - return self.matrixWorld - - def setPoseFrame(self, f): - self.__anim_poselist[f] = self.blenObject.matrix.copy() -# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() - - def getAnimParRelMatrix(self, frame): - if self.fbxParent: - #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX - return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() - else: - return self.__anim_poselist[frame] * GLOBAL_MATRIX - - def getAnimParRelMatrixRot(self, frame): - type = self.blenObject.type - if self.fbxParent: - matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() - else: - matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() - - # Lamps need to be rotated - if type =='LAMP': - matrix_rot = mtx_x90 * matrix_rot - elif type =='CAMERA': -# elif ob and type =='Camera': - y = Mathutils.Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) - - return matrix_rot - - # ---------------------------------------------- - - - - - - print('\nFBX export starting...', filename) - start_time = time.clock() -# start_time = Blender.sys.time() - try: - file = open(filename, 'w') - except: - return False - - sce = context.scene -# sce = bpy.data.scenes.active - world = sce.world - - - # ---------------------------- Write the header first - file.write(header_comment) - if time: - curtime = time.localtime()[0:6] - else: - curtime = (0,0,0,0,0,0) - # - file.write(\ -'''FBXHeaderExtension: { - FBXHeaderVersion: 1003 - FBXVersion: 6100 - CreationTimeStamp: { - Version: 1000 - Year: %.4i - Month: %.2i - Day: %.2i - Hour: %.2i - Minute: %.2i - Second: %.2i - Millisecond: 0 - } - Creator: "FBX SDK/FBX Plugins build 20070228" - OtherFlags: { - FlagPLE: 0 - } -}''' % (curtime)) - - file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) - file.write('\nCreator: "Blender3D version 2.5"') -# file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) - - pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way - - # --------------- funcs for exporting - def object_tx(ob, loc, matrix, matrix_mod = None): - ''' - Matrix mod is so armature objects can modify their bone matricies - ''' - if isinstance(ob, bpy.types.Bone): -# if isinstance(ob, Blender.Types.BoneType): - - # we know we have a matrix - # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) - matrix = mtx4_z90 * ob.armature_matrix # dont apply armature matrix anymore -# matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore - - parent = ob.parent - if parent: - #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) - par_matrix = mtx4_z90 * parent.armature_matrix # dont apply armature matrix anymore -# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore - matrix = matrix * par_matrix.copy().invert() - - matrix_rot = matrix.rotationPart() - - loc = tuple(matrix.translationPart()) - scale = tuple(matrix.scalePart()) - rot = tuple(matrix_rot.toEuler()) - - else: - # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore - #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX - if ob and not matrix: raise Exception("error: this should never happen!") - - matrix_rot = matrix - #if matrix: - # matrix = matrix_scale * matrix - - if matrix: - loc = tuple(matrix.translationPart()) - scale = tuple(matrix.scalePart()) - - matrix_rot = matrix.rotationPart() - # Lamps need to be rotated - if ob and ob.type =='Lamp': - matrix_rot = mtx_x90 * matrix_rot - rot = tuple(matrix_rot.toEuler()) - elif ob and ob.type =='Camera': - y = Mathutils.Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) - rot = tuple(matrix_rot.toEuler()) - else: - rot = tuple(matrix_rot.toEuler()) - else: - if not loc: - loc = 0,0,0 - scale = 1,1,1 - rot = 0,0,0 - - return loc, rot, scale, matrix, matrix_rot - - def write_object_tx(ob, loc, matrix, matrix_mod= None): - ''' - We have loc to set the location if non blender objects that have a location - - matrix_mod is only used for bones at the moment - ''' - loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) - - file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) - file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple(eulerRadToDeg(rot))) -# file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) - file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) - return loc, rot, scale, matrix, matrix_rot - - def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): - # if the type is 0 its an empty otherwise its a mesh - # only difference at the moment is one has a color - file.write(''' - Properties60: { - Property: "QuaternionInterpolate", "bool", "",0 - Property: "Visibility", "Visibility", "A+",1''') - - loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) - - # Rotation order, note, for FBX files Iv loaded normal order is 1 - # setting to zero. - # eEULER_XYZ = 0 - # eEULER_XZY - # eEULER_YZX - # eEULER_YXZ - # eEULER_ZXY - # eEULER_ZYX - - file.write(''' - Property: "RotationOffset", "Vector3D", "",0,0,0 - Property: "RotationPivot", "Vector3D", "",0,0,0 - Property: "ScalingOffset", "Vector3D", "",0,0,0 - Property: "ScalingPivot", "Vector3D", "",0,0,0 - Property: "TranslationActive", "bool", "",0 - Property: "TranslationMin", "Vector3D", "",0,0,0 - Property: "TranslationMax", "Vector3D", "",0,0,0 - Property: "TranslationMinX", "bool", "",0 - Property: "TranslationMinY", "bool", "",0 - Property: "TranslationMinZ", "bool", "",0 - Property: "TranslationMaxX", "bool", "",0 - Property: "TranslationMaxY", "bool", "",0 - Property: "TranslationMaxZ", "bool", "",0 - Property: "RotationOrder", "enum", "",0 - Property: "RotationSpaceForLimitOnly", "bool", "",0 - Property: "AxisLen", "double", "",10 - Property: "PreRotation", "Vector3D", "",0,0,0 - Property: "PostRotation", "Vector3D", "",0,0,0 - Property: "RotationActive", "bool", "",0 - Property: "RotationMin", "Vector3D", "",0,0,0 - Property: "RotationMax", "Vector3D", "",0,0,0 - Property: "RotationMinX", "bool", "",0 - Property: "RotationMinY", "bool", "",0 - Property: "RotationMinZ", "bool", "",0 - Property: "RotationMaxX", "bool", "",0 - Property: "RotationMaxY", "bool", "",0 - Property: "RotationMaxZ", "bool", "",0 - Property: "RotationStiffnessX", "double", "",0 - Property: "RotationStiffnessY", "double", "",0 - Property: "RotationStiffnessZ", "double", "",0 - Property: "MinDampRangeX", "double", "",0 - Property: "MinDampRangeY", "double", "",0 - Property: "MinDampRangeZ", "double", "",0 - Property: "MaxDampRangeX", "double", "",0 - Property: "MaxDampRangeY", "double", "",0 - Property: "MaxDampRangeZ", "double", "",0 - Property: "MinDampStrengthX", "double", "",0 - Property: "MinDampStrengthY", "double", "",0 - Property: "MinDampStrengthZ", "double", "",0 - Property: "MaxDampStrengthX", "double", "",0 - Property: "MaxDampStrengthY", "double", "",0 - Property: "MaxDampStrengthZ", "double", "",0 - Property: "PreferedAngleX", "double", "",0 - Property: "PreferedAngleY", "double", "",0 - Property: "PreferedAngleZ", "double", "",0 - Property: "InheritType", "enum", "",0 - Property: "ScalingActive", "bool", "",0 - Property: "ScalingMin", "Vector3D", "",1,1,1 - Property: "ScalingMax", "Vector3D", "",1,1,1 - Property: "ScalingMinX", "bool", "",0 - Property: "ScalingMinY", "bool", "",0 - Property: "ScalingMinZ", "bool", "",0 - Property: "ScalingMaxX", "bool", "",0 - Property: "ScalingMaxY", "bool", "",0 - Property: "ScalingMaxZ", "bool", "",0 - Property: "GeometricTranslation", "Vector3D", "",0,0,0 - Property: "GeometricRotation", "Vector3D", "",0,0,0 - Property: "GeometricScaling", "Vector3D", "",1,1,1 - Property: "LookAtProperty", "object", "" - Property: "UpVectorProperty", "object", "" - Property: "Show", "bool", "",1 - Property: "NegativePercentShapeSupport", "bool", "",1 - Property: "DefaultAttributeIndex", "int", "",0''') - if ob and not isinstance(ob, bpy.types.Bone): -# if ob and type(ob) != Blender.Types.BoneType: - # Only mesh objects have color - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Size", "double", "",100') - file.write('\n\t\t\tProperty: "Look", "enum", "",1') - - return loc, rot, scale, matrix, matrix_rot - - - # -------------------------------------------- Armatures - #def write_bone(bone, name, matrix_mod): - def write_bone(my_bone): - file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) - file.write('\n\t\tVersion: 232') - - #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] - poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore - pose_items.append( (my_bone.fbxName, poseMatrix) ) - - - # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) - file.write('\n\t\t\tProperty: "Size", "double", "",1') - - #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) - - """ - file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ - ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) - """ - - file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % - (my_bone.blenBone.armature_head - my_bone.blenBone.armature_tail).length) -# (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) - - #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') - file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 1') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Skeleton"') - file.write('\n\t}') - - def write_camera_switch(): - file.write(''' - Model: "Model::Camera Switcher", "CameraSwitcher" { - Version: 232''') - - write_object_props() - file.write(''' - Property: "Color", "Color", "A",0.8,0.8,0.8 - Property: "Camera Index", "Integer", "A+",100 - } - MultiLayer: 0 - MultiTake: 1 - Hidden: "True" - Shading: W - Culling: "CullingOff" - Version: 101 - Name: "Model::Camera Switcher" - CameraId: 0 - CameraName: 100 - CameraIndexName: - }''') - - def write_camera_dummy(name, loc, near, far, proj_type, up): - file.write('\n\tModel: "Model::%s", "Camera" {' % name ) - file.write('\n\t\tVersion: 232') - write_object_props(None, loc) - - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') - file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') - file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') - file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') - file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') - file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') - file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') - file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') - file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') - file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') - file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') - file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') - file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') - file.write('\n\t\t\tProperty: "AspectW", "double", "",320') - file.write('\n\t\t\tProperty: "AspectH", "double", "",200') - file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') - file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') - file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') - file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') - file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) - file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) - file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') - file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') - file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') - file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') - file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') - file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') - file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') - file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') - file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') - file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') - file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') - file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') - file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') - file.write('\n\t\t\tProperty: "Crop", "bool", "",0') - file.write('\n\t\t\tProperty: "Center", "bool", "",1') - file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') - file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') - file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') - file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') - file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') - file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') - file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') - file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') - file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') - file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') - file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') - file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) - file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') - file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') - file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') - file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') - file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') - file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') - file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') - file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tHidden: "True"') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Camera"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) - file.write('\n\t\tUp: %i,%i,%i' % up) - file.write('\n\t\tLookAt: 0,0,0') - file.write('\n\t\tShowInfoOnMoving: 1') - file.write('\n\t\tShowAudio: 0') - file.write('\n\t\tAudioColor: 0,1,0') - file.write('\n\t\tCameraOrthoZoom: 1') - file.write('\n\t}') - - def write_camera_default(): - # This sucks but to match FBX converter its easier to - # write the cameras though they are not needed. - write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) - write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) - write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) - write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) - - def write_camera(my_cam): - ''' - Write a blender camera - ''' - render = sce.render_data - width = render.resolution_x - height = render.resolution_y -# render = sce.render -# width = render.sizeX -# height = render.sizeY - aspect = float(width)/height - - data = my_cam.blenObject.data - - file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) - file.write('\n\t\tVersion: 232') - loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) - - file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') - file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) - file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') - file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units? -# file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? - file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto -# file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto - file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') - file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') - file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') - file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') - file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') - file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') - file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') - file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') - file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) - file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) - - '''Camera aspect ratio modes. - 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. - 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. - 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. - 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. - 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. - - Definition at line 234 of file kfbxcamera.h. ''' - - file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') - - file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') - file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') - file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') - file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clip_start) -# file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) - file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clip_end) -# file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) - file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') - file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') - file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) - file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') - file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') - file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') - file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') - file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') - file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') - file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') - file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') - file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') - file.write('\n\t\t\tProperty: "Crop", "bool", "",0') - file.write('\n\t\t\tProperty: "Center", "bool", "",1') - file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') - file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') - file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') - file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') - file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') - file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') - file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) - file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') - file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') - file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') - file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') - file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') - file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') - file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') - file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') - file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') - file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') - file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') - file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') - - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Camera"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) - file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,1,0) * matrix_rot) ) - file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,0,-1)*matrix_rot) ) - - #file.write('\n\t\tUp: 0,0,0' ) - #file.write('\n\t\tLookAt: 0,0,0' ) - - file.write('\n\t\tShowInfoOnMoving: 1') - file.write('\n\t\tShowAudio: 0') - file.write('\n\t\tAudioColor: 0,1,0') - file.write('\n\t\tCameraOrthoZoom: 1') - file.write('\n\t}') - - def write_light(my_light): - light = my_light.blenObject.data - file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) - file.write('\n\t\tVersion: 232') - - write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) - - # Why are these values here twice?????? - oh well, follow the holy sdk's output - - # Blender light types match FBX's, funny coincidence, we just need to - # be sure that all unsupported types are made into a point light - #ePOINT, - #eDIRECTIONAL - #eSPOT - light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 4} - light_type = light_type_items[light.type] -# light_type = light.type - if light_type > 2: light_type = 1 # hemi and area lights become directional - -# mode = light.mode - if light.shadow_method == 'RAY_SHADOW' or light.shadow_method == 'BUFFER_SHADOW': -# if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: - do_shadow = 1 - else: - do_shadow = 0 - - if light.only_shadow or (not light.diffuse and not light.specular): -# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): - do_light = 0 - else: - do_light = 1 - - scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case - - file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) - file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') - file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') - file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 - if light.type == 'SPOT': - file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spot_size * scale)) -# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) - file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') - file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.color)) -# file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 -# - # duplication? see ^ (Arystan) -# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) - file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') - file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) - file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) - file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') - file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') - file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') - file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') - file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.distance) -# file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) - file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') - file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') - file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') - file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') - file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') - file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') - file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) - file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Light"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t}') - - # matrixOnly is not used at the moment - def write_null(my_null = None, fbxName = None, matrixOnly = None): - # ob can be null - if not fbxName: fbxName = my_null.fbxName - - file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) - file.write('\n\t\tVersion: 232') - - # only use this for the root matrix at the moment - if matrixOnly: - poseMatrix = write_object_props(None, None, matrixOnly)[3] - - else: # all other Null's - if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] - else: poseMatrix = write_object_props()[3] - - pose_items.append((fbxName, poseMatrix)) - - file.write(''' - } - MultiLayer: 0 - MultiTake: 1 - Shading: Y - Culling: "CullingOff" - TypeFlags: "Null" - }''') - - # Material Settings - if world: world_amb = tuple(world.ambient_color) -# if world: world_amb = world.getAmb() - else: world_amb = (0,0,0) # Default value - - def write_material(matname, mat): - file.write('\n\tMaterial: "Material::%s", "" {' % matname) - - # Todo, add more material Properties. - if mat: - mat_cold = tuple(mat.diffuse_color) -# mat_cold = tuple(mat.rgbCol) - mat_cols = tuple(mat.specular_color) -# mat_cols = tuple(mat.specCol) - #mat_colm = tuple(mat.mirCol) # we wont use the mirror color - mat_colamb = world_amb -# mat_colamb = tuple([c for c in world_amb]) - - mat_dif = mat.diffuse_reflection -# mat_dif = mat.ref - mat_amb = mat.ambient -# mat_amb = mat.amb - mat_hard = (float(mat.specular_hardness)-1)/5.10 -# mat_hard = (float(mat.hard)-1)/5.10 - mat_spec = mat.specular_reflection/2.0 -# mat_spec = mat.spec/2.0 - mat_alpha = mat.alpha - mat_emit = mat.emit - mat_shadeless = mat.shadeless -# mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS - if mat_shadeless: - mat_shader = 'Lambert' - else: - if mat.diffuse_shader == 'LAMBERT': -# if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: - mat_shader = 'Lambert' - else: - mat_shader = 'Phong' - else: - mat_cols = mat_cold = 0.8, 0.8, 0.8 - mat_colamb = 0.0,0.0,0.0 - # mat_colm - mat_dif = 1.0 - mat_amb = 0.5 - mat_hard = 20.0 - mat_spec = 0.2 - mat_alpha = 1.0 - mat_emit = 0.0 - mat_shadeless = False - mat_shader = 'Phong' - - file.write('\n\t\tVersion: 102') - file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) - file.write('\n\t\tMultiLayer: 0') - - file.write('\n\t\tProperties60: {') - file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) - file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') - file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender - file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_emit) - - file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) - file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) - file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) - file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_dif) - file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') - file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') - file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) - file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) - file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') - file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') - file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') - file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') - file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) - file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) - file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) - file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') - - file.write('\n\t\t}') - file.write('\n\t}') - - def copy_image(image): - - rel = image.get_export_path(basepath, True) - base = os.path.basename(rel) - - if EXP_IMAGE_COPY: - absp = image.get_export_path(basepath, False) - if not os.path.exists(absp): - shutil.copy(image.get_abs_filename(), absp) - - return (rel, base) - - # tex is an Image (Arystan) - def write_video(texname, tex): - # Same as texture really! - file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) - - file.write(''' - Type: "Clip" - Properties60: { - Property: "FrameRate", "double", "",0 - Property: "LastFrame", "int", "",0 - Property: "Width", "int", "",0 - Property: "Height", "int", "",0''') - if tex: - fname_rel, fname_strip = copy_image(tex) -# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) - else: - fname = fname_strip = fname_rel = '' - - file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) - - - file.write(''' - Property: "StartFrame", "int", "",0 - Property: "StopFrame", "int", "",0 - Property: "PlaySpeed", "double", "",1 - Property: "Offset", "KTime", "",0 - Property: "InterlaceMode", "enum", "",0 - Property: "FreeRunning", "bool", "",0 - Property: "Loop", "bool", "",0 - Property: "AccessMode", "enum", "",0 - } - UseMipMap: 0''') - - file.write('\n\t\tFilename: "%s"' % fname_strip) - if fname_strip: fname_strip = '/' + fname_strip - file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative - file.write('\n\t}') - - - def write_texture(texname, tex, num): - # if tex == None then this is a dummy tex - file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) - file.write('\n\t\tType: "TextureVideoClip"') - file.write('\n\t\tVersion: 202') - # TODO, rare case _empty_ exists as a name. - file.write('\n\t\tTextureName: "Texture::%s"' % texname) - - file.write(''' - Properties60: { - Property: "Translation", "Vector", "A+",0,0,0 - Property: "Rotation", "Vector", "A+",0,0,0 - Property: "Scaling", "Vector", "A+",1,1,1''') - file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) - - - # WrapModeU/V 0==rep, 1==clamp, TODO add support - file.write(''' - Property: "TextureTypeUse", "enum", "",0 - Property: "CurrentTextureBlendMode", "enum", "",1 - Property: "UseMaterial", "bool", "",0 - Property: "UseMipMap", "bool", "",0 - Property: "CurrentMappingType", "enum", "",0 - Property: "UVSwap", "bool", "",0''') - - file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clamp_x) -# file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) - file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clamp_y) -# file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) - - file.write(''' - Property: "TextureRotationPivot", "Vector3D", "",0,0,0 - Property: "TextureScalingPivot", "Vector3D", "",0,0,0 - Property: "VideoProperty", "object", "" - }''') - - file.write('\n\t\tMedia: "Video::%s"' % texname) - - if tex: - fname_rel, fname_strip = copy_image(tex) -# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) - else: - fname = fname_strip = fname_rel = '' - - file.write('\n\t\tFileName: "%s"' % fname_strip) - file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command - - file.write(''' - ModelUVTranslation: 0,0 - ModelUVScaling: 1,1 - Texture_Alpha_Source: "None" - Cropping: 0,0,0,0 - }''') - - def write_deformer_skin(obname): - ''' - Each mesh has its own deformer - ''' - file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) - file.write(''' - Version: 100 - MultiLayer: 0 - Type: "Skin" - Properties60: { - } - Link_DeformAcuracy: 50 - }''') - - # in the example was 'Bip01 L Thigh_2' - def write_sub_deformer_skin(my_mesh, my_bone, weights): - - ''' - Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers - So the SubDeformer needs the mesh-object name as a prefix to make it unique - - Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, - a but silly but dosnt really matter - ''' - file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) - - file.write(''' - Version: 100 - MultiLayer: 0 - Type: "Cluster" - Properties60: { - Property: "SrcModel", "object", "" - Property: "SrcModelReference", "object", "" - } - UserData: "", ""''') - - # Support for bone parents - if my_mesh.fbxBoneParent: - if my_mesh.fbxBoneParent == my_bone: - # TODO - this is a bit lazy, we could have a simple write loop - # for this case because all weights are 1.0 but for now this is ok - # Parent Bones arent used all that much anyway. - vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.verts))] - else: - # This bone is not a parent of this mesh object, no weights - vgroup_data = [] - - else: - # Normal weight painted mesh - if my_bone.blenName in weights[0]: - # Before we used normalized wright list - #vgroup_data = me.getVertsFromGroup(bone.name, 1) - group_index = weights[0].index(my_bone.blenName) - vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] - else: - vgroup_data = [] - - file.write('\n\t\tIndexes: ') - - i = -1 - for vg in vgroup_data: - if i == -1: - file.write('%i' % vg[0]) - i=0 - else: - if i==23: - file.write('\n\t\t') - i=0 - file.write(',%i' % vg[0]) - i+=1 - - file.write('\n\t\tWeights: ') - i = -1 - for vg in vgroup_data: - if i == -1: - file.write('%.8f' % vg[1]) - i=0 - else: - if i==38: - file.write('\n\t\t') - i=0 - file.write(',%.8f' % vg[1]) - i+=1 - - if my_mesh.fbxParent: - # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! - m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) - else: - # Yes! this is it... - but dosnt work when the mesh is a. - m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) - - #m = mtx4_z90 * my_bone.restMatrix - matstr = mat4x4str(m) - matstr_i = mat4x4str(m.invert()) - - file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ - file.write('\n\t\tTransformLink: %s' % matstr) - file.write('\n\t}') - - def write_mesh(my_mesh): - - me = my_mesh.blenData - - # if there are non NULL materials on this mesh - if my_mesh.blenMaterials: do_materials = True - else: do_materials = False - - if my_mesh.blenTextures: do_textures = True - else: do_textures = False - - do_uvs = len(me.uv_textures) > 0 -# do_uvs = me.faceUV - - - file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) - file.write('\n\t\tVersion: 232') # newline is added in write_object_props - - poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3] - pose_items.append((my_mesh.fbxName, poseMatrix)) - - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 1') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - - - # Write the Real Mesh data here - file.write('\n\t\tVertices: ') - i=-1 - - for v in me.verts: - if i==-1: - file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 - else: - if i==7: - file.write('\n\t\t'); i=0 - file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) - i+=1 - - file.write('\n\t\tPolygonVertexIndex: ') - i=-1 - for f in me.faces: - fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3] -# fi = [v.index for v in f] - - # flip the last index, odd but it looks like - # this is how fbx tells one face from another - fi[-1] = -(fi[-1]+1) - fi = tuple(fi) - if i==-1: - if len(fi) == 3: file.write('%i,%i,%i' % fi ) -# if len(f) == 3: file.write('%i,%i,%i' % fi ) - else: file.write('%i,%i,%i,%i' % fi ) - i=0 - else: - if i==13: - file.write('\n\t\t') - i=0 - if len(fi) == 3: file.write(',%i,%i,%i' % fi ) -# if len(f) == 3: file.write(',%i,%i,%i' % fi ) - else: file.write(',%i,%i,%i,%i' % fi ) - i+=1 - - file.write('\n\t\tEdges: ') - i=-1 - for ed in me.edges: - if i==-1: - file.write('%i,%i' % (ed.verts[0], ed.verts[1])) -# file.write('%i,%i' % (ed.v1.index, ed.v2.index)) - i=0 - else: - if i==13: - file.write('\n\t\t') - i=0 - file.write(',%i,%i' % (ed.verts[0], ed.verts[1])) -# file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) - i+=1 - - file.write('\n\t\tGeometryVersion: 124') - - file.write(''' - LayerElementNormal: 0 { - Version: 101 - Name: "" - MappingInformationType: "ByVertice" - ReferenceInformationType: "Direct" - Normals: ''') - - i=-1 - for v in me.verts: - if i==-1: - file.write('%.15f,%.15f,%.15f' % tuple(v.normal)); i=0 -# file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 - else: - if i==2: - file.write('\n '); i=0 - file.write(',%.15f,%.15f,%.15f' % tuple(v.normal)) -# file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) - i+=1 - file.write('\n\t\t}') - - # Write Face Smoothing - file.write(''' - LayerElementSmoothing: 0 { - Version: 102 - Name: "" - MappingInformationType: "ByPolygon" - ReferenceInformationType: "Direct" - Smoothing: ''') - - i=-1 - for f in me.faces: - if i==-1: - file.write('%i' % f.smooth); i=0 - else: - if i==54: - file.write('\n '); i=0 - file.write(',%i' % f.smooth) - i+=1 - - file.write('\n\t\t}') - - # Write Edge Smoothing - file.write(''' - LayerElementSmoothing: 0 { - Version: 101 - Name: "" - MappingInformationType: "ByEdge" - ReferenceInformationType: "Direct" - Smoothing: ''') - -# SHARP = Blender.Mesh.EdgeFlags.SHARP - i=-1 - for ed in me.edges: - if i==-1: - file.write('%i' % (ed.sharp)); i=0 -# file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 - else: - if i==54: - file.write('\n '); i=0 - file.write(',%i' % (ed.sharp)) -# file.write(',%i' % ((ed.flag&SHARP)!=0)) - i+=1 - - file.write('\n\t\t}') -# del SHARP - - # small utility function - # returns a slice of data depending on number of face verts - # data is either a MeshTextureFace or MeshColor - def face_data(data, face): - if f.verts[3] == 0: - totvert = 3 - else: - totvert = 4 - - return data[:totvert] - - - # Write VertexColor Layers - # note, no programs seem to use this info :/ - collayers = [] - if len(me.vertex_colors): -# if me.vertexColors: - collayers = me.vertex_colors -# collayers = me.getColorLayerNames() - collayer_orig = me.active_vertex_color -# collayer_orig = me.activeColorLayer - for colindex, collayer in enumerate(collayers): -# me.activeColorLayer = collayer - file.write('\n\t\tLayerElementColor: %i {' % colindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % collayer.name) -# file.write('\n\t\t\tName: "%s"' % collayer) - - file.write(''' - MappingInformationType: "ByPolygonVertex" - ReferenceInformationType: "IndexToDirect" - Colors: ''') - - i = -1 - ii = 0 # Count how many Colors we write - - for f, cf in zip(me.faces, collayer.data): - colors = [cf.color1, cf.color2, cf.color3, cf.color4] - - # determine number of verts - colors = face_data(colors, f) - - for col in colors: - if i==-1: - file.write('%.4f,%.4f,%.4f,1' % tuple(col)) - i=0 - else: - if i==7: - file.write('\n\t\t\t\t') - i=0 - file.write(',%.4f,%.4f,%.4f,1' % tuple(col)) - i+=1 - ii+=1 # One more Color - -# for f in me.faces: -# for col in f.col: -# if i==-1: -# file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) -# i=0 -# else: -# if i==7: -# file.write('\n\t\t\t\t') -# i=0 -# file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) -# i+=1 -# ii+=1 # One more Color - - file.write('\n\t\t\tColorIndex: ') - i = -1 - for j in range(ii): - if i == -1: - file.write('%i' % j) - i=0 - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - file.write(',%i' % j) - i+=1 - - file.write('\n\t\t}') - - - - # Write UV and texture layers. - uvlayers = [] - if do_uvs: - uvlayers = me.uv_textures -# uvlayers = me.getUVLayerNames() - uvlayer_orig = me.active_uv_texture -# uvlayer_orig = me.activeUVLayer - for uvindex, uvlayer in enumerate(me.uv_textures): -# for uvindex, uvlayer in enumerate(uvlayers): -# me.activeUVLayer = uvlayer - file.write('\n\t\tLayerElementUV: %i {' % uvindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer.name) -# file.write('\n\t\t\tName: "%s"' % uvlayer) - - file.write(''' - MappingInformationType: "ByPolygonVertex" - ReferenceInformationType: "IndexToDirect" - UV: ''') - - i = -1 - ii = 0 # Count how many UVs we write - - for f, uf in zip(me.faces, uvlayer.data): -# for f in me.faces: - uvs = [uf.uv1, uf.uv2, uf.uv3, uf.uv4] - uvs = face_data(uvs, f) - - for uv in uvs: -# for uv in f.uv: - if i==-1: - file.write('%.6f,%.6f' % tuple(uv)) - i=0 - else: - if i==7: - file.write('\n ') - i=0 - file.write(',%.6f,%.6f' % tuple(uv)) - i+=1 - ii+=1 # One more UV - - file.write('\n\t\t\tUVIndex: ') - i = -1 - for j in range(ii): - if i == -1: - file.write('%i' % j) - i=0 - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - file.write(',%i' % j) - i+=1 - - file.write('\n\t\t}') - - if do_textures: - file.write('\n\t\tLayerElementTexture: %i {' % uvindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer.name) -# file.write('\n\t\t\tName: "%s"' % uvlayer) - - if len(my_mesh.blenTextures) == 1: - file.write('\n\t\t\tMappingInformationType: "AllSame"') - else: - file.write('\n\t\t\tMappingInformationType: "ByPolygon"') - - file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') - file.write('\n\t\t\tBlendMode: "Translucent"') - file.write('\n\t\t\tTextureAlpha: 1') - file.write('\n\t\t\tTextureId: ') - - if len(my_mesh.blenTextures) == 1: - file.write('0') - else: - texture_mapping_local = {None:-1} - - i = 0 # 1 for dummy - for tex in my_mesh.blenTextures: - if tex: # None is set above - texture_mapping_local[tex] = i - i+=1 - - i=-1 - for f in uvlayer.data: -# for f in me.faces: - img_key = f.image - - if i==-1: - i=0 - file.write( '%s' % texture_mapping_local[img_key]) - else: - if i==55: - file.write('\n ') - i=0 - - file.write(',%s' % texture_mapping_local[img_key]) - i+=1 - - else: - file.write(''' - LayerElementTexture: 0 { - Version: 101 - Name: "" - MappingInformationType: "NoMappingInformation" - ReferenceInformationType: "IndexToDirect" - BlendMode: "Translucent" - TextureAlpha: 1 - TextureId: ''') - file.write('\n\t\t}') - -# me.activeUVLayer = uvlayer_orig - - # Done with UV/textures. - - if do_materials: - file.write('\n\t\tLayerElementMaterial: 0 {') - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: ""') - - if len(my_mesh.blenMaterials) == 1: - file.write('\n\t\t\tMappingInformationType: "AllSame"') - else: - file.write('\n\t\t\tMappingInformationType: "ByPolygon"') - - file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') - file.write('\n\t\t\tMaterials: ') - - if len(my_mesh.blenMaterials) == 1: - file.write('0') - else: - # Build a material mapping for this - material_mapping_local = {} # local-mat & tex : global index. - - for j, mat_tex_pair in enumerate(my_mesh.blenMaterials): - material_mapping_local[mat_tex_pair] = j - - len_material_mapping_local = len(material_mapping_local) - - mats = my_mesh.blenMaterialList - - if me.active_uv_texture: - uv_faces = me.active_uv_texture.data - else: - uv_faces = [None] * len(me.faces) - - i=-1 - for f, uf in zip(me.faces, uv_faces): -# for f in me.faces: - try: mat = mats[f.material_index] -# try: mat = mats[f.mat] - except:mat = None - - if do_uvs: tex = uf.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ -# if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ - else: tex = None - - if i==-1: - i=0 - file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - - file.write(',%s' % (material_mapping_local[mat, tex])) - i+=1 - - file.write('\n\t\t}') - - file.write(''' - Layer: 0 { - Version: 100 - LayerElement: { - Type: "LayerElementNormal" - TypedIndex: 0 - }''') - - if do_materials: - file.write(''' - LayerElement: { - Type: "LayerElementMaterial" - TypedIndex: 0 - }''') - - # Always write this - if do_textures: - file.write(''' - LayerElement: { - Type: "LayerElementTexture" - TypedIndex: 0 - }''') - - if me.vertex_colors: -# if me.vertexColors: - file.write(''' - LayerElement: { - Type: "LayerElementColor" - TypedIndex: 0 - }''') - - if do_uvs: # same as me.faceUV - file.write(''' - LayerElement: { - Type: "LayerElementUV" - TypedIndex: 0 - }''') - - - file.write('\n\t\t}') - - if len(uvlayers) > 1: - for i in range(1, len(uvlayers)): - - file.write('\n\t\tLayer: %i {' % i) - file.write('\n\t\t\tVersion: 100') - - file.write(''' - LayerElement: { - Type: "LayerElementUV"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - - if do_textures: - - file.write(''' - LayerElement: { - Type: "LayerElementTexture"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - - file.write('\n\t\t}') - - if len(collayers) > 1: - # Take into account any UV layers - layer_offset = 0 - if uvlayers: layer_offset = len(uvlayers)-1 - - for i in range(layer_offset, len(collayers)+layer_offset): - file.write('\n\t\tLayer: %i {' % i) - file.write('\n\t\t\tVersion: 100') - - file.write(''' - LayerElement: { - Type: "LayerElementColor"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - file.write('\n\t\t}') - file.write('\n\t}') - - def write_group(name): - file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) - - file.write(''' - Properties60: { - Property: "MultiLayer", "bool", "",0 - Property: "Pickable", "bool", "",1 - Property: "Transformable", "bool", "",1 - Property: "Show", "bool", "",1 - } - MultiLayer: 0 - }''') - - - # add meshes here to clear because they are not used anywhere. - meshes_to_clear = [] - - ob_meshes = [] - ob_lights = [] - ob_cameras = [] - # in fbx we export bones as children of the mesh - # armatures not a part of a mesh, will be added to ob_arms - ob_bones = [] - ob_arms = [] - ob_null = [] # emptys - - # List of types that have blender objects (not bones) - ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] - - groups = [] # blender groups, only add ones that have objects in the selections - materials = {} # (mat, image) keys, should be a set() - textures = {} # should be a set() - - tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error - - # if EXP_OBS_SELECTED is false, use sceens objects - if not batch_objects: - if EXP_OBS_SELECTED: tmp_objects = context.selected_objects -# if EXP_OBS_SELECTED: tmp_objects = sce.objects.context - else: tmp_objects = sce.objects - else: - tmp_objects = batch_objects - - if EXP_ARMATURE: - # This is needed so applying modifiers dosnt apply the armature deformation, its also needed - # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. - # set every armature to its rest, backup the original values so we done mess up the scene - ob_arms_orig_rest = [arm.rest_position for arm in bpy.data.armatures] -# ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] - - for arm in bpy.data.armatures: - arm.rest_position = True -# arm.restPosition = True - - if ob_arms_orig_rest: - for ob_base in bpy.data.objects: - #if ob_base.type == 'Armature': - ob_base.make_display_list() -# ob_base.makeDisplayList() - - # This causes the makeDisplayList command to effect the mesh - sce.set_frame(sce.current_frame) -# Blender.Set('curframe', Blender.Get('curframe')) - - - for ob_base in tmp_objects: - - # ignore dupli children - if ob_base.parent and ob_base.parent.dupli_type != 'NONE': - continue - - obs = [(ob_base, ob_base.matrix)] - if ob_base.dupli_type != 'NONE': - ob_base.create_dupli_list() - obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list] - - for ob, mtx in obs: -# for ob, mtx in BPyObject.getDerivedObjects(ob_base): - tmp_ob_type = ob.type - if tmp_ob_type == 'CAMERA': -# if tmp_ob_type == 'Camera': - if EXP_CAMERA: - ob_cameras.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'LAMP': -# elif tmp_ob_type == 'Lamp': - if EXP_LAMP: - ob_lights.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'ARMATURE': -# elif tmp_ob_type == 'Armature': - if EXP_ARMATURE: - # TODO - armatures dont work in dupligroups! - if ob not in ob_arms: ob_arms.append(ob) - # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" - elif tmp_ob_type == 'EMPTY': -# elif tmp_ob_type == 'Empty': - if EXP_EMPTY: - ob_null.append(my_object_generic(ob, mtx)) - elif EXP_MESH: - origData = True - if tmp_ob_type != 'MESH': -# if tmp_ob_type != 'Mesh': -# me = bpy.data.meshes.new() - try: me = ob.create_mesh(True, 'PREVIEW') -# try: me.getFromObject(ob) - except: me = None - if me: - meshes_to_clear.append( me ) - mats = me.materials - origData = False - else: - # Mesh Type! - if EXP_MESH_APPLY_MOD: -# me = bpy.data.meshes.new() - me = ob.create_mesh(True, 'PREVIEW') -# me.getFromObject(ob) - - # so we keep the vert groups -# if EXP_ARMATURE: -# orig_mesh = ob.getData(mesh=1) -# if orig_mesh.getVertGroupNames(): -# ob.copy().link(me) -# # If new mesh has no vgroups we can try add if verts are teh same -# if not me.getVertGroupNames(): # vgroups were not kept by the modifier -# if len(me.verts) == len(orig_mesh.verts): -# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) -# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) - - # print ob, me, me.getVertGroupNames() - meshes_to_clear.append( me ) - origData = False - mats = me.materials - else: - me = ob.data -# me = ob.getData(mesh=1) - mats = me.materials - -# # Support object colors -# tmp_colbits = ob.colbits -# if tmp_colbits: -# tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. -# for i in xrange(16): -# if tmp_colbits & (1< 0: -# if me.faceUV: - uvlayer_orig = me.active_uv_texture -# uvlayer_orig = me.activeUVLayer - for uvlayer in me.uv_textures: -# for uvlayer in me.getUVLayerNames(): -# me.activeUVLayer = uvlayer - for f, uf in zip(me.faces, uvlayer.data): -# for f in me.faces: - tex = uf.image -# tex = f.image - textures[tex] = texture_mapping_local[tex] = None - - try: mat = mats[f.material_index] -# try: mat = mats[f.mat] - except: mat = None - - materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5 - - -# me.activeUVLayer = uvlayer_orig - else: - for mat in mats: - # 2.44 use mat.lib too for uniqueness - materials[mat, None] = material_mapping_local[mat, None] = None - else: - materials[None, None] = None - - if EXP_ARMATURE: - armob = ob.find_armature() - blenParentBoneName = None - - # parent bone - special case - if (not armob) and ob.parent and ob.parent.type == 'ARMATURE' and \ - ob.parent_type == 'BONE': -# if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE: - armob = ob.parent - blenParentBoneName = ob.parent_bone -# blenParentBoneName = ob.parentbonename - - - if armob and armob not in ob_arms: - ob_arms.append(armob) - - else: - blenParentBoneName = armob = None - - my_mesh = my_object_generic(ob, mtx) - my_mesh.blenData = me - my_mesh.origData = origData - my_mesh.blenMaterials = list(material_mapping_local.keys()) - my_mesh.blenMaterialList = mats - my_mesh.blenTextures = list(texture_mapping_local.keys()) - - # if only 1 null texture then empty the list - if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None: - my_mesh.blenTextures = [] - - my_mesh.fbxArm = armob # replace with my_object_generic armature instance later - my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later - - ob_meshes.append( my_mesh ) - - # not forgetting to free dupli_list - if ob_base.dupli_list: ob_base.free_dupli_list() - - - if EXP_ARMATURE: - # now we have the meshes, restore the rest arm position - for i, arm in enumerate(bpy.data.armatures): - arm.rest_position = ob_arms_orig_rest[i] -# arm.restPosition = ob_arms_orig_rest[i] - - if ob_arms_orig_rest: - for ob_base in bpy.data.objects: - if ob_base.type == 'ARMATURE': -# if ob_base.type == 'Armature': - ob_base.make_display_list() -# ob_base.makeDisplayList() - # This causes the makeDisplayList command to effect the mesh - sce.set_frame(sce.current_frame) -# Blender.Set('curframe', Blender.Get('curframe')) - - del tmp_ob_type, tmp_objects - - # now we have collected all armatures, add bones - for i, ob in enumerate(ob_arms): - - ob_arms[i] = my_arm = my_object_generic(ob) - - my_arm.fbxBones = [] - my_arm.blenData = ob.data - if ob.animation_data: - my_arm.blenAction = ob.animation_data.action - else: - my_arm.blenAction = None -# my_arm.blenAction = ob.action - my_arm.blenActionList = [] - - # fbxName, blenderObject, my_bones, blenderActions - #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, []) - - for bone in my_arm.blenData.bones: -# for bone in my_arm.blenData.bones.values(): - my_bone = my_bone_class(bone, my_arm) - my_arm.fbxBones.append( my_bone ) - ob_bones.append( my_bone ) - - # add the meshes to the bones and replace the meshes armature with own armature class - #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: - for my_mesh in ob_meshes: - # Replace - # ...this could be sped up with dictionary mapping but its unlikely for - # it ever to be a bottleneck - (would need 100+ meshes using armatures) - if my_mesh.fbxArm: - for my_arm in ob_arms: - if my_arm.blenObject == my_mesh.fbxArm: - my_mesh.fbxArm = my_arm - break - - for my_bone in ob_bones: - - # The mesh uses this bones armature! - if my_bone.fbxArm == my_mesh.fbxArm: - my_bone.blenMeshes[my_mesh.fbxName] = me - - - # parent bone: replace bone names with our class instances - # my_mesh.fbxBoneParent is None or a blender bone name initialy, replacing if the names match. - if my_mesh.fbxBoneParent == my_bone.blenName: - my_mesh.fbxBoneParent = my_bone - - bone_deformer_count = 0 # count how many bones deform a mesh - my_bone_blenParent = None - for my_bone in ob_bones: - my_bone_blenParent = my_bone.blenBone.parent - if my_bone_blenParent: - for my_bone_parent in ob_bones: - # Note 2.45rc2 you can compare bones normally - if my_bone_blenParent.name == my_bone_parent.blenName and my_bone.fbxArm == my_bone_parent.fbxArm: - my_bone.parent = my_bone_parent - break - - # Not used at the moment - # my_bone.calcRestMatrixLocal() - bone_deformer_count += len(my_bone.blenMeshes) - - del my_bone_blenParent - - - # Build blenObject -> fbxObject mapping - # this is needed for groups as well as fbxParenting -# for ob in bpy.data.objects: ob.tag = False -# bpy.data.objects.tag = False - - # using a list of object names for tagging (Arystan) - tagged_objects = [] - - tmp_obmapping = {} - for ob_generic in ob_all_typegroups: - for ob_base in ob_generic: - tagged_objects.append(ob_base.blenObject.name) -# ob_base.blenObject.tag = True - tmp_obmapping[ob_base.blenObject] = ob_base - - # Build Groups from objects we export - for blenGroup in bpy.data.groups: - fbxGroupName = None - for ob in blenGroup.objects: - if ob.name in tagged_objects: -# if ob.tag: - if fbxGroupName == None: - fbxGroupName = sane_groupname(blenGroup) - groups.append((fbxGroupName, blenGroup)) - - tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames - - groups.sort() # not really needed - - # Assign parents using this mapping - for ob_generic in ob_all_typegroups: - for my_ob in ob_generic: - parent = my_ob.blenObject.parent - if parent and parent.name in tagged_objects: # does it exist and is it in the mapping -# if parent and parent.tag: # does it exist and is it in the mapping - my_ob.fbxParent = tmp_obmapping[parent] - - - del tmp_obmapping - # Finished finding groups we use - - - materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.keys()] - textures = [(sane_texname(tex), tex) for tex in textures.keys() if tex] - materials.sort() # sort by name - textures.sort() - - camera_count = 8 - file.write(''' - -; Object definitions -;------------------------------------------------------------------ - -Definitions: { - Version: 100 - Count: %i''' % (\ - 1+1+camera_count+\ - len(ob_meshes)+\ - len(ob_lights)+\ - len(ob_cameras)+\ - len(ob_arms)+\ - len(ob_null)+\ - len(ob_bones)+\ - bone_deformer_count+\ - len(materials)+\ - (len(textures)*2))) # add 1 for the root model 1 for global settings - - del bone_deformer_count - - file.write(''' - ObjectType: "Model" { - Count: %i - }''' % (\ - 1+camera_count+\ - len(ob_meshes)+\ - len(ob_lights)+\ - len(ob_cameras)+\ - len(ob_arms)+\ - len(ob_null)+\ - len(ob_bones))) # add 1 for the root model - - file.write(''' - ObjectType: "Geometry" { - Count: %i - }''' % len(ob_meshes)) - - if materials: - file.write(''' - ObjectType: "Material" { - Count: %i - }''' % len(materials)) - - if textures: - file.write(''' - ObjectType: "Texture" { - Count: %i - }''' % len(textures)) # add 1 for an empty tex - file.write(''' - ObjectType: "Video" { - Count: %i - }''' % len(textures)) # add 1 for an empty tex - - tmp = 0 - # Add deformer nodes - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - tmp+=1 - - # Add subdeformers - for my_bone in ob_bones: - tmp += len(my_bone.blenMeshes) - - if tmp: - file.write(''' - ObjectType: "Deformer" { - Count: %i - }''' % tmp) - del tmp - - # we could avoid writing this possibly but for now just write it - - file.write(''' - ObjectType: "Pose" { - Count: 1 - }''') - - if groups: - file.write(''' - ObjectType: "GroupSelection" { - Count: %i - }''' % len(groups)) - - file.write(''' - ObjectType: "GlobalSettings" { - Count: 1 - } -}''') - - file.write(''' - -; Object properties -;------------------------------------------------------------------ - -Objects: {''') - - # To comply with other FBX FILES - write_camera_switch() - - # Write the null object - write_null(None, 'blend_root')# , GLOBAL_MATRIX) - - for my_null in ob_null: - write_null(my_null) - - for my_arm in ob_arms: - write_null(my_arm) - - for my_cam in ob_cameras: - write_camera(my_cam) - - for my_light in ob_lights: - write_light(my_light) - - for my_mesh in ob_meshes: - write_mesh(my_mesh) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - write_bone(my_bone) - - write_camera_default() - - for matname, (mat, tex) in materials: - write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard) - - # each texture uses a video, odd - for texname, tex in textures: - write_video(texname, tex) - i = 0 - for texname, tex in textures: - write_texture(texname, tex, i) - i+=1 - - for groupname, group in groups: - write_group(groupname) - - # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. - - # Write armature modifiers - # TODO - add another MODEL? - because of this skin definition. - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - write_deformer_skin(my_mesh.fbxName) - - # Get normalized weights for temorary use - if my_mesh.fbxBoneParent: - weights = None - else: - weights = meshNormalizedWeights(my_mesh.blenObject) -# weights = meshNormalizedWeights(my_mesh.blenData) - - #for bonename, bone, obname, bone_mesh, armob in ob_bones: - for my_bone in ob_bones: - if me in iter(my_bone.blenMeshes.values()): - write_sub_deformer_skin(my_mesh, my_bone, weights) - - # Write pose's really weired, only needed when an armature and mesh are used together - # each by themselves dont need pose data. for now only pose meshes and bones - - file.write(''' - Pose: "Pose::BIND_POSES", "BindPose" { - Type: "BindPose" - Version: 100 - Properties60: { - } - NbPoseNodes: ''') - file.write(str(len(pose_items))) - - - for fbxName, matrix in pose_items: - file.write('\n\t\tPoseNode: {') - file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) - if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) - else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) - file.write('\n\t\t}') - - file.write('\n\t}') - - - # Finish Writing Objects - # Write global settings - file.write(''' - GlobalSettings: { - Version: 1000 - Properties60: { - Property: "UpAxis", "int", "",1 - Property: "UpAxisSign", "int", "",1 - Property: "FrontAxis", "int", "",2 - Property: "FrontAxisSign", "int", "",1 - Property: "CoordAxis", "int", "",0 - Property: "CoordAxisSign", "int", "",1 - Property: "UnitScaleFactor", "double", "",100 - } - } -''') - file.write('}') - - file.write(''' - -; Object relations -;------------------------------------------------------------------ - -Relations: {''') - - file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') - - for my_null in ob_null: - file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) - - for my_arm in ob_arms: - file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) - - for my_mesh in ob_meshes: - file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) - - # TODO - limbs can have the same name for multiple armatures, should prefix. - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) - - for my_cam in ob_cameras: - file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) - - for my_light in ob_lights: - file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) - - file.write(''' - Model: "Model::Producer Perspective", "Camera" { - } - Model: "Model::Producer Top", "Camera" { - } - Model: "Model::Producer Bottom", "Camera" { - } - Model: "Model::Producer Front", "Camera" { - } - Model: "Model::Producer Back", "Camera" { - } - Model: "Model::Producer Right", "Camera" { - } - Model: "Model::Producer Left", "Camera" { - } - Model: "Model::Camera Switcher", "CameraSwitcher" { - }''') - - for matname, (mat, tex) in materials: - file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) - - if textures: - for texname, tex in textures: - file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) - for texname, tex in textures: - file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) - - # deformers - modifiers - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName - # is this bone effecting a mesh? - file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) - - # This should be at the end - # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') - - for groupname, group in groups: - file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) - - file.write('\n}') - file.write(''' - -; Object connections -;------------------------------------------------------------------ - -Connections: {''') - - # NOTE - The FBX SDK dosnt care about the order but some importers DO! - # for instance, defining the material->mesh connection - # before the mesh->blend_root crashes cinema4d - - - # write the fake root node - file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') - - for ob_generic in ob_all_typegroups: # all blender 'Object's we support - for my_ob in ob_generic: - if my_ob.fbxParent: - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) - else: - file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) - - if materials: - for my_mesh in ob_meshes: - # Connect all materials to all objects, not good form but ok for now. - for mat, tex in my_mesh.blenMaterials: - if mat: mat_name = mat.name - else: mat_name = None - - if tex: tex_name = tex.name - else: tex_name = None - - file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName)) - - if textures: - for my_mesh in ob_meshes: - if my_mesh.blenTextures: - # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) - for tex in my_mesh.blenTextures: - if tex: - file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) - - for texname, tex in textures: - file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) - - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) - - # limbs -> deformers - # for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) - - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - # Always parent to armature now - if my_bone.parent: - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) - else: - # the armature object is written as an empty and all root level bones connect to it - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) - - # groups - if groups: - for ob_generic in ob_all_typegroups: - for ob_base in ob_generic: - for fbxGroupName in ob_base.fbxGroupNames: - file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) - - for my_arm in ob_arms: - file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) - - file.write('\n}') - - - # Needed for scene footer as well as animation - render = sce.render_data -# render = sce.render - - # from the FBX sdk - #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) - def fbx_time(t): - # 0.5 + val is the same as rounding. - return int(0.5 + ((t/fps) * 46186158000)) - - fps = float(render.fps) - start = sce.start_frame -# start = render.sFrame - end = sce.end_frame -# end = render.eFrame - if end < start: start, end = end, start - if start==end: ANIM_ENABLE = False - - # animations for these object types - ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms - - if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: - - frame_orig = sce.current_frame -# frame_orig = Blender.Get('curframe') - - if ANIM_OPTIMIZE: - ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION - - # default action, when no actions are avaioable - tmp_actions = [None] # None is the default action - blenActionDefault = None - action_lastcompat = None - - # instead of tagging - tagged_actions = [] - - if ANIM_ACTION_ALL: -# bpy.data.actions.tag = False - tmp_actions = list(bpy.data.actions) - - - # find which actions are compatible with the armatures - # blenActions is not yet initialized so do it now. - tmp_act_count = 0 - for my_arm in ob_arms: - - # get the default name - if not blenActionDefault: - blenActionDefault = my_arm.blenAction - - arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) - - for action in tmp_actions: - - action_chan_names = arm_bone_names.intersection( set([g.name for g in action.groups]) ) -# action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) - - if action_chan_names: # at least one channel matches. - my_arm.blenActionList.append(action) - tagged_actions.append(action.name) -# action.tag = True - tmp_act_count += 1 - - # incase there is no actions applied to armatures - action_lastcompat = action - - if tmp_act_count: - # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. - if not blenActionDefault: - blenActionDefault = action_lastcompat - - del action_lastcompat - - file.write(''' -;Takes and animation section -;---------------------------------------------------- - -Takes: {''') - - if blenActionDefault: - file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) - else: - file.write('\n\tCurrent: "Default Take"') - - for blenAction in tmp_actions: - # we have tagged all actious that are used be selected armatures - if blenAction: - if blenAction.name in tagged_actions: -# if blenAction.tag: - print('\taction: "%s" exporting...' % blenAction.name) - else: - print('\taction: "%s" has no armature using it, skipping' % blenAction.name) - continue - - if blenAction == None: - # Warning, this only accounts for tmp_actions being [None] - file.write('\n\tTake: "Default Take" {') - act_start = start - act_end = end - else: - # use existing name - if blenAction == blenActionDefault: # have we alredy got the name - file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) - else: - file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) - - act_start, act_end = blenAction.get_frame_range() -# tmp = blenAction.getFrameNumbers() -# if tmp: -# act_start = min(tmp) -# act_end = max(tmp) -# del tmp -# else: -# # Fallback on this, theres not much else we can do? :/ -# # when an action has no length -# act_start = start -# act_end = end - - # Set the action active - for my_bone in ob_arms: - if blenAction in my_bone.blenActionList: - ob.action = blenAction - # print '\t\tSetting Action!', blenAction - # sce.update(1) - - file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed - file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed - file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed - - file.write(''' - - ;Models animation - ;----------------------------------------------------''') - - - # set pose data for all bones - # do this here incase the action changes - ''' - for my_bone in ob_bones: - my_bone.flushAnimData() - ''' - i = act_start - while i <= act_end: - sce.set_frame(i) -# Blender.Set('curframe', i) - for ob_generic in ob_anim_lists: - for my_ob in ob_generic: - #Blender.Window.RedrawAll() - if ob_generic == ob_meshes and my_ob.fbxArm: - # We cant animate armature meshes! - pass - else: - my_ob.setPoseFrame(i) - - i+=1 - - - #for bonename, bone, obname, me, armob in ob_bones: - for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): - - for my_ob in ob_generic: - - if ob_generic == ob_meshes and my_ob.fbxArm: - # do nothing, - pass - else: - - file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed - file.write('\n\t\t\tVersion: 1.1') - file.write('\n\t\t\tChannel: "Transform" {') - - context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end+1) ] - - # ---------------- - # ---------------- - for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale - - if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] - elif TX_CHAN=='S': context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] - elif TX_CHAN=='R': - # Was.... - # elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] - # - # ...but we need to use the previous euler for compatible conversion. - context_bone_anim_vecs = [] - prev_eul = None - for mtx in context_bone_anim_mats: - if prev_eul: prev_eul = mtx[1].toEuler(prev_eul) - else: prev_eul = mtx[1].toEuler() - context_bone_anim_vecs.append(eulerRadToDeg(prev_eul)) -# context_bone_anim_vecs.append(prev_eul) - - file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation - - for i in range(3): - # Loop on each axis of the bone - file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation - file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) - file.write('\n\t\t\t\t\t\tKeyVer: 4005') - - if not ANIM_OPTIMIZE: - # Just write all frames, simple but in-eficient - file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) - file.write('\n\t\t\t\t\t\tKey: ') - frame = act_start - while frame <= act_end: - if frame!=act_start: - file.write(',') - - # Curve types are 'C,n' for constant, 'L' for linear - # C,n is for bezier? - linear is best for now so we can do simple keyframe removal - file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) - frame+=1 - else: - # remove unneeded keys, j is the frame, needed when some frames are removed. - context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] - - # last frame to fisrt frame, missing 1 frame on either side. - # removeing in a backwards loop is faster - #for j in xrange( (act_end-act_start)-1, 0, -1 ): - # j = (act_end-act_start)-1 - j = len(context_bone_anim_keys)-2 - while j > 0 and len(context_bone_anim_keys) > 2: - # print j, len(context_bone_anim_keys) - # Is this key the same as the ones next to it? - - # co-linear horizontal... - if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ - abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: - - del context_bone_anim_keys[j] - - else: - frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1]) - frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range - frame_range_fac2 = 1.0 - frame_range_fac1 - - if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: - del context_bone_anim_keys[j] - else: - j-=1 - - # keep the index below the list length - if j > len(context_bone_anim_keys)-2: - j = len(context_bone_anim_keys)-2 - - if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: - # This axis has no moton, its okay to skip KeyCount and Keys in this case - pass - else: - # We only need to write these if there is at least one - file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) - file.write('\n\t\t\t\t\t\tKey: ') - for val, frame in context_bone_anim_keys: - if frame != context_bone_anim_keys[0][1]: # not the first - file.write(',') - # frame is alredy one less then blenders frame - file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) - - if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') - elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') - elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') - - file.write('\n\t\t\t\t\t}') - file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) - file.write('\n\t\t\t\t}') - - # --------------- - - file.write('\n\t\t\t}') - file.write('\n\t\t}') - - # end the take - file.write('\n\t}') - - # end action loop. set original actions - # do this after every loop incase actions effect eachother. - for my_bone in ob_arms: - my_bone.blenObject.action = my_bone.blenAction - - file.write('\n}') - - sce.set_frame(frame_orig) -# Blender.Set('curframe', frame_orig) - - else: - # no animation - file.write('\n;Takes and animation section') - file.write('\n;----------------------------------------------------') - file.write('\n') - file.write('\nTakes: {') - file.write('\n\tCurrent: ""') - file.write('\n}') - - - # write meshes animation - #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: - - - # Clear mesh data Only when writing with modifiers applied - for me in meshes_to_clear: - bpy.data.remove_mesh(me) -# me.verts = None - - # --------------------------- Footer - if world: - m = world.mist - has_mist = m.enabled -# has_mist = world.mode & 1 - mist_intense = m.intensity - mist_start = m.start - mist_end = m.depth - mist_height = m.height -# mist_intense, mist_start, mist_end, mist_height = world.mist - world_hor = world.horizon_color -# world_hor = world.hor - else: - has_mist = mist_intense = mist_start = mist_end = mist_height = 0 - world_hor = 0,0,0 - - file.write('\n;Version 5 settings') - file.write('\n;------------------------------------------------------------------') - file.write('\n') - file.write('\nVersion5: {') - file.write('\n\tAmbientRenderSettings: {') - file.write('\n\t\tVersion: 101') - file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) - file.write('\n\t}') - file.write('\n\tFogOptions: {') - file.write('\n\t\tFlogEnable: %i' % has_mist) - file.write('\n\t\tFogMode: 0') - file.write('\n\t\tFogDensity: %.3f' % mist_intense) - file.write('\n\t\tFogStart: %.3f' % mist_start) - file.write('\n\t\tFogEnd: %.3f' % mist_end) - file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) - file.write('\n\t}') - file.write('\n\tSettings: {') - file.write('\n\t\tFrameRate: "%i"' % int(fps)) - file.write('\n\t\tTimeFormat: 1') - file.write('\n\t\tSnapOnFrames: 0') - file.write('\n\t\tReferenceTimeIndex: -1') - file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) - file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) - file.write('\n\t}') - file.write('\n\tRendererSetting: {') - file.write('\n\t\tDefaultCamera: "Producer Perspective"') - file.write('\n\t\tDefaultViewingMode: 0') - file.write('\n\t}') - file.write('\n}') - file.write('\n') - - # Incase sombody imports this, clean up by clearing global dicts - sane_name_mapping_ob.clear() - sane_name_mapping_mat.clear() - sane_name_mapping_tex.clear() - - ob_arms[:] = [] - ob_bones[:] = [] - ob_cameras[:] = [] - ob_lights[:] = [] - ob_meshes[:] = [] - ob_null[:] = [] - - - # copy images if enabled -# if EXP_IMAGE_COPY: -# # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) -# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath) - - print('export finished in %.4f sec.' % (time.clock() - start_time)) -# print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) - return True - - -# -------------------------------------------- -# UI Function - not a part of the exporter. -# this is to seperate the user interface from the rest of the exporter. -# from Blender import Draw, Window -EVENT_NONE = 0 -EVENT_EXIT = 1 -EVENT_REDRAW = 2 -EVENT_FILESEL = 3 - -GLOBALS = {} - -# export opts - -def do_redraw(e,v): GLOBALS['EVENT'] = e - -# toggle between these 2, only allow one on at once -def do_obs_sel(e,v): - GLOBALS['EVENT'] = e - GLOBALS['EXP_OBS_SCENE'].val = 0 - GLOBALS['EXP_OBS_SELECTED'].val = 1 - -def do_obs_sce(e,v): - GLOBALS['EVENT'] = e - GLOBALS['EXP_OBS_SCENE'].val = 1 - GLOBALS['EXP_OBS_SELECTED'].val = 0 - -def do_batch_type_grp(e,v): - GLOBALS['EVENT'] = e - GLOBALS['BATCH_GROUP'].val = 1 - GLOBALS['BATCH_SCENE'].val = 0 - -def do_batch_type_sce(e,v): - GLOBALS['EVENT'] = e - GLOBALS['BATCH_GROUP'].val = 0 - GLOBALS['BATCH_SCENE'].val = 1 - -def do_anim_act_all(e,v): - GLOBALS['EVENT'] = e - GLOBALS['ANIM_ACTION_ALL'][0].val = 1 - GLOBALS['ANIM_ACTION_ALL'][1].val = 0 - -def do_anim_act_cur(e,v): - if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: - Draw.PupMenu('Warning%t|Cant use this with batch export group option') - else: - GLOBALS['EVENT'] = e - GLOBALS['ANIM_ACTION_ALL'][0].val = 0 - GLOBALS['ANIM_ACTION_ALL'][1].val = 1 - -def fbx_ui_exit(e,v): - GLOBALS['EVENT'] = e - -def do_help(e,v): - url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' - print('Trying to open web browser with documentation at this address...') - print('\t' + url) - - try: - import webbrowser - webbrowser.open(url) - except: - Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation") - print('...could not open a browser window.') - - - -# run when export is pressed -#def fbx_ui_write(e,v): -def fbx_ui_write(filename, context): - - # Dont allow overwriting files when saving normally - if not GLOBALS['BATCH_ENABLE'].val: - if not BPyMessages.Warning_SaveOver(filename): - return - - GLOBALS['EVENT'] = EVENT_EXIT - - # Keep the order the same as above for simplicity - # the [] is a dummy arg used for objects - - Blender.Window.WaitCursor(1) - - # Make the matrix - GLOBAL_MATRIX = mtx4_identity - GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val - if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n - if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n - if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n - - ret = write(\ - filename, None,\ - context, - GLOBALS['EXP_OBS_SELECTED'].val,\ - GLOBALS['EXP_MESH'].val,\ - GLOBALS['EXP_MESH_APPLY_MOD'].val,\ - GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ - GLOBALS['EXP_ARMATURE'].val,\ - GLOBALS['EXP_LAMP'].val,\ - GLOBALS['EXP_CAMERA'].val,\ - GLOBALS['EXP_EMPTY'].val,\ - GLOBALS['EXP_IMAGE_COPY'].val,\ - GLOBAL_MATRIX,\ - GLOBALS['ANIM_ENABLE'].val,\ - GLOBALS['ANIM_OPTIMIZE'].val,\ - GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ - GLOBALS['ANIM_ACTION_ALL'][0].val,\ - GLOBALS['BATCH_ENABLE'].val,\ - GLOBALS['BATCH_GROUP'].val,\ - GLOBALS['BATCH_SCENE'].val,\ - GLOBALS['BATCH_FILE_PREFIX'].val,\ - GLOBALS['BATCH_OWN_DIR'].val,\ - ) - - Blender.Window.WaitCursor(0) - GLOBALS.clear() - - if ret == False: - Draw.PupMenu('Error%t|Path cannot be written to!') - - -def fbx_ui(): - # Only to center the UI - x,y = GLOBALS['MOUSE'] - x-=180; y-=0 # offset... just to get it centered - - Draw.Label('Export Objects...', x+20,y+165, 200, 20) - - if not GLOBALS['BATCH_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) - GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) - Draw.EndAlign() - - Draw.BeginAlign() - GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') - GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') - GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') - GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') - Draw.EndAlign() - - y -= 35 - - Draw.BeginAlign() - GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') - GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') - GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') - GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') - GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) - Draw.EndAlign() - - if GLOBALS['EXP_MESH'].val: - # below mesh but - Draw.BeginAlign() - GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) - GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) - Draw.EndAlign() - - GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) - - - Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) - - GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) - if GLOBALS['ANIM_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) - if GLOBALS['ANIM_OPTIMIZE'].val: - GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 1, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') - Draw.EndAlign() - - Draw.BeginAlign() - GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) - GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) - Draw.EndAlign() - - - Draw.Label('Export Batch...', x+20,y-60, 300, 20) - GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) - - if GLOBALS['BATCH_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) - GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) - - # Own dir requires OS module - if os: - GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') - GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') - else: - GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') - - - Draw.EndAlign() - - #y+=80 - - ''' - Draw.BeginAlign() - GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') - Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) - ''' - # Until batch is added - # - - - #Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) - Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) - - #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) - #Draw.EndAlign() - - # exit when mouse out of the view? - # GLOBALS['EVENT'] = EVENT_EXIT - -#def write_ui(filename): -def write_ui(): - - # globals - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - GLOBALS['FILENAME'] = '' - ''' - # IF called from the fileselector - if filename == None: - GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) - else: - GLOBALS['FILENAME'].val = filename - ''' - GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity - GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) - - GLOBALS['EXP_MESH'] = Draw.Create(1) - GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) - GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) - GLOBALS['EXP_ARMATURE'] = Draw.Create(1) - GLOBALS['EXP_LAMP'] = Draw.Create(1) - GLOBALS['EXP_CAMERA'] = Draw.Create(1) - GLOBALS['EXP_EMPTY'] = Draw.Create(1) - GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) - # animation opts - GLOBALS['ANIM_ENABLE'] = Draw.Create(1) - GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) - GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(4) # decimal places - GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action - - # batch export options - GLOBALS['BATCH_ENABLE'] = Draw.Create(0) - GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. - GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above - GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) - GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) - # done setting globals - - # Used by the user interface - GLOBALS['_SCALE'] = Draw.Create(1.0) - GLOBALS['_XROT90'] = Draw.Create(True) - GLOBALS['_YROT90'] = Draw.Create(False) - GLOBALS['_ZROT90'] = Draw.Create(False) - - # best not do move the cursor - # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] != EVENT_EXIT: - - if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: - #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") - GLOBALS['ANIM_ACTION_ALL'][0].val = 1 - GLOBALS['ANIM_ACTION_ALL'][1].val = 0 - - if GLOBALS['EVENT'] == EVENT_FILESEL: - if GLOBALS['BATCH_ENABLE'].val: - txt = 'Batch FBX Dir' - name = Blender.sys.expandpath('//') - else: - txt = 'Export FBX' - name = Blender.sys.makename(ext='.fbx') - - Blender.Window.FileSelector(fbx_ui_write, txt, name) - #fbx_ui_write('/test.fbx') - break - - Draw.UIBlock(fbx_ui, 0) - - - # GLOBALS.clear() - -class EXPORT_OT_fbx(bpy.types.Operator): - ''' - Operator documentation text, will be used for the operator tooltip and python docs. - ''' - __idname__ = "export.fbx" - __label__ = "Export FBX" - - # 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=""), - bpy.props.BoolProperty(attr="EXP_OBS_SELECTED", name="Selected Objects", description="Export selected objects on visible layers", default=True), -# bpy.props.BoolProperty(attr="EXP_OBS_SCENE", name="Scene Objects", description="Export all objects in this scene", default=True), - bpy.props.FloatProperty(attr="_SCALE", name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0), - bpy.props.BoolProperty(attr="_XROT90", name="Rot X90", description="Rotate all objects 90 degrese about the X axis", default=True), - bpy.props.BoolProperty(attr="_YROT90", name="Rot Y90", description="Rotate all objects 90 degrese about the Y axis", default=False), - bpy.props.BoolProperty(attr="_ZROT90", name="Rot Z90", description="Rotate all objects 90 degrese about the Z axis", default=False), - bpy.props.BoolProperty(attr="EXP_EMPTY", name="Empties", description="Export empty objects", default=True), - bpy.props.BoolProperty(attr="EXP_CAMERA", name="Cameras", description="Export camera objects", default=True), - bpy.props.BoolProperty(attr="EXP_LAMP", name="Lamps", description="Export lamp objects", default=True), - bpy.props.BoolProperty(attr="EXP_ARMATURE", name="Armatures", description="Export armature objects", default=True), - bpy.props.BoolProperty(attr="EXP_MESH", name="Meshes", description="Export mesh objects", default=True), - bpy.props.BoolProperty(attr="EXP_MESH_APPLY_MOD", name="Modifiers", description="Apply modifiers to mesh objects", default=True), - bpy.props.BoolProperty(attr="EXP_MESH_HQ_NORMALS", name="HQ Normals", description="Generate high quality normals", default=True), - bpy.props.BoolProperty(attr="EXP_IMAGE_COPY", name="Copy Image Files", description="Copy image files to the destination path", default=False), - # armature animation - bpy.props.BoolProperty(attr="ANIM_ENABLE", name="Enable Animation", description="Export keyframe animation", default=True), - bpy.props.BoolProperty(attr="ANIM_OPTIMIZE", name="Optimize Keyframes", description="Remove double keyframes", default=True), - bpy.props.FloatProperty(attr="ANIM_OPTIMIZE_PRECISSION", name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0), -# bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True), - bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures, if false, use current action", default=False), - # batch - bpy.props.BoolProperty(attr="BATCH_ENABLE", name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False), - bpy.props.BoolProperty(attr="BATCH_GROUP", name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False), - bpy.props.BoolProperty(attr="BATCH_OWN_DIR", name="Own Dir", description="Create a dir for each exported file", default=True), - bpy.props.StringProperty(attr="BATCH_FILE_PREFIX", name="Prefix", description="Prefix each file with this name", maxlen= 1024, default=""), - ] - - def poll(self, context): - print("Poll") - return context.active_object != None - - def execute(self, context): - if not self.filename: - raise Exception("filename not set") - - GLOBAL_MATRIX = mtx4_identity - GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self._SCALE - if self._XROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n - if self._YROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n - if self._ZROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n - - write(self.filename, - None, # XXX - context, - self.EXP_OBS_SELECTED, - self.EXP_MESH, - self.EXP_MESH_APPLY_MOD, -# self.EXP_MESH_HQ_NORMALS, - self.EXP_ARMATURE, - self.EXP_LAMP, - self.EXP_CAMERA, - self.EXP_EMPTY, - self.EXP_IMAGE_COPY, - GLOBAL_MATRIX, - self.ANIM_ENABLE, - self.ANIM_OPTIMIZE, - self.ANIM_OPTIMIZE_PRECISSION, - self.ANIM_ACTION_ALL, - self.BATCH_ENABLE, - self.BATCH_GROUP, - self.BATCH_FILE_PREFIX, - self.BATCH_OWN_DIR) - - return ('FINISHED',) - - def invoke(self, context, event): - wm = context.manager - wm.add_fileselect(self.__operator__) - return ('RUNNING_MODAL',) - - -bpy.ops.add(EXPORT_OT_fbx) - -# if __name__ == "__main__": -# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply") - - -# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) -# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print -# - get rid of cleanName somehow -# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 -# + get rid of BPyObject_getObjectArmature, move it in RNA? -# - BATCH_ENABLE and BATCH_GROUP options: line 327 -# - implement all BPyMesh_* used here with RNA -# - getDerivedObjects is not fully replicated with .dupli* funcs -# - talk to Campbell, this code won't work? lines 1867-1875 -# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893 -# - no hq normals: 1900-1901 - -# TODO - -# - bpy.data.remove_scene: line 366 -# - bpy.sys.time move to bpy.sys.util? -# - new scene creation, activation: lines 327-342, 368 -# - uses bpy.sys.expandpath, *.relpath - replace at least relpath - -# SMALL or COSMETICAL -# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version') diff --git a/release/io/export_obj.py b/release/io/export_obj.py deleted file mode 100644 index e2ac78798bd..00000000000 --- a/release/io/export_obj.py +++ /dev/null @@ -1,993 +0,0 @@ -#!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 math and other in functions that use them for the sake of fast Blender startup -# import math -import os -import time - -import bpy -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, copy_images): - - world = scene.world - worldAmb = world.ambient_color - - dest_dir = os.path.dirname(filename) - - def copy_image(image): - rel = image.get_export_path(dest_dir, True) - - if copy_images: - abspath = image.get_export_path(dest_dir, False) - if not os.path.exists(abs_path): - shutil.copy(image.get_abs_filename(), abs_path) - - return rel - - - 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_intensity for c in mat.diffuse_color]) ) # Diffuse - file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular - if hasattr(mat, "ior"): - file.write('Ni %.6f\n' % mat.ior) # Refraction index - else: - file.write('Ni %.6f\n' % 1.0) - 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_intensity == 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! - # write relative image path - rel = copy_image(img) - file.write('map_Kd %s\n' % rel) # Diffuse mapping image -# 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 = copy_image(mtex.texture.image) -# 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() - -# XXX not used -def copy_file(source, dest): - file = open(source, 'rb') - data = file.read() - file.close() - - file = open(dest, 'wb') - file.write(data) - file.close() - - -# XXX not used -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 - -# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir) - - print('\tCopied %d images' % copyCount) -# print('\tCopied %d images' % copyCount) - -# XXX not converted -def test_nurbs_compat(ob): - if ob.type != 'Curve': - return False - - for nu in ob.data: - if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier - return True - - return False - - -# 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. - ''' - - # XXX - import math - - 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 = time.clock() -# 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(-math.pi/2, 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: - - # 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': - # XXX - print('creating dupli_list on', ob_main.name) - ob_main.create_dupli_list() - - obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list] - - # XXX debug print - print(ob_main.name, 'has', len(obs), 'dupli children') - else: - obs = [(ob_main, ob_main.matrix)] - - for ob, ob_mat in obs: - - # XXX postponed -# # Nurbs curve support -# if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): -# if EXPORT_ROTX90: -# ob_mat = ob_mat * mat_xrot90 - -# totverts += write_nurb(file, ob, ob_mat) - -# continue -# end nurbs - - if ob.type != 'MESH': - continue - - me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') - - if EXPORT_ROTX90: - me.transform(ob_mat * mat_xrot90) - else: - 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_textures) > 0 - else: - faceuv = False - - # XXX - todo, find a better way to do triangulation - # ...removed convert_to_triface because it relies on editmesh - ''' - # 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: - me.calc_normals() -# 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_texture.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_texture - 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_texture.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, EXPORT_COPY_IMAGES) -# if EXPORT_COPY_IMAGES: -# dest_dir = os.path.basename(filename) -# # 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" % (time.clock() - 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 - ''' - __idname__ = "export.obj" - __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 OBJ file", maxlen= 1024, default= ""), - - # context group - bpy.props.BoolProperty(attr="use_selection", name="Selection Only", description="", default= False), - 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 -# - get rid of cleanName somehow diff --git a/release/io/export_ply.py b/release/io/export_ply.py deleted file mode 100644 index 8e79c3741bb..00000000000 --- a/release/io/export_ply.py +++ /dev/null @@ -1,279 +0,0 @@ -import bpy - -__author__ = "Bruce Merry" -__version__ = "0.93" -__bpydoc__ = """\ -This script exports Stanford PLY files from Blender. It supports normals, -colours, and texture coordinates per face or per vertex. -Only one mesh can be exported at a time. -""" - -# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za -# -# 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. -# Vector rounding se we can use as keys -# -# Updated on Aug 11, 2008 by Campbell Barton -# - added 'comment' prefix to comments - Needed to comply with the PLY spec. -# -# Updated on Jan 1, 2007 by Gabe Ghearing -# - fixed normals so they are correctly smooth/flat -# - fixed crash when the model doesn't have uv coords or vertex colors -# - fixed crash when the model has vertex colors but doesn't have uv coords -# - changed float32 to float and uint8 to uchar for compatibility -# Errata/Notes as of Jan 1, 2007 -# - script exports texture coords if they exist even if TexFace isn't selected (not a big deal to me) -# - ST(R) should probably be renamed UV(T) like in most PLY files (importer needs to be updated to take either) -# -# Updated on Jan 3, 2007 by Gabe Ghearing -# - fixed "sticky" vertex UV exporting -# - added pupmenu to enable/disable exporting normals, uv coords, and colors -# Errata/Notes as of Jan 3, 2007 -# - ST(R) coords should probably be renamed UV(T) like in most PLY files (importer needs to be updated to take either) -# - edges should be exported since PLY files support them -# - code is getting spaghettish, it should be refactored... -# - - -def rvec3d(v): return round(v[0], 6), round(v[1], 6), round(v[2], 6) -def rvec2d(v): return round(v[0], 6), round(v[1], 6) - -def write(filename, scene, ob, \ - EXPORT_APPLY_MODIFIERS= True,\ - EXPORT_NORMALS= True,\ - EXPORT_UV= True,\ - EXPORT_COLORS= True\ - ): - - if not filename.lower().endswith('.ply'): - filename += '.ply' - - if not ob: - raise Exception("Error, Select 1 active object") - return - - file = open(filename, 'w') - - - #EXPORT_EDGES = Draw.Create(0) - """ - is_editmode = Blender.Window.EditMode() - if is_editmode: - Blender.Window.EditMode(0, '', 0) - - Window.WaitCursor(1) - """ - - #mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX - if EXPORT_APPLY_MODIFIERS: - mesh = ob.create_mesh(True, 'PREVIEW') - else: - mesh = ob.data - - if not mesh: - raise ("Error, could not get mesh data from active object") - return - - # mesh.transform(ob.matrixWorld) # XXX - - faceUV = len(mesh.uv_textures) > 0 - vertexUV = len(mesh.sticky) > 0 - vertexColors = len(mesh.vertex_colors) > 0 - - if (not faceUV) and (not vertexUV): EXPORT_UV = False - if not vertexColors: EXPORT_COLORS = False - - if not EXPORT_UV: faceUV = vertexUV = False - if not EXPORT_COLORS: vertexColors = False - - if faceUV: - active_uv_layer = None - for lay in mesh.uv_textures: - if lay.active: - active_uv_layer= lay.data - break - if not active_uv_layer: - EXPORT_UV = False - faceUV = None - - if vertexColors: - active_col_layer = None - for lay in mesh.vertex_colors: - if lay.active: - active_col_layer= lay.data - if not active_col_layer: - EXPORT_COLORS = False - vertexColors = None - - # incase - color = uvcoord = uvcoord_key = normal = normal_key = None - - mesh_verts = mesh.verts # save a lookup - ply_verts = [] # list of dictionaries - # vdict = {} # (index, normal, uv) -> new index - 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): - - - smooth = f.smooth - if not smooth: - normal = tuple(f.normal) - normal_key = rvec3d(normal) - - if faceUV: - uv = active_uv_layer[i] - uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/ - if vertexColors: - col = active_col_layer[i] - col = col.color1, col.color2, col.color3, col.color4 - - f_verts= f.verts - - pf= ply_faces[i] - for j, vidx in enumerate(f_verts): - v = mesh_verts[vidx] - - if smooth: - normal= tuple(v.normal) - normal_key = rvec3d(normal) - - if faceUV: - uvcoord= uv[j][0], 1.0-uv[j][1] - uvcoord_key = rvec2d(uvcoord) - elif vertexUV: - uvcoord= v.uvco[0], 1.0-v.uvco[1] - uvcoord_key = rvec2d(uvcoord) - - if vertexColors: - color= col[j] - color= int(color[0]*255.0), int(color[1]*255.0), int(color[2]*255.0) - - - key = normal_key, uvcoord_key, color - - vdict_local = vdict[vidx] - pf_vidx = vdict_local.get(key) # Will be None initially - - if pf_vidx == None: # same as vdict_local.has_key(key) - pf_vidx = vdict_local[key] = vert_count; - ply_verts.append((vidx, normal, uvcoord, color)) - vert_count += 1 - - pf.append(pf_vidx) - - file.write('ply\n') - file.write('format ascii 1.0\n') - version = "2.5" # Blender.Get('version') - file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1] )) - - file.write('element vertex %d\n' % len(ply_verts)) - - file.write('property float x\n') - file.write('property float y\n') - file.write('property float z\n') - - # XXX - """ - if EXPORT_NORMALS: - file.write('property float nx\n') - file.write('property float ny\n') - file.write('property float nz\n') - """ - if EXPORT_UV: - file.write('property float s\n') - file.write('property float t\n') - if EXPORT_COLORS: - file.write('property uchar red\n') - file.write('property uchar green\n') - file.write('property uchar blue\n') - - file.write('element face %d\n' % len(mesh.faces)) - file.write('property list uchar uint vertex_indices\n') - file.write('end_header\n') - - for i, v in enumerate(ply_verts): - file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co - """ - if EXPORT_NORMALS: - file.write('%.6f %.6f %.6f ' % v[1]) # no - """ - if EXPORT_UV: file.write('%.6f %.6f ' % v[2]) # uv - if EXPORT_COLORS: file.write('%u %u %u' % v[3]) # col - file.write('\n') - - for pf in ply_faces: - if len(pf)==3: file.write('3 %d %d %d\n' % tuple(pf)) - else: file.write('4 %d %d %d %d\n' % tuple(pf)) - - file.close() - print("writing", filename, "done") - - if EXPORT_APPLY_MODIFIERS: - bpy.data.remove_mesh(mesh) - - # XXX - """ - if is_editmode: - Blender.Window.EditMode(1, '', 0) - """ - -class EXPORT_OT_ply(bpy.types.Operator): - '''Export a single object as a stanford PLY with normals, colours and texture coordinates.''' - __idname__ = "export.ply" - __label__ = "Export PLY" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [ - bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= ""), - bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True), - bpy.props.BoolProperty(attr="use_normals", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True), - bpy.props.BoolProperty(attr="use_uvs", name="Export UVs", description="Exort the active UV layer", default= True), - bpy.props.BoolProperty(attr="use_colors", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True) - ] - - def poll(self, context): - return context.active_object != None - - def execute(self, context): - # print("Selected: " + context.active_object.name) - - if not self.path: - raise Exception("filename not set") - - write(self.path, context.scene, context.active_object,\ - EXPORT_APPLY_MODIFIERS = self.use_modifiers, - EXPORT_NORMALS = self.use_normals, - EXPORT_UV = self.use_uvs, - EXPORT_COLORS = self.use_colors, - ) - - return ('FINISHED',) - - def invoke(self, context, event): - wm = context.manager - wm.add_fileselect(self.__operator__) - return ('RUNNING_MODAL',) - - -bpy.ops.add(EXPORT_OT_ply) - -if __name__ == "__main__": - bpy.ops.EXPORT_OT_ply(path="/tmp/test.ply") - - diff --git a/release/io/export_x3d.py b/release/io/export_x3d.py deleted file mode 100644 index f23ccf8d2dc..00000000000 --- a/release/io/export_x3d.py +++ /dev/null @@ -1,1239 +0,0 @@ -#!BPY -""" Registration info for Blender menus: -Name: 'X3D Extensible 3D (.x3d)...' -Blender: 245 -Group: 'Export' -Tooltip: 'Export selection to Extensible 3D file (.x3d)' -""" - -__author__ = ("Bart", "Campbell Barton") -__email__ = ["Bart, bart:neeneenee*de"] -__url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml"] -__version__ = "2006/01/17" -__bpydoc__ = """\ -This script exports to X3D format. - -Usage: - -Run this script from "File->Export" menu. A pop-up will ask whether you -want to export only selected or all relevant objects. - -Known issues:
- Doesn't handle multiple materials (don't use material indices);
- Doesn't handle multiple UV textures on a single mesh (create a mesh for each texture);
- Can't get the texture array associated with material * not the UV ones; -""" - - -# $Id$ -# -#------------------------------------------------------------------------ -# X3D exporter for blender 2.36 or above -# -# ***** 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 ***** -# - -#################################### -# Library dependancies -#################################### - -import math -import os - -import bpy -import Mathutils - -from export_3ds import create_derived_objects, free_derived_objects - -# import Blender -# from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh -# from Blender.Scene import Render -# import BPyObject -# import BPyMesh - -# -DEG2RAD=0.017453292519943295 -MATWORLD= Mathutils.RotationMatrix(-90, 4, 'x') - -#################################### -# Global Variables -#################################### - -filename = "" -# filename = Blender.Get('filename') -_safeOverwrite = True - -extension = '' - -########################################################## -# Functions for writing output file -########################################################## - -class x3d_class: - - def __init__(self, filename): - #--- public you can change these --- - self.writingcolor = 0 - self.writingtexture = 0 - self.writingcoords = 0 - self.proto = 1 - self.matonly = 0 - self.share = 0 - self.billnode = 0 - self.halonode = 0 - self.collnode = 0 - self.tilenode = 0 - self.verbose=2 # level of verbosity in console 0-none, 1-some, 2-most - self.cp=3 # decimals for material color values 0.000 - 1.000 - self.vp=3 # decimals for vertex coordinate values 0.000 - n.000 - self.tp=3 # decimals for texture coordinate values 0.000 - 1.000 - self.it=3 - - #--- class private don't touch --- - self.texNames={} # dictionary of textureNames - self.matNames={} # dictionary of materiaNames - self.meshNames={} # dictionary of meshNames - self.indentLevel=0 # keeps track of current indenting - self.filename=filename - self.file = None - if filename.lower().endswith('.x3dz'): - try: - import gzip - self.file = gzip.open(filename, "w") - except: - print("failed to import compression modules, exporting uncompressed") - self.filename = filename[:-1] # remove trailing z - - if self.file == None: - self.file = open(self.filename, "w") - - self.bNav=0 - self.nodeID=0 - self.namesReserved=[ "Anchor","Appearance","Arc2D","ArcClose2D","AudioClip","Background","Billboard", - "BooleanFilter","BooleanSequencer","BooleanToggle","BooleanTrigger","Box","Circle2D", - "Collision","Color","ColorInterpolator","ColorRGBA","component","Cone","connect", - "Contour2D","ContourPolyline2D","Coordinate","CoordinateDouble","CoordinateInterpolator", - "CoordinateInterpolator2D","Cylinder","CylinderSensor","DirectionalLight","Disk2D", - "ElevationGrid","EspduTransform","EXPORT","ExternProtoDeclare","Extrusion","field", - "fieldValue","FillProperties","Fog","FontStyle","GeoCoordinate","GeoElevationGrid", - "GeoLocationLocation","GeoLOD","GeoMetadata","GeoOrigin","GeoPositionInterpolator", - "GeoTouchSensor","GeoViewpoint","Group","HAnimDisplacer","HAnimHumanoid","HAnimJoint", - "HAnimSegment","HAnimSite","head","ImageTexture","IMPORT","IndexedFaceSet", - "IndexedLineSet","IndexedTriangleFanSet","IndexedTriangleSet","IndexedTriangleStripSet", - "Inline","IntegerSequencer","IntegerTrigger","IS","KeySensor","LineProperties","LineSet", - "LoadSensor","LOD","Material","meta","MetadataDouble","MetadataFloat","MetadataInteger", - "MetadataSet","MetadataString","MovieTexture","MultiTexture","MultiTextureCoordinate", - "MultiTextureTransform","NavigationInfo","Normal","NormalInterpolator","NurbsCurve", - "NurbsCurve2D","NurbsOrientationInterpolator","NurbsPatchSurface", - "NurbsPositionInterpolator","NurbsSet","NurbsSurfaceInterpolator","NurbsSweptSurface", - "NurbsSwungSurface","NurbsTextureCoordinate","NurbsTrimmedSurface","OrientationInterpolator", - "PixelTexture","PlaneSensor","PointLight","PointSet","Polyline2D","Polypoint2D", - "PositionInterpolator","PositionInterpolator2D","ProtoBody","ProtoDeclare","ProtoInstance", - "ProtoInterface","ProximitySensor","ReceiverPdu","Rectangle2D","ROUTE","ScalarInterpolator", - "Scene","Script","Shape","SignalPdu","Sound","Sphere","SphereSensor","SpotLight","StaticGroup", - "StringSensor","Switch","Text","TextureBackground","TextureCoordinate","TextureCoordinateGenerator", - "TextureTransform","TimeSensor","TimeTrigger","TouchSensor","Transform","TransmitterPdu", - "TriangleFanSet","TriangleSet","TriangleSet2D","TriangleStripSet","Viewpoint","VisibilitySensor", - "WorldInfo","X3D","XvlShell","VertexShader","FragmentShader","MultiShaderAppearance","ShaderAppearance" ] - self.namesStandard=[ "Empty","Empty.000","Empty.001","Empty.002","Empty.003","Empty.004","Empty.005", - "Empty.006","Empty.007","Empty.008","Empty.009","Empty.010","Empty.011","Empty.012", - "Scene.001","Scene.002","Scene.003","Scene.004","Scene.005","Scene.06","Scene.013", - "Scene.006","Scene.007","Scene.008","Scene.009","Scene.010","Scene.011","Scene.012", - "World","World.000","World.001","World.002","World.003","World.004","World.005" ] - self.namesFog=[ "","LINEAR","EXPONENTIAL","" ] - -########################################################## -# Writing nodes routines -########################################################## - - def writeHeader(self): - #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '<').replace('>', '>') - bfile = self.filename.replace('<', '<').replace('>', '>') # use outfile name - self.file.write("\n") - self.file.write("\n") - self.file.write("\n") - self.file.write("\n") - self.file.write("\t\n" % os.path.basename(bfile)) - # self.file.write("\t\n" % sys.basename(bfile)) - self.file.write("\t\n" % '2.5') - # self.file.write("\t\n" % Blender.Get('version')) - self.file.write("\t\n") - self.file.write("\n") - self.file.write("\n") - - # This functionality is poorly defined, disabling for now - campbell - ''' - def writeInline(self): - inlines = Blender.Scene.Get() - allinlines = len(inlines) - if scene != inlines[0]: - return - else: - for i in xrange(allinlines): - nameinline=inlines[i].name - if (nameinline not in self.namesStandard) and (i > 0): - self.file.write("" % nameinline) - self.file.write("\n\n") - - - def writeScript(self): - textEditor = Blender.Text.Get() - alltext = len(textEditor) - for i in xrange(alltext): - nametext = textEditor[i].name - nlines = textEditor[i].getNLines() - if (self.proto == 1): - if (nametext == "proto" or nametext == "proto.js" or nametext == "proto.txt") and (nlines != None): - nalllines = len(textEditor[i].asLines()) - alllines = textEditor[i].asLines() - for j in xrange(nalllines): - self.writeIndented(alllines[j] + "\n") - elif (self.proto == 0): - if (nametext == "route" or nametext == "route.js" or nametext == "route.txt") and (nlines != None): - nalllines = len(textEditor[i].asLines()) - alllines = textEditor[i].asLines() - for j in xrange(nalllines): - self.writeIndented(alllines[j] + "\n") - self.writeIndented("\n") - ''' - - def writeViewpoint(self, ob, mat, scene): - context = scene.render_data - # context = scene.render - ratio = float(context.resolution_x)/float(context.resolution_y) - # ratio = float(context.imageSizeY())/float(context.imageSizeX()) - lens = (360* (math.atan(ratio *16 / ob.data.lens) / math.pi))*(math.pi/180) - # lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180) - lens = min(lens, math.pi) - - # get the camera location, subtract 90 degress from X to orient like X3D does - # mat = ob.matrixWorld - mat is now passed! - - loc = self.rotatePointForVRML(mat.translationPart()) - rot = mat.toEuler() - rot = (((rot[0]-90)), rot[1], rot[2]) - # rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD) - nRot = self.rotatePointForVRML( rot ) - # convert to Quaternion and to Angle Axis - Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2]) - Q1 = self.multiplyQuaternions(Q[0], Q[1]) - Qf = self.multiplyQuaternions(Q1, Q[2]) - angleAxis = self.quaternionToAngleAxis(Qf) - self.file.write("\n\n" % (lens)) - - def writeFog(self, world): - if world: - mtype = world.mist.falloff - # mtype = world.getMistype() - mparam = world.mist - # mparam = world.getMist() - grd = world.horizon_color - # grd = world.getHor() - grd0, grd1, grd2 = grd[0], grd[1], grd[2] - else: - return - if (mtype == 'LINEAR' or mtype == 'INVERSE_QUADRATIC'): - mtype = 1 if mtype == 'LINEAR' else 2 - # if (mtype == 1 or mtype == 2): - self.file.write("\n\n" % round(mparam[2],self.cp)) - else: - return - - def writeNavigationInfo(self, scene): - self.file.write('\n') - - def writeSpotLight(self, ob, mtx, lamp, world): - safeName = self.cleanStr(ob.name) - if world: - ambi = world.ambient_color - # ambi = world.amb - ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 - else: - ambi = 0 - ambientIntensity = 0 - - # compute cutoff and beamwidth - intensity=min(lamp.energy/1.75,1.0) - beamWidth=((lamp.spot_size*math.pi)/180.0)*.37; - # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37; - cutOffAngle=beamWidth*1.3 - - dx,dy,dz=self.computeDirection(mtx) - # note -dx seems to equal om[3][0] - # note -dz seems to equal om[3][1] - # note dy seems to equal om[3][2] - - #location=(ob.matrixWorld*MATWORLD).translationPart() # now passed - location=(mtx*MATWORLD).translationPart() - - radius = lamp.distance*math.cos(beamWidth) - # radius = lamp.dist*math.cos(beamWidth) - self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) - - - def writeDirectionalLight(self, ob, mtx, lamp, world): - safeName = self.cleanStr(ob.name) - if world: - ambi = world.ambient_color - # ambi = world.amb - ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 - else: - ambi = 0 - ambientIntensity = 0 - - intensity=min(lamp.energy/1.75,1.0) - (dx,dy,dz)=self.computeDirection(mtx) - self.file.write("\n\n" % (round(dx,4),round(dy,4),round(dz,4))) - - def writePointLight(self, ob, mtx, lamp, world): - safeName = self.cleanStr(ob.name) - if world: - ambi = world.ambient_color - # ambi = world.amb - ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 - else: - ambi = 0 - ambientIntensity = 0 - - # location=(ob.matrixWorld*MATWORLD).translationPart() # now passed - location= (mtx*MATWORLD).translationPart() - - self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) - ''' - def writeNode(self, ob, mtx): - obname=str(ob.name) - if obname in self.namesStandard: - return - else: - dx,dy,dz = self.computeDirection(mtx) - # location=(ob.matrixWorld*MATWORLD).translationPart() - location=(mtx*MATWORLD).translationPart() - self.writeIndented("<%s\n" % obname,1) - self.writeIndented("direction=\"%s %s %s\"\n" % (round(dx,3),round(dy,3),round(dz,3))) - self.writeIndented("location=\"%s %s %s\"\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) - self.writeIndented("/>\n",-1) - self.writeIndented("\n") - ''' - def secureName(self, name): - name = name + str(self.nodeID) - self.nodeID=self.nodeID+1 - if len(name) <= 3: - newname = "_" + str(self.nodeID) - return "%s" % (newname) - else: - for bad in ['"','#',"'",',','.','[','\\',']','{','}']: - name=name.replace(bad,'_') - if name in self.namesReserved: - newname = name[0:3] + "_" + str(self.nodeID) - return "%s" % (newname) - elif name[0].isdigit(): - newname = "_" + name + str(self.nodeID) - return "%s" % (newname) - else: - newname = name - return "%s" % (newname) - - def writeIndexedFaceSet(self, ob, mesh, mtx, world, EXPORT_TRI = False): - imageMap={} # set of used images - sided={} # 'one':cnt , 'two':cnt - vColors={} # 'multi':1 - meshName = self.cleanStr(ob.name) - - meshME = self.cleanStr(ob.data.name) # We dont care if its the mesh name or not - # meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not - if len(mesh.faces) == 0: return - mode = [] - # mode = 0 - if mesh.active_uv_texture: - # if mesh.faceUV: - for face in mesh.active_uv_texture.data: - # for face in mesh.faces: - if face.halo and 'HALO' not in mode: - mode += ['HALO'] - if face.billboard and 'BILLBOARD' not in mode: - mode += ['BILLBOARD'] - if face.object_color and 'OBJECT_COLOR' not in mode: - mode += ['OBJECT_COLOR'] - if face.collision and 'COLLISION' not in mode: - mode += ['COLLISION'] - # mode |= face.mode - - if 'HALO' in mode and self.halonode == 0: - # if mode & Mesh.FaceModes.HALO and self.halonode == 0: - self.writeIndented("\n",1) - self.halonode = 1 - elif 'BILLBOARD' in mode and self.billnode == 0: - # elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: - self.writeIndented("\n",1) - self.billnode = 1 - elif 'OBJECT_COLOR' in mode and self.matonly == 0: - # elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0: - self.matonly = 1 - # TF_TILES is marked as deprecated in DNA_meshdata_types.h - # elif mode & Mesh.FaceModes.TILES and self.tilenode == 0: - # self.tilenode = 1 - elif 'COLLISION' not in mode and self.collnode == 0: - # elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0: - self.writeIndented("\n",1) - self.collnode = 1 - - nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) - - if nIFSCnt > 1: - self.writeIndented("\n" % ("G_", meshName),1) - - if 'two' in sided and sided['two'] > 0: - bTwoSided=1 - else: - bTwoSided=0 - - # mtx = ob.matrixWorld * MATWORLD # mtx is now passed - mtx = mtx * MATWORLD - - loc= mtx.translationPart() - sca= mtx.scalePart() - quat = mtx.toQuat() - rot= quat.axis - - self.writeIndented('\n' % \ - (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle) ) - # self.writeIndented('\n' % \ - # (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) ) - - self.writeIndented("\n",1) - maters=mesh.materials - hasImageTexture=0 - issmooth=0 - - if len(maters) > 0 or mesh.active_uv_texture: - # if len(maters) > 0 or mesh.faceUV: - self.writeIndented("\n", 1) - # right now this script can only handle a single material per mesh. - if len(maters) >= 1: - mat=maters[0] - # matFlags = mat.getMode() - if not mat.face_texture: - # if not matFlags & Blender.Material.Modes['TEXFACE']: - self.writeMaterial(mat, self.cleanStr(mat.name,''), world) - # self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) - if len(maters) > 1: - print("Warning: mesh named %s has multiple materials" % meshName) - print("Warning: only one material per object handled") - - #-- textures - face = None - if mesh.active_uv_texture: - # if mesh.faceUV: - for face in mesh.active_uv_texture.data: - # for face in mesh.faces: - if face.image: - # if (hasImageTexture == 0) and (face.image): - self.writeImageTexture(face.image) - # hasImageTexture=1 # keep track of face texture - break - if self.tilenode == 1 and face and face.image: - # if self.tilenode == 1: - self.writeIndented("\n" % (face.image.xrep, face.image.yrep)) - self.tilenode = 0 - self.writeIndented("\n", -1) - - #-- IndexedFaceSet or IndexedLineSet - - # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5 - ifStyle="IndexedFaceSet" - # look up mesh name, use it if available - if meshME in self.meshNames: - self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1) - self.meshNames[meshME]+=1 - else: - if int(mesh.users) > 1: - self.writeIndented("<%s DEF=\"ME_%s\" " % (ifStyle, meshME), 1) - self.meshNames[meshME]=1 - else: - self.writeIndented("<%s " % ifStyle, 1) - - if bTwoSided == 1: - self.file.write("solid=\"false\" ") - else: - self.file.write("solid=\"true\" ") - - for face in mesh.faces: - if face.smooth: - issmooth=1 - break - if issmooth==1: - creaseAngle=(mesh.autosmooth_angle)*(math.pi/180.0) - # creaseAngle=(mesh.degr)*(math.pi/180.0) - self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) - - #--- output textureCoordinates if UV texture used - if mesh.active_uv_texture: - # if mesh.faceUV: - if self.matonly == 1 and self.share == 1: - self.writeFaceColors(mesh) - elif hasImageTexture == 1: - self.writeTextureCoordinates(mesh) - #--- output coordinates - self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) - - self.writingcoords = 1 - self.writingtexture = 1 - self.writingcolor = 1 - self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) - - #--- output textureCoordinates if UV texture used - if mesh.active_uv_texture: - # if mesh.faceUV: - if hasImageTexture == 1: - self.writeTextureCoordinates(mesh) - elif self.matonly == 1 and self.share == 1: - self.writeFaceColors(mesh) - #--- output vertexColors - self.matonly = 0 - self.share = 0 - - self.writingcoords = 0 - self.writingtexture = 0 - self.writingcolor = 0 - #--- output closing braces - self.writeIndented("\n" % ifStyle, -1) - self.writeIndented("\n", -1) - self.writeIndented("\n", -1) - - if self.halonode == 1: - self.writeIndented("\n", -1) - self.halonode = 0 - - if self.billnode == 1: - self.writeIndented("\n", -1) - self.billnode = 0 - - if self.collnode == 1: - self.writeIndented("\n", -1) - self.collnode = 0 - - if nIFSCnt > 1: - self.writeIndented("
\n", -1) - - self.file.write("\n") - - def writeCoordinates(self, ob, mesh, meshName, EXPORT_TRI = False): - # create vertex list and pre rotate -90 degrees X for VRML - - if self.writingcoords == 0: - self.file.write('coordIndex="') - for face in mesh.faces: - fv = face.verts - # fv = face.v - - if len(fv)==3: - # if len(face)==3: - self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) - # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) - else: - if EXPORT_TRI: - self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) - # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) - self.file.write("%i %i %i -1, " % (fv[0], fv[2], fv[3])) - # self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index)) - else: - self.file.write("%i %i %i %i -1, " % (fv[0], fv[1], fv[2], fv[3])) - # self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index)) - - self.file.write("\">\n") - else: - #-- vertices - # mesh.transform(ob.matrixWorld) - self.writeIndented("") - self.writeIndented("\n", -1) - - def writeTextureCoordinates(self, mesh): - texCoordList=[] - texIndexList=[] - j=0 - - for face in mesh.active_uv_texture.data: - # for face in mesh.faces: - uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.verts[3] else [face.uv1, face.uv2, face.uv3] - - for uv in uvs: - # for uv in face.uv: - texIndexList.append(j) - texCoordList.append(uv) - j=j+1 - texIndexList.append(-1) - if self.writingtexture == 0: - self.file.write("\n\t\t\ttexCoordIndex=\"") - texIndxStr="" - for i in range(len(texIndexList)): - texIndxStr = texIndxStr + "%d, " % texIndexList[i] - if texIndexList[i]==-1: - self.file.write(texIndxStr) - texIndxStr="" - self.file.write("\"\n\t\t\t") - else: - self.writeIndented("") - self.writeIndented("\n", -1) - - def writeFaceColors(self, mesh): - if self.writingcolor == 0: - self.file.write("colorPerVertex=\"false\" ") - elif mesh.active_vertex_color: - # else: - self.writeIndented(" 2: - print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2])) - # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) - aColor = self.rgbToFS(c) - self.file.write("%s, " % aColor) - - # for face in mesh.faces: - # if face.col: - # c=face.col[0] - # if self.verbose > 2: - # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) - # aColor = self.rgbToFS(c) - # self.file.write("%s, " % aColor) - self.file.write("\" />") - self.writeIndented("\n",-1) - - def writeMaterial(self, mat, matName, world): - # look up material name, use it if available - if matName in self.matNames: - self.writeIndented("\n" % matName) - self.matNames[matName]+=1 - return; - - self.matNames[matName]=1 - - ambient = mat.ambient/3 - # ambient = mat.amb/3 - diffuseR, diffuseG, diffuseB = tuple(mat.diffuse_color) - # diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] - if world: - ambi = world.ambient_color - # ambi = world.getAmb() - ambi0, ambi1, ambi2 = (ambi[0]*mat.ambient)*2, (ambi[1]*mat.ambient)*2, (ambi[2]*mat.ambient)*2 - # ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2 - else: - ambi0, ambi1, ambi2 = 0, 0, 0 - emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2 - - shininess = mat.specular_hardness/512.0 - # shininess = mat.hard/512.0 - specR = (mat.specular_color[0]+0.001)/(1.25/(mat.specular_reflection+0.001)) - # specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001)) - specG = (mat.specular_color[1]+0.001)/(1.25/(mat.specular_reflection+0.001)) - # specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001)) - specB = (mat.specular_color[2]+0.001)/(1.25/(mat.specular_reflection+0.001)) - # specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001)) - transp = 1-mat.alpha - # matFlags = mat.getMode() - if mat.shadeless: - # if matFlags & Blender.Material.Modes['SHADELESS']: - ambient = 1 - shine = 1 - specR = emitR = diffuseR - specG = emitG = diffuseG - specB = emitB = diffuseB - self.writeIndented("" % (round(transp,self.cp))) - self.writeIndented("\n",-1) - - def writeImageTexture(self, image): - name = image.name - filename = image.filename.split('/')[-1].split('\\')[-1] - if name in self.texNames: - self.writeIndented("\n" % self.cleanStr(name)) - self.texNames[name] += 1 - return - else: - self.writeIndented("" % name) - self.writeIndented("\n",-1) - self.texNames[name] = 1 - - def writeBackground(self, world, alltextures): - if world: worldname = world.name - else: return - blending = (world.blend_sky, world.paper_sky, world.real_sky) - # blending = world.getSkytype() - grd = world.horizon_color - # grd = world.getHor() - grd0, grd1, grd2 = grd[0], grd[1], grd[2] - sky = world.zenith_color - # sky = world.getZen() - sky0, sky1, sky2 = sky[0], sky[1], sky[2] - mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2] - mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2 - self.file.write("\n\n") - -########################################################## -# export routine -########################################################## - - def export(self, scene, world, alltextures,\ - EXPORT_APPLY_MODIFIERS = False,\ - EXPORT_TRI= False,\ - ): - - print("Info: starting X3D export to " + self.filename + "...") - self.writeHeader() - # self.writeScript() - self.writeNavigationInfo(scene) - self.writeBackground(world, alltextures) - self.writeFog(world) - self.proto = 0 - - - # # COPIED FROM OBJ EXPORTER - # if EXPORT_APPLY_MODIFIERS: - # temp_mesh_name = '~tmp-mesh' - - # # Get the container mesh. - used for applying modifiers and non mesh objects. - # containerMesh = meshName = tempMesh = None - # for meshName in Blender.NMesh.GetNames(): - # if meshName.startswith(temp_mesh_name): - # tempMesh = Mesh.Get(meshName) - # if not tempMesh.users: - # containerMesh = tempMesh - # if not containerMesh: - # containerMesh = Mesh.New(temp_mesh_name) - # -------------------------- - - - for ob_main in [o for o in scene.objects if o.is_visible()]: - # for ob_main in scene.objects.context: - - free, derived = create_derived_objects(ob_main) - - if derived == None: continue - - for ob, ob_mat in derived: - # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): - objType=ob.type - objName=ob.name - self.matonly = 0 - if objType == "CAMERA": - # if objType == "Camera": - self.writeViewpoint(ob, ob_mat, scene) - elif objType in ("MESH", "CURVE", "SURF", "TEXT") : - # elif objType in ("Mesh", "Curve", "Surf", "Text") : - if EXPORT_APPLY_MODIFIERS or objType != 'MESH': - # if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': - me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') - # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) - else: - me = ob.data - # me = ob.getData(mesh=1) - - self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI) - - # free mesh created with create_mesh() - if me != ob.data: - bpy.data.remove_mesh(me) - - elif objType == "LAMP": - # elif objType == "Lamp": - data= ob.data - datatype=data.type - if datatype == 'POINT': - # if datatype == Lamp.Types.Lamp: - self.writePointLight(ob, ob_mat, data, world) - elif datatype == 'SPOT': - # elif datatype == Lamp.Types.Spot: - self.writeSpotLight(ob, ob_mat, data, world) - elif datatype == 'SUN': - # elif datatype == Lamp.Types.Sun: - self.writeDirectionalLight(ob, ob_mat, data, world) - else: - self.writeDirectionalLight(ob, ob_mat, data, world) - # do you think x3d could document what to do with dummy objects? - #elif objType == "Empty" and objName != "Empty": - # self.writeNode(ob, ob_mat) - else: - #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) - pass - - if free: - free_derived_objects(ob_main) - - self.file.write("\n\n") - - # if EXPORT_APPLY_MODIFIERS: - # if containerMesh: - # containerMesh.verts = None - - self.cleanup() - -########################################################## -# Utility methods -########################################################## - - def cleanup(self): - self.file.close() - self.texNames={} - self.matNames={} - self.indentLevel=0 - print("Info: finished X3D export to %s\n" % self.filename) - - def cleanStr(self, name, prefix='rsvd_'): - """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" - - newName=name[:] - if len(newName) == 0: - self.nNodeID+=1 - return "%s%d" % (prefix, self.nNodeID) - - if newName in self.namesReserved: - newName='%s%s' % (prefix,newName) - - if newName[0].isdigit(): - newName='%s%s' % ('_',newName) - - for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']: - newName=newName.replace(bad,'_') - return newName - - def countIFSSetsNeeded(self, mesh, imageMap, sided, vColors): - """ - countIFFSetsNeeded() - should look at a blender mesh to determine - how many VRML IndexFaceSets or IndexLineSets are needed. A - new mesh created under the following conditions: - - o - split by UV Textures / one per mesh - o - split by face, one sided and two sided - o - split by smooth and flat faces - o - split when faces only have 2 vertices * needs to be an IndexLineSet - """ - - imageNameMap={} - faceMap={} - nFaceIndx=0 - - if mesh.active_uv_texture: - # if mesh.faceUV: - for face in mesh.active_uv_texture.data: - # for face in mesh.faces: - sidename=''; - if face.twoside: - # if face.mode & Mesh.FaceModes.TWOSIDE: - sidename='two' - else: - sidename='one' - - if sidename in sided: - sided[sidename]+=1 - else: - sided[sidename]=1 - - image = face.image - if image: - faceName="%s_%s" % (face.image.name, sidename); - try: - imageMap[faceName].append(face) - except: - imageMap[faceName]=[face.image.name,sidename,face] - - if self.verbose > 2: - for faceName in imageMap.keys(): - ifs=imageMap[faceName] - print("Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ - (faceName, ifs[0], ifs[1], len(ifs)-2)) - - return len(imageMap) - - def faceToString(self,face): - - print("Debug: face.flag=0x%x (bitflags)" % face.flag) - if face.sel: - print("Debug: face.sel=true") - - print("Debug: face.mode=0x%x (bitflags)" % face.mode) - if face.mode & Mesh.FaceModes.TWOSIDE: - print("Debug: face.mode twosided") - - print("Debug: face.transp=0x%x (enum)" % face.transp) - if face.transp == Mesh.FaceTranspModes.SOLID: - print("Debug: face.transp.SOLID") - - if face.image: - print("Debug: face.image=%s" % face.image.name) - print("Debug: face.materialIndex=%d" % face.materialIndex) - - # XXX not used - # def getVertexColorByIndx(self, mesh, indx): - # c = None - # for face in mesh.faces: - # j=0 - # for vertex in face.v: - # if vertex.index == indx: - # c=face.col[j] - # break - # j=j+1 - # if c: break - # return c - - def meshToString(self,mesh): - # print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors) - print("Debug: mesh.faceUV=%d" % (len(mesh.uv_textures) > 0)) - # print("Debug: mesh.faceUV=%d" % mesh.faceUV) - print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0)) - # print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()) - print("Debug: mesh.verts=%d" % len(mesh.verts)) - print("Debug: mesh.faces=%d" % len(mesh.faces)) - print("Debug: mesh.materials=%d" % len(mesh.materials)) - - def rgbToFS(self, c): - s="%s %s %s" % (round(c[0]/255.0,self.cp), - round(c[1]/255.0,self.cp), - round(c[2]/255.0,self.cp)) - - # s="%s %s %s" % ( - # round(c.r/255.0,self.cp), - # round(c.g/255.0,self.cp), - # round(c.b/255.0,self.cp)) - return s - - def computeDirection(self, mtx): - x,y,z=(0,-1.0,0) # point down - - ax,ay,az = (mtx*MATWORLD).toEuler() - - # ax *= DEG2RAD - # ay *= DEG2RAD - # az *= DEG2RAD - - # rot X - x1=x - y1=y*math.cos(ax)-z*math.sin(ax) - z1=y*math.sin(ax)+z*math.cos(ax) - - # rot Y - x2=x1*math.cos(ay)+z1*math.sin(ay) - y2=y1 - z2=z1*math.cos(ay)-x1*math.sin(ay) - - # rot Z - x3=x2*math.cos(az)-y2*math.sin(az) - y3=x2*math.sin(az)+y2*math.cos(az) - z3=z2 - - return [x3,y3,z3] - - - # swap Y and Z to handle axis difference between Blender and VRML - #------------------------------------------------------------------------ - def rotatePointForVRML(self, v): - x = v[0] - y = v[2] - z = -v[1] - - vrmlPoint=[x, y, z] - return vrmlPoint - - # For writing well formed VRML code - #------------------------------------------------------------------------ - def writeIndented(self, s, inc=0): - if inc < 1: - self.indentLevel = self.indentLevel + inc - - spaces="" - for x in range(self.indentLevel): - spaces = spaces + "\t" - self.file.write(spaces + s) - - if inc > 0: - self.indentLevel = self.indentLevel + inc - - # Converts a Euler to three new Quaternions - # Angles of Euler are passed in as radians - #------------------------------------------------------------------------ - def eulerToQuaternions(self, x, y, z): - Qx = [math.cos(x/2), math.sin(x/2), 0, 0] - Qy = [math.cos(y/2), 0, math.sin(y/2), 0] - Qz = [math.cos(z/2), 0, 0, math.sin(z/2)] - - quaternionVec=[Qx,Qy,Qz] - return quaternionVec - - # Multiply two Quaternions together to get a new Quaternion - #------------------------------------------------------------------------ - def multiplyQuaternions(self, Q1, Q2): - result = [((Q1[0] * Q2[0]) - (Q1[1] * Q2[1]) - (Q1[2] * Q2[2]) - (Q1[3] * Q2[3])), - ((Q1[0] * Q2[1]) + (Q1[1] * Q2[0]) + (Q1[2] * Q2[3]) - (Q1[3] * Q2[2])), - ((Q1[0] * Q2[2]) + (Q1[2] * Q2[0]) + (Q1[3] * Q2[1]) - (Q1[1] * Q2[3])), - ((Q1[0] * Q2[3]) + (Q1[3] * Q2[0]) + (Q1[1] * Q2[2]) - (Q1[2] * Q2[1]))] - - return result - - # Convert a Quaternion to an Angle Axis (ax, ay, az, angle) - # angle is in radians - #------------------------------------------------------------------------ - def quaternionToAngleAxis(self, Qf): - scale = math.pow(Qf[1],2) + math.pow(Qf[2],2) + math.pow(Qf[3],2) - ax = Qf[1] - ay = Qf[2] - az = Qf[3] - - if scale > .0001: - ax/=scale - ay/=scale - az/=scale - - angle = 2 * math.acos(Qf[0]) - - result = [ax, ay, az, angle] - return result - -########################################################## -# Callbacks, needed before Main -########################################################## - -def x3d_export(filename, - context, - EXPORT_APPLY_MODIFIERS=False, - EXPORT_TRI=False, - EXPORT_GZIP=False): - - if EXPORT_GZIP: - if not filename.lower().endswith('.x3dz'): - filename = '.'.join(filename.split('.')[:-1]) + '.x3dz' - else: - if not filename.lower().endswith('.x3d'): - filename = '.'.join(filename.split('.')[:-1]) + '.x3d' - - - scene = context.scene - # scene = Blender.Scene.GetCurrent() - world = scene.world - - # XXX these are global textures while .Get() returned only scene's? - alltextures = bpy.data.textures - # alltextures = Blender.Texture.Get() - - wrlexport=x3d_class(filename) - wrlexport.export(\ - scene,\ - world,\ - alltextures,\ - \ - EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS,\ - EXPORT_TRI = EXPORT_TRI,\ - ) - - -def x3d_export_ui(filename): - if not filename.endswith(extension): - filename += extension - #if _safeOverwrite and sys.exists(filename): - # result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0") - #if(result != 1): - # return - - # Get user options - EXPORT_APPLY_MODIFIERS = Draw.Create(1) - EXPORT_TRI = Draw.Create(0) - EXPORT_GZIP = Draw.Create( filename.lower().endswith('.x3dz') ) - - # Get USER Options - pup_block = [\ - ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object.'),\ - ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ - ('Compress', EXPORT_GZIP, 'GZip the resulting file, requires a full python install'),\ - ] - - if not Draw.PupBlock('Export...', pup_block): - return - - Blender.Window.EditMode(0) - Blender.Window.WaitCursor(1) - - x3d_export(filename,\ - EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val,\ - EXPORT_TRI = EXPORT_TRI.val,\ - EXPORT_GZIP = EXPORT_GZIP.val\ - ) - - Blender.Window.WaitCursor(0) - - - -######################################################### -# main routine -######################################################### - - -# if __name__ == '__main__': -# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) - -class EXPORT_OT_x3d(bpy.types.Operator): - ''' - X3D Exporter - ''' - __idname__ = "export.x3d" - __label__ = 'Export X3D' - - # 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 X3D file", maxlen=1024, default=""), - - bpy.props.BoolProperty(attr="apply_modifiers", name="Apply Modifiers", description="Use transformed mesh data from each object.", default=True), - bpy.props.BoolProperty(attr="triangulate", name="Triangulate", description="Triangulate quads.", default=False), - bpy.props.BoolProperty(attr="compress", name="Compress", description="GZip the resulting file, requires a full python install.", default=False), - ] - - def execute(self, context): - x3d_export(self.filename, context, self.apply_modifiers, self.triangulate, self.compress) - 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_x3d) - -# NOTES -# - blender version is hardcoded diff --git a/release/io/import_3ds.py b/release/io/import_3ds.py deleted file mode 100644 index 99825471764..00000000000 --- a/release/io/import_3ds.py +++ /dev/null @@ -1,1166 +0,0 @@ -#!BPY -""" -Name: '3D Studio (.3ds)...' -Blender: 244 -Group: 'Import' -Tooltip: 'Import from 3DS file format (.3ds)' -""" - -__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton', 'Mario Lapin'] -__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") -__version__= '0.996' -__bpydoc__= '''\ - -3ds Importer - -This script imports a 3ds file and the materials into Blender for editing. - -Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). - -0.996 by Mario Lapin (mario.lapin@gmail.com) 13/04/200
- - Implemented workaround to correct association between name, geometry and materials of - imported meshes. - - Without this patch, version 0.995 of this importer would associate to each mesh object the - geometry and the materials of the previously parsed mesh object. By so, the name of the - first mesh object would be thrown away, and the name of the last mesh object would be - automatically merged with a '.001' at the end. No object would desappear, however object's - names and materials would be completely jumbled. - -0.995 by Campbell Barton
-- workaround for buggy mesh vert delete -- minor tweaks - -0.99 by Bob Holcomb
-- added support for floating point color values that previously broke on import. - -0.98 by Campbell Barton
-- import faces and verts to lists instead of a mesh, convert to a mesh later -- use new index mapping feature of mesh to re-map faces that were not added. - -0.97 by Campbell Barton
-- Strip material names of spaces -- Added import as instance to import the 3ds into its own - scene and add a group instance to the current scene -- New option to scale down imported objects so they are within a limited bounding area. - -0.96 by Campbell Barton
-- Added workaround for bug in setting UV's for Zero vert index UV faces. -- Removed unique name function, let blender make the names unique. - -0.95 by Campbell Barton
-- Removed workarounds for Blender 2.41 -- Mesh objects split by material- many 3ds objects used more then 16 per mesh. -- Removed a lot of unneeded variable creation. - -0.94 by Campbell Barton
-- Face import tested to be about overall 16x speedup over 0.93. -- Material importing speedup. -- Tested with more models. -- Support some corrupt models. - -0.93 by Campbell Barton
-- Tested with 400 3ds files from turbosquid and samples. -- Tactfully ignore faces that used the same verts twice. -- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. -- Converted from NMesh to Mesh. -- Faster and cleaner new names. -- Use external comprehensive image loader. -- Re intergrated 0.92 and 0.9 changes -- Fixes for 2.41 compat. -- Non textured faces do not use a texture flag. - -0.92
-- Added support for diffuse, alpha, spec, bump maps in a single material - -0.9
-- Reorganized code into object/material block functions
-- Use of Matrix() to copy matrix data
-- added support for material transparency
- -0.83 2005-08-07: Campell Barton -- Aggressive image finding and case insensitivy for posisx systems. - -0.82a 2005-07-22 -- image texture loading (both for face uv and renderer) - -0.82 - image texture loading (for face uv) - -0.81a (fork- not 0.9) Campbell Barton 2005-06-08 -- Simplified import code -- Never overwrite data -- Faster list handling -- Leaves import selected - -0.81 Damien McGinnes 2005-01-09 -- handle missing images better - -0.8 Damien McGinnes 2005-01-08 -- copies sticky UV coords to face ones -- handles images better -- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script - -''' - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Bob Holcomb -# -# 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 ***** -# -------------------------------------------------------------------------- - -# Importing modules - -import os -import time -import struct - -from import_obj import unpack_face_list, load_image - -import bpy -import Mathutils - -# import Blender -# from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils -# from Blender.Mathutils import Vector -# import BPyImage - -# import BPyMessages - -# try: -# from struct import calcsize, unpack -# except: -# calcsize= unpack= None - - - -# # If python version is less than 2.4, try to get set stuff from module -# try: -# set -# except: -# from sets import Set as set - -BOUNDS_3DS = [] - - -#this script imports uvcoords as sticky vertex coords -#this parameter enables copying these to face uv coords -#which shold be more useful. - -def createBlenderTexture(material, name, image): - texture = bpy.data.textures.new(name) - texture.setType('Image') - texture.image = image - material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - - - -###################################################### -# Data Structures -###################################################### - -#Some of the chunks that we will see -#----- Primary Chunk, at the beginning of each file -PRIMARY = int('0x4D4D',16) - -#------ Main Chunks -OBJECTINFO = int('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information -VERSION = int('0x0002',16); #This gives the version of the .3ds file -EDITKEYFRAME= int('0xB000',16); #This is the header for all of the key frame info - -#------ sub defines of OBJECTINFO -MATERIAL = 45055 #0xAFFF // This stored the texture info -OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc... - -#>------ sub defines of MATERIAL -#------ sub defines of MATERIAL_BLOCK -MAT_NAME = int('0xA000',16) # This holds the material name -MAT_AMBIENT = int('0xA010',16) # Ambient color of the object/material -MAT_DIFFUSE = int('0xA020',16) # This holds the color of the object/material -MAT_SPECULAR = int('0xA030',16) # SPecular color of the object/material -MAT_SHINESS = int('0xA040',16) # ?? -MAT_TRANSPARENCY= int('0xA050',16) # Transparency value of material -MAT_SELF_ILLUM = int('0xA080',16) # Self Illumination value of material -MAT_WIRE = int('0xA085',16) # Only render's wireframe - -MAT_TEXTURE_MAP = int('0xA200',16) # This is a header for a new texture map -MAT_SPECULAR_MAP= int('0xA204',16) # This is a header for a new specular map -MAT_OPACITY_MAP = int('0xA210',16) # This is a header for a new opacity map -MAT_REFLECTION_MAP= int('0xA220',16) # This is a header for a new reflection map -MAT_BUMP_MAP = int('0xA230',16) # This is a header for a new bump map -MAT_MAP_FILENAME = int('0xA300',16) # This holds the file name of the texture - -MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats -MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes - -#>------ sub defines of OBJECT -OBJECT_MESH = int('0x4100',16); # This lets us know that we are reading a new object -OBJECT_LAMP = int('0x4600',16); # This lets un know we are reading a light object -OBJECT_LAMP_SPOT = int('0x4610',16); # The light is a spotloght. -OBJECT_LAMP_OFF = int('0x4620',16); # The light off. -OBJECT_LAMP_ATTENUATE = int('0x4625',16); -OBJECT_LAMP_RAYSHADE = int('0x4627',16); -OBJECT_LAMP_SHADOWED = int('0x4630',16); -OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16); -OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16); -OBJECT_LAMP_SEE_CONE = int('0x4650',16); -OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16); -OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16); -OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16); -OBJECT_LAMP_EXCLUDE = int('0x4654',16); -OBJECT_LAMP_RANGE = int('0x4655',16); -OBJECT_LAMP_ROLL = int('0x4656',16); -OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16); -OBJECT_LAMP_RAY_BIAS = int('0x4658',16); -OBJECT_LAMP_INNER_RANGE = int('0x4659',16); -OBJECT_LAMP_OUTER_RANGE = int('0x465A',16); -OBJECT_LAMP_MULTIPLIER = int('0x465B',16); -OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16); - - - -OBJECT_CAMERA= int('0x4700',16); # This lets un know we are reading a camera object - -#>------ sub defines of CAMERA -OBJECT_CAM_RANGES= int('0x4720',16); # The camera range values - -#>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = int('0x4110',16); # The objects vertices -OBJECT_FACES = int('0x4120',16); # The objects faces -OBJECT_MATERIAL = int('0x4130',16); # This is found if the object has a material, either texture map or color -OBJECT_UV = int('0x4140',16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = int('0x4160',16); # The Object Matrix - -global scn -scn = None - -#the chunk class -class chunk: - ID = 0 - length = 0 - bytes_read = 0 - - #we don't read in the bytes_read, we compute that - binary_format=' 3): - print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version) - - #is it an object info chunk? - elif (new_chunk.ID == OBJECTINFO): - #print 'elif (new_chunk.ID == OBJECTINFO):' - # print 'found an OBJECTINFO chunk' - process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) - - #keep track of how much we read in the main chunk - new_chunk.bytes_read += temp_chunk.bytes_read - - #is it an object chunk? - elif (new_chunk.ID == OBJECT): - - if CreateBlenderObject: - putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) - contextMesh_vertls = []; contextMesh_facels = [] - - ## preparando para receber o proximo objeto - contextMeshMaterials = {} # matname:[face_idxs] - contextMeshUV = None - #contextMesh.vertexUV = 1 # Make sticky coords. - # Reset matrix - contextMatrix_rot = None - #contextMatrix_tx = None - - CreateBlenderObject = True - tempName = read_string(file) - contextObName = tempName - new_chunk.bytes_read += len(tempName)+1 - - #is it a material chunk? - elif (new_chunk.ID == MATERIAL): - -# print("read material") - - #print 'elif (new_chunk.ID == MATERIAL):' - contextMaterial = bpy.data.add_material('Material') -# contextMaterial = bpy.data.materials.new('Material') - - elif (new_chunk.ID == MAT_NAME): - #print 'elif (new_chunk.ID == MAT_NAME):' - material_name = read_string(file) - -# print("material name", material_name) - - #plus one for the null character that ended the string - new_chunk.bytes_read += len(material_name)+1 - - contextMaterial.name = material_name.rstrip() # remove trailing whitespace - MATDICT[material_name]= (contextMaterial.name, contextMaterial) - - elif (new_chunk.ID == MAT_AMBIENT): - #print 'elif (new_chunk.ID == MAT_AMBIENT):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID == MAT_FLOAT_COLOR): - contextMaterial.mirror_color = read_float_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3f')) -# temp_chunk.bytes_read += 12 -# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] - elif (temp_chunk.ID == MAT_24BIT_COLOR): - contextMaterial.mirror_color = read_byte_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3B')) -# temp_chunk.bytes_read += 3 -# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - new_chunk.bytes_read += temp_chunk.bytes_read - - elif (new_chunk.ID == MAT_DIFFUSE): - #print 'elif (new_chunk.ID == MAT_DIFFUSE):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID == MAT_FLOAT_COLOR): - contextMaterial.diffuse_color = read_float_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3f')) -# temp_chunk.bytes_read += 12 -# contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)] - elif (temp_chunk.ID == MAT_24BIT_COLOR): - contextMaterial.diffuse_color = read_byte_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3B')) -# temp_chunk.bytes_read += 3 -# contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - -# print("read material diffuse color", contextMaterial.diffuse_color) - - new_chunk.bytes_read += temp_chunk.bytes_read - - elif (new_chunk.ID == MAT_SPECULAR): - #print 'elif (new_chunk.ID == MAT_SPECULAR):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID == MAT_FLOAT_COLOR): - contextMaterial.specular_color = read_float_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3f')) -# temp_chunk.bytes_read += 12 -# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] - elif (temp_chunk.ID == MAT_24BIT_COLOR): - contextMaterial.specular_color = read_byte_color(temp_chunk) -# temp_data = file.read(struct.calcsize('3B')) -# temp_chunk.bytes_read += 3 -# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - new_chunk.bytes_read += temp_chunk.bytes_read - - elif (new_chunk.ID == MAT_TEXTURE_MAP): - read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR") -# #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' -# new_texture= bpy.data.textures.new('Diffuse') -# new_texture.setType('Image') -# img = None -# while (new_chunk.bytes_read BOUNDS_3DS[i + 3]: - BOUNDS_3DS[i + 3]= v[i] # min - - # Get the max axis x/y/z - max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) - # print max_axis - if max_axis < 1 << 30: # Should never be false but just make sure. - - # Get a new scale factor if set as an option - SCALE = 1.0 - while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS: - SCALE/=10 - - # SCALE Matrix - SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) -# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) - - for ob in importedObjects: - ob.setMatrix(ob.matrixWorld * SCALE_MAT) - - # Done constraining to bounds. - - # Select all new objects. - print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1))) -# print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))) - file.close() -# Blender.Window.WaitCursor(0) - - -DEBUG = False -# if __name__=='__main__' and not DEBUG: -# if calcsize == None: -# Blender.Draw.PupMenu('Error%t|a full python installation not found') -# else: -# Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') - -# For testing compatibility -#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) -#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) -''' - -else: - import os - # DEBUG ONLY - TIME = Blender.sys.time() - import os - print 'Searching for files' - os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') - # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') - print '...Done' - file = open('/tmp/temp3ds_list', 'r') - lines = file.readlines() - file.close() - # sort by filesize for faster testing - lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] - lines_size.sort() - lines = [f[1] for f in lines_size] - - - def between(v,a,b): - if v <= max(a,b) and v >= min(a,b): - return True - return False - - for i, _3ds in enumerate(lines): - if between(i, 650,800): - #_3ds= _3ds[:-1] - print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) - _3ds_file= _3ds.split('/')[-1].split('\\')[-1] - newScn = Blender.Scene.New(_3ds_file) - newScn.makeCurrent() - load_3ds(_3ds, False) - - print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) - -''' - -class IMPORT_OT_3ds(bpy.types.Operator): - ''' - 3DS Importer - ''' - __idname__ = "import.3ds" - __label__ = 'Import 3DS' - - # 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 importing the 3DS file", maxlen=1024, default= ""), -# bpy.props.FloatProperty(attr="size_constraint", name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0), -# bpy.props.BoolProperty(attr="search_images", name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True), -# bpy.props.BoolProperty(attr="apply_matrix", name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False), - ] - - def execute(self, context): - load_3ds(self.filename, context, 0.0, False, False) - return ('FINISHED',) - - def invoke(self, context, event): - wm = context.manager - wm.add_fileselect(self.__operator__) - return ('RUNNING_MODAL',) - ''' - def poll(self, context): - print("Poll") - return context.active_object != None''' - -bpy.ops.add(IMPORT_OT_3ds) - -# NOTES: -# why add 1 extra vertex? and remove it when done? -# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time) diff --git a/release/io/import_obj.py b/release/io/import_obj.py deleted file mode 100644 index 9a00dc1cc2a..00000000000 --- a/release/io/import_obj.py +++ /dev/null @@ -1,1633 +0,0 @@ -#!BPY - -""" -Name: 'Wavefront (.obj)...' -Blender: 249 -Group: 'Import' -Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' -""" - -__author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone" -__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org'] -__version__= "2.11" - -__bpydoc__= """\ -This script imports a Wavefront OBJ files to Blender. - -Usage: -Run this script from "File->Import" menu and then load the desired OBJ file. -Note, This loads mesh objects and materials only, nurbs and curves are not supported. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton 2007 -# -# 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 os -import time -import bpy -import Mathutils -import Geometry - -# from Blender import Mesh, Draw, Window, Texture, Material, sys -# # import BPyMesh -# import BPyImage -# import BPyMessages - -# try: import os -# except: os= False - -# Generic path functions -def stripFile(path): - '''Return directory, where the file is''' - lastSlash= max(path.rfind('\\'), path.rfind('/')) - if lastSlash != -1: - path= path[:lastSlash] - return '%s%s' % (path, os.sep) -# return '%s%s' % (path, sys.sep) - -def stripPath(path): - '''Strips the slashes from the back of a string''' - return path.split('/')[-1].split('\\')[-1] - -def stripExt(name): # name is a string - '''Strips the prefix off the name before writing''' - index= name.rfind('.') - if index != -1: - return name[ : index ] - else: - return name -# end path funcs - -def unpack_list(list_of_tuples): - l = [] - for t in list_of_tuples: - l.extend(t) - return l - -# same as above except that it adds 0 for triangle faces -def unpack_face_list(list_of_tuples): - l = [] - for t in list_of_tuples: - face = [i for i in t] - if len(face) != 3 and len(face) != 4: - raise RuntimeError("{0} vertices in face.".format(len(face))) - if len(face) == 3: - face.append(0) - l.extend(face) - return l - -def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True): - ''' - Takes a polyline of indices (fgon) - and returns a list of face indicie lists. - Designed to be used for importers that need indices for an fgon to create from existing verts. - - from_data: either a mesh, or a list/tuple of vectors. - indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. - PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. - ''' - - if not set: # Need sets for this, otherwise do a normal fill. - PREF_FIX_LOOPS= False - - Vector= Mathutils.Vector - if not indices: - return [] - - # return [] - def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) - def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length - - def vert_treplet(v, i): - return v, rvec(v), i, mlen(v) - - def ed_key_mlen(v1, v2): - if v1[3] > v2[3]: - return v2[1], v1[1] - else: - return v1[1], v2[1] - - - if not PREF_FIX_LOOPS: - ''' - Normal single concave loop filling - ''' - if type(from_data) in (tuple, list): - verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] - else: - verts= [from_data.verts[i].co for ii, i in enumerate(indices)] - - for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): - if verts[i][1]==verts[i-1][0]: - verts.pop(i-1) - - fill= Geometry.PolyFill([verts]) - - else: - ''' - Seperate this loop into multiple loops be finding edges that are used twice - This is used by lightwave LWO files a lot - ''' - - if type(from_data) in (tuple, list): - verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] - else: - verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] - - edges= [(i, i-1) for i in range(len(verts))] - if edges: - edges[0]= (0,len(verts)-1) - - if not verts: - return [] - - - edges_used= set() - edges_doubles= set() - # We need to check if any edges are used twice location based. - for ed in edges: - edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) - if edkey in edges_used: - edges_doubles.add(edkey) - else: - edges_used.add(edkey) - - # Store a list of unconnected loop segments split by double edges. - # will join later - loop_segments= [] - - v_prev= verts[0] - context_loop= [v_prev] - loop_segments= [context_loop] - - for v in verts: - if v!=v_prev: - # Are we crossing an edge we removed? - if ed_key_mlen(v, v_prev) in edges_doubles: - context_loop= [v] - loop_segments.append(context_loop) - else: - if context_loop and context_loop[-1][1]==v[1]: - #raise "as" - pass - else: - context_loop.append(v) - - v_prev= v - # Now join loop segments - - def join_seg(s1,s2): - if s2[-1][1]==s1[0][1]: # - s1,s2= s2,s1 - elif s1[-1][1]==s2[0][1]: - pass - else: - return False - - # If were stuill here s1 and s2 are 2 segments in the same polyline - s1.pop() # remove the last vert from s1 - s1.extend(s2) # add segment 2 to segment 1 - - if s1[0][1]==s1[-1][1]: # remove endpoints double - s1.pop() - - s2[:]= [] # Empty this segment s2 so we dont use it again. - return True - - joining_segments= True - while joining_segments: - joining_segments= False - segcount= len(loop_segments) - - for j in range(segcount-1, -1, -1): #reversed(range(segcount)): - seg_j= loop_segments[j] - if seg_j: - for k in range(j-1, -1, -1): # reversed(range(j)): - if not seg_j: - break - seg_k= loop_segments[k] - - if seg_k and join_seg(seg_j, seg_k): - joining_segments= True - - loop_list= loop_segments - - for verts in loop_list: - while verts and verts[0][1]==verts[-1][1]: - verts.pop() - - loop_list= [verts for verts in loop_list if len(verts)>2] - # DONE DEALING WITH LOOP FIXING - - - # vert mapping - vert_map= [None]*len(indices) - ii=0 - for verts in loop_list: - if len(verts)>2: - for i, vert in enumerate(verts): - vert_map[i+ii]= vert[2] - ii+=len(verts) - - fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) - #draw_loops(loop_list) - #raise 'done loop' - # map to original indicies - fill= [[vert_map[i] for i in reversed(f)] for f in fill] - - - if not fill: - print('Warning Cannot scanfill, fallback on a triangle fan.') - fill= [ [0, i-1, i] for i in range(2, len(indices)) ] - else: - # Use real scanfill. - # See if its flipped the wrong way. - flip= None - for fi in fill: - if flip != None: - break - for i, vi in enumerate(fi): - if vi==0 and fi[i-1]==1: - flip= False - break - elif vi==1 and fi[i-1]==0: - flip= True - break - - if not flip: - for i, fi in enumerate(fill): - fill[i]= tuple([ii for ii in reversed(fi)]) - - return fill - -def line_value(line_split): - ''' - Returns 1 string represneting the value for this line - None will be returned if theres only 1 word - ''' - length= len(line_split) - if length == 1: - return None - - elif length == 2: - return line_split[1] - - elif length > 2: - return ' '.join( line_split[1:] ) - -# limited replacement for BPyImage.comprehensiveImageLoad -def load_image(imagepath, dirname): - - if os.path.exists(imagepath): - return bpy.data.add_image(imagepath) - - variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))] - - for path in variants: - if os.path.exists(path): - return bpy.data.add_image(path) - else: - print(path, "doesn't exist") - - # TODO comprehensiveImageLoad also searched in bpy.config.textureDir - return None - -def obj_image_load(imagepath, DIR, IMAGE_SEARCH): - - if '_' in imagepath: - image= load_image(imagepath.replace('_', ' '), DIR) - if image: return image - - return load_image(imagepath, DIR) - -# def obj_image_load(imagepath, DIR, IMAGE_SEARCH): -# ''' -# Mainly uses comprehensiveImageLoad -# but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. -# ''' - -# if '_' in imagepath: -# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) -# if image: return image -# # Did the exporter rename the image? -# image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) -# if image: return image - -# # Return an image, placeholder if it dosnt exist -# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) -# return image - - -def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): - ''' - Create all the used materials in this obj, - assign colors and images to the materials from all referenced material libs - ''' - DIR= stripFile(filepath) - - #==================================================================================# - # This function sets textures defined in .mtl file # - #==================================================================================# - def load_material_image(blender_material, context_material_name, imagepath, type): - - texture= bpy.data.add_texture(type) - texture.type= 'IMAGE' -# texture= bpy.data.textures.new(type) -# texture.setType('Image') - - # Absolute path - c:\.. etc would work here - image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) - has_data = image.has_data if image else False - - if image: - texture.image = image - - # Adds textures for materials (rendering) - if type == 'Kd': - if has_data and image.depth == 32: - # Image has alpha - - # XXX bitmask won't work? - blender_material.add_texture(texture, "UV", ("COLOR", "ALPHA")) - texture.mipmap = True - texture.interpolation = True - texture.use_alpha = True - blender_material.z_transparency = True - blender_material.alpha = 0.0 - -# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) -# texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') -# blender_material.mode |= Material.Modes.ZTRANSP -# blender_material.alpha = 0.0 - else: - blender_material.add_texture(texture, "UV", "COLOR") -# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - - # adds textures to faces (Textured/Alt-Z mode) - # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. - unique_material_images[context_material_name]= image, has_data # set the texface image - - elif type == 'Ka': - blender_material.add_texture(texture, "UV", "AMBIENT") -# blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API - - elif type == 'Ks': - blender_material.add_texture(texture, "UV", "SPECULARITY") -# blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) - - elif type == 'Bump': - blender_material.add_texture(texture, "UV", "NORMAL") -# blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) - elif type == 'D': - blender_material.add_texture(texture, "UV", "ALPHA") - blender_material.z_transparency = True - blender_material.alpha = 0.0 -# blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) -# blender_material.mode |= Material.Modes.ZTRANSP -# blender_material.alpha = 0.0 - # Todo, unset deffuse material alpha if it has an alpha channel - - elif type == 'refl': - blender_material.add_texture(texture, "UV", "REFLECTION") -# blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) - - - # Add an MTL with the same name as the obj if no MTLs are spesified. - temp_mtl= stripExt(stripPath(filepath))+ '.mtl' - - if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs: -# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: - material_libs.append( temp_mtl ) - del temp_mtl - - #Create new materials - for name in unique_materials: # .keys() - if name != None: - unique_materials[name]= bpy.data.add_material(name) -# unique_materials[name]= bpy.data.materials.new(name) - unique_material_images[name]= None, False # assign None to all material images to start with, add to later. - - unique_materials[None]= None - unique_material_images[None]= None, False - - for libname in material_libs: - mtlpath= DIR + libname - if not os.path.exists(mtlpath): -# if not sys.exists(mtlpath): - #print '\tError Missing MTL: "%s"' % mtlpath - pass - else: - #print '\t\tloading mtl: "%s"' % mtlpath - context_material= None - mtl= open(mtlpath, 'rU') - for line in mtl: #.xreadlines(): - if line.startswith('newmtl'): - context_material_name= line_value(line.split()) - if context_material_name in unique_materials: - context_material = unique_materials[ context_material_name ] - else: - context_material = None - - elif context_material: - # we need to make a material to assign properties to it. - line_split= line.split() - line_lower= line.lower().lstrip() - if line_lower.startswith('ka'): - context_material.mirror_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) -# context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('kd'): - context_material.diffuse_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) -# context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('ks'): - context_material.specular_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) -# context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('ns'): - context_material.specular_hardness = int((float(line_split[1])*0.51)) -# context_material.setHardness( int((float(line_split[1])*0.51)) ) - elif line_lower.startswith('ni'): # Refraction index - context_material.ior = max(1, min(float(line_split[1]), 3)) -# context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 - elif line_lower.startswith('d') or line_lower.startswith('tr'): - context_material.alpha = float(line_split[1]) -# context_material.setAlpha(float(line_split[1])) - elif line_lower.startswith('map_ka'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Ka') - elif line_lower.startswith('map_ks'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Ks') - elif line_lower.startswith('map_kd'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Kd') - elif line_lower.startswith('map_bump'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Bump') - elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'D') - - elif line_lower.startswith('refl'): # Reflectionmap - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'refl') - mtl.close() - - - - -def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): - ''' - Takes vert_loc and faces, and seperates into multiple sets of - (verts_loc, faces, unique_materials, dataname) - This is done so objects do not overload the 16 material limit. - ''' - - filename = stripExt(stripPath(filepath)) - - if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: - # use the filename for the object name since we arnt chopping up the mesh. - return [(verts_loc, faces, unique_materials, filename)] - - - def key_to_name(key): - # if the key is a tuple, join it to make a string - if type(key) == tuple: - return '%s_%s' % key - elif not key: - return filename # assume its a string. make sure this is true if the splitting code is changed - else: - return key - - # Return a key that makes the faces unique. - if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: - def face_key(face): - return face[4] # object - - elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: - def face_key(face): - return face[2] # material - - else: # Both - def face_key(face): - return face[4], face[2] # object,material - - - face_split_dict= {} - - oldkey= -1 # initialize to a value that will never match the key - - for face in faces: - - key= face_key(face) - - if oldkey != key: - # Check the key has changed. - try: - verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] - except KeyError: - faces_split= [] - verts_split= [] - unique_materials_split= {} - vert_remap= [-1]*len(verts_loc) - - face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) - - oldkey= key - - face_vert_loc_indicies= face[0] - - # Remap verts to new vert list and add where needed - for enum, i in enumerate(face_vert_loc_indicies): - if vert_remap[i] == -1: - new_index= len(verts_split) - vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. - face_vert_loc_indicies[enum] = new_index # remap to the local index - verts_split.append( verts_loc[i] ) # add the vert to the local verts - - else: - face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index - - matname= face[2] - if matname and matname not in unique_materials_split: - unique_materials_split[matname] = unique_materials[matname] - - faces_split.append(face) - - - # remove one of the itemas and reorder - return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())] - - -def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): - ''' - Takes all the data gathered and generates a mesh, adding the new object to new_objects - deals with fgons, sharp edges and assigning materials - ''' - if not has_ngons: - CREATE_FGONS= False - - if unique_smooth_groups: - sharp_edges= {} - smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ]) - context_smooth_group_old= -1 - - # Split fgons into tri's - fgon_edges= {} # Used for storing fgon keys - if CREATE_EDGES: - edges= [] - - context_object= None - - # reverse loop through face indicies - for f_idx in range(len(faces)-1, -1, -1): - - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object= faces[f_idx] - - len_face_vert_loc_indicies = len(face_vert_loc_indicies) - - if len_face_vert_loc_indicies==1: - faces.pop(f_idx)# cant add single vert faces - - elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines - if CREATE_EDGES: - # generators are better in python 2.4+ but can't be used in 2.3 - # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) - edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in range(len_face_vert_loc_indicies-1)] ) - - faces.pop(f_idx) - else: - - # Smooth Group - if unique_smooth_groups and context_smooth_group: - # Is a part of of a smooth group and is a face - if context_smooth_group_old is not context_smooth_group: - edge_dict= smooth_group_users[context_smooth_group] - context_smooth_group_old= context_smooth_group - - for i in range(len_face_vert_loc_indicies): - i1= face_vert_loc_indicies[i] - i2= face_vert_loc_indicies[i-1] - if i1>i2: i1,i2= i2,i1 - - try: - edge_dict[i1,i2]+= 1 - except KeyError: - edge_dict[i1,i2]= 1 - - # FGons into triangles - if has_ngons and len_face_vert_loc_indicies > 4: - - ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies) - faces.extend(\ - [(\ - [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ - [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ - context_material,\ - context_smooth_group,\ - context_object)\ - for ngon in ngon_face_indices]\ - ) - - # edges to make fgons - if CREATE_FGONS: - edge_users= {} - for ngon in ngon_face_indices: - for i in (0,1,2): - i1= face_vert_loc_indicies[ngon[i ]] - i2= face_vert_loc_indicies[ngon[i-1]] - if i1>i2: i1,i2= i2,i1 - - try: - edge_users[i1,i2]+=1 - except KeyError: - edge_users[i1,i2]= 1 - - for key, users in edge_users.items(): - if users>1: - fgon_edges[key]= None - - # remove all after 3, means we dont have to pop this one. - faces.pop(f_idx) - - - # Build sharp edges - if unique_smooth_groups: - for edge_dict in list(smooth_group_users.values()): - for key, users in list(edge_dict.items()): - if users==1: # This edge is on the boundry of a group - sharp_edges[key]= None - - - # map the material names to an index - material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys() - - materials= [None] * len(unique_materials) - - for name, index in list(material_mapping.items()): - materials[index]= unique_materials[name] - - me= bpy.data.add_mesh(dataname) -# me= bpy.data.meshes.new(dataname) - - # make sure the list isnt too big - for material in materials[0:16]: - me.add_material(material) -# me.materials= materials[0:16] # make sure the list isnt too big. - #me.verts.extend([(0,0,0)]) # dummy vert - - me.add_geometry(len(verts_loc), 0, len(faces)) - - # verts_loc is a list of (x, y, z) tuples - me.verts.foreach_set("co", unpack_list(verts_loc)) -# me.verts.extend(verts_loc) - - # faces is a list of (vert_indices, texco_indices, ...) tuples - # XXX faces should not contain edges - # XXX no check for valid face indices - me.faces.foreach_set("verts", unpack_face_list([f[0] for f in faces])) -# face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) - - if verts_tex and me.faces: - me.add_uv_texture() -# me.faceUV= 1 - # TEXMODE= Mesh.FaceModes['TEX'] - - context_material_old= -1 # avoid a dict lookup - mat= 0 # rare case it may be un-initialized. - me_faces= me.faces -# ALPHA= Mesh.FaceTranspModes.ALPHA - - for i, face in enumerate(faces): - if len(face[0]) < 2: - pass #raise "bad face" - elif len(face[0])==2: - if CREATE_EDGES: - edges.append(face[0]) - else: -# face_index_map= face_mapping[i] - - # since we use foreach_set to add faces, all of them are added - if 1: -# if face_index_map!=None: # None means the face wasnt added - - blender_face = me.faces[i] -# blender_face= me_faces[face_index_map] - - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object= face - - - - if context_smooth_group: - blender_face.smooth= True - - if context_material: - if context_material_old is not context_material: - mat= material_mapping[context_material] - if mat>15: - mat= 15 - context_material_old= context_material - - blender_face.material_index= mat -# blender_face.mat= mat - - - if verts_tex: - - blender_tface= me.uv_textures[0].data[i] - - if context_material: - image, has_data= unique_material_images[context_material] - if image: # Can be none if the material dosnt have an image. - blender_tface.image= image -# blender_face.image= image - if has_data: -# if has_data and image.depth == 32: - blender_tface.transp = 'ALPHA' -# blender_face.transp |= ALPHA - - # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. - if len(face_vert_loc_indicies)==4: - if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: - face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] - else: # length of 3 - if face_vert_loc_indicies[2]==0: - face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] - # END EEEKADOODLE FIX - - # assign material, uv's and image - blender_tface.uv1= verts_tex[face_vert_tex_indicies[0]] - blender_tface.uv2= verts_tex[face_vert_tex_indicies[1]] - blender_tface.uv3= verts_tex[face_vert_tex_indicies[2]] - - if blender_face.verts[3] != 0: - blender_tface.uv4= verts_tex[face_vert_tex_indicies[3]] - -# for ii, uv in enumerate(blender_face.uv): -# uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] - del me_faces -# del ALPHA - - if CREATE_EDGES: - - me.add_geometry(0, len(edges), 0) - - # edges should be a list of (a, b) tuples - me.edges.foreach_set("verts", unpack_list(edges)) -# me_edges.extend( edges ) - -# del me_edges - - # Add edge faces. -# me_edges= me.edges - - def edges_match(e1, e2): - return (e1[0] == e2[0] and e1[1] == e2[1]) or (e1[0] == e2[1] and e1[1] == e2[0]) - - # XXX slow -# if CREATE_FGONS and fgon_edges: -# for fgon_edge in fgon_edges.keys(): -# for ed in me.edges: -# if edges_match(fgon_edge, ed.verts): -# ed.fgon = True - -# if CREATE_FGONS and fgon_edges: -# FGON= Mesh.EdgeFlags.FGON -# for ed in me.findEdges( fgon_edges.keys() ): -# if ed!=None: -# me_edges[ed].flag |= FGON -# del FGON - - # XXX slow -# if unique_smooth_groups and sharp_edges: -# for sharp_edge in sharp_edges.keys(): -# for ed in me.edges: -# if edges_match(sharp_edge, ed.verts): -# ed.sharp = True - -# if unique_smooth_groups and sharp_edges: -# SHARP= Mesh.EdgeFlags.SHARP -# for ed in me.findEdges( sharp_edges.keys() ): -# if ed!=None: -# me_edges[ed].flag |= SHARP -# del SHARP - - me.update() -# me.calcNormals() - - ob= bpy.data.add_object("MESH", "Mesh") - ob.data= me - scn.add_object(ob) -# ob= scn.objects.new(me) - new_objects.append(ob) - - # Create the vertex groups. No need to have the flag passed here since we test for the - # content of the vertex_groups. If the user selects to NOT have vertex groups saved then - # the following test will never run - for group_name, group_indicies in vertex_groups.items(): - group= ob.add_vertex_group(group_name) -# me.addVertGroup(group_name) - for vertex_index in group_indicies: - ob.add_vertex_to_group(vertex_index, group, 1.0, 'REPLACE') -# me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE) - - -def create_nurbs(scn, context_nurbs, vert_loc, new_objects): - ''' - Add nurbs object to blender, only support one type at the moment - ''' - deg = context_nurbs.get('deg', (3,)) - curv_range = context_nurbs.get('curv_range', None) - curv_idx = context_nurbs.get('curv_idx', []) - parm_u = context_nurbs.get('parm_u', []) - parm_v = context_nurbs.get('parm_v', []) - name = context_nurbs.get('name', 'ObjNurb') - cstype = context_nurbs.get('cstype', None) - - if cstype == None: - print('\tWarning, cstype not found') - return - if cstype != 'bspline': - print('\tWarning, cstype is not supported (only bspline)') - return - if not curv_idx: - print('\tWarning, curv argument empty or not set') - return - if len(deg) > 1 or parm_v: - print('\tWarning, surfaces not supported') - return - - cu = bpy.data.curves.new(name, 'Curve') - cu.flag |= 1 # 3D curve - - nu = None - for pt in curv_idx: - - pt = vert_loc[pt] - pt = (pt[0], pt[1], pt[2], 1.0) - - if nu == None: - nu = cu.appendNurb(pt) - else: - nu.append(pt) - - nu.orderU = deg[0]+1 - - # get for endpoint flag from the weighting - if curv_range and len(parm_u) > deg[0]+1: - do_endpoints = True - for i in range(deg[0]+1): - - if abs(parm_u[i]-curv_range[0]) > 0.0001: - do_endpoints = False - break - - if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001: - do_endpoints = False - break - - else: - do_endpoints = False - - if do_endpoints: - nu.flagU |= 2 - - - # close - ''' - do_closed = False - if len(parm_u) > deg[0]+1: - for i in xrange(deg[0]+1): - #print curv_idx[i], curv_idx[-(i+1)] - - if curv_idx[i]==curv_idx[-(i+1)]: - do_closed = True - break - - if do_closed: - nu.flagU |= 1 - ''' - - ob = scn.objects.new(cu) - new_objects.append(ob) - - -def strip_slash(line_split): - if line_split[-1][-1]== '\\': - if len(line_split[-1])==1: - line_split.pop() # remove the \ item - else: - line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number - return True - return False - - - -def get_float_func(filepath): - ''' - find the float function for this obj file - - weather to replace commas or not - ''' - file= open(filepath, 'rU') - for line in file: #.xreadlines(): - line = line.lstrip() - if line.startswith('v'): # vn vt v - if ',' in line: - return lambda f: float(f.replace(',', '.')) - elif '.' in line: - return float - - # incase all vert values were ints - return float - -def load_obj(filepath, - context, - CLAMP_SIZE= 0.0, - CREATE_FGONS= True, - CREATE_SMOOTH_GROUPS= True, - CREATE_EDGES= True, - SPLIT_OBJECTS= True, - SPLIT_GROUPS= True, - SPLIT_MATERIALS= True, - ROTATE_X90= True, - IMAGE_SEARCH=True, - POLYGROUPS=False): - ''' - Called by the user interface or another script. - load_obj(path) - should give acceptable results. - This function passes the file and sends the data off - to be split into objects and then converted into mesh objects - ''' - print('\nimporting obj "%s"' % filepath) - - if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: - POLYGROUPS = False - - time_main= time.time() -# time_main= sys.time() - - verts_loc= [] - verts_tex= [] - faces= [] # tuples of the faces - material_libs= [] # filanems to material libs this uses - vertex_groups = {} # when POLYGROUPS is true - - # Get the string to float conversion func for this file- is 'float' for almost all files. - float_func= get_float_func(filepath) - - # Context variables - context_material= None - context_smooth_group= None - context_object= None - context_vgroup = None - - # Nurbs - context_nurbs = {} - nurbs = [] - context_parm = '' # used by nurbs too but could be used elsewhere - - has_ngons= False - # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 - - # Until we can use sets - unique_materials= {} - unique_material_images= {} - unique_smooth_groups= {} - # unique_obects= {} - no use for this variable since the objects are stored in the face. - - # when there are faces that end with \ - # it means they are multiline- - # since we use xreadline we cant skip to the next line - # so we need to know weather - context_multi_line= '' - - print('\tparsing obj file "%s"...' % filepath) - time_sub= time.time() -# time_sub= sys.time() - - file= open(filepath, 'rU') - for line in file: #.xreadlines(): - line = line.lstrip() # rare cases there is white space at the start of the line - - if line.startswith('v '): - line_split= line.split() - # rotate X90: (x,-z,y) - verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) - - elif line.startswith('vn '): - pass - - elif line.startswith('vt '): - line_split= line.split() - verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) - - # Handel faces lines (as faces) and the second+ lines of fa multiline face here - # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) - elif line.startswith('f') or context_multi_line == 'f': - - if context_multi_line: - # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face - line_split= line.split() - - else: - line_split= line[2:].split() - face_vert_loc_indicies= [] - face_vert_tex_indicies= [] - - # Instance a face - faces.append((\ - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object\ - )) - - if strip_slash(line_split): - context_multi_line = 'f' - else: - context_multi_line = '' - - for v in line_split: - obj_vert= v.split('/') - - vert_loc_index= int(obj_vert[0])-1 - # Add the vertex to the current group - # *warning*, this wont work for files that have groups defined around verts - if POLYGROUPS and context_vgroup: - vertex_groups[context_vgroup].append(vert_loc_index) - - # Make relative negative vert indicies absolute - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - face_vert_loc_indicies.append(vert_loc_index) - - if len(obj_vert)>1 and obj_vert[1]: - # formatting for faces with normals and textures us - # loc_index/tex_index/nor_index - - vert_tex_index= int(obj_vert[1])-1 - # Make relative negative vert indicies absolute - if vert_tex_index < 0: - vert_tex_index= len(verts_tex) + vert_tex_index + 1 - - face_vert_tex_indicies.append(vert_tex_index) - else: - # dummy - face_vert_tex_indicies.append(0) - - if len(face_vert_loc_indicies) > 4: - has_ngons= True - - elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'): - # very similar to the face load function above with some parts removed - - if context_multi_line: - # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face - line_split= line.split() - - else: - line_split= line[2:].split() - face_vert_loc_indicies= [] - face_vert_tex_indicies= [] - - # Instance a face - faces.append((\ - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object\ - )) - - if strip_slash(line_split): - context_multi_line = 'l' - else: - context_multi_line = '' - - isline= line.startswith('l') - - for v in line_split: - vert_loc_index= int(v)-1 - - # Make relative negative vert indicies absolute - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - face_vert_loc_indicies.append(vert_loc_index) - - elif line.startswith('s'): - if CREATE_SMOOTH_GROUPS: - context_smooth_group= line_value(line.split()) - if context_smooth_group=='off': - context_smooth_group= None - elif context_smooth_group: # is not None - unique_smooth_groups[context_smooth_group]= None - - elif line.startswith('o'): - if SPLIT_OBJECTS: - context_object= line_value(line.split()) - # unique_obects[context_object]= None - - elif line.startswith('g'): - if SPLIT_GROUPS: - context_object= line_value(line.split()) - # print 'context_object', context_object - # unique_obects[context_object]= None - elif POLYGROUPS: - context_vgroup = line_value(line.split()) - if context_vgroup and context_vgroup != '(null)': - vertex_groups.setdefault(context_vgroup, []) - else: - context_vgroup = None # dont assign a vgroup - - elif line.startswith('usemtl'): - context_material= line_value(line.split()) - unique_materials[context_material]= None - elif line.startswith('mtllib'): # usemap or usemat - material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line - - - # Nurbs support - elif line.startswith('cstype '): - context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline' - elif line.startswith('curv ') or context_multi_line == 'curv': - line_split= line.split() - - curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline - - if not context_multi_line: - context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2]) - line_split[0:3] = [] # remove first 3 items - - if strip_slash(line_split): - context_multi_line = 'curv' - else: - context_multi_line = '' - - - for i in line_split: - vert_loc_index = int(i)-1 - - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - curv_idx.append(vert_loc_index) - - elif line.startswith('parm') or context_multi_line == 'parm': - line_split= line.split() - - if context_multi_line: - context_multi_line = '' - else: - context_parm = line_split[1] - line_split[0:2] = [] # remove first 2 - - if strip_slash(line_split): - context_multi_line = 'parm' - else: - context_multi_line = '' - - if context_parm.lower() == 'u': - context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] ) - elif context_parm.lower() == 'v': # surfaces not suported yet - context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] ) - # else: # may want to support other parm's ? - - elif line.startswith('deg '): - context_nurbs['deg']= [int(i) for i in line.split()[1:]] - elif line.startswith('end'): - # Add the nurbs curve - if context_object: - context_nurbs['name'] = context_object - nurbs.append(context_nurbs) - context_nurbs = {} - context_parm = '' - - ''' # How to use usemap? depricated? - elif line.startswith('usema'): # usemap or usemat - context_image= line_value(line.split()) - ''' - - file.close() - time_new= time.time() -# time_new= sys.time() - print('%.4f sec' % (time_new-time_sub)) - time_sub= time_new - - - print('\tloading materials and images...') - create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) - - time_new= time.time() -# time_new= sys.time() - print('%.4f sec' % (time_new-time_sub)) - time_sub= time_new - - if not ROTATE_X90: - verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] - - # deselect all -# if context.selected_objects: -# bpy.ops.OBJECT_OT_select_all_toggle() - - scene = context.scene -# scn = bpy.data.scenes.active -# scn.objects.selected = [] - new_objects= [] # put new objects here - - print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) )) - # Split the mesh by objects/materials, may - if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True - else: SPLIT_OB_OR_GROUP = False - - for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): - # Create meshes from the data, warning 'vertex_groups' wont support splitting - create_mesh(scene, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) - - # nurbs support -# for context_nurbs in nurbs: -# create_nurbs(scn, context_nurbs, verts_loc, new_objects) - - - axis_min= [ 1000000000]*3 - axis_max= [-1000000000]*3 - -# if CLAMP_SIZE: -# # Get all object bounds -# for ob in new_objects: -# for v in ob.getBoundBox(): -# for axis, value in enumerate(v): -# if axis_min[axis] > value: axis_min[axis]= value -# if axis_max[axis] < value: axis_max[axis]= value - -# # Scale objects -# max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) -# scale= 1.0 - -# while CLAMP_SIZE < max_axis * scale: -# scale= scale/10.0 - -# for ob in new_objects: -# ob.setSize(scale, scale, scale) - - # Better rotate the vert locations - #if not ROTATE_X90: - # for ob in new_objects: - # ob.RotX = -1.570796326794896558 - - time_new= time.time() -# time_new= sys.time() - - print('%.4f sec' % (time_new-time_sub)) - print('finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main))) - - -DEBUG= True - - -def load_obj_ui(filepath, BATCH_LOAD= False): - if BPyMessages.Error_NoFile(filepath): - return - - global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 - - CREATE_SMOOTH_GROUPS= Draw.Create(0) - CREATE_FGONS= Draw.Create(1) - CREATE_EDGES= Draw.Create(1) - SPLIT_OBJECTS= Draw.Create(0) - SPLIT_GROUPS= Draw.Create(0) - SPLIT_MATERIALS= Draw.Create(0) - CLAMP_SIZE= Draw.Create(10.0) - IMAGE_SEARCH= Draw.Create(1) - POLYGROUPS= Draw.Create(0) - KEEP_VERT_ORDER= Draw.Create(1) - ROTATE_X90= Draw.Create(1) - - - # Get USER Options - # Note, Works but not pretty, instead use a more complicated GUI - ''' - pup_block= [\ - 'Import...',\ - ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ - ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ - ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ - 'Separate objects from obj...',\ - ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ - ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ - ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ - 'Options...',\ - ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ - ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ - ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ - ] - - if not Draw.PupBlock('Import OBJ...', pup_block): - return - - if KEEP_VERT_ORDER.val: - SPLIT_OBJECTS.val = False - SPLIT_GROUPS.val = False - SPLIT_MATERIALS.val = False - ''' - - - - # BEGIN ALTERNATIVE UI ******************* - if True: - - EVENT_NONE = 0 - EVENT_EXIT = 1 - EVENT_REDRAW = 2 - EVENT_IMPORT = 3 - - GLOBALS = {} - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - - def obj_ui_set_event(e,v): - GLOBALS['EVENT'] = e - - def do_split(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS - if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val: - KEEP_VERT_ORDER.val = 0 - POLYGROUPS.val = 0 - else: - KEEP_VERT_ORDER.val = 1 - - def do_vertorder(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER - if KEEP_VERT_ORDER.val: - SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 - else: - if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val): - KEEP_VERT_ORDER.val = 1 - - def do_polygroups(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS - if POLYGROUPS.val: - SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 - - def do_help(e,v): - url = __url__[0] - print('Trying to open web browser with documentation at this address...') - print('\t' + url) - - try: - import webbrowser - webbrowser.open(url) - except: - print('...could not open a browser window.') - - def obj_ui(): - ui_x, ui_y = GLOBALS['MOUSE'] - - # Center based on overall pup size - ui_x -= 165 - ui_y -= 90 - - global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 - - Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21) - Draw.BeginAlign() - CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges') - CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons') - CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges') - Draw.EndAlign() - - Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20) - Draw.BeginAlign() - SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split) - SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split) - SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split) - Draw.EndAlign() - - # Only used for user feedback - KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder) - - ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.') - - Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20) - CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)') - POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups) - IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)') - Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event) - Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event) - Draw.EndAlign() - - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT): - Draw.UIBlock(obj_ui, 0) - - if GLOBALS['EVENT'] != EVENT_IMPORT: - return - - # END ALTERNATIVE UI ********************* - - - - - - - - Window.WaitCursor(1) - - if BATCH_LOAD: # load the dir - try: - files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] - except: - Window.WaitCursor(0) - Draw.PupMenu('Error%t|Could not open path ' + filepath) - return - - if not files: - Window.WaitCursor(0) - Draw.PupMenu('Error%t|No files at path ' + filepath) - return - - for f in files: - scn= bpy.data.scenes.new( stripExt(f) ) - scn.makeCurrent() - - load_obj(sys.join(filepath, f),\ - CLAMP_SIZE.val,\ - CREATE_FGONS.val,\ - CREATE_SMOOTH_GROUPS.val,\ - CREATE_EDGES.val,\ - SPLIT_OBJECTS.val,\ - SPLIT_GROUPS.val,\ - SPLIT_MATERIALS.val,\ - ROTATE_X90.val,\ - IMAGE_SEARCH.val,\ - POLYGROUPS.val - ) - - else: # Normal load - load_obj(filepath,\ - CLAMP_SIZE.val,\ - CREATE_FGONS.val,\ - CREATE_SMOOTH_GROUPS.val,\ - CREATE_EDGES.val,\ - SPLIT_OBJECTS.val,\ - SPLIT_GROUPS.val,\ - SPLIT_MATERIALS.val,\ - ROTATE_X90.val,\ - IMAGE_SEARCH.val,\ - POLYGROUPS.val - ) - - Window.WaitCursor(0) - - -def load_obj_ui_batch(file): - load_obj_ui(file, True) - -DEBUG= False - -# if __name__=='__main__' and not DEBUG: -# if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: -# Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') -# else: -# Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') - - # For testing compatibility -''' -else: - # DEBUG ONLY - TIME= sys.time() - DIR = '/fe/obj' - import os - print 'Searching for files' - def fileList(path): - for dirpath, dirnames, filenames in os.walk(path): - for filename in filenames: - yield os.path.join(dirpath, filename) - - files = [f for f in fileList(DIR) if f.lower().endswith('.obj')] - files.sort() - - for i, obj_file in enumerate(files): - if 0 < i < 20: - print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files) - newScn= bpy.data.scenes.new(os.path.basename(obj_file)) - newScn.makeCurrent() - load_obj(obj_file, False, IMAGE_SEARCH=0) - - print 'TOTAL TIME: %.6f' % (sys.time() - TIME) -''' -#load_obj('/test.obj') -#load_obj('/fe/obj/mba1.obj') - - - -class IMPORT_OT_obj(bpy.types.Operator): - ''' - Operator documentation text, will be used for the operator tooltip and python docs. - ''' - __idname__ = "import.obj" - __label__ = "Import 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= ""), - - bpy.props.BoolProperty(attr="CREATE_SMOOTH_GROUPS", name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True), - bpy.props.BoolProperty(attr="CREATE_FGONS", name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True), - bpy.props.BoolProperty(attr="CREATE_EDGES", name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True), - bpy.props.BoolProperty(attr="SPLIT_OBJECTS", name="Object", description="Import OBJ Objects into Blender Objects", default= True), - bpy.props.BoolProperty(attr="SPLIT_GROUPS", name="Group", description="Import OBJ Groups into Blender Objects", default= True), - bpy.props.BoolProperty(attr="SPLIT_MATERIALS", name="Material", description="Import each material into a seperate mesh (Avoids > 16 per mesh error)", default= True), - # old comment: only used for user feedback - # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj - # bpy.props.BoolProperty(attr="KEEP_VERT_ORDER", name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True), - bpy.props.BoolProperty(attr="ROTATE_X90", name="-X90", description="Rotate X 90.", default= True), - bpy.props.FloatProperty(attr="CLAMP_SIZE", name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.01, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0), - bpy.props.BoolProperty(attr="POLYGROUPS", name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True), - bpy.props.BoolProperty(attr="IMAGE_SEARCH", name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True), - ] - - ''' - def poll(self, context): - return True ''' - - def execute(self, context): - # print("Selected: " + context.active_object.name) - - if not self.filename: - raise Exception("filename not set") - - load_obj(self.filename, - context, - self.CLAMP_SIZE, - self.CREATE_FGONS, - self.CREATE_SMOOTH_GROUPS, - self.CREATE_EDGES, - self.SPLIT_OBJECTS, - self.SPLIT_GROUPS, - self.SPLIT_MATERIALS, - self.ROTATE_X90, - self.IMAGE_SEARCH, - self.POLYGROUPS) - - return ('FINISHED',) - - def invoke(self, context, event): - wm = context.manager - wm.add_fileselect(self.__operator__) - return ('RUNNING_MODAL',) - - -bpy.ops.add(IMPORT_OT_obj) - - -# NOTES (all line numbers refer to 2.4x import_obj.py, not this file) -# check later: line 489 -# can convert now: edge flags, edges: lines 508-528 -# ngon (uses python module BPyMesh): 384-414 -# nurbs: 947- -# NEXT clamp size: get bound box with RNA -# get back to l 140 (here) -# search image in bpy.config.textureDir - load_image -# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load) -# bitmask won't work? - 132 -# uses operator bpy.ops.OBJECT_OT_select_all_toggle() to deselect all (not necessary?) -# uses bpy.sys.time() diff --git a/release/io/netrender/__init__.py b/release/io/netrender/__init__.py deleted file mode 100644 index 4a1dd2238e3..00000000000 --- a/release/io/netrender/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# This directory is a Python package. - -import model -import operators -import client -import slave -import master -import master_html -import utils -import balancing -import ui - -# store temp data in bpy module - -import bpy - -bpy.data.netrender_jobs = [] -bpy.data.netrender_slaves = [] -bpy.data.netrender_blacklist = [] \ No newline at end of file diff --git a/release/io/netrender/balancing.py b/release/io/netrender/balancing.py deleted file mode 100644 index 637dd5ff92e..00000000000 --- a/release/io/netrender/balancing.py +++ /dev/null @@ -1,94 +0,0 @@ -import time - -from netrender.utils import * -import netrender.model - -class RatingRule: - def rate(self, job): - return 0 - -class ExclusionRule: - def test(self, job): - return False - -class PriorityRule: - def test(self, job): - return False - -class Balancer: - def __init__(self): - self.rules = [] - self.priorities = [] - self.exceptions = [] - - def addRule(self, rule): - self.rules.append(rule) - - def addPriority(self, priority): - self.priorities.append(priority) - - def addException(self, exception): - self.exceptions.append(exception) - - def applyRules(self, job): - return sum((rule.rate(job) for rule in self.rules)) - - def applyPriorities(self, job): - for priority in self.priorities: - if priority.test(job): - return True # priorities are first - - return False - - def applyExceptions(self, job): - for exception in self.exceptions: - if exception.test(job): - return True # exceptions are last - - return False - - def sortKey(self, job): - return (1 if self.applyExceptions(job) else 0, # exceptions after - 0 if self.applyPriorities(job) else 1, # priorities first - self.applyRules(job)) - - def balance(self, jobs): - if jobs: - jobs.sort(key=self.sortKey) - return jobs[0] - else: - return None - -# ========================== - -class RatingUsage(RatingRule): - def rate(self, job): - # less usage is better - return job.usage / job.priority - -class NewJobPriority(PriorityRule): - def __init__(self, limit = 1): - self.limit = limit - - def test(self, job): - return job.countFrames(status = DONE) < self.limit - -class MinimumTimeBetweenDispatchPriority(PriorityRule): - def __init__(self, limit = 10): - self.limit = limit - - def test(self, job): - return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit - -class ExcludeQueuedEmptyJob(ExclusionRule): - def test(self, job): - return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0 - -class ExcludeSlavesLimit(ExclusionRule): - def __init__(self, count_jobs, count_slaves, limit = 0.75): - self.count_jobs = count_jobs - self.count_slaves = count_slaves - self.limit = limit - - def test(self, job): - return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py deleted file mode 100644 index 65b2937867f..00000000000 --- a/release/io/netrender/client.py +++ /dev/null @@ -1,203 +0,0 @@ -import bpy -import sys, os, re -import http, http.client, http.server, urllib -import subprocess, shutil, time, hashlib - -import netrender.slave as slave -import netrender.master as master -from netrender.utils import * - - -def clientSendJob(conn, scene, anim = False, chunks = 5): - netsettings = scene.network_render - job = netrender.model.RenderJob() - - if anim: - for f in range(scene.start_frame, scene.end_frame + 1): - job.addFrame(f) - else: - job.addFrame(scene.current_frame) - - filename = bpy.data.filename - job.addFile(filename) - - job_name = netsettings.job_name - path, name = os.path.split(filename) - if job_name == "[default]": - job_name = name - - ########################### - # LIBRARIES - ########################### - for lib in bpy.data.libraries: - lib_path = lib.filename - - if lib_path.startswith("//"): - lib_path = path + os.sep + lib_path[2:] - - job.addFile(lib_path) - - ########################### - # POINT CACHES - ########################### - - root, ext = os.path.splitext(name) - cache_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that - - if os.path.exists(cache_path): - caches = {} - pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)_[0-9]+\.bphys") - for cache_file in sorted(os.listdir(cache_path)): - match = pattern.match(cache_file) - - if match: - cache_id = match.groups()[0] - cache_frame = int(match.groups()[1]) - - cache_files = caches.get(cache_id, []) - cache_files.append((cache_frame, cache_file)) - caches[cache_id] = cache_files - - for cache in caches.values(): - cache.sort() - - if len(cache) == 1: - cache_frame, cache_file = cache[0] - job.addFile(cache_path + cache_file, cache_frame, cache_frame) - else: - for i in range(len(cache)): - current_item = cache[i] - next_item = cache[i+1] if i + 1 < len(cache) else None - previous_item = cache[i - 1] if i > 0 else None - - current_frame, current_file = current_item - - if not next_item and not previous_item: - job.addFile(cache_path + current_file, current_frame, current_frame) - elif next_item and not previous_item: - next_frame = next_item[0] - job.addFile(cache_path + current_file, current_frame, next_frame - 1) - elif not next_item and previous_item: - previous_frame = previous_item[0] - job.addFile(cache_path + current_file, previous_frame + 1, current_frame) - else: - next_frame = next_item[0] - previous_frame = previous_item[0] - job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) - - ########################### - # IMAGES - ########################### - for image in bpy.data.images: - if image.source == "FILE" and not image.packed_file: - job.addFile(image.filename) - - # print(job.files) - - job.name = job_name - - for slave in scene.network_render.slaves_blacklist: - job.blacklist.append(slave.id) - - job.chunks = netsettings.chunks - job.priority = netsettings.priority - - # try to send path first - conn.request("POST", "/job", repr(job.serialize())) - response = conn.getresponse() - - job_id = response.getheader("job-id") - - # if not ACCEPTED (but not processed), send files - if response.status == http.client.ACCEPTED: - for filepath, start, end in job.files: - f = open(filepath, "rb") - conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath}) - f.close() - response = conn.getresponse() - - # server will reply with NOT_FOUD until all files are found - - return job_id - -def requestResult(conn, job_id, frame): - conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)}) - -@rnaType -class NetworkRenderEngine(bpy.types.RenderEngine): - __idname__ = 'NET_RENDER' - __label__ = "Network Render" - def render(self, scene): - if scene.network_render.mode == "RENDER_CLIENT": - self.render_client(scene) - elif scene.network_render.mode == "RENDER_SLAVE": - self.render_slave(scene) - elif scene.network_render.mode == "RENDER_MASTER": - self.render_master(scene) - else: - print("UNKNOWN OPERATION MODE") - - def render_master(self, scene): - netsettings = scene.network_render - - address = "" if netsettings.server_address == "[default]" else netsettings.server_address - - master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break) - - - def render_slave(self, scene): - slave.render_slave(self, scene) - - def render_client(self, scene): - netsettings = scene.network_render - self.update_stats("", "Network render client initiation") - - - conn = clientConnection(scene) - - if conn: - # Sending file - - self.update_stats("", "Network render exporting") - - job_id = netsettings.job_id - - # reading back result - - self.update_stats("", "Network render waiting for results") - - requestResult(conn, job_id, scene.current_frame) - response = conn.getresponse() - - if response.status == http.client.NO_CONTENT: - netsettings.job_id = clientSendJob(conn, scene) - requestResult(conn, job_id, scene.current_frame) - - while response.status == http.client.ACCEPTED and not self.test_break(): - time.sleep(1) - requestResult(conn, job_id, scene.current_frame) - response = conn.getresponse() - - if response.status != http.client.OK: - conn.close() - return - - r = scene.render_data - x= int(r.resolution_x*r.resolution_percentage*0.01) - y= int(r.resolution_y*r.resolution_percentage*0.01) - - f = open(netsettings.path + "output.exr", "wb") - buf = response.read(1024) - - while buf: - f.write(buf) - buf = response.read(1024) - - f.close() - - result = self.begin_result(0, 0, x, y) - result.load_from_file(netsettings.path + "output.exr", 0, 0) - self.end_result(result) - - conn.close() - diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py deleted file mode 100644 index a3e186a9cfd..00000000000 --- a/release/io/netrender/master.py +++ /dev/null @@ -1,752 +0,0 @@ -import sys, os -import http, http.client, http.server, urllib, socket -import subprocess, shutil, time, hashlib - -from netrender.utils import * -import netrender.model -import netrender.balancing -import netrender.master_html - -class MRenderFile: - def __init__(self, filepath, start, end): - self.filepath = filepath - self.start = start - self.end = end - self.found = False - - def test(self): - self.found = os.path.exists(self.filepath) - return self.found - - -class MRenderSlave(netrender.model.RenderSlave): - def __init__(self, name, address, stats): - super().__init__() - self.id = hashlib.md5(bytes(repr(name) + repr(address), encoding='utf8')).hexdigest() - self.name = name - self.address = address - self.stats = stats - self.last_seen = time.time() - - self.job = None - self.job_frames = [] - - netrender.model.RenderSlave._slave_map[self.id] = self - - def seen(self): - self.last_seen = time.time() - - def finishedFrame(self, frame_number): - self.job_frames.remove(frame_number) - if not self.job_frames: - self.job = None - -class MRenderJob(netrender.model.RenderJob): - def __init__(self, job_id, name, files, chunks = 1, priority = 1, blacklist = []): - super().__init__() - self.id = job_id - self.name = name - self.files = files - self.frames = [] - self.chunks = chunks - self.priority = priority - self.usage = 0.0 - self.blacklist = blacklist - self.last_dispatched = time.time() - - # special server properties - self.last_update = 0 - self.save_path = "" - self.files_map = {path: MRenderFile(path, start, end) for path, start, end in files} - self.status = JOB_WAITING - - def save(self): - if self.save_path: - f = open(self.save_path + "job.txt", "w") - f.write(repr(self.serialize())) - f.close() - - def testStart(self): - for f in self.files_map.values(): - if not f.test(): - return False - - self.start() - return True - - def testFinished(self): - for f in self.frames: - if f.status == QUEUED or f.status == DISPATCHED: - break - else: - self.status = JOB_FINISHED - - def start(self): - self.status = JOB_QUEUED - - def addLog(self, frames): - log_name = "_".join(("%04d" % f for f in frames)) + ".log" - log_path = self.save_path + log_name - - for number in frames: - frame = self[number] - if frame: - frame.log_path = log_path - - def addFrame(self, frame_number): - frame = MRenderFrame(frame_number) - self.frames.append(frame) - return frame - - def reset(self, all): - for f in self.frames: - f.reset(all) - - def getFrames(self): - frames = [] - for f in self.frames: - if f.status == QUEUED: - self.last_dispatched = time.time() - frames.append(f) - if len(frames) >= self.chunks: - break - - return frames - -class MRenderFrame(netrender.model.RenderFrame): - def __init__(self, frame): - super().__init__() - self.number = frame - self.slave = None - self.time = 0 - self.status = QUEUED - self.log_path = None - - def reset(self, all): - if all or self.status == ERROR: - self.slave = None - self.time = 0 - self.status = QUEUED - - -# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -class RenderHandler(http.server.BaseHTTPRequestHandler): - def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"): - self.send_response(code) - self.send_header("Content-type", content) - - for key, value in headers.items(): - self.send_header(key, value) - - self.end_headers() - - def do_HEAD(self): - - if self.path == "/status": - job_id = self.headers.get('job-id', "") - job_frame = int(self.headers.get('job-frame', -1)) - - job = self.server.getJobID(job_id) - if job: - frame = job[job_frame] - - - if frame: - self.send_head(http.client.OK) - else: - # no such frame - self.send_head(http.client.NO_CONTENT) - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - def do_GET(self): - - if self.path == "/version": - self.send_head() - self.server.stats("", "Version check") - self.wfile.write(VERSION) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/render": - job_id = self.headers['job-id'] - job_frame = int(self.headers['job-frame']) - - job = self.server.getJobID(job_id) - - if job: - frame = job[job_frame] - - if frame: - if frame.status in (QUEUED, DISPATCHED): - self.send_head(http.client.ACCEPTED) - elif frame.status == DONE: - self.server.stats("", "Sending result to client") - f = open(job.save_path + "%04d" % job_frame + ".exr", 'rb') - - self.send_head() - - shutil.copyfileobj(f, self.wfile) - - f.close() - elif frame.status == ERROR: - self.send_head(http.client.PARTIAL_CONTENT) - else: - # no such frame - self.send_head(http.client.NO_CONTENT) - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/log": - job_id = self.headers['job-id'] - job_frame = int(self.headers['job-frame']) - - job = self.server.getJobID(job_id) - - if job: - frame = job[job_frame] - - if frame: - if not frame.log_path or frame.status in (QUEUED, DISPATCHED): - self.send_head(http.client.PROCESSING) - else: - self.server.stats("", "Sending log to client") - f = open(frame.log_path, 'rb') - - self.send_head() - - shutil.copyfileobj(f, self.wfile) - - f.close() - else: - # no such frame - self.send_head(http.client.NO_CONTENT) - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/status": - job_id = self.headers.get('job-id', "") - job_frame = int(self.headers.get('job-frame', -1)) - - if job_id: - - job = self.server.getJobID(job_id) - if job: - if job_frame != -1: - frame = job[frame] - - if frame: - message = frame.serialize() - else: - # no such frame - self.send_heat(http.client.NO_CONTENT) - return - else: - message = job.serialize() - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - return - else: # status of all jobs - message = [] - - for job in self.server: - message.append(job.serialize()) - - - self.server.stats("", "Sending status") - self.send_head() - self.wfile.write(bytes(repr(message), encoding='utf8')) - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/job": - self.server.balance() - - slave_id = self.headers['slave-id'] - - slave = self.server.getSeenSlave(slave_id) - - if slave: # only if slave id is valid - job, frames = self.server.newDispatch(slave_id) - - if job and frames: - for f in frames: - print("dispatch", f.number) - f.status = DISPATCHED - f.slave = slave - - slave.job = job - slave.job_frames = [f.number for f in frames] - - self.send_head(headers={"job-id": job.id}) - - message = job.serialize(frames) - - self.wfile.write(bytes(repr(message), encoding='utf8')) - - self.server.stats("", "Sending job to slave") - else: - # no job available, return error code - slave.job = None - slave.job_frames = [] - - self.send_head(http.client.ACCEPTED) - else: # invalid slave id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/file": - slave_id = self.headers['slave-id'] - - slave = self.server.getSeenSlave(slave_id) - - if slave: # only if slave id is valid - job_id = self.headers['job-id'] - job_file = self.headers['job-file'] - - job = self.server.getJobID(job_id) - - if job: - render_file = job.files_map.get(job_file, None) - - if render_file: - self.server.stats("", "Sending file to slave") - f = open(render_file.filepath, 'rb') - - self.send_head() - shutil.copyfileobj(f, self.wfile) - - f.close() - else: - # no such file - self.send_head(http.client.NO_CONTENT) - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - else: # invalid slave id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/slaves": - message = [] - - self.server.stats("", "Sending slaves status") - - for slave in self.server.slaves: - message.append(slave.serialize()) - - self.send_head() - - self.wfile.write(bytes(repr(message), encoding='utf8')) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - else: - # hand over the rest to the html section - netrender.master_html.get(self) - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - def do_POST(self): - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - if self.path == "/job": - - length = int(self.headers['content-length']) - - job_info = netrender.model.RenderJob.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) - - job_id = self.server.nextJobID() - - job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist) - - for frame in job_info.frames: - frame = job.addFrame(frame.number) - - self.server.addJob(job) - - headers={"job-id": job_id} - - if job.testStart(): - self.server.stats("", "New job, missing files") - self.send_head(headers=headers) - else: - self.server.stats("", "New job, started") - self.send_head(http.client.ACCEPTED, headers=headers) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/cancel": - job_id = self.headers.get('job-id', "") - - job = self.server.getJobID(job_id) - - if job: - self.server.stats("", "Cancelling job") - self.server.removeJob(job) - self.send_head() - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/clear": - # cancel all jobs - self.server.stats("", "Clearing jobs") - self.server.clear() - - self.send_head() - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/reset": - job_id = self.headers.get('job-id', "") - job_frame = int(self.headers.get('job-frame', "-1")) - all = bool(self.headers.get('reset-all', "False")) - - job = self.server.getJobID(job_id) - - if job: - if job_frame != -1: - - frame = job[job_frame] - if frame: - self.server.stats("", "Reset job frame") - frame.reset(all) - self.send_head() - else: - # no such frame - self.send_head(http.client.NO_CONTENT) - - else: - self.server.stats("", "Reset job") - job.reset(all) - self.send_head() - - else: # job not found - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/slave": - length = int(self.headers['content-length']) - job_frame_string = self.headers['job-frame'] - - self.server.stats("", "New slave connected") - - slave_info = netrender.model.RenderSlave.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) - - slave_id = self.server.addSlave(slave_info.name, self.client_address, slave_info.stats) - - self.send_head(headers = {"slave-id": slave_id}) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/log": - slave_id = self.headers['slave-id'] - - slave = self.server.getSeenSlave(slave_id) - - if slave: # only if slave id is valid - length = int(self.headers['content-length']) - - log_info = netrender.model.LogFile.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) - - job = self.server.getJobID(log_info.job_id) - - if job: - self.server.stats("", "Log announcement") - job.addLog(log_info.frames) - self.send_head(http.client.OK) - else: - # no such job id - self.send_head(http.client.NO_CONTENT) - else: # invalid slave id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - def do_PUT(self): - - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - if self.path == "/file": - self.server.stats("", "Receiving job") - - length = int(self.headers['content-length']) - job_id = self.headers['job-id'] - job_file = self.headers['job-file'] - - job = self.server.getJobID(job_id) - - if job: - - render_file = job.files_map.get(job_file, None) - - if render_file: - main_file = job.files[0][0] # filename of the first file - - main_path, main_name = os.path.split(main_file) - - if job_file != main_file: - file_path = prefixPath(job.save_path, job_file, main_path) - else: - file_path = job.save_path + main_name - - buf = self.rfile.read(length) - - # add same temp file + renames as slave - - f = open(file_path, "wb") - f.write(buf) - f.close() - del buf - - render_file.filepath = file_path # set the new path - - if job.testStart(): - self.server.stats("", "File upload, starting job") - self.send_head(http.client.OK) - else: - self.server.stats("", "File upload, file missings") - self.send_head(http.client.ACCEPTED) - else: # invalid file - self.send_head(http.client.NO_CONTENT) - else: # job not found - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/render": - self.server.stats("", "Receiving render result") - - slave_id = self.headers['slave-id'] - - slave = self.server.getSeenSlave(slave_id) - - if slave: # only if slave id is valid - job_id = self.headers['job-id'] - - job = self.server.getJobID(job_id) - - if job: - job_frame = int(self.headers['job-frame']) - job_result = int(self.headers['job-result']) - job_time = float(self.headers['job-time']) - - frame = job[job_frame] - - if frame: - if job_result == DONE: - length = int(self.headers['content-length']) - buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb') - f.write(buf) - f.close() - - del buf - elif job_result == ERROR: - # blacklist slave on this job on error - job.blacklist.append(slave.id) - - self.server.stats("", "Receiving result") - - slave.finishedFrame(job_frame) - - frame.status = job_result - frame.time = job_time - - job.testFinished() - - self.send_head() - else: # frame not found - self.send_head(http.client.NO_CONTENT) - else: # job not found - self.send_head(http.client.NO_CONTENT) - else: # invalid slave id - self.send_head(http.client.NO_CONTENT) - # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - elif self.path == "/log": - self.server.stats("", "Receiving log file") - - job_id = self.headers['job-id'] - - job = self.server.getJobID(job_id) - - if job: - job_frame = int(self.headers['job-frame']) - - frame = job[job_frame] - - if frame and frame.log_path: - length = int(self.headers['content-length']) - buf = self.rfile.read(length) - f = open(frame.log_path, 'ab') - f.write(buf) - f.close() - - del buf - - self.server.getSeenSlave(self.headers['slave-id']) - - self.send_head() - else: # frame not found - self.send_head(http.client.NO_CONTENT) - else: # job not found - self.send_head(http.client.NO_CONTENT) - -class RenderMasterServer(http.server.HTTPServer): - def __init__(self, address, handler_class, path): - super().__init__(address, handler_class) - self.jobs = [] - self.jobs_map = {} - self.slaves = [] - self.slaves_map = {} - self.job_id = 0 - self.path = path + "master_" + str(os.getpid()) + os.sep - - self.slave_timeout = 2 - - self.balancer = netrender.balancing.Balancer() - self.balancer.addRule(netrender.balancing.RatingUsage()) - self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) - self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves, limit = 0.9)) - self.balancer.addPriority(netrender.balancing.NewJobPriority()) - self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority(limit = 2)) - - if not os.path.exists(self.path): - os.mkdir(self.path) - - def nextJobID(self): - self.job_id += 1 - return str(self.job_id) - - def addSlave(self, name, address, stats): - slave = MRenderSlave(name, address, stats) - self.slaves.append(slave) - self.slaves_map[slave.id] = slave - - return slave.id - - def removeSlave(self, slave): - self.slaves.remove(slave) - self.slaves_map.pop(slave.id) - - def getSlave(self, slave_id): - return self.slaves_map.get(slave_id, None) - - def getSeenSlave(self, slave_id): - slave = self.getSlave(slave_id) - if slave: - slave.seen() - - return slave - - def timeoutSlaves(self): - removed = [] - - t = time.time() - - for slave in self.slaves: - if (t - slave.last_seen) / 60 > self.slave_timeout: - removed.append(slave) - - if slave.job: - for f in slave.job_frames: - slave.job[f].status = ERROR - - for slave in removed: - self.removeSlave(slave) - - def updateUsage(self): - blend = 0.5 - for job in self.jobs: - job.usage *= (1 - blend) - - if self.slaves: - slave_usage = blend / self.countSlaves() - - for slave in self.slaves: - if slave.job: - slave.job.usage += slave_usage - - - def clear(self): - removed = self.jobs[:] - - for job in removed: - self.removeJob(job) - - def balance(self): - self.balancer.balance(self.jobs) - - def countJobs(self, status = JOB_QUEUED): - total = 0 - for j in self.jobs: - if j.status == status: - total += 1 - - return total - - def countSlaves(self): - return len(self.slaves) - - def removeJob(self, job): - self.jobs.remove(job) - self.jobs_map.pop(job.id) - - for slave in self.slaves: - if slave.job == job: - slave.job = None - slave.job_frames = [] - - def addJob(self, job): - self.jobs.append(job) - self.jobs_map[job.id] = job - - # create job directory - job.save_path = self.path + "job_" + job.id + os.sep - if not os.path.exists(job.save_path): - os.mkdir(job.save_path) - - job.save() - - def getJobID(self, id): - return self.jobs_map.get(id, None) - - def __iter__(self): - for job in self.jobs: - yield job - - def newDispatch(self, slave_id): - if self.jobs: - for job in self.jobs: - if not self.balancer.applyExceptions(job) and slave_id not in job.blacklist: - return job, job.getFrames() - - return None, None - -def runMaster(address, broadcast, path, update_stats, test_break): - httpd = RenderMasterServer(address, RenderHandler, path) - httpd.timeout = 1 - httpd.stats = update_stats - - if broadcast: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - - start_time = time.time() - - while not test_break(): - httpd.handle_request() - - if time.time() - start_time >= 10: # need constant here - httpd.timeoutSlaves() - - httpd.updateUsage() - - if broadcast: - print("broadcasting address") - s.sendto(bytes("%i" % address[1], encoding='utf8'), 0, ('', 8000)) - start_time = time.time() diff --git a/release/io/netrender/master_html.py b/release/io/netrender/master_html.py deleted file mode 100644 index 6a956a70e9f..00000000000 --- a/release/io/netrender/master_html.py +++ /dev/null @@ -1,142 +0,0 @@ -import re - -from netrender.utils import * - - -def get(handler): - def output(text): - handler.wfile.write(bytes(text, encoding='utf8')) - - def link(text, url): - return "%s" % (url, text) - - def startTable(border=1): - output("" % border) - - def headerTable(*headers): - output("") - - for c in headers: - output("") - - output("") - - def rowTable(*data): - output("") - - for c in data: - output("") - - output("") - - def endTable(): - output("
" + c + "
" + str(c) + "
") - - handler.send_head(content = "text/html") - - if handler.path == "/html" or handler.path == "/": - output("NetRender") - - output("

Master

") - - output("

Slaves

") - - startTable() - headerTable("name", "address", "last seen", "stats", "job") - - for slave in handler.server.slaves: - rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None") - - endTable() - - output("

Jobs

") - - startTable() - headerTable( - "name", - "priority", - "usage", - "wait", - "length", - "done", - "dispatched", - "error", - "first", - "exception" - ) - - handler.server.balance() - - for job in handler.server.jobs: - results = job.framesStatus() - rowTable( - link(job.name, "/html/job" + job.id), - job.priority, - "%0.1f%%" % (job.usage * 100), - "%is" % int(time.time() - job.last_dispatched), - len(job), - results[DONE], - results[DISPATCHED], - results[ERROR], - handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job) - ) - - endTable() - - output("") - - elif handler.path.startswith("/html/job"): - job_id = handler.path[9:] - - output("NetRender") - - job = handler.server.getJobID(job_id) - - if job: - output("

Frames

") - - startTable() - headerTable("no", "status", "render time", "slave", "log") - - for frame in job.frames: - rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else " ", link("view log", "/html/log%s_%i" % (job_id, frame.number)) if frame.log_path else " ") - - endTable() - else: - output("no such job") - - output("") - - elif handler.path.startswith("/html/log"): - pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)") - - output("NetRender") - - match = pattern.match(handler.path[9:]) - if match: - job_id = match.groups()[0] - frame_number = int(match.groups()[1]) - - job = handler.server.getJobID(job_id) - - if job: - frame = job[frame_number] - - if frame: - f = open(frame.log_path, 'rb') - - output("
")
-						
-						shutil.copyfileobj(f, handler.wfile)
-						
-						output("
") - - f.close() - else: - output("no such frame") - else: - output("no such job") - else: - output("malformed url") - - output("") diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py deleted file mode 100644 index be97f8d0a81..00000000000 --- a/release/io/netrender/model.py +++ /dev/null @@ -1,198 +0,0 @@ -import sys, os -import http, http.client, http.server, urllib -import subprocess, shutil, time, hashlib - -from netrender.utils import * - -class LogFile: - def __init__(self, job_id = 0, frames = []): - self.job_id = job_id - self.frames = frames - - def serialize(self): - return { - "job_id": self.job_id, - "frames": self.frames - } - - @staticmethod - def materialize(data): - if not data: - return None - - logfile = LogFile() - logfile.job_id = data["job_id"] - logfile.frames = data["frames"] - - return logfile - -class RenderSlave: - _slave_map = {} - - def __init__(self): - self.id = "" - self.name = "" - self.address = ("",0) - self.stats = "" - self.total_done = 0 - self.total_error = 0 - self.last_seen = 0.0 - - def serialize(self): - return { - "id": self.id, - "name": self.name, - "address": self.address, - "stats": self.stats, - "total_done": self.total_done, - "total_error": self.total_error, - "last_seen": self.last_seen - } - - @staticmethod - def materialize(data): - if not data: - return None - - slave_id = data["id"] - - if slave_id in RenderSlave._slave_map: - return RenderSlave._slave_map[slave_id] - else: - slave = RenderSlave() - slave.id = slave_id - slave.name = data["name"] - slave.address = data["address"] - slave.stats = data["stats"] - slave.total_done = data["total_done"] - slave.total_error = data["total_error"] - slave.last_seen = data["last_seen"] - - RenderSlave._slave_map[slave_id] = slave - - return slave - -class RenderJob: - def __init__(self): - self.id = "" - self.name = "" - self.files = [] - self.frames = [] - self.chunks = 0 - self.priority = 0 - self.usage = 0.0 - self.blacklist = [] - self.last_dispatched = 0.0 - - def addFile(self, file_path, start=-1, end=-1): - self.files.append((file_path, start, end)) - - def addFrame(self, frame_number): - frame = RenderFrame(frame_number) - self.frames.append(frame) - return frame - - def __len__(self): - return len(self.frames) - - def countFrames(self, status=QUEUED): - total = 0 - for f in self.frames: - if f.status == status: - total += 1 - - return total - - def countSlaves(self): - return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED))) - - def framesStatus(self): - results = { - QUEUED: 0, - DISPATCHED: 0, - DONE: 0, - ERROR: 0 - } - - for frame in self.frames: - results[frame.status] += 1 - - return results - - def __contains__(self, frame_number): - for f in self.frames: - if f.number == frame_number: - return True - else: - return False - - def __getitem__(self, frame_number): - for f in self.frames: - if f.number == frame_number: - return f - else: - return None - - def serialize(self, frames = None): - min_frame = min((f.number for f in frames)) if frames else -1 - max_frame = max((f.number for f in frames)) if frames else -1 - return { - "id": self.id, - "name": self.name, - "files": [f for f in self.files if f[1] == -1 or not frames or (f[1] <= min_frame <= f[2] or f[1] <= max_frame <= f[2])], - "frames": [f.serialize() for f in self.frames if not frames or f in frames], - "chunks": self.chunks, - "priority": self.priority, - "usage": self.usage, - "blacklist": self.blacklist, - "last_dispatched": self.last_dispatched - } - - @staticmethod - def materialize(data): - if not data: - return None - - job = RenderJob() - job.id = data["id"] - job.name = data["name"] - job.files = data["files"] - job.frames = [RenderFrame.materialize(f) for f in data["frames"]] - job.chunks = data["chunks"] - job.priority = data["priority"] - job.usage = data["usage"] - job.blacklist = data["blacklist"] - job.last_dispatched = data["last_dispatched"] - - return job - -class RenderFrame: - def __init__(self, number = 0): - self.number = number - self.time = 0 - self.status = QUEUED - self.slave = None - - def statusText(self): - return STATUS_TEXT[self.status] - - def serialize(self): - return { - "number": self.number, - "time": self.time, - "status": self.status, - "slave": None if not self.slave else self.slave.serialize() - } - - @staticmethod - def materialize(data): - if not data: - return None - - frame = RenderFrame() - frame.number = data["number"] - frame.time = data["time"] - frame.status = data["status"] - frame.slave = RenderSlave.materialize(data["slave"]) - - return frame diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py deleted file mode 100644 index 42d1f6a0b86..00000000000 --- a/release/io/netrender/operators.py +++ /dev/null @@ -1,423 +0,0 @@ -import bpy -import sys, os -import http, http.client, http.server, urllib, socket -import webbrowser - -from netrender.utils import * -import netrender.client as client -import netrender.model - -@rnaOperator -class RENDER_OT_netclientanim(bpy.types.Operator): - ''' - Operator documentation text, will be used for the operator tooltip and python docs. - ''' - __idname__ = "render.netclientanim" - __label__ = "Net Render Client Anim" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - scene = context.scene - - conn = clientConnection(scene) - - if conn: - # Sending file - scene.network_render.job_id = client.clientSendJob(conn, scene, True) - conn.close() - - bpy.ops.screen.render('INVOKE_AREA', animation=True) - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientsend(bpy.types.Operator): - ''' - Operator documentation text, will be used for the operator tooltip and python docs. - ''' - __idname__ = "render.netclientsend" - __label__ = "Net Render Client Send" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - scene = context.scene - - conn = clientConnection(scene) - - if conn: - # Sending file - scene.network_render.job_id = client.clientSendJob(conn, scene, True) - conn.close() - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientstatus(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientstatus" - __label__ = "Net Render Client Status" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - conn = clientConnection(context.scene) - - if conn: - conn.request("GET", "/status") - - response = conn.getresponse() - print( response.status, response.reason ) - - jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8'))) - - while(len(netsettings.jobs) > 0): - netsettings.jobs.remove(0) - - bpy.data.netrender_jobs = [] - - for j in jobs: - bpy.data.netrender_jobs.append(j) - netsettings.jobs.add() - job = netsettings.jobs[-1] - - j.results = j.framesStatus() # cache frame status - - job.name = j.name - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientblacklistslave(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientblacklistslave" - __label__ = "Net Render Client Blacklist Slave" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - - if netsettings.active_slave_index >= 0: - - # deal with data - slave = bpy.data.netrender_slaves.pop(netsettings.active_slave_index) - bpy.data.netrender_blacklist.append(slave) - - # deal with rna - netsettings.slaves_blacklist.add() - netsettings.slaves_blacklist[-1].name = slave.name - - netsettings.slaves.remove(netsettings.active_slave_index) - netsettings.active_slave_index = -1 - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientwhitelistslave" - __label__ = "Net Render Client Whitelist Slave" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - - if netsettings.active_blacklisted_slave_index >= 0: - - # deal with data - slave = bpy.data.netrender_blacklist.pop(netsettings.active_blacklisted_slave_index) - bpy.data.netrender_slaves.append(slave) - - # deal with rna - netsettings.slaves.add() - netsettings.slaves[-1].name = slave.name - - netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index) - netsettings.active_blacklisted_slave_index = -1 - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - - -@rnaOperator -class RENDER_OT_netclientslaves(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientslaves" - __label__ = "Net Render Client Slaves" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - conn = clientConnection(context.scene) - - if conn: - conn.request("GET", "/slaves") - - response = conn.getresponse() - print( response.status, response.reason ) - - slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8'))) - - while(len(netsettings.slaves) > 0): - netsettings.slaves.remove(0) - - bpy.data.netrender_slaves = [] - - for s in slaves: - for i in range(len(bpy.data.netrender_blacklist)): - slave = bpy.data.netrender_blacklist[i] - if slave.id == s.id: - bpy.data.netrender_blacklist[i] = s - netsettings.slaves_blacklist[i].name = s.name - break - else: - bpy.data.netrender_slaves.append(s) - - netsettings.slaves.add() - slave = netsettings.slaves[-1] - slave.name = s.name - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientcancel(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientcancel" - __label__ = "Net Render Client Cancel" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - netsettings = context.scene.network_render - return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 - - def execute(self, context): - netsettings = context.scene.network_render - conn = clientConnection(context.scene) - - if conn: - job = bpy.data.netrender_jobs[netsettings.active_job_index] - - conn.request("POST", "/cancel", headers={"job-id":job.id}) - - response = conn.getresponse() - print( response.status, response.reason ) - - netsettings.jobs.remove(netsettings.active_job_index) - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class RENDER_OT_netclientcancelall(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientcancelall" - __label__ = "Net Render Client Cancel All" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - conn = clientConnection(context.scene) - - if conn: - conn.request("POST", "/clear") - - response = conn.getresponse() - print( response.status, response.reason ) - - while(len(netsettings.jobs) > 0): - netsettings.jobs.remove(0) - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class netclientdownload(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientdownload" - __label__ = "Net Render Client Download" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - netsettings = context.scene.network_render - return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 - - def execute(self, context): - netsettings = context.scene.network_render - rd = context.scene.render_data - - conn = clientConnection(context.scene) - - if conn: - job = bpy.data.netrender_jobs[netsettings.active_job_index] - - for frame in job.frames: - client.requestResult(conn, job.id, frame.number) - response = conn.getresponse() - - if response.status != http.client.OK: - print("missing", frame.number) - continue - - print("got back", frame.number) - - f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb") - buf = response.read(1024) - - while buf: - f.write(buf) - buf = response.read(1024) - - f.close() - - conn.close() - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class netclientscan(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientscan" - __label__ = "Net Render Client Scan" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - - try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - s.settimeout(30) - - s.bind(('', 8000)) - - buf, address = s.recvfrom(64) - - print("received:", buf) - - netsettings.server_address = address[0] - netsettings.server_port = int(str(buf, encoding='utf8')) - except socket.timeout: - print("no server info") - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) - -@rnaOperator -class netclientweb(bpy.types.Operator): - '''Operator documentation text, will be used for the operator tooltip and python docs.''' - __idname__ = "render.netclientweb" - __label__ = "Net Render Client Web" - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - - __props__ = [] - - def poll(self, context): - return True - - def execute(self, context): - netsettings = context.scene.network_render - - - # open connection to make sure server exists - conn = clientConnection(context.scene) - - if conn: - conn.close() - - webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port)) - - return ('FINISHED',) - - def invoke(self, context, event): - return self.execute(context) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py deleted file mode 100644 index 657e31001e0..00000000000 --- a/release/io/netrender/slave.py +++ /dev/null @@ -1,207 +0,0 @@ -import sys, os, platform -import http, http.client, http.server, urllib -import subprocess, time - -from netrender.utils import * -import netrender.model - -CANCEL_POLL_SPEED = 2 -MAX_TIMEOUT = 10 -INCREMENT_TIMEOUT = 1 - -if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5 - import ctypes - def SetErrorMode(): - val = ctypes.windll.kernel32.SetErrorMode(0x0002) - ctypes.windll.kernel32.SetErrorMode(val | 0x0002) - return val - - def RestoreErrorMode(val): - ctypes.windll.kernel32.SetErrorMode(val) -else: - def SetErrorMode(): - return 0 - - def RestoreErrorMode(val): - pass - -def slave_Info(): - sysname, nodename, release, version, machine, processor = platform.uname() - slave = netrender.model.RenderSlave() - slave.name = nodename - slave.stats = sysname + " " + release + " " + machine + " " + processor - return slave - -def testCancel(conn, job_id, frame_number): - conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) - response = conn.getresponse() - - # cancelled if job isn't found anymore - if response.status == http.client.NO_CONTENT: - return True - else: - return False - -def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None): - job_full_path = prefixPath(JOB_PREFIX, file_path, main_path) - - if not os.path.exists(job_full_path): - temp_path = JOB_PREFIX + "slave.temp.blend" - conn.request("GET", "/file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) - response = conn.getresponse() - - if response.status != http.client.OK: - return None # file for job not returned by server, need to return an error code to server - - f = open(temp_path, "wb") - buf = response.read(1024) - - while buf: - f.write(buf) - buf = response.read(1024) - - f.close() - - os.renames(temp_path, job_full_path) - - return job_full_path - - -def render_slave(engine, scene): - netsettings = scene.network_render - timeout = 1 - - engine.update_stats("", "Network render node initiation") - - conn = clientConnection(scene) - - if conn: - conn.request("POST", "/slave", repr(slave_Info().serialize())) - response = conn.getresponse() - - slave_id = response.getheader("slave-id") - - NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep - if not os.path.exists(NODE_PREFIX): - os.mkdir(NODE_PREFIX) - - while not engine.test_break(): - - conn.request("GET", "/job", headers={"slave-id":slave_id}) - response = conn.getresponse() - - if response.status == http.client.OK: - timeout = 1 # reset timeout on new job - - job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8'))) - - JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep - if not os.path.exists(JOB_PREFIX): - os.mkdir(JOB_PREFIX) - - job_path = job.files[0][0] # data in files have format (path, start, end) - main_path, main_file = os.path.split(job_path) - - job_full_path = testFile(conn, job.id, slave_id, JOB_PREFIX, job_path) - print("Fullpath", job_full_path) - print("File:", main_file, "and %i other files" % (len(job.files) - 1,)) - engine.update_stats("", "Render File", main_file, "for job", job.id) - - for file_path, start, end in job.files[1:]: - print("\t", file_path) - testFile(conn, job.id, slave_id, JOB_PREFIX, file_path, main_path) - - frame_args = [] - - for frame in job.frames: - print("frame", frame.number) - frame_args += ["-f", str(frame.number)] - - # announce log to master - logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames]) - conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) - response = conn.getresponse() - - first_frame = job.frames[0].number - - # start render - start_t = time.time() - - val = SetErrorMode() - process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - RestoreErrorMode(val) - - headers = {"job-id":job.id, "slave-id":slave_id} - - cancelled = False - stdout = bytes() - run_t = time.time() - while process.poll() == None and not cancelled: - stdout += process.stdout.read(32) - current_t = time.time() - cancelled = engine.test_break() - if current_t - run_t > CANCEL_POLL_SPEED: - - # update logs if needed - if stdout: - # (only need to update on one frame, they are linked - headers["job-frame"] = str(first_frame) - conn.request("PUT", "/log", stdout, headers=headers) - response = conn.getresponse() - - stdout = bytes() - - run_t = current_t - if testCancel(conn, job.id, first_frame): - cancelled = True - - if cancelled: - # kill process if needed - if process.poll() == None: - process.terminate() - continue # to next frame - - total_t = time.time() - start_t - - avg_t = total_t / len(job.frames) - - status = process.returncode - - print("status", status) - - # flush the rest of the logs - if stdout: - # (only need to update on one frame, they are linked - headers["job-frame"] = str(first_frame) - conn.request("PUT", "/log", stdout, headers=headers) - response = conn.getresponse() - - headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} - - if status == 0: # non zero status is error - headers["job-result"] = str(DONE) - for frame in job.frames: - headers["job-frame"] = str(frame.number) - # send result back to server - f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') - conn.request("PUT", "/render", f, headers=headers) - f.close() - response = conn.getresponse() - else: - headers["job-result"] = str(ERROR) - for frame in job.frames: - headers["job-frame"] = str(frame.number) - # send error result back to server - conn.request("PUT", "/render", headers=headers) - response = conn.getresponse() - else: - if timeout < MAX_TIMEOUT: - timeout += INCREMENT_TIMEOUT - - for i in range(timeout): - time.sleep(1) - if engine.test_break(): - conn.close() - return - - conn.close() diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py deleted file mode 100644 index 7681d4865e9..00000000000 --- a/release/io/netrender/ui.py +++ /dev/null @@ -1,321 +0,0 @@ -import bpy -import sys, os -import http, http.client, http.server, urllib -import subprocess, shutil, time, hashlib - -import netrender.slave as slave -import netrender.master as master - -from netrender.utils import * - -VERSION = b"0.3" - -PATH_PREFIX = "/tmp/" - -QUEUED = 0 -DISPATCHED = 1 -DONE = 2 -ERROR = 3 - -class RenderButtonsPanel(bpy.types.Panel): - __space_type__ = "PROPERTIES" - __region_type__ = "WINDOW" - __context__ = "scene" - # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - def poll(self, context): - rd = context.scene.render_data - return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) - -# Setting panel, use in the scene for now. -@rnaType -class SCENE_PT_network_settings(RenderButtonsPanel): - __label__ = "Network Settings" - COMPAT_ENGINES = set(['NET_RENDER']) - - def draw_header(self, context): - layout = self.layout - scene = context.scene - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render_data - - layout.active = True - - split = layout.split() - - col = split.column() - - col.itemR(scene.network_render, "mode") - col.itemR(scene.network_render, "path") - col.itemR(scene.network_render, "server_address") - col.itemR(scene.network_render, "server_port") - - if scene.network_render.mode == "RENDER_MASTER": - col.itemR(scene.network_render, "server_broadcast") - else: - col.itemO("render.netclientscan", icon="ICON_FILE_REFRESH", text="") - -@rnaType -class SCENE_PT_network_job(RenderButtonsPanel): - __label__ = "Job Settings" - COMPAT_ENGINES = set(['NET_RENDER']) - - def poll(self, context): - scene = context.scene - return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render_data - - layout.active = True - - split = layout.split() - - col = split.column() - - col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") - col.itemO("render.netclientsend", icon="ICON_FILE_BLEND", text="Send job") - col.itemO("render.netclientweb", icon="ICON_QUESTION", text="Open Master Monitor") - col.itemR(scene.network_render, "job_name") - col.itemR(scene.network_render, "priority") - col.itemR(scene.network_render, "chunks") - -@rnaType -class SCENE_PT_network_slaves(RenderButtonsPanel): - __label__ = "Slaves Status" - COMPAT_ENGINES = set(['NET_RENDER']) - - def poll(self, context): - scene = context.scene - return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" - - def draw(self, context): - layout = self.layout - - scene = context.scene - netsettings = scene.network_render - - row = layout.row() - row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2) - - col = row.column() - - subcol = col.column(align=True) - subcol.itemO("render.netclientslaves", icon="ICON_FILE_REFRESH", text="") - subcol.itemO("render.netclientblacklistslave", icon="ICON_ZOOMOUT", text="") - - if len(bpy.data.netrender_slaves) == 0 and len(netsettings.slaves) > 0: - while(len(netsettings.slaves) > 0): - netsettings.slaves.remove(0) - - if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0: - layout.itemS() - - slave = bpy.data.netrender_slaves[netsettings.active_slave_index] - - layout.itemL(text="Name: " + slave.name) - layout.itemL(text="Address: " + slave.address[0]) - layout.itemL(text="Seen: " + time.ctime(slave.last_seen)) - layout.itemL(text="Stats: " + slave.stats) - -@rnaType -class SCENE_PT_network_slaves_blacklist(RenderButtonsPanel): - __label__ = "Slaves Blacklist" - COMPAT_ENGINES = set(['NET_RENDER']) - - def poll(self, context): - scene = context.scene - return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" - - def draw(self, context): - layout = self.layout - - scene = context.scene - netsettings = scene.network_render - - row = layout.row() - row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2) - - col = row.column() - - subcol = col.column(align=True) - subcol.itemO("render.netclientwhitelistslave", icon="ICON_ZOOMOUT", text="") - - if len(bpy.data.netrender_blacklist) == 0 and len(netsettings.slaves_blacklist) > 0: - while(len(netsettings.slaves_blacklist) > 0): - netsettings.slaves_blacklist.remove(0) - - if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0: - layout.itemS() - - slave = bpy.data.netrender_blacklist[netsettings.active_blacklisted_slave_index] - - layout.itemL(text="Name: " + slave.name) - layout.itemL(text="Address: " + slave.address[0]) - layout.itemL(text="Seen: " + slave.last_seen) - layout.itemL(text="Stats: " + time.ctime(slave.stats)) - -@rnaType -class SCENE_PT_network_jobs(RenderButtonsPanel): - __label__ = "Jobs" - COMPAT_ENGINES = set(['NET_RENDER']) - - def poll(self, context): - scene = context.scene - return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" - - def draw(self, context): - layout = self.layout - - scene = context.scene - netsettings = scene.network_render - - row = layout.row() - row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2) - - col = row.column() - - subcol = col.column(align=True) - subcol.itemO("render.netclientstatus", icon="ICON_FILE_REFRESH", text="") - subcol.itemO("render.netclientcancel", icon="ICON_ZOOMOUT", text="") - subcol.itemO("render.netclientcancelall", icon="ICON_PANEL_CLOSE", text="") - subcol.itemO("render.netclientdownload", icon='ICON_RENDER_ANIMATION', text="") - - if len(bpy.data.netrender_jobs) == 0 and len(netsettings.jobs) > 0: - while(len(netsettings.jobs) > 0): - netsettings.jobs.remove(0) - - if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0: - layout.itemS() - - job = bpy.data.netrender_jobs[netsettings.active_job_index] - - layout.itemL(text="Name: %s" % job.name) - layout.itemL(text="Length: %04i" % len(job)) - layout.itemL(text="Done: %04i" % job.results[DONE]) - layout.itemL(text="Error: %04i" % job.results[ERROR]) - -@rnaType -class NetRenderSettings(bpy.types.IDPropertyGroup): - pass - -@rnaType -class NetRenderSlave(bpy.types.IDPropertyGroup): - pass - -@rnaType -class NetRenderJob(bpy.types.IDPropertyGroup): - pass - -bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") - -NetRenderSettings.StringProperty( attr="server_address", - name="Server address", - description="IP or name of the master render server", - maxlen = 128, - default = "[default]") - -NetRenderSettings.IntProperty( attr="server_port", - name="Server port", - description="port of the master render server", - default = 8000, - min=1, - max=65535) - -NetRenderSettings.BoolProperty( attr="server_broadcast", - name="Broadcast server address", - description="broadcast server address on local network", - default = True) - -if os.name == 'nt': - NetRenderSettings.StringProperty( attr="path", - name="Path", - description="Path for temporary files", - maxlen = 128, - default = "C:/tmp/") -else: - NetRenderSettings.StringProperty( attr="path", - name="Path", - description="Path for temporary files", - maxlen = 128, - default = "/tmp/") - -NetRenderSettings.StringProperty( attr="job_name", - name="Job name", - description="Name of the job", - maxlen = 128, - default = "[default]") - -NetRenderSettings.IntProperty( attr="chunks", - name="Chunks", - description="Number of frame to dispatch to each slave in one chunk", - default = 5, - min=1, - max=65535) - -NetRenderSettings.IntProperty( attr="priority", - name="Priority", - description="Priority of the job", - default = 1, - min=1, - max=10) - -NetRenderSettings.StringProperty( attr="job_id", - name="Network job id", - description="id of the last sent render job", - maxlen = 64, - default = "") - -NetRenderSettings.IntProperty( attr="active_slave_index", - name="Index of the active slave", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", - name="Index of the active slave", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.IntProperty( attr="active_job_index", - name="Index of the active job", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.EnumProperty(attr="mode", - items=( - ("RENDER_CLIENT", "Client", "Act as render client"), - ("RENDER_MASTER", "Master", "Act as render master"), - ("RENDER_SLAVE", "Slave", "Act as render slave"), - ), - name="network mode", - description="mode of operation of this instance", - default="RENDER_CLIENT") - -NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") -NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") -NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") - -NetRenderSlave.StringProperty( attr="name", - name="Name of the slave", - description="", - maxlen = 64, - default = "") - -NetRenderJob.StringProperty( attr="name", - name="Name of the job", - description="", - maxlen = 128, - default = "") diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py deleted file mode 100644 index 06393a738a0..00000000000 --- a/release/io/netrender/utils.py +++ /dev/null @@ -1,86 +0,0 @@ -import bpy -import sys, os -import re -import http, http.client, http.server, urllib -import subprocess, shutil, time, hashlib - -import netrender.model - -VERSION = b"0.5" - -# Jobs status -JOB_WAITING = 0 # before all data has been entered -JOB_PAUSED = 1 # paused by user -JOB_FINISHED = 2 # finished rendering -JOB_QUEUED = 3 # ready to be dispatched - -# Frames status -QUEUED = 0 -DISPATCHED = 1 -DONE = 2 -ERROR = 3 - -STATUS_TEXT = { - QUEUED: "Queued", - DISPATCHED: "Dispatched", - DONE: "Done", - ERROR: "Error" - } - -def rnaType(rna_type): - bpy.types.register(rna_type) - return rna_type - -def rnaOperator(rna_op): - bpy.ops.add(rna_op) - return rna_op - -def clientConnection(scene): - netsettings = scene.network_render - - if netsettings.server_address == "[default]": - bpy.ops.render.netclientscan() - - conn = http.client.HTTPConnection(netsettings.server_address, netsettings.server_port) - - if clientVerifyVersion(conn): - return conn - else: - conn.close() - return None - -def clientVerifyVersion(conn): - conn.request("GET", "/version") - response = conn.getresponse() - - if response.status != http.client.OK: - conn.close() - return False - - server_version = response.read() - - if server_version != VERSION: - print("Incorrect server version!") - print("expected", VERSION, "received", server_version) - return False - - return True - -def prefixPath(prefix_directory, file_path, prefix_path): - if os.path.isabs(file_path): - # if an absolute path, make sure path exists, if it doesn't, use relative local path - full_path = file_path - if not os.path.exists(full_path): - p, n = os.path.split(full_path) - - if prefix_path and p.startswith(prefix_path): - directory = prefix_directory + p[len(prefix_path):] - full_path = directory + n - if not os.path.exists(directory): - os.mkdir(directory) - else: - full_path = prefix_directory + n - else: - full_path = prefix_directory + file_path - - return full_path diff --git a/release/scripts/3ds_export.py b/release/scripts/3ds_export.py deleted file mode 100644 index 87680bce1b0..00000000000 --- a/release/scripts/3ds_export.py +++ /dev/null @@ -1,1019 +0,0 @@ -#!BPY -# coding: utf-8 -""" -Name: '3D Studio (.3ds)...' -Blender: 243 -Group: 'Export' -Tooltip: 'Export to 3DS file format (.3ds).' -""" - -__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] -__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") -__version__ = "0.90a" -__bpydoc__ = """\ - -3ds Exporter - -This script Exports a 3ds file. - -Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information -from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Bob Holcomb -# -# 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 ***** -# -------------------------------------------------------------------------- - - -###################################################### -# Importing modules -###################################################### - -import Blender -import bpy -from BPyMesh import getMeshFromObject -from BPyObject import getDerivedObjects -try: - import struct -except: - struct = None - -# So 3ds max can open files, limit names to 12 in length -# this is verry annoying for filenames! -name_unique = [] -name_mapping = {} -def sane_name(name): - name_fixed = name_mapping.get(name) - if name_fixed != None: - return name_fixed - - if len(name) > 12: - new_name = name[:12] - else: - new_name = name - - i = 0 - - while new_name in name_unique: - new_name = new_name[:-4] + '.%.3d' % i - i+=1 - - name_unique.append(new_name) - name_mapping[name] = new_name - return new_name - -###################################################### -# Data Structures -###################################################### - -#Some of the chunks that we will export -#----- Primary Chunk, at the beginning of each file -PRIMARY= long("0x4D4D",16) - -#------ Main Chunks -OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information -VERSION = long("0x0002",16); #This gives the version of the .3ds file -KFDATA = long("0xB000",16); #This is the header for all of the key frame info - -#------ sub defines of OBJECTINFO -MATERIAL=45055 #0xAFFF // This stored the texture info -OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... - -#>------ sub defines of MATERIAL -MATNAME = long("0xA000",16); # This holds the material name -MATAMBIENT = long("0xA010",16); # Ambient color of the object/material -MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material -MATSPECULAR = long("0xA030",16); # SPecular color of the object/material -MATSHINESS = long("0xA040",16); # ?? -MATMAP = long("0xA200",16); # This is a header for a new material -MATMAPFILE = long("0xA300",16); # This holds the file name of the texture - -RGB1= long("0x0011",16) -RGB2= long("0x0012",16) - -#>------ sub defines of OBJECT -OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object -OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object -OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object - -#>------ sub defines of CAMERA -OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values - -#>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = long("0x4110",16); # The objects vertices -OBJECT_FACES = long("0x4120",16); # The objects faces -OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color -OBJECT_UV = long("0x4140",16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix - -#>------ sub defines of KFDATA -KFDATA_KFHDR = long("0xB00A",16); -KFDATA_KFSEG = long("0xB008",16); -KFDATA_KFCURTIME = long("0xB009",16); -KFDATA_OBJECT_NODE_TAG = long("0xB002",16); - -#>------ sub defines of OBJECT_NODE_TAG -OBJECT_NODE_ID = long("0xB030",16); -OBJECT_NODE_HDR = long("0xB010",16); -OBJECT_PIVOT = long("0xB013",16); -OBJECT_INSTANCE_NAME = long("0xB011",16); -POS_TRACK_TAG = long("0xB020",16); -ROT_TRACK_TAG = long("0xB021",16); -SCL_TRACK_TAG = long("0xB022",16); - -def uv_key(uv): - return round(uv.x, 6), round(uv.y, 6) - -# size defines: -SZ_SHORT = 2 -SZ_INT = 4 -SZ_FLOAT = 4 - -class _3ds_short(object): - '''Class representing a short (2-byte integer) for a 3ds file. - *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' - __slots__ = 'value' - def __init__(self, val=0): - self.value=val - - def get_size(self): - return SZ_SHORT - - def write(self,file): - file.write(struct.pack("= mat_ls_len: - mat_index = f.mat = 0 - mat = mat_ls[mat_index] - if mat: mat_name = mat.name - else: mat_name = None - # else there alredy set to none - - img = f.image - if img: img_name = img.name - else: img_name = None - - materialDict.setdefault((mat_name, img_name), (mat, img) ) - - - else: - for mat in mat_ls: - if mat: # material may be None so check its not. - materialDict.setdefault((mat.name, None), (mat, None) ) - - # Why 0 Why! - for f in data.faces: - if f.mat >= mat_ls_len: - f.mat = 0 - - # Make material chunks for all materials used in the meshes: - for mat_and_image in materialDict.itervalues(): - object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) - - # Give all objects a unique ID and build a dictionary from object name to object id: - """ - name_to_id = {} - for ob, data in mesh_objects: - name_to_id[ob.name]= len(name_to_id) - #for ob in empty_objects: - # name_to_id[ob.name]= len(name_to_id) - """ - - # Create object chunks for all meshes: - i = 0 - for ob, blender_mesh in mesh_objects: - # create a new object chunk - object_chunk = _3ds_chunk(OBJECT) - - # set the object name - object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) - - # make a mesh chunk out of the mesh: - object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) - object_info.add_subchunk(object_chunk) - - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - # make a kf object node for the object: - kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) - ''' - blender_mesh.verts = None - i+=i - - # Create chunks for all empties: - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - for ob in empty_objects: - # Empties only require a kf object node: - kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) - pass - ''' - - # Add main object info chunk to primary chunk: - primary.add_subchunk(object_info) - - ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX - # Add main keyframe data chunk to primary chunk: - primary.add_subchunk(kfdata) - ''' - - # At this point, the chunk hierarchy is completely built. - - # Check the size: - primary.get_size() - # Open the file for writing: - file = open( filename, 'wb' ) - - # Recursively write the chunks to file: - primary.write(file) - - # Close the file: - file.close() - - # Debugging only: report the exporting time: - Blender.Window.WaitCursor(0) - print "3ds export time: %.2f" % (Blender.sys.time() - time1) - - # Debugging only: dump the chunk hierarchy: - #primary.dump() - - -if __name__=='__main__': - if struct: - Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) - else: - Blender.Draw.PupMenu("Error%t|This script requires a full python installation") -# save_3ds('/test_b.3ds') diff --git a/release/scripts/3ds_import.py b/release/scripts/3ds_import.py deleted file mode 100644 index bcde82c4869..00000000000 --- a/release/scripts/3ds_import.py +++ /dev/null @@ -1,1007 +0,0 @@ -#!BPY -""" -Name: '3D Studio (.3ds)...' -Blender: 244 -Group: 'Import' -Tooltip: 'Import from 3DS file format (.3ds)' -""" - -__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton', 'Mario Lapin'] -__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") -__version__= '0.996' -__bpydoc__= '''\ - -3ds Importer - -This script imports a 3ds file and the materials into Blender for editing. - -Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). - -0.996 by Mario Lapin (mario.lapin@gmail.com) 13/04/200
- - Implemented workaround to correct association between name, geometry and materials of - imported meshes. - - Without this patch, version 0.995 of this importer would associate to each mesh object the - geometry and the materials of the previously parsed mesh object. By so, the name of the - first mesh object would be thrown away, and the name of the last mesh object would be - automatically merged with a '.001' at the end. No object would desappear, however object's - names and materials would be completely jumbled. - -0.995 by Campbell Barton
-- workaround for buggy mesh vert delete -- minor tweaks - -0.99 by Bob Holcomb
-- added support for floating point color values that previously broke on import. - -0.98 by Campbell Barton
-- import faces and verts to lists instead of a mesh, convert to a mesh later -- use new index mapping feature of mesh to re-map faces that were not added. - -0.97 by Campbell Barton
-- Strip material names of spaces -- Added import as instance to import the 3ds into its own - scene and add a group instance to the current scene -- New option to scale down imported objects so they are within a limited bounding area. - -0.96 by Campbell Barton
-- Added workaround for bug in setting UV's for Zero vert index UV faces. -- Removed unique name function, let blender make the names unique. - -0.95 by Campbell Barton
-- Removed workarounds for Blender 2.41 -- Mesh objects split by material- many 3ds objects used more then 16 per mesh. -- Removed a lot of unneeded variable creation. - -0.94 by Campbell Barton
-- Face import tested to be about overall 16x speedup over 0.93. -- Material importing speedup. -- Tested with more models. -- Support some corrupt models. - -0.93 by Campbell Barton
-- Tested with 400 3ds files from turbosquid and samples. -- Tactfully ignore faces that used the same verts twice. -- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. -- Converted from NMesh to Mesh. -- Faster and cleaner new names. -- Use external comprehensive image loader. -- Re intergrated 0.92 and 0.9 changes -- Fixes for 2.41 compat. -- Non textured faces do not use a texture flag. - -0.92
-- Added support for diffuse, alpha, spec, bump maps in a single material - -0.9
-- Reorganized code into object/material block functions
-- Use of Matrix() to copy matrix data
-- added support for material transparency
- -0.83 2005-08-07: Campell Barton -- Aggressive image finding and case insensitivy for posisx systems. - -0.82a 2005-07-22 -- image texture loading (both for face uv and renderer) - -0.82 - image texture loading (for face uv) - -0.81a (fork- not 0.9) Campbell Barton 2005-06-08 -- Simplified import code -- Never overwrite data -- Faster list handling -- Leaves import selected - -0.81 Damien McGinnes 2005-01-09 -- handle missing images better - -0.8 Damien McGinnes 2005-01-08 -- copies sticky UV coords to face ones -- handles images better -- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script - -''' - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Bob Holcomb -# -# 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 ***** -# -------------------------------------------------------------------------- - -# Importing modules - -import Blender -import bpy -from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils -from Blender.Mathutils import Vector -import BPyImage - -import BPyMessages - -try: - from struct import calcsize, unpack -except: - calcsize= unpack= None - - - -# If python version is less than 2.4, try to get set stuff from module -try: - set -except: - from sets import Set as set - -BOUNDS_3DS= [] - - -#this script imports uvcoords as sticky vertex coords -#this parameter enables copying these to face uv coords -#which shold be more useful. - -def createBlenderTexture(material, name, image): - texture= bpy.data.textures.new(name) - texture.setType('Image') - texture.image= image - material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - - - -###################################################### -# Data Structures -###################################################### - -#Some of the chunks that we will see -#----- Primary Chunk, at the beginning of each file -PRIMARY= long('0x4D4D',16) - -#------ Main Chunks -OBJECTINFO = long('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information -VERSION = long('0x0002',16); #This gives the version of the .3ds file -EDITKEYFRAME= long('0xB000',16); #This is the header for all of the key frame info - -#------ sub defines of OBJECTINFO -MATERIAL=45055 #0xAFFF // This stored the texture info -OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... - -#>------ sub defines of MATERIAL -#------ sub defines of MATERIAL_BLOCK -MAT_NAME = long('0xA000',16) # This holds the material name -MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material -MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material -MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material -MAT_SHINESS = long('0xA040',16) # ?? -MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material -MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material -MAT_WIRE = long('0xA085',16) # Only render's wireframe - -MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map -MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map -MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map -MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map -MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map -MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture - -MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats -MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes - -#>------ sub defines of OBJECT -OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object -OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object -OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght. -OBJECT_LAMP_OFF = long('0x4620',16); # The light off. -OBJECT_LAMP_ATTENUATE = long('0x4625',16); -OBJECT_LAMP_RAYSHADE = long('0x4627',16); -OBJECT_LAMP_SHADOWED = long('0x4630',16); -OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16); -OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16); -OBJECT_LAMP_SEE_CONE = long('0x4650',16); -OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16); -OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16); -OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16); -OBJECT_LAMP_EXCLUDE= long('0x4654',16); -OBJECT_LAMP_RANGE= long('0x4655',16); -OBJECT_LAMP_ROLL= long('0x4656',16); -OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16); -OBJECT_LAMP_RAY_BIAS= long('0x4658',16); -OBJECT_LAMP_INNER_RANGE= long('0x4659',16); -OBJECT_LAMP_OUTER_RANGE= long('0x465A',16); -OBJECT_LAMP_MULTIPLIER = long('0x465B',16); -OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16); - - - -OBJECT_CAMERA= long('0x4700',16); # This lets un know we are reading a camera object - -#>------ sub defines of CAMERA -OBJECT_CAM_RANGES= long('0x4720',16); # The camera range values - -#>------ sub defines of OBJECT_MESH -OBJECT_VERTICES = long('0x4110',16); # The objects vertices -OBJECT_FACES = long('0x4120',16); # The objects faces -OBJECT_MATERIAL = long('0x4130',16); # This is found if the object has a material, either texture map or color -OBJECT_UV = long('0x4140',16); # The UV texture coordinates -OBJECT_TRANS_MATRIX = long('0x4160',16); # The Object Matrix - -global scn -scn= None - -#the chunk class -class chunk: - ID=0 - length=0 - bytes_read=0 - - #we don't read in the bytes_read, we compute that - binary_format='3): - print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version - - #is it an object info chunk? - elif (new_chunk.ID==OBJECTINFO): - #print 'elif (new_chunk.ID==OBJECTINFO):' - # print 'found an OBJECTINFO chunk' - process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) - - #keep track of how much we read in the main chunk - new_chunk.bytes_read+=temp_chunk.bytes_read - - #is it an object chunk? - elif (new_chunk.ID==OBJECT): - - if CreateBlenderObject: - putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) - contextMesh_vertls= []; contextMesh_facels= [] - - ## preparando para receber o proximo objeto - contextMeshMaterials= {} # matname:[face_idxs] - contextMeshUV= None - #contextMesh.vertexUV= 1 # Make sticky coords. - # Reset matrix - contextMatrix_rot= None - #contextMatrix_tx= None - - CreateBlenderObject= True - tempName= read_string(file) - contextObName= tempName - new_chunk.bytes_read += len(tempName)+1 - - #is it a material chunk? - elif (new_chunk.ID==MATERIAL): - #print 'elif (new_chunk.ID==MATERIAL):' - contextMaterial= bpy.data.materials.new('Material') - - elif (new_chunk.ID==MAT_NAME): - #print 'elif (new_chunk.ID==MAT_NAME):' - material_name= read_string(file) - - #plus one for the null character that ended the string - new_chunk.bytes_read+= len(material_name)+1 - - contextMaterial.name= material_name.rstrip() # remove trailing whitespace - MATDICT[material_name]= (contextMaterial.name, contextMaterial) - - elif (new_chunk.ID==MAT_AMBIENT): - #print 'elif (new_chunk.ID==MAT_AMBIENT):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read - - elif (new_chunk.ID==MAT_DIFFUSE): - #print 'elif (new_chunk.ID==MAT_DIFFUSE):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read - - elif (new_chunk.ID==MAT_SPECULAR): - #print 'elif (new_chunk.ID==MAT_SPECULAR):' - read_chunk(file, temp_chunk) - if (temp_chunk.ID==MAT_FLOAT_COLOR): - temp_data=file.read(calcsize('3f')) - temp_chunk.bytes_read+=12 - contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] - elif (temp_chunk.ID==MAT_24BIT_COLOR): - temp_data=file.read(calcsize('3B')) - temp_chunk.bytes_read+= 3 - contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb - else: - skip_to_end(file, temp_chunk) - new_chunk.bytes_read+= temp_chunk.bytes_read - - elif (new_chunk.ID==MAT_TEXTURE_MAP): - #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' - new_texture= bpy.data.textures.new('Diffuse') - new_texture.setType('Image') - img = None - while (new_chunk.bytes_read BOUNDS_3DS[i+3]: - BOUNDS_3DS[i+3]= v[i] # min - - # Get the max axis x/y/z - max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) - # print max_axis - if max_axis < 1<<30: # Should never be false but just make sure. - - # Get a new scale factor if set as an option - SCALE=1.0 - while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS: - SCALE/=10 - - # SCALE Matrix - SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) - - for ob in importedObjects: - ob.setMatrix(ob.matrixWorld*SCALE_MAT) - - # Done constraining to bounds. - - # Select all new objects. - print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)) - file.close() - Blender.Window.WaitCursor(0) - - -DEBUG= False -if __name__=='__main__' and not DEBUG: - if calcsize==None: - Blender.Draw.PupMenu('Error%t|a full python installation not found') - else: - Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') - -# For testing compatibility -#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) -#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) -''' - -else: - import os - # DEBUG ONLY - TIME= Blender.sys.time() - import os - print 'Searching for files' - os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') - # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') - print '...Done' - file= open('/tmp/temp3ds_list', 'r') - lines= file.readlines() - file.close() - # sort by filesize for faster testing - lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] - lines_size.sort() - lines = [f[1] for f in lines_size] - - - def between(v,a,b): - if v <= max(a,b) and v >= min(a,b): - return True - return False - - for i, _3ds in enumerate(lines): - if between(i, 650,800): - #_3ds= _3ds[:-1] - print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) - _3ds_file= _3ds.split('/')[-1].split('\\')[-1] - newScn= Blender.Scene.New(_3ds_file) - newScn.makeCurrent() - load_3ds(_3ds, False) - - print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) - -''' diff --git a/release/scripts/Axiscopy.py b/release/scripts/Axiscopy.py deleted file mode 100644 index 6a31432edb6..00000000000 --- a/release/scripts/Axiscopy.py +++ /dev/null @@ -1,125 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: <- these words are ignored -Name: 'Axis Orientation Copy' -Blender: 242 -Group: 'Object' -Tip: 'Copy local axis orientation of active object to all selected meshes (changes mesh data)' -""" - -__author__ = "A Vanpoucke (xand)" -__url__ = ("blenderartists.org", "www.blender.org", -"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "2 17/12/05" - -__bpydoc__ = """\ -This script copies the axis orientation -- X, Y and Z rotations -- of the -active object to all selected meshes. - -It's useful to align the orientations of all meshes of a structure, a human -skeleton, for example. - -Usage: - -Select all mesh objects that need to have their orientations changed -(reminder: keep SHIFT pressed after the first, to add each new one to the -selection), then select the object whose orientation will be copied from and -finally run this script to update the angles. - -Notes:
- This script changes mesh data: the vertices are transformed.
- Before copying the orientation to each object, the script stores its -transformation matrix. Then the angles are copied and after that the object's -vertices are transformed "back" so that they still have the same positions as -before. In other words, the rotations are updated, but you won't notice that -just from looking at the objects.
- Checking their X, Y and Z rotation values with "Transform Properties" in -the 3D View's Object menu shows the angles are now the same of the active -object. Or simply look at the transform manipulator handles in local transform -orientation. -""" - - -# $Id$ -# -#---------------------------------------------- -# A Vanpoucke (xand) -#from the previous script realignaxis -#---------------------------------------------- -# Communiquer les problemes et erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2003, 2004: A Vanpoucke -# -# 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 ***** -# -------------------------------------------------------------------------- - -from Blender import * -from Blender import Mathutils -from Blender.Mathutils import * -import BPyMessages - -def realusers(data): - users = data.users - if data.fakeUser: users -= 1 - return users - - - -def main(): - - scn_obs= Scene.GetCurrent().objects - ob_act = scn_obs.active - scn_obs = scn_obs.context - - if not ob_act: - BPyMessages.Error_NoActive() - - obs = [(ob, ob.getData(mesh=1)) for ob in scn_obs if ob != ob_act] - - for ob, me in obs: - - if ob.type != 'Mesh': - Draw.PupMenu("Error%t|Selection must be made up of mesh objects only") - return - - if realusers(me) != 1: - Draw.PupMenu("Error%t|Meshes must be single user") - return - - if len(obs) < 1: - Draw.PupMenu("Error: you must select at least 2 objects") - return - - result = Draw.PupMenu("Copy axis orientation from: " + ob_act.name + " ?%t|OK") - if result == -1: - return - - for ob_target, me_target in obs: - if ob_act.rot != ob_target.rot: - rot_target = ob_target.matrixWorld.rotationPart().toEuler().toMatrix() - rot_source = ob_act.matrixWorld.rotationPart().toEuler().toMatrix() - rot_source_inv = rot_source.copy().invert() - tx_mat = rot_target * rot_source_inv - tx_mat.resize4x4() - me_target.transform(tx_mat) - ob_target.rot=ob_act.rot - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/DirectX8Exporter.py b/release/scripts/DirectX8Exporter.py deleted file mode 100644 index 8a0ecaf0eb7..00000000000 --- a/release/scripts/DirectX8Exporter.py +++ /dev/null @@ -1,1196 +0,0 @@ -#!BPY - -""" -# Name: 'DirectX (.x)...' -# Blender: 242 -# Group: 'Export' -# Tooltip: 'Export to DirectX text file format format for XNA Animation Component Library.' -""" -__author__ = "vertex color exporting feature is added by mnemoto (original:minahito (original:Arben (Ben) Omari))" -__url__ = ("blender.org", "blenderartists.org", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it","Adjuster's site http://ex.homeunix.net/") -__version__ = "3.1" - -__bpydoc__ = """\ -This script exports a Blender mesh with armature to DirectX 8's text file -format. - -Notes:
- Check author's site or the elYsiun forum for a new beta version of the -DX exporter. -""" -# DirectXExporter.py version 3.0 -# Copyright (C) 2006 Arben OMARI -- omariarben@everyday.com -# -# 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. - -# This script export meshes created with Blender in DirectX8 file format -# it exports meshes,armatures,materials,normals,texturecoords and animations - -# Grab the latest version here :www.omariben.too.it - -# [Notice] -# This script is the custom version of Mr.Arben Omari's great work. -# If you have a question about the adjusted part, visit http://sunday-lab.blogspot.com/. - -import Blender -from Blender import Types, Object, NMesh, Material,Armature,Mesh -from Blender.Mathutils import * -from Blender import Draw, BGL -from Blender.BGL import * -try: import math -except: math = None - -global mat_flip,index_list,space,bone_list,mat_dict -global anim,flip_norm,swap_zy,flip_z,speed,ticks,no_light,recalc_norm,Bl_norm -bone_list =[] -index_list = [] -mat_dict = {} -space = 0;flip_z = 1;anim=0;swap_yz=0;flip_norm=0;speed=0;ticks= 25 -Bl_norm = 1;recalc_norm = 0;no_light = 0 - -toggle_val = 0 -toggle1_val = 0 -toggle2_val = 0 -toggle3_val = 1 -toggle4_val = 0 -toggle5_val = 1 -toggle6_val = 0 -toggle7_val = 0 -anim_tick = Draw.Create(25) - -#*********************************************** -# DirectX file spec only allows letters, digits, and -# underscore in Names. -#*********************************************** -def make_legal_name(starting_name): - new_name = starting_name.replace('.','_') - new_name = new_name.replace(' ','_') - if new_name[0].isdigit(): - new_name = '_' + new_name - return new_name - -#*********************************************** -# MAIN -#*********************************************** - -def my_callback(filename): - if filename.find('.x', -2) <= 0: filename += '.x' - xexport = xExport(filename) - xexport.SelectObjs() - -def my_callback_sel(filename): - if filename.find('.x', -2) <= 0: filename += '.x' - xexport = xExport(filename) - xexport.exportSelMesh() -def event(evt, val): - if evt == Draw.ESCKEY: - Draw.Exit() - return - -def button_event(evt): - global toggle_val,toggle1_val,toggle2_val,toggle3_val,toggle4_val,toggle5_val,toggle6_val,toggle7_val - global flip_z,swap_yz,flip_norm,anim,ticks,speed,no_light,Bl_norm,recalc_norm - arg = __script__['arg'] - if evt == 1: - toggle_val = 1 - toggle_val - anim = toggle_val - Draw.Redraw(1) - if evt == 2: - toggle1_val = 1 - toggle1_val - flip_norm = toggle1_val - Draw.Redraw(1) - if evt == 3: - toggle2_val = 1 - toggle2_val - swap_yz = toggle2_val - Draw.Redraw(1) - if evt == 4: - toggle3_val = 1 - toggle3_val - flip_z = toggle3_val - Draw.Redraw(1) - if evt == 5: - toggle4_val = 1 - toggle4_val - speed = toggle4_val - Draw.Redraw(1) - if evt == 10: - toggle5_val = 1 - toggle5_val - if toggle5_val==1: - toggle6_val = 0 - toggle7_val = 0 - else : - toggle6_val = 1 - toggle7_val = 1 - no_light = toggle7_val - recalc_norm = toggle6_val - Bl_norm = toggle5_val - Draw.Redraw(1) - if evt == 11: - toggle6_val = 1 - toggle6_val - if toggle6_val==1: - toggle5_val = 0 - toggle7_val = 0 - else : - toggle5_val = 1 - toggle7_val = 1 - no_light = toggle7_val - recalc_norm = toggle6_val - Bl_norm = toggle5_val - Draw.Redraw(1) - if evt == 12: - toggle7_val = 1 - toggle7_val - if toggle7_val==1: - toggle6_val = 0 - toggle5_val = 0 - else : - toggle6_val = 1 - toggle5_val = 1 - no_light = toggle7_val - recalc_norm = toggle6_val - Bl_norm = toggle5_val - Draw.Redraw(1) - if evt == 6: - ticks = anim_tick.val - if evt == 7: - fname = Blender.sys.makename(ext = ".x") - Blender.Window.FileSelector(my_callback, "Export DirectX", fname) - if evt == 8: - fname = Blender.sys.makename(ext = ".x") - Blender.Window.FileSelector(my_callback_sel, "Export DirectX", fname) - if evt == 9: - Draw.Exit() - - -def draw(): - global animsg,flipmsg,swapmsg,anim_tick - global flip_z,swap_yz,flip_norm,anim,ticks,speed,recalc_norm,Bl_norm,no_light - glClearColor(0.55,0.6,0.6,1) - glClear(BGL.GL_COLOR_BUFFER_BIT) - #external box - glColor3f(0.2,0.3,0.3) - rect(10,402,300,382) - #-- - #glColor3f(0.3,0.4,0.4) - #rect(11,399,298,398) - #-- - glColor3f(0.5,0.75,0.65) - rect(14,398,292,30) - #-- - glColor3f(0.5,0.75,0.65) - rect(14,366,292,160) - #-- - glColor3f(0.5,0.75,0.65) - rect(14,202,292,60) - #-- - glColor3f(0.5,0.75,0.65) - rect(14,138,292,40) - #-- - glColor3f(0.5,0.75,0.65) - rect(14,94,292,70) - - glColor3f(0.8,.8,0.6) - glRasterPos2i(20, 380) - Draw.Text("DirectX Exporter ",'large') - Draw.Text("(for Blender 2.41)", 'small') - #-------Aniamtion toggle--------------------------------------------- - Draw.Toggle("Anim", 1, 20, 330, 55, 20, toggle_val,"export animations") - if toggle_val : - anim = 1 - animsg = "animation will be exported" - else: - anim = 0 - animsg = "animation will be not exported" - glRasterPos2i(100,335) - Draw.Text(animsg) - #---Flip normals toggle----------------------------------------------- - Draw.Toggle("Flip norm", 2, 20, 300, 55, 20, toggle1_val,"invert normals") - if toggle1_val : - flip_norm = 1 - flipmsg = "flipped normals" - else: - flip_norm = 0 - flipmsg = "not flipped normals" - glRasterPos2i(100,305) - Draw.Text(flipmsg) - #------Swap yz toggle---------------------------------------------------------------- - Draw.Toggle("Swap zy", 3, 20, 270, 55, 20, toggle2_val,"swap z,y axis(y up)") - if toggle2_val : - swap_yz = 1 - swapmsg = "Y-axis up" - else: - swap_yz = 0 - swapmsg = "Z-axis up" - glRasterPos2i(100,275) - Draw.Text(swapmsg) - #------Flip z toggle---------------------------------------------------------------- - Draw.Toggle("Flip z", 4, 20, 240, 55, 20, toggle3_val,"flip z axis") - if toggle3_val : - flip_z = 1 - zmsg = "left handed system" - else: - flip_z = 0 - zmsg = "right handed system" - glRasterPos2i(100,245) - Draw.Text(zmsg) - #------Speed toggle---------------------------------------------------------------- - Draw.Toggle("Speed", 5, 20, 210, 55, 20, toggle4_val,"Animation speed") - if toggle4_val : - speed = 1 - spedmsg = "set speed" - anim_tick = Draw.Number("", 6,200, 210, 85, 20, anim_tick.val,1,100000,"ticks per second") - else: - speed = 0 - spedmsg = "" - glRasterPos2i(100,215) - Draw.Text(spedmsg) - #------Blender Normals toggle---------------------------------------------------------------- - Draw.Toggle("Bl.normals", 10, 20, 105, 75, 25, toggle5_val,"export normals as in Blender") - if toggle5_val : - Bl_norm = 1 - #------Recalculute Normals toggle---------------------------------------------------------------- - Draw.Toggle("recalc.no", 11, 120, 105, 75, 25, toggle6_val,"export recalculated normals") - if toggle6_val : - recalc_norm = 1 - #------Recalculute Normals toggle---------------------------------------------------------------- - Draw.Toggle("no smooth", 12, 220, 105, 75, 25, toggle7_val,"every vertex has the face normal,no smoothing") - if toggle7_val : - no_light = 1 - #------Draw Button export---------------------------------------------------------------- - exp_butt = Draw.Button("Export All",7,20, 155, 75, 30, "export all the scene objects") - sel_butt = Draw.Button("Export Sel",8,120, 155, 75, 30, "export the selected object") - exit_butt = Draw.Button("Exit",9,220, 155, 75, 30, "exit") - glRasterPos2i(20,75) - Draw.Text("(C) 2006 Arben OMARI ") - glRasterPos2i(20,55) - Draw.Text("http://www.omariben.too.it") - glRasterPos2i(20,35) - Draw.Text("aromar@tin.it") - -def rect(x,y,width,height): - glBegin(GL_LINE_LOOP) - glVertex2i(x,y) - glVertex2i(x+width,y) - glVertex2i(x+width,y-height) - glVertex2i(x,y-height) - glEnd() - -def rectFill(x,y,width,height): - glBegin(GL_POLYGON) - glVertex2i(x,y) - glVertex2i(x+width,y) - glVertex2i(x+width,y-height) - glVertex2i(x,y-height) - glEnd() - - - -Draw.Register(draw, event, button_event) - - -#*********************************************** -#*********************************************** -# EXPORTER -#*********************************************** -#*********************************************** - -class xExport: - def __init__(self, filename): - self.file = open(filename, "w") - -#********************************************************************************************************************************************* - #*********************************************** - #Select Scene objects - #*********************************************** - def analyzeScene(self): - parent_list = [] - for obj in Blender.Scene.GetCurrent().objects: - if obj.type in ('Mesh', 'Armature', 'Empty'): - if obj.parent == None : - parent_list.append(obj) - - return parent_list - - def getChildren(self,obj): - obs = Blender.Scene.GetCurrent().objects - return [ ob for ob in obs if ob.parent == obj ] - - def getArmChildren(self,obj): - for ob in Blender.Scene.GetCurrent().objects: #Object.Get(): - if ob.parent == obj : - return ob - - def getLocMat(self, obj): - pare = obj.parent - mat = obj.matrixWorld - mat_id = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) - if pare: - mat_p = pare.matrixWorld - mat_c = Matrix(mat_p) - mat_c.invert() - mat_f = mat * mat_c - else : - mat_id.invert() - mat_f = mat * mat_id - return mat_f - - def writeObjFrames(self,obj): - global space,chld_obj,ch_list - mesh = obj.getData() - if obj.type == "Empty" : - mat = self.getLocMat(obj) - mat_c = Matrix(mat) - self.writeArmFrames(mat_c, make_legal_name(obj.name)) - if type(mesh) == Types.ArmatureType : - Child_obj = self.getArmChildren(obj) - chld_obj = obj - ch_list.append(Child_obj) - self.writeRootBone(obj, Child_obj) - if obj.type == 'Mesh' and obj not in ch_list: - self.exportMesh(obj) - - - def writeChildObj(self,obj): - global space,ch_list - space += 1 - if obj : - for ob in obj: - if ob not in ch_list: - self.writeObjFrames(ob) - ch_list.append(ob) - ch_ob = self.getChildren(ob) - self.writeChildObj(ch_ob) - self.closeBrackets() - self.file.write(" // End of the Object %s \n" % (ob.name)) - - - def writeRootFrame(self): - global flip_z,swap_yz,speed - if speed: - self.writeAnimTicks() - if flip_z: - mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]) - else : - mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) - if swap_yz : - mat_rot = RotationMatrix(-90, 4, 'x') - mat_flip = mat_rot * mat_flip - self.writeArmFrames(mat_flip, "RootFrame") - - ################################################################## - def SelectObjs(self): - global space,chld_obj,ch_list,flip_z,swap_yz,speed - print "exporting..." - self.writeHeader() - self.writeRootFrame() - obj_list = self.analyzeScene() - space += 1 - ch_list = [] - for obj in obj_list: - self.writeObjFrames(obj) - ch_l = self.getChildren(obj) - for ch in ch_l: - - - if ch and ch.type == "Armature": - ch_list.append(ch) - self.writeObjFrames(ch) - else : - self.writeChildObj(ch_l) - if obj.type != "Armature": - self.file.write(" } // SI End of the Object %s \n" % (obj.name)) - - - - self.file.write("} // End of the Root Frame\n") - if anim : - self.file.write("AnimationSet AnimationSet0 {\n") - for obj in Blender.Scene.GetCurrent().objects: - if obj.type in ('Mesh', 'Empty'): - ip_list = obj.ipo - if ip_list != None : - self.writeAnimationObj(obj) - elif obj.type == 'Armature': - act_list = obj.getAction() - if act_list != None : - self.writeAnimation(obj) - #ip_list = obj.ipo - #if ip_list != None : - # self.writeAnimationObj(obj) - - self.file.write("} // End of Animation Set\n") - self.writeEnd() - ####################################################### - - - def writeAnimTicks(self): - global ticks - self.file.write("AnimTicksPerSecond {\n") - self.file.write("%d; \n" % (ticks)) - self.file.write("}\n") - - #*********************************************** - #Export Mesh without Armature - #*********************************************** - def exportMesh(self, obj): - tex = [] - mesh = obj.getData() - self.writeTextures(obj, tex) - self.writeMeshcoordArm(obj, arm_ob = None) - self.writeMeshMaterialList(obj, mesh, tex) - self.writeMeshNormals(obj, mesh) - self.writeMeshTextureCoords(obj, mesh) - self.writeMeshVertexColors(obj, mesh) - self.file.write(" } // End of the Mesh %s \n" % (obj.name)) - - - #*********************************************** - #Export the Selected Mesh - #*********************************************** - def exportSelMesh(self): - print "exporting ..." - self.writeHeader() - self.writeRootFrame() - tex = [] - objs = Object.GetSelected() - for obj in objs: - if obj.type == 'Mesh': - mesh = obj.data - self.writeTextures(obj, tex) - self.writeMeshcoordArm(obj, arm_ob = None) - self.writeMeshMaterialList(obj, mesh, tex) - self.writeMeshNormals(obj, mesh) - self.writeMeshTextureCoords(obj, mesh) - self.writeMeshVertexColors(obj, mesh) - self.file.write(" }\n") - self.file.write("}\n") - ind = objs.index(obj) - if ind == len(objs)-1: - self.file.write("}\n") - ip_list = obj.ipo - if ip_list != None : - self.file.write("AnimationSet AnimationSet0 {\n") - self.writeAnimationObj(obj) - self.file.write("}\n") - else : - print "The selected object is not a mesh" - print "...finished" - #*********************************************** - #Export Mesh with Armature - #*********************************************** - def exportMeshArm(self,arm,arm_ob,ch_obj): - tex = [] - mesh = ch_obj.getData() - self.writeTextures(ch_obj, tex) - self.writeMeshcoordArm(ch_obj ,arm_ob) - self.writeMeshMaterialList(ch_obj, mesh, tex) - self.writeMeshNormals(ch_obj, mesh) - self.writeMeshTextureCoords(ch_obj, mesh) - self.writeSkinWeights(arm,mesh) - #self.file.write(" } // End of the Frame %s \n" % (ch_obj.name)) - self.file.write(" } // End of the Object %s \n" % (ch_obj.name)) - - #*********************************************** - #Export Root Bone - #*********************************************** - def writeRootBone(self, chld_obj, child_obj): - global space,root_bon - arms = chld_obj.getData() - mat_arm = self.getLocMat(chld_obj) - for bon in arms.bones.values(): - if bon.hasParent(): - pass - else: - root_bon = bon - space += 1 - mat_r = self.writeAnimCombineMatrix(root_bon,1) - self.writeArmFrames(mat_r, make_legal_name(root_bon.name)) - - bon_c = root_bon.children - self.writeChildren(bon_c) - self.file.write(" } // End of the Bone %s \n" % (root_bon.name)) - self.exportMeshArm(arms, chld_obj ,child_obj) - - #*********************************************** - #Create Children structure - #*********************************************** - def writeBon(self,bon): - global space - mat_r = self.writeAnimCombineMatrix(bon,1) - self.writeArmFrames(mat_r, make_legal_name(bon.name)) - - - def writeChildren(self,bon_c): - global space,bone_list - space += 1 - if bon_c: - for bo in bon_c: - if bo.name not in bone_list: - self.writeBon(bo) - bone_list.append(bo.name) - bo_c = bo.children - self.writeChildren(bo_c) - self.closeBrackets() - - - - def closeBrackets(self): - global space - space = space-1 - tab = " " - self.file.write("%s" % (tab * space)) - self.file.write("}\n") - - - - #*********************************************** - #Offset Matrix - #*********************************************** - def writeMatrixOffset(self,bon): - global chld_obj - Blender.Set('curframe', 1) - pose = chld_obj.getPose() - pos_b = pose.bones[bon.name] - mat_b = pos_b.poseMatrix - mat_c = Matrix(mat_b) - mat_c.invert() - return mat_c - - - #*********************************************** - #Combine Matrix - #*********************************************** - def writeCombineMatrix(self,bon): - global chld_obj - - Blender.Set('curframe', 1) - pose = chld_obj.getPose() - pos_b = pose.bones[bon.name] - mat_b = pos_b.poseMatrix - if bon.hasParent(): - pare = bon.parent - pos_p = pose.bones[pare.name] - mat_p = pos_p.poseMatrix - - else: - mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) - mat_c = Matrix(mat_p) - mat_c.invert() - mat_f = mat_b * mat_c - - return mat_f - #*********************************************** - #Combine Matrix - #*********************************************** - def writeAnimCombineMatrix(self,bon,fre): - global chld_obj - Blender.Set('curframe', fre) - pose = chld_obj.getPose() - pos_b = pose.bones[bon.name] - mat_b = pos_b.poseMatrix - if bon.hasParent(): - pare = bon.parent - pos_p = pose.bones[pare.name] - mat_p = pos_p.poseMatrix - - else: - mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) - mat_c = Matrix(mat_p) - mat_c.invert() - mat_f = mat_b * mat_c - - return mat_f - - -#********************************************************************************************************************************************* - #*********************************************** - #Write SkinWeights - #*********************************************** - def writeSkinWeights(self, arm, mesh): - global index_list - v_dict = {} - Blender.Set('curframe',1) - self.file.write(" XSkinMeshHeader {\n") - max_infl = 0 - for bo in arm.bones.values() : - name = bo.name - try : - vertx_list = mesh.getVertsFromGroup(name,1) - for inde in vertx_list : - vert_infl = mesh.getVertexInfluences(inde[0]) - ln_infl = len(vert_infl) - if ln_infl > max_infl : - max_infl = ln_infl - - except: - pass - - self.file.write(" %d; \n" % (max_infl)) - self.file.write(" %d; \n" % (max_infl * 3)) - self.file.write(" %d; \n" % (len(arm.bones.values()))) - self.file.write(" }\n") - - for bo in arm.bones.values() : - bo_list = [] - weight_list = [] - name = bo.name - f_name = make_legal_name(name) - try : - vert_list = mesh.getVertsFromGroup(name,1) - le = 0 - for indx in vert_list: - ver_infl = mesh.getVertexInfluences(indx[0]) - infl = 0.0 - if len(ver_infl) != 0: - sum = 0.0 - for bone_n, weight in ver_infl: - if bone_n == name: - infl = weight - sum += weight - infl /= sum - - i = -1 - for el in index_list : - i += 1 - if el == indx[0] : - le +=1 - bo_list.append(i) - weight_list.append(infl) - - - self.file.write(" SkinWeights {\n") - self.file.write(' "%s"; \n' % (f_name)) - self.file.write(' %d; \n' % (le)) - count = 0 - for ind in bo_list : - count += 1 - if count == len(bo_list): - self.file.write(" %d; \n" % (ind)) - else : - self.file.write(" %d, \n" % (ind)) - cou = 0 - for wegh in weight_list : - cou += 1 - - if cou == len(weight_list): - self.file.write(" %f; \n" % (round(wegh,6))) - else : - self.file.write(" %f, \n" % (round(wegh,6))) - - - matx = self.writeMatrixOffset(bo) - self.writeOffsFrames(matx, name) - except : - pass - self.file.write(" } // End of XSkinMeshHeader\n") - - - #*********************************************** - # Write Matrices - #*********************************************** - def writeArmFrames(self, matx, name): - global space - tab = " " - self.file.write("%s" % (tab * space)) - self.file.write("Frame ") - self.file.write("%s {\n\n" % (name)) - self.file.write("%s" % (tab * space)) - self.file.write(" FrameTransformMatrix {\n") - self.writeFrame(matx) - - #*********************************************** - # Write Frames - #*********************************************** - def writeOffsFrames(self, matx, name): - space = 1 - self.writeFrame(matx) - - #*********************************************** - # Write Frames - #*********************************************** - def writeFrame(self, matx): - tab = " " - self.file.write("%s" % (tab * space)) - self.file.write(" %f,%f,%f,%f,\n" % - (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) - self.file.write("%s" % (tab * space)) - self.file.write(" %f,%f,%f,%f,\n" % - (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) - self.file.write("%s" % (tab * space)) - self.file.write(" %f,%f,%f,%f,\n" % - (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) - self.file.write("%s" % (tab * space)) - self.file.write(" %f,%f,%f,%f;;\n" % - (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) - self.file.write("%s" % (tab * space)) - self.file.write(" }\n") -#********************************************************************************************************************************************* - - #*********************************************** - #HEADER - #*********************************************** - def writeHeader(self): - self.file.write("xof 0303txt 0032\n\n\n") - self.file.write("template VertexDuplicationIndices { \n\ - \n\ - DWORD nIndices;\n\ - DWORD nOriginalVertices;\n\ - array DWORD indices[nIndices];\n\ -}\n\ -template XSkinMeshHeader {\n\ - <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\ - WORD nMaxSkinWeightsPerVertex;\n\ - WORD nMaxSkinWeightsPerFace;\n\ - WORD nBones;\n\ -}\n\ -template SkinWeights {\n\ - <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\ - STRING transformNodeName;\n\ - DWORD nWeights;\n\ - array DWORD vertexIndices[nWeights];\n\ - array float weights[nWeights];\n\ - Matrix4x4 matrixOffset;\n\ -}\n\n") - - #*********************************************** - #CLOSE FILE - #*********************************************** - def writeEnd(self): - self.file.close() - print "... finished" - - - #*********************************************** - #EXPORT TEXTURES - #*********************************************** - def writeTextures(self,name, tex): - mesh = name.data - for face in mesh.faces: - if face.image and face.image.name not in tex: - tex.append(face.image.name) - - - - #*********************************************** - #EXPORT MESH DATA with Armature - #*********************************************** - def writeMeshcoordArm(self, obj ,arm_ob): - global index_list,flip_z - #TransformMatrix - mat = self.getLocMat(obj) - self.writeArmFrames(mat, make_legal_name(obj.name)) - mesh = NMesh.GetRawFromObject(obj.name) - self.file.write("Mesh {\n") - numface=len(mesh.faces) - #VERTICES NUMBER - numvert = 0 - for face in mesh.faces: - numvert = numvert + len(face.v) - self.file.write("%d;\n" % (numvert)) - if numvert == 0: - print "Mesh named",mesh.name,"has no vertices.Problems may occur using the .x file" - #VERTICES COORDINATES - counter = 0 - for face in mesh.faces: - counter += 1 - for n in range(len(face.v)): - index_list.append(face.v[n].index) - vec_vert = Vector([(face.v[n].co[0]), face.v[n].co[1], face.v[n].co[2], 1]) - if arm_ob : - f_vec_vert = vec_vert * mat - else : - f_vec_vert = vec_vert - self.file.write("%f; %f; %f;" % (round(f_vec_vert[0],4), round(f_vec_vert[1],4), round(f_vec_vert[2],4))) - if counter == numface : - if n == len(face.v)-1 : - self.file.write(";\n") - else : - self.file.write(",\n") - else : - self.file.write(",\n") - if flip_z: - a3 = 0;b3 = 2;c3 = 1 - a4 = 0;b4 = 3;c4 = 2;d4 = 1 - else: - a3 = 0;b3 = 1;c3 = 2 - a4 = 0;b4 = 1;c4 = 2;d4 = 3 - - #FACES NUMBER - self.file.write("%s;\n" % (numface)) - coun,counter = 0, 0 - for face in mesh.faces : - coun += 1 - separator = ',' - if coun == numface: - separator = ';' - if len(face.v) == 3: - self.file.write("3; %d, %d, %d;%c\n" % (counter + a3, counter + b3, counter + c3, separator)) - counter += 3 - elif len(face.v) == 4: - self.file.write("4; %d, %d, %d, %d;%c\n" % (counter + a4, counter + b4, counter + c4, counter + d4, separator)) - counter += 4 - elif len(face.v) < 3: - print "WARNING:the mesh has faces with less then 3 vertices" - print " It my be not exported correctly." - - - #*********************************************** - #MESH MATERIAL LIST - #*********************************************** - def writeMeshMaterialList(self, obj, mesh, tex): - self.file.write(" MeshMaterialList {\n") - #HOW MANY MATERIALS ARE USED - count = 0 - for mat in mesh.getMaterials(): - count+=1 - self.file.write(" %d;\n" % (len(tex) + count)) - #HOW MANY FACES IT HAS - numfaces=len(mesh.faces) - self.file.write(" %d;\n" % (numfaces)) - ##MATERIALS INDEX FOR EVERY FACE - counter = 0 - for face in mesh.faces : - counter += 1 - mater = face.materialIndex - if counter == numfaces: - if face.image and face.image.name in tex : - self.file.write(" %d;;\n" % (tex.index(face.image.name) + count)) - else : - self.file.write(" %d;;\n" % (mater)) - else : - if face.image and face.image.name in tex : - self.file.write(" %d,\n" % (tex.index(face.image.name) + count)) - else : - self.file.write(" %d,\n" % (mater)) - - ##MATERIAL NAME - for mat in mesh.getMaterials(): - self.file.write(" Material") - self.file.write(" %s "% (make_legal_name(mat.name))) - self.file.write("{\n") - self.file.write(" %f; %f; %f;" % (mat.R, mat.G, mat.B)) - self.file.write("%s;;\n" % (mat.alpha)) - self.file.write(" %f;\n" % (mat.spec)) - self.file.write(" %f; %f; %f;;\n" % (mat.specR, mat.specG, mat.specB)) - self.file.write(" 0.0; 0.0; 0.0;;\n") - self.file.write(" } //End of Material\n") - - for mat in tex: - self.file.write(" Material Mat") - self.file.write("%s "% (len(tex))) - self.file.write("{\n") - self.file.write(" 1.0; 1.0; 1.0; 1.0;;\n") - self.file.write(" 1.0;\n") - self.file.write(" 1.0; 1.0; 1.0;;\n") - self.file.write(" 0.0; 0.0; 0.0;;\n") - self.file.write(" TextureFilename {") - self.file.write(' "%s";'% (mat)) - self.file.write(" }\n") - self.file.write(" } // End of Material\n") - self.file.write(" } //End of MeshMaterialList\n") - - #*********************************************** - #MESH NORMALS - #*********************************************** - def writeMeshNormals(self,name,mesh): - global flip_norm,flip_z,no_light,recalc_norm,Bl_norm - - self.file.write(" MeshNormals {\n") - #VERTICES NUMBER - numvert = 0 - for face in mesh.faces: - numvert = numvert + len(face.v) - self.file.write("%d;\n" % (numvert)) - numfaces=len(mesh.faces) - if flip_norm : - fl = -1 - else : - fl = 1 - #VERTICES NORMAL - if Bl_norm: - self.writeBlenderNormals(mesh,fl) - if recalc_norm: - self.writeRecalcNormals(mesh,fl) - if no_light: - self.writeNoSmothing(mesh,fl) - - - - if flip_z: - a3 = 0;b3 = 2;c3 = 1 - a4 = 0;b4 = 3;c4 = 2;d4 = 1 - else: - a3 = 0;b3 = 1;c3 = 2 - a4 = 0;b4 = 1;c4 = 2;d4 = 3 - - #FACES NUMBER - self.file.write("%s;\n" % (numfaces)) - coun,counter = 0, 0 - for face in mesh.faces : - coun += 1 - if coun == numfaces: - if len(face.v) == 3: - self.file.write("3; %d, %d, %d;;\n" % (counter + a3, counter + b3, counter + c3)) - counter += 3 - else : - self.file.write("4; %d, %d, %d, %d;;\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) - counter += 4 - else: - - if len(face.v) == 3: - self.file.write("3; %d, %d, %d;,\n" % (counter + a3, counter + b3, counter + c3)) - counter += 3 - else : - self.file.write("4; %d, %d, %d, %d;,\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) - counter += 4 - self.file.write("} //End of MeshNormals\n") - - def writeBlenderNormals(self,mesh,fl): - numfaces=len(mesh.faces) - #VERTICES NORMAL - counter = 0 - for face in mesh.faces: - counter += 1 - for n in range(len(face.v)): - self.file.write(" %f; %f; %f;" % ( - (round(face.v[n].no[0],6)*fl),(round(face.v[n].no[1],6)*fl),(round(face.v[n].no[2],6)*fl))) - if counter == numfaces : - if n == len(face.v)-1 : - self.file.write(";\n") - else : - self.file.write(",\n") - else : - self.file.write(",\n") - - def writeRecalcNormals(self,mesh,fl): - numfaces=len(mesh.faces) - normal_list = {} - idx = 0 - for vertex in mesh.verts: - v_norm = Vector([0, 0, 0]) - normal_list[idx] = v_norm - idx += 1 - for face in mesh.faces: - for verts in face.v: - if verts.index == vertex.index : - v_norm[0] += face.no[0] - v_norm[1] += face.no[1] - v_norm[2] += face.no[2] - - v_norm.normalize() - - counter = 0 - for face in mesh.faces: - counter += 1 - n = 0 - for vert in face.v: - n += 1 - norm = normal_list[vert.index] - - self.file.write(" %f; %f; %f;" % ( - (round(norm[0],6)*fl),(round(norm[1],6)*fl),(round(norm[2],6)*fl))) - if counter == numfaces : - if n == len(face.v) : - self.file.write(";\n") - else : - self.file.write(",\n") - else : - self.file.write(",\n") - - def writeNoSmothing(self,mesh,fl): - numfaces=len(mesh.faces) - counter = 0 - for face in mesh.faces: - counter += 1 - n = 0 - for n in range(len(face.v)): - n += 1 - self.file.write(" %f; %f; %f;" % ( - (round(face.no[0],6)*fl),(round(face.no[1],6)*fl),(round(face.no[2],6)*fl))) - - - if counter == numfaces : - if n == len(face.v) : - self.file.write(";\n") - else : - self.file.write(",\n") - else : - self.file.write(",\n") - #*********************************************** - #MESH TEXTURE COORDS - #*********************************************** - def writeMeshTextureCoords(self, name, mesh): - if mesh.hasFaceUV(): - self.file.write("MeshTextureCoords {\n") - #VERTICES NUMBER - numvert = 0 - for face in mesh.faces: - numvert += len(face.v) - self.file.write("%d;\n" % (numvert)) - #UV COORDS - numfaces = len(mesh.faces) - counter = -1 - co = 0 - for face in mesh.faces: - counter += 1 - co += 1 - for n in range(len(face.v)): - self.file.write("%f;%f;" % (mesh.faces[counter].uv[n][0], -mesh.faces[counter].uv[n][1])) - if co == numfaces : - if n == len(face.v) - 1 : - self.file.write(";\n") - else : - self.file.write(",\n") - else : - self.file.write(",\n") - - self.file.write("} //End of MeshTextureCoords\n") - - #*********************************************** - #MESH VORTEX COLORS - #*********************************************** - def writeMeshVertexColors(self, name, mesh): - if mesh.hasVertexColours(): - self.file.write("MeshVertexColors {\n") - #VERTICES NUMBER - numvert = reduce( lambda i,f: len(f)+i, mesh.faces, 0) - self.file.write("%d;\n" % (numvert)) - #VERTEX COLORS - - vcounter =0 - for f in mesh.faces: - col = f.col - for i,c in enumerate(col): - # Note vcol alpha has no meaning - self.file.write("%d;%f;%f;%f;%f;" % (vcounter,c.r/255.0, c.g/255.0, c.b/255.0, 1.0)) # c.a/255.0)) - vcounter+=1 - if vcounter == numvert : - self.file.write(";\n") - else : - self.file.write(",\n") - - self.file.write("} //End of MeshVertexColors\n") - -#***********************************************#***********************************************#*********************************************** - #*********************************************** - #FRAMES - #*********************************************** - def writeFrames(self, matx): - - self.file.write("%f,%f,%f,%f," % - (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) - self.file.write("%f,%f,%f,%f," % - (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) - self.file.write("%f,%f,%f,%f," % - (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) - self.file.write("%f,%f,%f,%f;;" % - (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) - - - - - - #*********************************************** - #WRITE ANIMATION KEYS - #*********************************************** - def writeAnimation(self,arm_ob): - global mat_dict, root_bon - arm = arm_ob.getData() - act_list = arm_ob.getAction() - ip = act_list.getAllChannelIpos() - for bon in arm.bones.values() : - point_list = [] - name = bon.name - name_f = make_legal_name(name) - try : - ip_bon_channel = ip[bon.name] - ip_bon_name = ip_bon_channel.getName() - - ip_bon = Blender.Ipo.Get(ip_bon_name) - poi = ip_bon.getCurves() - - for po in poi[3].getPoints(): - a = po.getPoints() - point_list.append(int(a[0])) - #point_list.pop(0) - - self.file.write(" Animation { \n") - self.file.write(" { %s }\n" %(name_f)) - self.file.write(" AnimationKey { \n") - self.file.write(" 4;\n") - self.file.write(" %d; \n" % (len(point_list))) - - for fr in point_list: - - if name == root_bon.name : - - - mat_b = self.writeAnimCombineMatrix(bon,fr) - mat_arm = self.getLocMat(arm_ob) - mat = mat_b * mat_arm - else: - mat = self.writeAnimCombineMatrix(bon,fr) - - self.file.write(" %d;" % (fr)) - self.file.write("16;") - - self.writeFrames(mat) - - if fr == point_list[len(point_list)-1]: - self.file.write(";\n") - else: - self.file.write(",\n") - self.file.write(" }\n") - self.file.write(" }\n") - self.file.write("\n") - except: - pass - - - - #*********************************************** - #WRITE ANIMATION KEYS - #*********************************************** - def writeAnimationObj(self, obj): - point_list = [] - ip = obj.ipo - poi = ip.getCurves() - for po in poi[0].getPoints(): - a = po.getPoints() - point_list.append(int(a[0])) - - self.file.write(" Animation {\n") - self.file.write(" { ") - self.file.write("%s }\n" % (make_legal_name(obj.name))) - self.file.write(" AnimationKey { \n") - self.file.write(" 4;\n") - self.file.write(" %d; \n" % (len(point_list))) - for fr in point_list: - self.file.write(" %d;" % (fr)) - self.file.write("16;") - Blender.Set('curframe',fr) - - #mat_new = self.getLocMat(obj) - mat_new = obj.matrixLocal - self.writeFrames(mat_new) - - if fr == point_list[len(point_list)-1]: - self.file.write(";\n") - else: - self.file.write(",\n") - self.file.write(" }\n") - self.file.write(" }\n") - - - -#***********************************************#***********************************************#*********************************************** - - - - - diff --git a/release/scripts/DirectX8Importer.py b/release/scripts/DirectX8Importer.py deleted file mode 100644 index 0dda654944d..00000000000 --- a/release/scripts/DirectX8Importer.py +++ /dev/null @@ -1,238 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: -Name: 'DirectX(.x)...' -Blender: 244 -Group: 'Import' - -Tip: 'Import from DirectX text file format format.' -""" -# DirectXImporter.py version 1.2 -# Copyright (C) 2005 Arben OMARI -- omariarben@everyday.com -# -# 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. - -# This script import meshes from DirectX text file format - -# Grab the latest version here :www.omariben.too.it -import bpy -import Blender -from Blender import Mesh,Object,Material,Texture,Image,Draw - - -class xImport: - def __init__(self, filename): - global my_path - self.file = open(filename, "r") - my_path = Blender.sys.dirname(filename) - - # - self.lines = [l_split for l in self.file.readlines() for l_split in (' '.join(l.split()),) if l_split] - - def Import(self): - lines = self.lines - print "importing into Blender ..." - scene = bpy.data.scenes.active - - mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies - context_indicies = None # will raise an error if used! - - - #Get the line of Texture Coords - nr_uv_ind = 0 - - #Get Materials - nr_fac_mat = 0 - i = -1 - mat_list = [] - tex_list = [] - mesh_line_indicies = [] - for j, line in enumerate(lines): - l = line.strip() - words = line.split() - if words[0] == "Material" : - #context_indicies["Material"] = j - self.loadMaterials(j, mat_list, tex_list) - elif words[0] == "MeshTextureCoords" : - context_indicies["MeshTextureCoords"] = j - #nr_uv_ind = j - elif words[0] == "MeshMaterialList" : - context_indicies["MeshMaterialList"] = j+2 - #nr_fac_mat = j + 2 - elif words[0] == "Mesh": # Avoid a second loop - context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0} - - for mesh_index, value in mesh_indicies.iteritems(): - mesh = Mesh.New() - self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list) - - mesh.materials = mat_list[:16] - if value['MeshMaterialList']: - self.loadMeshMaterials(value['MeshMaterialList'], mesh) - scene.objects.new(mesh) - - self.file.close() - print "... finished" - - #------------------------------------------------------------------------------ - # CREATE THE MESH - #------------------------------------------------------------------------------ - def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list): - v_ind = nr_vr_ind + 1 - lin = self.lines[v_ind] - if lin : - lin_c = self.CleanLine(lin) - nr_vert = int((lin_c.split()[0])) - else : - v_ind = nr_vr_ind + 2 - lin = self.lines[v_ind] - lin_c = self.CleanLine(lin) - nr_vert = int((lin_c.split()[0])) - - #-------------------------------------------------- - nr_fac_li = v_ind + nr_vert +1 - lin_f = self.lines[nr_fac_li] - if lin_f : - lin_fc = self.CleanLine(lin_f) - nr_face = int((lin_fc.split()[0])) - else : - nr_fac_li = v_ind + nr_vert +1 - lin_f = self.lines[nr_fac_li] - lin_fc = self.CleanLine(lin_f) - nr_face = int((lin_fc.split()[0])) - - #Get Coordinates - verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR - for l in xrange(v_ind + 1, (v_ind + nr_vert +1)): - line_v = self.lines[l] - lin_v = self.CleanLine(line_v) - words = lin_v.split() - if len(words)==3: - verts_list.append((float(words[0]),float(words[1]),float(words[2]))) - - mesh.verts.extend(verts_list) - del verts_list - - face_list = [] - #Make Faces - i = 0 - mesh_verts = mesh.verts - for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)): - i += 1 - line_f = self.lines[f] - lin_f = self.CleanLine(line_f) - - # +1 for dummy vert only! - words = lin_f.split() - if len(words) == 5: - face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4]))) - elif len(words) == 4: - face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]))) - - mesh.faces.extend(face_list) - del face_list - - if nr_uv : - mesh.faceUV = True - for f in mesh.faces: - fuv = f.uv - for ii, v in enumerate(f): - # _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split() - - # Use a dummy vert - _u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split() - - fuv[ii].x = float(_u) - fuv[ii].y = float(_v) - - if nr_fac_mat : - fac_line = self.lines[nr_fac_mat + i] - fixed_fac = self.CleanLine(fac_line) - w_tex = int(fixed_fac.split()[0]) - f.image = tex_list[w_tex] - - # remove dummy vert - mesh.verts.delete([0,]) - - def CleanLine(self,line): - return line.replace(\ - ";", " ").replace(\ - '"', ' ').replace(\ - "{", " ").replace(\ - "}", " ").replace(\ - ",", " ").replace(\ - "'", " ") - - #------------------------------------------------------------------ - # CREATE MATERIALS - #------------------------------------------------------------------ - def loadMaterials(self, nr_mat, mat_list, tex_list): - - def load_image(name): - try: - return Image.Load(Blender.sys.join(my_path,name)) - except: - return None - - mat = bpy.data.materials.new() - line = self.lines[nr_mat + 1] - fixed_line = self.CleanLine(line) - words = fixed_line.split() - mat.rgbCol = [float(words[0]),float(words[1]),float(words[2])] - mat.setAlpha(float(words[3])) - mat_list.append(mat) - l = self.lines[nr_mat + 5] - fix_3_line = self.CleanLine(l) - tex_n = fix_3_line.split() - - if tex_n and tex_n[0] == "TextureFilename" : - - if len(tex_n) > 1: - tex_list.append(load_image(tex_n[1])) - - if len(tex_n) <= 1 : - - l_succ = self.lines[nr_mat + 6] - fix_3_succ = self.CleanLine(l_succ) - tex_n_succ = fix_3_succ.split() - tex_list.append(load_image(tex_n_succ[0])) - else : - tex_list.append(None) # no texture for this index - - return mat_list, tex_list - #------------------------------------------------------------------ - # SET MATERIALS - #------------------------------------------------------------------ - def loadMeshMaterials(self, nr_fc_mat, mesh): - for face in mesh.faces: - nr_fc_mat += 1 - line = self.lines[nr_fc_mat] - fixed_line = self.CleanLine(line) - wrd = fixed_line.split() - mat_idx = int(wrd[0]) - face.mat = mat_idx - -#------------------------------------------------------------------ -# MAIN -#------------------------------------------------------------------ -def my_callback(filename): - if not filename.lower().endswith('.x'): print "Not an .x file" - ximport = xImport(filename) - ximport.Import() - -arg = __script__['arg'] - -if __name__ == '__main__': - Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x") - -#my_callback('/fe/x/directxterrain.x') -#my_callback('/fe/x/Male_Normal_MAX.X') -#my_callback('/fe/x/male_ms3d.x') diff --git a/release/scripts/IDPropBrowser.py b/release/scripts/IDPropBrowser.py deleted file mode 100644 index 2a14760270a..00000000000 --- a/release/scripts/IDPropBrowser.py +++ /dev/null @@ -1,523 +0,0 @@ -#!BPY - -""" -Name: 'ID Property Browser' -Blender: 242 -Group: 'Help' -Tooltip: 'Browse ID properties' -""" - -__author__ = "Joe Eagar" -__version__ = "0.3.108" -__email__ = "joeedh@gmail.com" -__bpydoc__ = """\ - -Allows browsing, creating and editing of ID Properties -for various ID block types such as mesh, scene, object, -etc. -""" - -# -------------------------------------------------------------------------- -# ID Property Browser. -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - - -from Blender import * -from Blender.BGL import * -from Blender.Types import IDGroupType, IDArrayType -import Blender - -def IsInRectWH(mx, my, x, y, wid, hgt): - if mx >= x and mx <= x + wid: - if my >= y and my <= y + hgt: - return 1 - return 0 - -Button_Back = 1 -Button_New = 2 -Button_MatMenu = 3 -Button_TypeMenu = 4 - -ButStart = 55 - -IDP_String = 0 -IDP_Int = 1 -IDP_Float = 2 -IDP_Array = 5 -IDP_Group = 6 - -ButDelStart = 255 -#max limit for string input button -strmax = 100 - -State_Normal = 0 -State_InArray = 1 - -#IDTypeModules entries are of form [module, active_object_index, module_name] -IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]] -IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]] -IDTypeModules += [[Image, 0, "Images"]] - -class IDArrayBrowser: - array = 0 - parentbrowser = 0 - buts = 0 - - def __init__(self): - self.buts = [] - - def Draw(self): - pb = self.parentbrowser - x = pb.x - y = pb.y - width = pb.width - height = pb.height - pad = pb.pad - itemhgt = pb.itemhgt - cellwid = 65 - y = y + height - itemhgt - pad - - Draw.PushButton("Back", Button_Back, x, y, 40, 20) - y -= itemhgt + pad - - self.buts = [] - Draw.BeginAlign() - for i in xrange(len(self.array)): - st = "" - if type(self.array[0]) == float: - st = "%.5f" % self.array[i] - else: st = str(self.array[i]) - - b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30) - self.buts.append(b) - x += cellwid + pad - if x + cellwid + pad > width: - x = 0 - y -= itemhgt + pad - Draw.EndAlign() - def Button(self, bval): - if bval == Button_Back: - self.parentbrowser.state = State_Normal - self.parentbrowser.array = 0 - self.buts = [] - Draw.Draw() - self.array = 0 - elif bval >= ButStart: - i = bval - ButStart - st = self.buts[i].val - n = 0 - if type(self.array[0]) == float: - try: - n = int(st) - except: - return - elif type(self.array[0]) == int: - try: - n = float(st) - except: - return - - self.array[i] = n - Draw.Draw() - - def Evt(self, evt, val): - if evt == Draw.ESCKEY: - Draw.Exit() - -class IDPropertyBrowser: - width = 0 - height = 0 - x = 0 - y = 0 - scrollx = 0 - scrolly = 0 - itemhgt = 22 - pad = 2 - - group = 0 - parents = 0 #list stack of parent groups - active_item = -1 - mousecursor = 0 - _i = 0 - buts = [] - - state = 0 - array = 0 - prop = 0 - - IDList = 0 - idindex = 0 - idblock = 0 - - type = 0 # attach buildin type() method to class - # since oddly it's not available to button - # callbacks! EEK! :( - - def __init__(self, idgroup, mat, x, y, wid, hgt): - self.group = idgroup - self.prop = idgroup - self.x = x - self.y = y - self.width = wid - self.height = hgt - self.mousecursor = [0, 0] - self.parents = [] - self.idblock = mat - self.type = type - - def DrawBox(self, glmode, x, y, width, height): - glBegin(glmode) - glVertex2f(x, y) - glVertex2f(x+width, y) - glVertex2f(x+width, y+height) - glVertex2f(x, y+height) - glEnd() - - def Draw(self): - global IDTypeModules - - #first draw outlining box :) - glColor3f(0, 0, 0) - self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height) - - itemhgt = self.itemhgt - pad = self.pad - x = self.x - y = self.y + self.height - itemhgt - pad - - if self.state == State_InArray: - self.array.Draw() - return - - plist = [] - self.buts = [] - for p in self.group.iteritems(): - plist.append(p) - - #-------do top buttons----------# - Draw.BeginAlign() - Draw.PushButton("New", Button_New, x, y, 40, 20) - x += 40 + pad - #do the menu button for all materials - st = "" - - blocks = IDTypeModules[self.IDList][0].Get() - i = 1 - mi = 0 - for m in blocks: - if m.name == self.idblock.name: - mi = i - st += m.name + " %x" + str(i) + "|" - i += 1 - - self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi) - - x += 100 + pad - - st = "" - i = 0 - for e in IDTypeModules: - st += e[2] + " %x" + str(i+1) + "|" - i += 1 - - cur = self.IDList + 1 - self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur) - x = self.x - y -= self.itemhgt + self.pad - Draw.EndAlign() - - - #-----------do property items---------# - i = 0 - while y > self.y - 20 - pad and i < len(plist): - k = plist[i][0] - p = plist[i][1] - if i == self.active_item: - glColor3f(0.5, 0.4, 0.3) - self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt) - - glColor3f(0, 0, 0) - self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt) - - glRasterPos2f(x+pad*2, y+5) - Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name) - tlen = Draw.GetStringWidth(str(k)) - - type_p = type(p) - if type_p == str: - b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax) - self.buts.append(b) - elif type_p in [int, float]: - #only do precision to 5 points on floats - st = "" - if type_p == float: - st = "%.5f" % p - else: st = str(p) - b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax) - self.buts.append(b) - else: - glRasterPos2f(x+pad*2 +tlen+10, y+5) - if type_p == Types.IDArrayType: - Draw.Text('(array, click to edit)') - elif type_p == Types.IDGroupType: - Draw.Text('(group, click to edit)') - - - self.buts.append(None) - - Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20) - - i += 1 - y -= self.itemhgt + self.pad - - if len(self.parents) != 0: - Draw.PushButton("Back", Button_Back, x, y, 40, 20) - x = x + 40 + pad - - def SetActive(self): - m = self.mousecursor - itemhgt = self.itemhgt - pad = self.pad - - x = self.x + pad - y = self.y + self.height - itemhgt - pad - itemhgt - - plist = [] - for p in self.group.iteritems(): - plist.append(p) - - self.active_item = -1 - i = 0 - while y > self.y and i < len(plist): - p = plist[i] - if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt): - self.active_item = i - - i += 1 - y -= self.itemhgt + self.pad - - def EventIn(self, evt, val): - if self.state == State_InArray: - self.array.Evt(evt, val) - - if evt == Draw.ESCKEY: - Draw.Exit() - if evt == Draw.MOUSEX or evt == Draw.MOUSEY: - size = Buffer(GL_FLOAT, 4) - glGetFloatv(GL_SCISSOR_BOX, size) - if evt == Draw.MOUSEX: - self.mousecursor[0] = val - size[0] - else: - self.mousecursor[1] = val - size[1] - del size - - self.SetActive() - self._i += 1 - if self._i == 5: - Draw.Draw() - self._i = 0 - - - if evt == Draw.LEFTMOUSE and val == 1: - plist = list(self.group.iteritems()) - a = self.active_item - if a >= 0 and a < len(plist): - p = plist[a] - - basictypes = [IDGroupType, float, str, int] - if type(p[1]) == IDGroupType: - self.parents.append(self.group) - self.group = p[1] - self.active_item = -1 - Draw.Draw() - elif type(p[1]) == IDArrayType: - self.array = IDArrayBrowser() - self.array.array = p[1] - self.array.parentbrowser = self - self.state = State_InArray - Draw.Draw() - - if evt == Draw.TKEY and val == 1: - try: - self.prop['float'] = 0.0 - self.prop['int'] = 1 - self.prop['string'] = "hi!" - self.prop['float array'] = [0, 0, 1.0, 0] - self.prop['int array'] = [0, 0, 0, 0] - self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}} - Draw.Draw() - except: - Draw.PupMenu("Can only do T once per block, the test names are already taken!") - - - def Button(self, bval): - global IDTypeModules - if self.state == State_InArray: - self.array.Button(bval) - return - - if bval == Button_MatMenu: - global IDTypeModules - - val = self.idindex = self.menubut.val - 1 - i = self.IDList - block = IDTypeModules[i][0].Get()[val] - self.idblock = block - self.prop = block.properties - self.group = self.prop - self.active_item = -1 - self.parents = [] - Draw.Draw() - - if bval == Button_TypeMenu: - i = IDTypeModules[self.idmenu.val-1] - if len(i[0].Get()) == 0: - Draw.PupMenu("Error%t|There are no " + i[2] + "!") - return - - IDTypeModules[self.IDList][1] = self.idindex - self.IDList = self.idmenu.val-1 - val = self.idindex = IDTypeModules[self.IDList][1] - i = self.IDList - block = IDTypeModules[i][0].Get()[val] - self.idblock = block - self.prop = block.properties - self.group = self.prop - self.active_item = -1 - self.parents = [] - Draw.Draw() - - if bval >= ButDelStart: - plist = [p for p in self.group] - prop = plist[bval - ButDelStart] - del self.group[prop] - Draw.Draw() - - elif bval >= ButStart: - plist = list(self.group.iteritems()) - - prop = plist[bval - ButStart] - print prop - - if self.type(prop[1]) == str: - self.group[prop[0]] = self.buts[bval - ButStart].val - elif self.type(prop[1]) == int: - i = self.buts[bval - ButStart].val - try: - i = int(i) - self.group[prop[0]] = i - except: - Draw.Draw() - return - Draw.Draw() - elif self.type(prop[1]) == float: - f = self.buts[bval - ButStart].val - try: - f = float(f) - self.group[prop[0]] = f - except: - Draw.Draw() - return - Draw.Draw() - - elif bval == Button_Back: - self.group = self.parents[len(self.parents)-1] - self.parents.pop(len(self.parents)-1) - Draw.Draw() - - elif bval == Button_New: - name = Draw.Create("untitled") - stype = Draw.Create(0) - gtype = Draw.Create(0) - ftype = Draw.Create(0) - itype = Draw.Create(0) - atype = Draw.Create(0) - - block = [] - block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property")) - block.append("Type") - block.append(("String", stype)) - block.append(("Subgroup", gtype)) - block.append(("Float", ftype)) - block.append(("Int", itype)) - block.append(("Array", atype)) - - retval = Blender.Draw.PupBlock("New IDProperty", block) - if retval == 0: return - - name = name.val - i = 1 - stop = 0 - while stop == 0: - stop = 1 - for p in self.group: - if p == name: - d = name.rfind(".") - if d != -1: - name = name[:d] - name = name + "." + str(i).zfill(3) - i += 1 - stop = 0 - - type = "String" - if stype.val: - self.group[name] = "" - elif gtype.val: - self.group[name] = {} - elif ftype.val: - self.group[name] = 0.0 - elif itype.val: - self.group[name] = 0 #newProperty("Int", name, 0) - elif atype.val: - arrfloat = Draw.Create(1) - arrint = Draw.Create(0) - arrlen = Draw.Create(3) - block = [] - block.append("Type") - block.append(("Float", arrfloat, "Make a float array")) - block.append(("Int", arrint, "Make an integer array")) - block.append(("Len", arrlen, 2, 200)) - - if Blender.Draw.PupBlock("Array Properties", block): - if arrfloat.val: - tmpl = 0.0 - elif arrint.val: - tmpl = 0 - else: - return - - self.group[name] = [tmpl] * arrlen.val - - - def Go(self): - Draw.Register(self.Draw, self.EventIn, self.Button) - -scenes = Scene.Get() - -size = Window.GetAreaSize() -browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1]) -browser.Go() - -#a = prop.newProperty("String", "hwello!", "bleh") -#b = prop.newProperty("Group", "subgroup") - -#for p in prop: - #print p.name diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py deleted file mode 100644 index 57f27c7e3a2..00000000000 --- a/release/scripts/ac3d_export.py +++ /dev/null @@ -1,828 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: -Name: 'AC3D (.ac)...' -Blender: 243 -Group: 'Export' -Tip: 'Export selected meshes to AC3D (.ac) format' -""" - -__author__ = "Willian P. Germano" -__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org", - "PLib 3d gaming lib, http://plib.sf.net") -__version__ = "2.44 2007-05-05" - -__bpydoc__ = """\ -This script exports selected Blender meshes to AC3D's .ac file format. - -AC3D is a simple commercial 3d modeller also built with OpenGL. -The .ac file format is an easy to parse text format well supported, -for example, by the PLib 3d gaming library (AC3D 3.x). - -Supported:
- UV-textured meshes with hierarchy (grouping) information. - -Missing:
- The 'url' tag, specific to AC3D. It is easy to add by hand to the exported -file, if needed. - -Known issues:
- The ambient and emit data we can retrieve from Blender are single values, -that this script copies to R, G, B, giving shades of gray.
- Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.
- In AC3D 4 "compatibility mode":
- - shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];
- - crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0]; - -Config Options:
- toggle:
- - AC3D 4 mode: unset it to export without the 'crease' tag that was -introduced with AC3D 4.0 and with the old material handling;
- - global coords: transform all vertices of all meshes to global coordinates;
- - skip data: set it if you don't want mesh names (ME:, not OB: field) -to be exported as strings for AC's "data" tags (19 chars max);
- - rgb mirror color can be exported as ambient and/or emissive if needed, -since Blender handles these differently;
- - default mat: a default (white) material is added if some mesh was -left without mats -- it's better to always add your own materials;
- - no split: don't split meshes (see above);
- - set texture dir: override the actual textures path with a given default -path (or simply export the texture names, without dir info, if the path is -empty);
- - per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;
- - only selected: only consider selected objects when looking for meshes -to export (read notes below about tokens, too);
- strings:
- - export dir: default dir to export to;
- - texture dir: override textures path with this path if 'set texture dir' -toggle is "on". - -Notes:
- This version updates:
- - modified meshes are correctly exported, no need to apply the modifiers in Blender;
- - correctly export each used material, be it assigned to the object or to its mesh data;
- - exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.
- - there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;
- Multiple textures per mesh are supported (mesh gets split);
- Parents are exported as a group containing both the parent and its children;
- Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;
- Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set. -""" - -# $Id$ -# -# -------------------------------------------------------------------------- -# AC3DExport version 2.44 -# Program versions: Blender 2.42+ and AC3Db files (means version 0xb) -# new: updated for new Blender version and Mesh module; supports lines (edges) again; -# option to export vertices transformed to global coordinates or not; now the modified -# (by existing mesh modifiers) mesh is exported; materials are properly exported, no -# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose -# edges use color of first material found in the mesh, if any. -# -------------------------------------------------------------------------- -# Thanks: Steve Baker for discussions and inspiration; for testing, bug -# reports, suggestions, patches: David Megginson, Filippo di Natale, -# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason. -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br -# -# 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, -# -------------------------------------------------------------------------- - -import Blender -from Blender import Object, Mesh, Material, Image, Mathutils, Registry -from Blender import sys as bsys - -# Globals -REPORT_DATA = { - 'main': [], - 'errors': [], - 'warns': [], - 'nosplit': [], - 'noexport': [] -} -TOKENS_DONT_EXPORT = ['!', '#'] -TOKENS_DONT_SPLIT = ['=', '$'] - -MATIDX_ERROR = 0 - -# flags: -LOOSE = Mesh.EdgeFlags['LOOSE'] -FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE'] -MESH_TWOSIDED = Mesh.Modes['TWOSIDED'] - -REG_KEY = 'ac3d_export' - -# config options: -GLOBAL_COORDS = True -SKIP_DATA = False -MIRCOL_AS_AMB = False -MIRCOL_AS_EMIS = False -ADD_DEFAULT_MAT = True -SET_TEX_DIR = True -TEX_DIR = '' -AC3D_4 = True # export crease value, compatible with AC3D 4 loaders -NO_SPLIT = False -ONLY_SELECTED = True -EXPORT_DIR = '' -PER_FACE_1_OR_2_SIDED = True - -tooltips = { - 'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates", - 'SKIP_DATA': "don't export mesh names as data fields", - 'MIRCOL_AS_AMB': "export mirror color as ambient color", - 'MIRCOL_AS_EMIS': "export mirror color as emissive color", - 'ADD_DEFAULT_MAT': "always add a default white material", - 'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")", - 'EXPORT_DIR': "default / last folder used to export .ac files to", - 'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)", - 'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support", - 'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)", - 'ONLY_SELECTED': "export only selected objects", - 'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)" -} - -def update_RegistryInfo(): - d = {} - d['SKIP_DATA'] = SKIP_DATA - d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB - d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS - d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT - d['SET_TEX_DIR'] = SET_TEX_DIR - d['TEX_DIR'] = TEX_DIR - d['AC3D_4'] = AC3D_4 - d['NO_SPLIT'] = NO_SPLIT - d['EXPORT_DIR'] = EXPORT_DIR - d['ONLY_SELECTED'] = ONLY_SELECTED - d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED - d['tooltips'] = tooltips - d['GLOBAL_COORDS'] = GLOBAL_COORDS - Registry.SetKey(REG_KEY, d, True) - -# Looking for a saved key in Blender.Registry dict: -rd = Registry.GetKey(REG_KEY, True) - -if rd: - try: - AC3D_4 = rd['AC3D_4'] - SKIP_DATA = rd['SKIP_DATA'] - MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB'] - MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS'] - ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT'] - SET_TEX_DIR = rd['SET_TEX_DIR'] - TEX_DIR = rd['TEX_DIR'] - EXPORT_DIR = rd['EXPORT_DIR'] - ONLY_SELECTED = rd['ONLY_SELECTED'] - NO_SPLIT = rd['NO_SPLIT'] - PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED'] - GLOBAL_COORDS = rd['GLOBAL_COORDS'] - except KeyError: update_RegistryInfo() - -else: - update_RegistryInfo() - -VERBOSE = True -CONFIRM_OVERWRITE = True - -# check General scripts config key for default behaviors -rd = Registry.GetKey('General', True) -if rd: - try: - VERBOSE = rd['verbose'] - CONFIRM_OVERWRITE = rd['confirm_overwrite'] - except: pass - - -# The default material to be used when necessary (see ADD_DEFAULT_MAT) -DEFAULT_MAT = \ -'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \ -spec 0.5 0.5 0.5 shi 64 trans 0' - -# This transformation aligns Blender and AC3D coordinate systems: -BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1]) - -def Round_s(f): - "Round to default precision and turn value to a string" - r = round(f,6) # precision set to 10e-06 - if r == int(r): - return str(int(r)) - else: - return str(r) - -def transform_verts(verts, m): - vecs = [] - for v in verts: - x, y, z = v.co - vec = Mathutils.Vector([x, y, z, 1]) - vecs.append(vec*m) - return vecs - -def get_loose_edges(mesh): - loose = LOOSE - return [e for e in mesh.edges if e.flag & loose] - -# --- - -# meshes with more than one texture assigned -# are split and saved as these foomeshes -class FooMesh: - - class FooVert: - def __init__(self, v): - self.v = v - self.index = 0 - - class FooFace: - def __init__(self, foomesh, f): - self.f = f - foov = foomesh.FooVert - self.v = [foov(f.v[0]), foov(f.v[1])] - len_fv = len(f.v) - if len_fv > 2 and f.v[2]: - self.v.append(foov(f.v[2])) - if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3])) - - def __getattr__(self, attr): - if attr == 'v': return self.v - return getattr(self.f, attr) - - def __len__(self): - return len(self.f) - - def __init__(self, tex, faces, mesh): - self.name = mesh.name - self.mesh = mesh - self.looseEdges = [] - self.faceUV = mesh.faceUV - self.degr = mesh.degr - vidxs = [0]*len(mesh.verts) - foofaces = [] - for f in faces: - foofaces.append(self.FooFace(self, f)) - for v in f.v: - if v: vidxs[v.index] = 1 - i = 0 - fooverts = [] - for v in mesh.verts: - if vidxs[v.index]: - fooverts.append(v) - vidxs[v.index] = i - i += 1 - for f in foofaces: - for v in f.v: - if v: v.index = vidxs[v.v.index] - self.faces = foofaces - self.verts = fooverts - - -class AC3DExport: # the ac3d exporter part - - def __init__(self, scene_objects, file): - - global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT - - header = 'AC3Db' - self.file = file - self.buf = '' - self.mbuf = [] - self.mlist = [] - world_kids = 0 - parents_list = self.parents_list = [] - kids_dict = self.kids_dict = {} - objs = [] - exp_objs = self.exp_objs = [] - tree = {} - - file.write(header+'\n') - - objs = \ - [o for o in scene_objects if o.type in ['Mesh', 'Empty']] - - # create a tree from parents to children objects - - for obj in objs[:]: - parent = obj.parent - lineage = [obj] - - while parent: - parents_list.append(parent.name) - obj = parent - parent = parent.getParent() - lineage.insert(0, obj) - - d = tree - for i in xrange(len(lineage)): - lname = lineage[i].getType()[:2] + lineage[i].name - if lname not in d.keys(): - d[lname] = {} - d = d[lname] - - # traverse the tree to get an ordered list of names of objects to export - self.traverse_dict(tree) - - world_kids = len(tree.keys()) - - # get list of objects to export, start writing the .ac file - - objlist = [Object.Get(name) for name in exp_objs] - - meshlist = [o for o in objlist if o.type == 'Mesh'] - - # create a temporary mesh to hold actual (modified) mesh data - TMP_mesh = Mesh.New('tmp_for_ac_export') - - # write materials - - self.MATERIALS(meshlist, TMP_mesh) - mbuf = self.mbuf - if not mbuf or ADD_DEFAULT_MAT: - mbuf.insert(0, "%s\n" % DEFAULT_MAT) - mbuf = "".join(mbuf) - file.write(mbuf) - - file.write('OBJECT world\nkids %s\n' % world_kids) - - # write the objects - - for obj in objlist: - self.obj = obj - - objtype = obj.type - objname = obj.name - kidsnum = kids_dict[objname] - - # A parent plus its children are exported as a group. - # If the parent is a mesh, its rot and loc are exported as the - # group rot and loc and the mesh (w/o rot and loc) is added to the group. - if kidsnum: - self.OBJECT('group') - self.name(objname) - if objtype == 'Mesh': - kidsnum += 1 - if not GLOBAL_COORDS: - localmatrix = obj.getMatrix('localspace') - if not obj.getParent(): - localmatrix *= BLEND_TO_AC3D_MATRIX - self.rot(localmatrix.rotationPart()) - self.loc(localmatrix.translationPart()) - self.kids(kidsnum) - - if objtype == 'Mesh': - mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data - mesh.getFromObject(objname) - self.mesh = mesh - if mesh.faceUV: - meshes = self.split_mesh(mesh) - else: - meshes = [mesh] - if len(meshes) > 1: - if NO_SPLIT or self.dont_split(objname): - self.export_mesh(mesh, ob) - REPORT_DATA['nosplit'].append(objname) - else: - self.OBJECT('group') - self.name(objname) - self.kids(len(meshes)) - counter = 0 - for me in meshes: - self.export_mesh(me, obj, - name = '%s_%s' % (obj.name, counter), foomesh = True) - self.kids() - counter += 1 - else: - self.export_mesh(mesh, obj) - self.kids() - - - def traverse_dict(self, d): - kids_dict = self.kids_dict - exp_objs = self.exp_objs - keys = d.keys() - keys.sort() # sort for predictable output - keys.reverse() - for k in keys: - objname = k[2:] - klen = len(d[k]) - kids_dict[objname] = klen - if self.dont_export(objname): - d.pop(k) - parent = Object.Get(objname).getParent() - if parent: kids_dict[parent.name] -= 1 - REPORT_DATA['noexport'].append(objname) - continue - if klen: - self.traverse_dict(d[k]) - exp_objs.insert(0, objname) - else: - if k.find('Em', 0) == 0: # Empty w/o children - d.pop(k) - parent = Object.Get(objname).getParent() - if parent: kids_dict[parent.name] -= 1 - else: - exp_objs.insert(0, objname) - - def dont_export(self, name): # if name starts with '!' or '#' - length = len(name) - if length >= 1: - if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export - if length > 1 and name[1] == name[0]: - return 0 - return 1 - - def dont_split(self, name): # if name starts with '=' or '$' - length = len(name) - if length >= 1: - if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split - if length > 1 and name[1] == name[0]: - return 0 - return 1 - - def split_mesh(self, mesh): - tex_dict = {0:[]} - for f in mesh.faces: - if f.image: - if not f.image.name in tex_dict: tex_dict[f.image.name] = [] - tex_dict[f.image.name].append(f) - else: tex_dict[0].append(f) - keys = tex_dict.keys() - len_keys = len(keys) - if not tex_dict[0]: - len_keys -= 1 - tex_dict.pop(0) - keys.remove(0) - elif len_keys > 1: - lines = [] - anyimgkey = [k for k in keys if k != 0][0] - for f in tex_dict[0]: - if len(f.v) < 3: - lines.append(f) - if len(tex_dict[0]) == len(lines): - for l in lines: - tex_dict[anyimgkey].append(l) - len_keys -= 1 - tex_dict.pop(0) - if len_keys > 1: - foo_meshes = [] - for k in keys: - faces = tex_dict[k] - foo_meshes.append(FooMesh(k, faces, mesh)) - foo_meshes[0].edges = get_loose_edges(mesh) - return foo_meshes - return [mesh] - - def export_mesh(self, mesh, obj, name = None, foomesh = False): - file = self.file - self.OBJECT('poly') - if not name: name = obj.name - self.name(name) - if not SKIP_DATA: - meshname = obj.getData(name_only = True) - self.data(len(meshname), meshname) - if mesh.faceUV: - texline = self.texture(mesh.faces) - if texline: file.write(texline) - if AC3D_4: - self.crease(mesh.degr) - - # If exporting using local coordinates, children object coordinates should not be - # transformed to ac3d's coordinate system, since that will be accounted for in - # their topmost parents (the parents w/o parents) transformations. - if not GLOBAL_COORDS: - # We hold parents in a list, so they also don't get transformed, - # because for each parent we create an ac3d group to hold both the - # parent and its children. - if obj.name not in self.parents_list: - localmatrix = obj.getMatrix('localspace') - if not obj.getParent(): - localmatrix *= BLEND_TO_AC3D_MATRIX - self.rot(localmatrix.rotationPart()) - self.loc(localmatrix.translationPart()) - matrix = None - else: - matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX - - self.numvert(mesh.verts, matrix) - self.numsurf(mesh, foomesh) - - def MATERIALS(self, meshlist, me): - for meobj in meshlist: - me.getFromObject(meobj) - mats = me.materials - mbuf = [] - mlist = self.mlist - for m in mats: - if not m: continue - name = m.name - if name not in mlist: - mlist.append(name) - M = Material.Get(name) - material = 'MATERIAL "%s"' % name - mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]), - Round_s(M.mirCol[2])) - rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B)) - ambval = Round_s(M.amb) - amb = "amb %s %s %s" % (ambval, ambval, ambval) - spec = "spec %s %s %s" % (Round_s(M.specCol[0]), - Round_s(M.specCol[1]), Round_s(M.specCol[2])) - if AC3D_4: - emit = Round_s(M.emit) - emis = "emis %s %s %s" % (emit, emit, emit) - shival = int(M.spec * 64) - else: - emis = "emis 0 0 0" - shival = 72 - shi = "shi %s" % shival - trans = "trans %s" % (Round_s(1 - M.alpha)) - if MIRCOL_AS_AMB: - amb = "amb %s" % mirCol - if MIRCOL_AS_EMIS: - emis = "emis %s" % mirCol - mbuf.append("%s %s %s %s %s %s %s\n" \ - % (material, rgb, amb, emis, spec, shi, trans)) - self.mlist = mlist - self.mbuf.append("".join(mbuf)) - - def OBJECT(self, type): - self.file.write('OBJECT %s\n' % type) - - def name(self, name): - if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT: - if len(name) > 1: name = name[1:] - self.file.write('name "%s"\n' % name) - - def kids(self, num = 0): - self.file.write('kids %s\n' % num) - - def data(self, num, str): - self.file.write('data %s\n%s\n' % (num, str)) - - def texture(self, faces): - tex = "" - for f in faces: - if f.image: - tex = f.image.name - break - if tex: - image = Image.Get(tex) - texfname = image.filename - if SET_TEX_DIR: - texfname = bsys.basename(texfname) - if TEX_DIR: - texfname = bsys.join(TEX_DIR, texfname) - buf = 'texture "%s"\n' % texfname - xrep = image.xrep - yrep = image.yrep - buf += 'texrep %s %s\n' % (xrep, yrep) - self.file.write(buf) - - def rot(self, matrix): - rot = '' - not_I = 0 # not identity - matstr = [] - for i in [0, 1, 2]: - r = map(Round_s, matrix[i]) - not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0') - not_I -= (r[i] == '1') - for j in [0, 1, 2]: - matstr.append(' %s' % r[j]) - if not_I: # no need to write identity - self.file.write('rot%s\n' % "".join(matstr)) - - def loc(self, loc): - loc = map(Round_s, loc) - if loc != ['0', '0', '0']: # no need to write default - self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2])) - - def crease(self, crease): - self.file.write('crease %f\n' % crease) - - def numvert(self, verts, matrix): - file = self.file - nvstr = [] - nvstr.append("numvert %s\n" % len(verts)) - - if matrix: - verts = transform_verts(verts, matrix) - for v in verts: - v = map (Round_s, v) - nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) - else: - for v in verts: - v = map(Round_s, v.co) - nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) - - file.write("".join(nvstr)) - - def numsurf(self, mesh, foomesh = False): - - global MATIDX_ERROR - - # local vars are faster and so better in tight loops - lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT - lc_MATIDX_ERROR = MATIDX_ERROR - lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED - lc_FACE_TWOSIDED = FACE_TWOSIDED - lc_MESH_TWOSIDED = MESH_TWOSIDED - - faces = mesh.faces - hasFaceUV = mesh.faceUV - if foomesh: - looseEdges = mesh.looseEdges - else: - looseEdges = get_loose_edges(mesh) - - file = self.file - - file.write("numsurf %s\n" % (len(faces) + len(looseEdges))) - - if not foomesh: verts = list(self.mesh.verts) - - materials = self.mesh.materials - mlist = self.mlist - matidx_error_reported = False - objmats = [] - for omat in materials: - if omat: objmats.append(omat.name) - else: objmats.append(None) - for f in faces: - if not objmats: - m_idx = 0 - elif objmats[f.mat] in mlist: - m_idx = mlist.index(objmats[f.mat]) - else: - if not lc_MATIDX_ERROR: - rdat = REPORT_DATA['warns'] - rdat.append("Object %s" % self.obj.name) - rdat.append("has at least one material *index* assigned but not") - rdat.append("defined (not linked to an existing material).") - rdat.append("Result: some faces may be exported with a wrong color.") - rdat.append("You can assign materials in the Edit Buttons window (F9).") - elif not matidx_error_reported: - midxmsg = "- Same for object %s." % self.obj.name - REPORT_DATA['warns'].append(midxmsg) - lc_MATIDX_ERROR += 1 - matidx_error_reported = True - m_idx = 0 - if lc_ADD_DEFAULT_MAT: m_idx -= 1 - refs = len(f) - flaglow = 0 # polygon - if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute - two_side = f.mode & lc_FACE_TWOSIDED - else: # global, for the whole mesh - two_side = self.mesh.mode & lc_MESH_TWOSIDED - two_side = (two_side > 0) << 1 - flaghigh = f.smooth | two_side - surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) - if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1 - matstr = "mat %s\n" % m_idx - refstr = "refs %s\n" % refs - u, v, vi = 0, 0, 0 - fvstr = [] - if foomesh: - for vert in f.v: - fvstr.append(str(vert.index)) - if hasFaceUV: - u = f.uv[vi][0] - v = f.uv[vi][1] - vi += 1 - fvstr.append(" %s %s\n" % (u, v)) - else: - for vert in f.v: - fvstr.append(str(verts.index(vert))) - if hasFaceUV: - u = f.uv[vi][0] - v = f.uv[vi][1] - vi += 1 - fvstr.append(" %s %s\n" % (u, v)) - - fvstr = "".join(fvstr) - - file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) - - # material for loose edges - edges_mat = 0 # default to first material - for omat in objmats: # but look for a material from this mesh - if omat in mlist: - edges_mat = mlist.index(omat) - if lc_ADD_DEFAULT_MAT: edges_mat += 1 - break - - for e in looseEdges: - fvstr = [] - #flaglow = 2 # 1 = closed line, 2 = line - #flaghigh = 0 - #surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) - surfstr = "SURF 0x02\n" - - fvstr.append("%d 0 0\n" % verts.index(e.v1)) - fvstr.append("%d 0 0\n" % verts.index(e.v2)) - fvstr = "".join(fvstr) - - matstr = "mat %d\n" % edges_mat # for now, use first material - refstr = "refs 2\n" # 2 verts - - file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) - - MATIDX_ERROR = lc_MATIDX_ERROR - -# End of Class AC3DExport - -from Blender.Window import FileSelector - -def report_data(): - global VERBOSE - - if not VERBOSE: return - - d = REPORT_DATA - msgs = { - '0main': '%s\nExporting meshes to AC3D format' % str(19*'-'), - '1warns': 'Warnings', - '2errors': 'Errors', - '3nosplit': 'Not split (because name starts with "=" or "$")', - '4noexport': 'Not exported (because name starts with "!" or "#")' - } - if NO_SPLIT: - l = msgs['3nosplit'] - l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0] - msgs['3nosplit'] = l - keys = msgs.keys() - keys.sort() - for k in keys: - msgk = msgs[k] - msg = '\n'.join(d[k[1:]]) - if msg: - print '\n-%s:' % msgk - print msg - -# File Selector callback: -def fs_callback(filename): - global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE - - if not filename.endswith('.ac'): filename = '%s.ac' % filename - - if bsys.exists(filename) and CONFIRM_OVERWRITE: - if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1: - return - - Blender.Window.WaitCursor(1) - starttime = bsys.time() - - export_dir = bsys.dirname(filename) - if export_dir != EXPORT_DIR: - EXPORT_DIR = export_dir - update_RegistryInfo() - - try: - file = open(filename, 'w') - except IOError, (errno, strerror): - error = "IOError #%s: %s" % (errno, strerror) - REPORT_DATA['errors'].append("Saving failed - %s." % error) - error_msg = "Couldn't save file!%%t|%s" % error - Blender.Draw.PupMenu(error_msg) - return - - try: - test = AC3DExport(OBJS, file) - except: - file.close() - raise - else: - file.close() - endtime = bsys.time() - starttime - REPORT_DATA['main'].append("Done. Saved to: %s" % filename) - REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime) - - if VERBOSE: report_data() - Blender.Window.WaitCursor(0) - - -# -- End of definitions - -scn = Blender.Scene.GetCurrent() - -if ONLY_SELECTED: - OBJS = list(scn.objects.context) -else: - OBJS = list(scn.objects) - -if not OBJS: - Blender.Draw.PupMenu('ERROR: no objects selected') -else: - fname = bsys.makename(ext=".ac") - if EXPORT_DIR: - fname = bsys.join(EXPORT_DIR, bsys.basename(fname)) - FileSelector(fs_callback, "Export AC3D", fname) diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py deleted file mode 100644 index 2f5512e7150..00000000000 --- a/release/scripts/ac3d_import.py +++ /dev/null @@ -1,783 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: -Name: 'AC3D (.ac)...' -Blender: 243 -Group: 'Import' -Tip: 'Import an AC3D (.ac) file.' -""" - -__author__ = "Willian P. Germano" -__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org", - "PLib 3d gaming lib, http://plib.sf.net") -__version__ = "2.48.1 2009-01-11" - -__bpydoc__ = """\ -This script imports AC3D models into Blender. - -AC3D is a simple and affordable commercial 3d modeller also built with OpenGL. -The .ac file format is an easy to parse text format well supported, -for example, by the PLib 3d gaming library. - -Supported:
- UV-textured meshes with hierarchy (grouping) information. - -Missing:
- The url tag is irrelevant for Blender. - -Known issues:
- - Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.
- -Config Options:
- - display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.
- - subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.
- - emis as mircol: store the emissive rgb color from AC3D as mirror color in Blender -- this is a hack to preserve the values and be able to export them using the equivalent option in the exporter.
- - textures dir (string): if non blank, when imported texture paths are -wrong in the .ac file, Blender will also look for them at this dir. - -Notes:
- - When looking for assigned textures, Blender tries in order: the actual -paths from the .ac file, the .ac file's dir and the default textures dir path -users can configure (see config options above). -""" - -# $Id$ -# -# -------------------------------------------------------------------------- -# AC3DImport version 2.43.1 Feb 21, 2007 -# Program versions: Blender 2.43 and AC3Db files (means version 0xb) -# changed: better triangulation of ngons, more fixes to support bad .ac files, -# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier) -# -------------------------------------------------------------------------- -# Thanks: Melchior Franz for extensive bug testing and reporting, making this -# version cope much better with old or bad .ac files, among other improvements; -# Stewart Andreason for reporting a serious crash; Francesco Brisa for the -# emis as mircol functionality (w/ patch). -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004-2009: Willian P. Germano, wgermano _at_ ig.com.br -# -# 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 ***** -# -------------------------------------------------------------------------- - -from math import radians - -import Blender -from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier -from Blender.sys import dirsep -from Blender.Mathutils import Vector, Matrix, Euler -from Blender.Geometry import PolyFill - -# Default folder for AC3D textures, to override wrong paths, change to your -# liking or leave as "": -TEXTURES_DIR = "" - -DISPLAY_TRANSP = True - -SUBDIV = True - -EMIS_AS_MIRCOL = False - - -tooltips = { - 'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.', - 'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.', - 'TEXTURES_DIR': 'Additional folder to look for missing textures.', - 'EMIS_AS_MIRCOL': 'Store emis color as mirror color in Blender.' -} - -def update_registry(): - global TEXTURES_DIR, DISPLAY_TRANSP, EMIS_AS_MIRCOL - rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV), ('EMIS_AS_MIRCOL', EMIS_AS_MIRCOL)]) - Registry.SetKey('ac3d_import', rd, True) - -rd = Registry.GetKey('ac3d_import', True) - -if rd: - if 'GROUP' in rd: - update_registry() - try: - TEXTURES_DIR = rd['TEXTURES_DIR'] - DISPLAY_TRANSP = rd['DISPLAY_TRANSP'] - SUBDIV = rd['SUBDIV'] - EMIS_AS_MIRCOL = rd['EMIS_AS_MIRCOL'] - except: - update_registry() -else: update_registry() - -if TEXTURES_DIR: - oldtexdir = TEXTURES_DIR - if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/') - if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep) - if oldtexdir != TEXTURES_DIR: update_registry() - - -VERBOSE = True -rd = Registry.GetKey('General', True) -if rd: - if rd.has_key('verbose'): - VERBOSE = rd['verbose'] - - -errmsg = "" - -# Matrix to align ac3d's coordinate system with Blender's one, -# it's a -90 degrees rotation around the x axis: -AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0]) - -AC_WORLD = 0 -AC_GROUP = 1 -AC_POLY = 2 -AC_LIGHT = 3 -AC_OB_TYPES = { - 'world': AC_WORLD, - 'group': AC_GROUP, - 'poly': AC_POLY, - 'light': AC_LIGHT - } - -AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types - -def inform(msg): - global VERBOSE - if VERBOSE: print msg - -def euler_in_radians(eul): - "Used while there's a bug in the BPY API" - eul.x = radians(eul.x) - eul.y = radians(eul.y) - eul.z = radians(eul.z) - return eul - -class Obj: - - def __init__(self, type): - self.type = type - self.dad = None - self.name = '' - self.data = '' - self.tex = '' - self.texrep = [1,1] - self.texoff = None - self.loc = [] - self.rot = [] - self.size = [] - self.crease = 30 - self.subdiv = 0 - self.vlist = [] - self.flist_cfg = [] - self.flist_v = [] - self.flist_uv = [] - self.elist = [] - self.matlist = [] - self.kids = 0 - - self.bl_obj = None # the actual Blender object created from this data - -class AC3DImport: - - def __init__(self, filename): - - global errmsg - - self.scene = Scene.GetCurrent() - - self.i = 0 - errmsg = '' - self.importdir = bsys.dirname(filename) - try: - file = open(filename, 'r') - except IOError, (errno, strerror): - errmsg = "IOError #%s: %s" % (errno, strerror) - Blender.Draw.PupMenu('ERROR: %s' % errmsg) - inform(errmsg) - return None - header = file.read(5) - header, version = header[:4], header[-1] - if header != 'AC3D': - file.close() - errmsg = 'AC3D header not found (invalid file)' - Blender.Draw.PupMenu('ERROR: %s' % errmsg) - inform(errmsg) - return None - elif version != 'b': - inform('AC3D file version 0x%s.' % version) - inform('This importer is for version 0xb, so it may fail.') - - self.token = {'OBJECT': self.parse_obj, - 'numvert': self.parse_vert, - 'numsurf': self.parse_surf, - 'name': self.parse_name, - 'data': self.parse_data, - 'kids': self.parse_kids, - 'loc': self.parse_loc, - 'rot': self.parse_rot, - 'MATERIAL': self.parse_mat, - 'texture': self.parse_tex, - 'texrep': self.parse_texrep, - 'texoff': self.parse_texoff, - 'subdiv': self.parse_subdiv, - 'crease': self.parse_crease} - - self.objlist = [] - self.mlist = [] - self.kidsnumlist = [] - self.dad = None - - self.lines = file.readlines() - self.lines.append('') - self.parse_file() - file.close() - - self.testAC3DImport() - - def parse_obj(self, value): - kidsnumlist = self.kidsnumlist - if kidsnumlist: - while not kidsnumlist[-1]: - kidsnumlist.pop() - if kidsnumlist: - self.dad = self.dad.dad - else: - inform('Ignoring unexpected data at end of file.') - return -1 # bad file with more objects than reported - kidsnumlist[-1] -= 1 - if value in AC_OB_TYPES: - new = Obj(AC_OB_TYPES[value]) - else: - if value not in AC_OB_BAD_TYPES_LIST: - AC_OB_BAD_TYPES_LIST.append(value) - inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value) - new = Obj(AC_OB_TYPES['poly']) - new.dad = self.dad - new.name = value - self.objlist.append(new) - - def parse_kids(self, value): - kids = int(value) - if kids: - self.kidsnumlist.append(kids) - self.dad = self.objlist[-1] - self.objlist[-1].kids = kids - - def parse_name(self, value): - name = value.split('"')[1] - self.objlist[-1].name = name - - def parse_data(self, value): - data = self.lines[self.i].strip() - self.objlist[-1].data = data - - def parse_tex(self, value): - line = self.lines[self.i - 1] # parse again to properly get paths with spaces - texture = line.split('"')[1] - self.objlist[-1].tex = texture - - def parse_texrep(self, trash): - trep = self.lines[self.i - 1] - trep = trep.split() - trep = [float(trep[1]), float(trep[2])] - self.objlist[-1].texrep = trep - self.objlist[-1].texoff = [0, 0] - - def parse_texoff(self, trash): - toff = self.lines[self.i - 1] - toff = toff.split() - toff = [float(toff[1]), float(toff[2])] - self.objlist[-1].texoff = toff - - def parse_mat(self, value): - i = self.i - 1 - lines = self.lines - line = lines[i].split() - mat_name = '' - mat_col = mat_amb = mat_emit = mat_spec_col = mat_mir_col = [0,0,0] - mat_alpha = 1 - mat_spec = 1.0 - - while line[0] == 'MATERIAL': - mat_name = line[1].split('"')[1] - mat_col = map(float,[line[3],line[4],line[5]]) - v = map(float,[line[7],line[8],line[9]]) - mat_amb = (v[0]+v[1]+v[2]) / 3.0 - v = map(float,[line[11],line[12],line[13]]) - mat_emit = (v[0]+v[1]+v[2]) / 3.0 - if EMIS_AS_MIRCOL: - mat_emit = 0 - mat_mir_col = map(float,[line[11],line[12],line[13]]) - - mat_spec_col = map(float,[line[15],line[16],line[17]]) - mat_spec = float(line[19]) / 64.0 - mat_alpha = float(line[-1]) - mat_alpha = 1 - mat_alpha - self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_mir_col, mat_alpha]) - i += 1 - line = lines[i].split() - - self.i = i - - def parse_rot(self, trash): - i = self.i - 1 - ob = self.objlist[-1] - rot = self.lines[i].split(' ', 1)[1] - rot = map(float, rot.split()) - matrix = Matrix(rot[:3], rot[3:6], rot[6:]) - ob.rot = matrix - size = matrix.scalePart() # vector - ob.size = size - - def parse_loc(self, trash): - i = self.i - 1 - loc = self.lines[i].split(' ', 1)[1] - loc = map(float, loc.split()) - self.objlist[-1].loc = Vector(loc) - - def parse_crease(self, value): - # AC3D: range is [0.0, 180.0]; Blender: [1, 80] - value = float(value) - self.objlist[-1].crease = int(value) - - def parse_subdiv(self, value): - self.objlist[-1].subdiv = int(value) - - def parse_vert(self, value): - i = self.i - lines = self.lines - obj = self.objlist[-1] - vlist = obj.vlist - n = int(value) - - while n: - line = lines[i].split() - line = map(float, line) - vlist.append(line) - n -= 1 - i += 1 - - if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues - vlist.insert(0, line) - - self.i = i - - def parse_surf(self, value): - i = self.i - is_smooth = 0 - double_sided = 0 - lines = self.lines - obj = self.objlist[-1] - vlist = obj.vlist - matlist = obj.matlist - numsurf = int(value) - NUMSURF = numsurf - - badface_notpoly = badface_multirefs = 0 - - while numsurf: - flags = lines[i].split()[1][2:] - if len(flags) > 1: - flaghigh = int(flags[0]) - flaglow = int(flags[1]) - else: - flaghigh = 0 - flaglow = int(flags[0]) - - is_smooth = flaghigh & 1 - twoside = flaghigh & 2 - nextline = lines[i+1].split() - if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file) - matid = 0 - if not matid in matlist: matlist.append(matid) - i += 2 - else: - matid = int(nextline[1]) - if not matid in matlist: matlist.append(matid) - nextline = lines[i+2].split() - i += 3 - refs = int(nextline[1]) - face = [] - faces = [] - edges = [] - fuv = [] - fuvs = [] - rfs = refs - - while rfs: - line = lines[i].split() - v = int(line[0]) + 1 # + 1 to avoid vindex == 0 - uv = [float(line[1]), float(line[2])] - face.append(v) - fuv.append(Vector(uv)) - rfs -= 1 - i += 1 - - if flaglow: # it's a line or closed line, not a polygon - while len(face) >= 2: - cut = face[:2] - edges.append(cut) - face = face[1:] - - if flaglow == 1 and edges: # closed line - face = [edges[-1][-1], edges[0][0]] - edges.append(face) - - else: # polygon - - # check for bad face, that references same vertex more than once - lenface = len(face) - if lenface < 3: - # less than 3 vertices, not a face - badface_notpoly += 1 - elif sum(map(face.count, face)) != lenface: - # multiple references to the same vertex - badface_multirefs += 1 - else: # ok, seems fine - if len(face) > 4: # ngon, triangulate it - polyline = [] - for vi in face: - polyline.append(Vector(vlist[vi])) - tris = PolyFill([polyline]) - for t in tris: - tri = [face[t[0]], face[t[1]], face[t[2]]] - triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]] - faces.append(tri) - fuvs.append(triuvs) - else: # tri or quad - faces.append(face) - fuvs.append(fuv) - - obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces)) - obj.flist_v.extend(faces) - obj.flist_uv.extend(fuvs) - obj.elist.extend(edges) # loose edges - - numsurf -= 1 - - if badface_notpoly or badface_multirefs: - inform('Object "%s" - ignoring bad faces:' % obj.name) - if badface_notpoly: - inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly) - if badface_multirefs: - inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs) - - self.i = i - - def parse_file(self): - i = 1 - lines = self.lines - line = lines[i].split() - - while line: - kw = '' - for k in self.token.keys(): - if line[0] == k: - kw = k - break - i += 1 - if kw: - self.i = i - result = self.token[kw](line[1]) - if result: - break # bad .ac file, stop parsing - i = self.i - line = lines[i].split() - - # for each group of meshes we try to find one that can be used as - # parent of the group in Blender. - # If not found, we can use an Empty as parent. - def found_parent(self, groupname, olist): - l = [o for o in olist if o.type == AC_POLY \ - and not o.kids and not o.rot and not o.loc] - if l: - for o in l: - if o.name == groupname: - return o - #return l[0] - return None - - def build_hierarchy(self): - blmatrix = AC_TO_BLEND_MATRIX - - olist = self.objlist[1:] - olist.reverse() - - scene = self.scene - - newlist = [] - - for o in olist: - kids = o.kids - if kids: - children = newlist[-kids:] - newlist = newlist[:-kids] - if o.type == AC_GROUP: - parent = self.found_parent(o.name, children) - if parent: - children.remove(parent) - o.bl_obj = parent.bl_obj - else: # not found, use an empty - empty = scene.objects.new('Empty', o.name) - o.bl_obj = empty - - bl_children = [c.bl_obj for c in children if c.bl_obj != None] - - o.bl_obj.makeParent(bl_children, 0, 1) - for child in children: - blob = child.bl_obj - if not blob: continue - if child.rot: - eul = euler_in_radians(child.rot.toEuler()) - blob.setEuler(eul) - if child.size: - blob.size = child.size - if not child.loc: - child.loc = Vector(0.0, 0.0, 0.0) - blob.setLocation(child.loc) - - newlist.append(o) - - for o in newlist: # newlist now only has objs w/o parents - blob = o.bl_obj - if not blob: - continue - if o.size: - o.bl_obj.size = o.size - if not o.rot: - blob.setEuler([1.5707963267948966, 0, 0]) - else: - matrix = o.rot * blmatrix - eul = euler_in_radians(matrix.toEuler()) - blob.setEuler(eul) - if o.loc: - o.loc *= blmatrix - else: - o.loc = Vector(0.0, 0.0, 0.0) - blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0 - - # XXX important: until we fix the BPy API so it doesn't increase user count - # when wrapping a Blender object, this piece of code is needed for proper - # object (+ obdata) deletion in Blender: - for o in self.objlist: - if o.bl_obj: - o.bl_obj = None - - def testAC3DImport(self): - - FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE'] - FACE_TEX = Mesh.FaceModes['TEX'] - MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH'] - - MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP'] - MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW'] - - scene = self.scene - - bl_images = {} # loaded texture images - missing_textures = [] # textures we couldn't find - - objlist = self.objlist[1:] # skip 'world' - - bmat = [] - has_transp_mats = False - for mat in self.mlist: - name = mat[0] - m = Material.New(name) - m.rgbCol = (mat[1][0], mat[1][1], mat[1][2]) - m.amb = mat[2] - m.emit = mat[3] - m.specCol = (mat[4][0], mat[4][1], mat[4][2]) - m.spec = mat[5] - m.mirCol = (mat[6][0], mat[6][1], mat[6][2]) - m.alpha = mat[7] - if m.alpha < 1.0: - m.mode |= MAT_MODE_ZTRANSP - has_transp_mats = True - bmat.append(m) - - if has_transp_mats: - for mat in bmat: - mat.mode |= MAT_MODE_TRANSPSHADOW - - obj_idx = 0 # index of current obj in loop - for obj in objlist: - if obj.type == AC_GROUP: - continue - elif obj.type == AC_LIGHT: - light = Lamp.New('Lamp') - object = scene.objects.new(light, obj.name) - #object.select(True) - obj.bl_obj = object - if obj.data: - light.name = obj.data - continue - - # type AC_POLY: - - # old .ac files used empty meshes as groups, convert to a real ac group - if not obj.vlist and obj.kids: - obj.type = AC_GROUP - continue - - mesh = Mesh.New() - object = scene.objects.new(mesh, obj.name) - #object.select(True) - obj.bl_obj = object - if obj.data: mesh.name = obj.data - mesh.degr = obj.crease # will auto clamp to [1, 80] - - if not obj.vlist: # no vertices? nothing more to do - continue - - mesh.verts.extend(obj.vlist) - - objmat_indices = [] - for mat in bmat: - if bmat.index(mat) in obj.matlist: - objmat_indices.append(bmat.index(mat)) - mesh.materials += [mat] - if DISPLAY_TRANSP and mat.alpha < 1.0: - object.transp = True - - for e in obj.elist: - mesh.edges.extend(e) - - if obj.flist_v: - mesh.faces.extend(obj.flist_v) - - facesnum = len(mesh.faces) - - if facesnum == 0: # shouldn't happen, of course - continue - - mesh.faceUV = True - - # checking if the .ac file had duplicate faces (Blender ignores them) - if facesnum != len(obj.flist_v): - # it has, ugh. Let's clean the uv list: - lenfl = len(obj.flist_v) - flist = obj.flist_v - uvlist = obj.flist_uv - cfglist = obj.flist_cfg - for f in flist: - f.sort() - fi = lenfl - while fi > 0: # remove data related to duplicates - fi -= 1 - if flist[fi] in flist[:fi]: - uvlist.pop(fi) - cfglist.pop(fi) - - img = None - if obj.tex != '': - if obj.tex in bl_images.keys(): - img = bl_images[obj.tex] - elif obj.tex not in missing_textures: - texfname = None - objtex = obj.tex - baseimgname = bsys.basename(objtex) - if bsys.exists(objtex) == 1: - texfname = objtex - elif bsys.exists(bsys.join(self.importdir, objtex)): - texfname = bsys.join(self.importdir, objtex) - else: - if baseimgname.find('\\') > 0: - baseimgname = bsys.basename(objtex.replace('\\','/')) - objtex = bsys.join(self.importdir, baseimgname) - if bsys.exists(objtex) == 1: - texfname = objtex - else: - objtex = bsys.join(TEXTURES_DIR, baseimgname) - if bsys.exists(objtex): - texfname = objtex - if texfname: - try: - img = Image.Load(texfname) - # Commented because it's unnecessary: - #img.xrep = int(obj.texrep[0]) - #img.yrep = int(obj.texrep[1]) - if img: - bl_images[obj.tex] = img - except: - inform("Couldn't load texture: %s" % baseimgname) - else: - missing_textures.append(obj.tex) - inform("Couldn't find texture: %s" % baseimgname) - - for i in range(facesnum): - f = obj.flist_cfg[i] - fmat = f[0] - is_smooth = f[1] - twoside = f[2] - bface = mesh.faces[i] - bface.smooth = is_smooth - if twoside: bface.mode |= FACE_TWOSIDE - if img: - bface.mode |= FACE_TEX - bface.image = img - bface.mat = objmat_indices.index(fmat) - fuv = obj.flist_uv[i] - if obj.texoff: - uoff = obj.texoff[0] - voff = obj.texoff[1] - urep = obj.texrep[0] - vrep = obj.texrep[1] - for uv in fuv: - uv[0] *= urep - uv[1] *= vrep - uv[0] += uoff - uv[1] += voff - - mesh.faces[i].uv = fuv - - # finally, delete the 1st vertex we added to prevent vindices == 0 - mesh.verts.delete(0) - - mesh.calcNormals() - - mesh.mode = MESH_AUTOSMOOTH - - # subdiv: create SUBSURF modifier in Blender - if SUBDIV and obj.subdiv > 0: - subdiv = obj.subdiv - subdiv_render = subdiv - # just to be safe: - if subdiv_render > 6: subdiv_render = 6 - if subdiv > 3: subdiv = 3 - modif = object.modifiers.append(Modifier.Types.SUBSURF) - modif[Modifier.Settings.LEVELS] = subdiv - modif[Modifier.Settings.RENDLEVELS] = subdiv_render - - obj_idx += 1 - - self.build_hierarchy() - scene.update() - -# End of class AC3DImport - -def filesel_callback(filename): - - inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename) - Window.WaitCursor(1) - starttime = bsys.time() - test = AC3DImport(filename) - Window.WaitCursor(0) - endtime = bsys.time() - starttime - inform('Done! Data imported in %.3f seconds.\n' % endtime) - -Window.EditMode(0) - -Window.FileSelector(filesel_callback, "Import AC3D", "*.ac") diff --git a/release/scripts/add_mesh_empty.py b/release/scripts/add_mesh_empty.py deleted file mode 100644 index 537bd1e2c3d..00000000000 --- a/release/scripts/add_mesh_empty.py +++ /dev/null @@ -1,13 +0,0 @@ -#!BPY -""" -Name: 'Empty mesh' -Blender: 243 -Group: 'AddMesh' -""" -import BPyAddMesh -import Blender - -def main(): - BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], []) - -main() \ No newline at end of file diff --git a/release/scripts/add_mesh_torus.py b/release/scripts/add_mesh_torus.py deleted file mode 100644 index 2941c56420e..00000000000 --- a/release/scripts/add_mesh_torus.py +++ /dev/null @@ -1,69 +0,0 @@ -#!BPY -""" -Name: 'Torus' -Blender: 243 -Group: 'AddMesh' -""" -import BPyAddMesh -import Blender -try: from math import cos, sin, pi -except: math = None - -def add_torus(PREF_MAJOR_RAD, PREF_MINOR_RAD, PREF_MAJOR_SEG, PREF_MINOR_SEG): - Vector = Blender.Mathutils.Vector - RotationMatrix = Blender.Mathutils.RotationMatrix - verts = [] - faces = [] - i1 = 0 - tot_verts = PREF_MAJOR_SEG * PREF_MINOR_SEG - for major_index in xrange(PREF_MAJOR_SEG): - verts_tmp = [] - mtx = RotationMatrix( 360 * float(major_index)/PREF_MAJOR_SEG, 3, 'z' ) - - for minor_index in xrange(PREF_MINOR_SEG): - angle = 2*pi*minor_index/PREF_MINOR_SEG - - verts.append( Vector(PREF_MAJOR_RAD+(cos(angle)*PREF_MINOR_RAD), 0, (sin(angle)*PREF_MINOR_RAD)) * mtx ) - if minor_index+1==PREF_MINOR_SEG: - i2 = (major_index)*PREF_MINOR_SEG - i3 = i1 + PREF_MINOR_SEG - i4 = i2 + PREF_MINOR_SEG - - else: - i2 = i1 + 1 - i3 = i1 + PREF_MINOR_SEG - i4 = i3 + 1 - - if i2>=tot_verts: i2 = i2-tot_verts - if i3>=tot_verts: i3 = i3-tot_verts - if i4>=tot_verts: i4 = i4-tot_verts - - faces.append( (i3,i4,i2,i1) ) - i1+=1 - - return verts, faces - -def main(): - Draw = Blender.Draw - PREF_MAJOR_RAD = Draw.Create(1.0) - PREF_MINOR_RAD = Draw.Create(0.25) - PREF_MAJOR_SEG = Draw.Create(48) - PREF_MINOR_SEG = Draw.Create(16) - - if not Draw.PupBlock('Add Torus', [\ - ('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\ - ('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring'),\ - ('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Number of segments for the main ring of the torus'),\ - ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Number of segments for the minor ring of the torus'),\ - ]): - return - - verts, faces = add_torus(PREF_MAJOR_RAD.val, PREF_MINOR_RAD.val, PREF_MAJOR_SEG.val, PREF_MINOR_SEG.val) - - BPyAddMesh.add_mesh_simple('Torus', verts, [], faces) - -if cos and sin and pi: - main() -else: - Blender.Draw.PupMenu("Error%t|This script requires a full python installation") - diff --git a/release/scripts/animation_bake_constraints.py b/release/scripts/animation_bake_constraints.py deleted file mode 100644 index 16855828460..00000000000 --- a/release/scripts/animation_bake_constraints.py +++ /dev/null @@ -1,792 +0,0 @@ -#!BPY - -""" -Name: 'Bake Constraints' -Blender: 246 -Group: 'Animation' -Tooltip: 'Bake a Constrained object/rig to IPOs' -Fillename: 'Bake_Constraint.py' -""" - -__author__ = "Roger Wickes (rogerwickes(at)yahoo.com)" -__script__ = "Animation Bake Constraints" -__version__ = "0.7" -__url__ = ["Communicate problems and errors, http://www.blenderartists.com/forum/private.php?do=newpm to PapaSmurf"] -__email__= ["Roger Wickes, rogerwickes@yahoo.com", "scripts"] -__bpydoc__ = """\ - -bake_constraints - -This script bakes the real-world LocRot of an object (the net effect of any constraints - -(Copy, Limit, Track, Follow, - that affect Location, Rotation) -(usually one constrained to match another's location and/or Tracked to another) -and creates a clone with a set of Ipo Curves named Ipo -These curves control a non-constrained object and thus make it mimic the constrained object -Actions can be then be edited without the need for the drivers/constraining objects - -Developed for use with MoCap data, where a bone is constrained to point at an empty -moving through space and time. This records the actual locrot of the armature -so that the motion can be edited, reoriented, scaled, and used as NLA Actions - -see also wiki Scripts/Manual/ Tutorial/Motion Capture
- -Usage:
- - Select the reference Object(s) you want to bake
- - Set the frame range to bake in the Anim Panel
- - Set the test code (if you want a self-test) in the RT field in the Anim Panel
- -- Set RT:1 to create a test armature
- -- Set RT: up to 100 for more debug messages and status updates
-
- - Run the script
- - The clone copy of the object is created and it has an IPO curve assigned to it.
- - The clone shadows the object by an offset locrot (see usrDelta)
- - That Object has Ipo Location and Rotation curves that make the clone mimic the movement
- of the selected object, but without using constraints.
- - If the object was an Armature, the clone's bones move identically in relation to the
- original armature, and an Action is created that drives the bone movements.
- -Version History: - 0.1: bakes Loc Rot for a constrained object - 0.2: bakes Loc and Rot for the bones within Armature object - 0.3: UI for setting options - 0.3.1 add manual to script library - 0.4: bake multiple objects - 0.5: root bone worldspace rotation - 0.6: re-integration with BPyArmature - 0.7: bakes parents and leaves clones selected - -License, Copyright, and Attribution: - by Roger WICKES May 2008, released under Blender Artistic Licence to Public Domain - feel free to add to any Blender Python Scripts Bundle. - Thanks to Jean-Baptiste PERIN, IdeasMan42 (Campbell Barton), Basil_Fawlty/Cage_drei (Andrew Cruse) - much lifted/learned from blender.org/documentation/245PytonDoc and wiki - some modules based on c3D_Import.py, PoseLib16.py and IPO/Armature code examples e.g. camera jitter - -Pseudocode: - Initialize - If at least one object is selected - For each selected object, - create a cloned object - remove any constraints on the clone - create or reset an ipo curve named like the object - for each frame - set the clone's locrot key based on the reference object - if it's an armature, - create an action (which is an Ipo for each bone) - for each frame of the animation - for each bone in the armature - set the key - Else you're a smurf - -Test Conditions and Regressions: - 1. (v0.1) Non-armatures (the cube), with ipo curve and constraints at the object level - 2. armatures, with ipo curve and constraints at the object level - 3. armatures, with bones that have ipo curves and constraints - 4. objects without parents, children with unselected parents, select children first. - -Naming conventions: - arm = a specific objec type armature - bone = bones that make up the skeleton of an armature - - ob = object, an instance of an object type - ebone = edit bone, a bone in edit mode - pbone = pose bone, a posed bone in an object - tst = testing, self-test routines - usr = user-entered or designated stuff -""" -######################################## - -import Blender -from Blender import * -from Blender.Mathutils import * -import struct -import string -import bpy -import BPyMessages -import BPyArmature -# reload(BPyArmature) -from BPyArmature import getBakedPoseData - -Vector= Blender.Mathutils.Vector -Euler= Blender.Mathutils.Euler -Matrix= Blender.Mathutils.Matrix #invert() function at least -RotationMatrix = Blender.Mathutils.RotationMatrix -TranslationMatrix= Blender.Mathutils.TranslationMatrix -Quaternion = Blender.Mathutils.Quaternion -Vector = Blender.Mathutils.Vector -POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT] - -#================= -# Global Variables -#================= - -# set senstitivity for displaying debug/console messages. 0=none, 100=max -# then call debug(num,string) to conditionally display status/info in console window -MODE=Blender.Get('rt') #execution mode: 0=run normal, 1=make test armature -DEBUG=Blender.Get('rt') #how much detail on internal processing for user to see. range 0-100 -BATCH=False #called from command line? is someone there? Would you like some cake? - -#there are two coordinate systems, the real, or absolute 3D space, -# and the local relative to a parent. -COORDINATE_SYSTEMS = ['local','real'] -COORD_LOCAL = 0 -COORD_REAL = 1 - -# User Settings - Change these options manually or via GUI (future TODO) -usrCoord = COORD_REAL # what the user wants -usrParent = False # True=clone keeps original parent, False = clone's parent is the clone of the original parent (if cloned) -usrFreeze = 2 #2=yes, 0=no. Freezes shadow object in place at current frame as origin -# delta is amount to offset/change from the reference object. future set in a ui, so technically not a constant -usrDelta = [10,10,0,0,0,0] #order specific - Loc xyz Rot xyz -usrACTION = True # Offset baked Action frames to start at frame 1 - -CURFRAME = 'curframe' #keyword to use when getting the frame number that the scene is presently on -ARMATURE = 'Armature' #en anglais -BONE_SPACES = ['ARMATURESPACE','BONESPACE'] - # 'ARMATURESPACE' - this matrix of the bone in relation to the armature - # 'BONESPACE' - the matrix of the bone in relation to itself - -#Ipo curves created are prefixed with a name, like Ipo_ or Bake_ followed by the object/bone name -#bakedArmName = "b." #used for both the armature class and object instance -usrObjectNamePrefix= "" -#ipoBoneNamePrefix = "" -# for example, if on entry an armature named Man was selected, and the object prefix was "a." -# on exit an armature and an IPO curve named a.Man exists for the object as a whole -# if that armature had bones (spine, neck, arm) and the bone prefix was "a." -# the bones and IPO curves will be (a.spine, a.neck, a.arm) - -R2D = 18/3.141592653589793 # radian to grad -BLENDER_VERSION = Blender.Get('version') - -# Gets the current scene, there can be many scenes in 1 blend file. -scn = Blender.Scene.GetCurrent() - -#================= -# Methods -#================= -######################################## -def debug(num,msg): #use log4j or just console here. - if DEBUG >= num: - if BATCH == False: - print 'debug: '[:num/10+7]+msg - #TODO: else write out to file (runs faster if it doesnt have to display details) - return - -######################################## -def error(str): - debug(0,'ERROR: '+str) - if BATCH == False: - Draw.PupMenu('ERROR%t|'+str) - return - -######################################## -def getRenderInfo(): - context=scn.getRenderingContext() - staframe = context.startFrame() - endframe = context.endFrame() - if endframe= 1: - for i in range(10): - curFrame+=frameinc - Blender.Set(CURFRAME,curFrame) # computes the constrained location of the 'real' objects - Blender.Redraw() - Blender.Set(CURFRAME, staFrame) - return - -######################################## -def bakeBones(ref_ob,arm_ob): #copy pose from ref_ob to arm_ob - scrub() - staFrame,endFrame,curFrame = getRenderInfo() - act = getBakedPoseData(ref_ob, staFrame, endFrame, ACTION_BAKE = True, ACTION_BAKE_FIRST_FRAME = usrACTION) # bake the pose positions of the reference ob to the armature ob - arm_ob.action = act - scrub() - - # user comprehension feature - change action name and channel ipo names to match the names of the bone they drive - debug (80,'Renaming each action ipo to match the bone they pose') - act.name = arm_ob.name - arm_channels = act.getAllChannelIpos() - pose= arm_ob.getPose() - pbones= pose.bones.values() #we want the bones themselves, not the dictionary lookup - for pbone in pbones: - debug (100,'Channel listing for %s: %s' % (pbone.name,arm_channels[pbone.name] )) - ipo=arm_channels[pbone.name] - ipo.name = pbone.name # since bone names are unique within an armature, the pose names can be the same since they are within an Action - - return - -######################################## -def getOrCreateCurve(ipo, curvename): - """ - Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo - Either an ipo curve named C{curvename} exists before the call then this curve is returned, - Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned - """ - try: - mycurve = ipo.getCurve(curvename) - if mycurve != None: - pass - else: - mycurve = ipo.addCurve(curvename) - except: - mycurve = ipo.addCurve(curvename) - return mycurve - -######################################## -def eraseCurve(ipo,numCurves): - debug(90,'Erasing %i curves for %' % (numCurves,ipo.GetName())) - for i in range(numCurves): - nbBezPoints= ipo.getNBezPoints(i) - for j in range(nbBezPoints): - ipo.delBezPoint(i) - return - -######################################## -def resetIPO(ipo): - debug(60,'Resetting ipo curve named %s' %ipo.name) - numCurves = ipo.getNcurves() #like LocX, LocY, etc - if numCurves > 0: - eraseCurve(ipo, numCurves) #erase data if one exists - return - -######################################## -def resetIPOs(ob): #resets all IPO curvess assocated with an object and its bones - debug(30,'Resetting any ipo curves linked to %s' %ob.getName()) - ipo = ob.getIpo() #may be None - ipoName = ipo.getName() #name of the IPO that guides/controls this object - debug(70,'Object IPO is %s' %ipoName) - try: - ipo = Ipo.Get(ipoName) - except: - ipo = Ipo.New('Object', ipoName) - resetIPO(ipo) - if ob.getType() == ARMATURE: - arm_data=ob.getData() - bones=arm_data.bones.values() - for bone in bones: - #for each bone: get the name and check for a Pose IPO - debug(10,'Processing '+ bone.name) - return - -######################################## -def parse(string,delim): - index = string.find(delim) # -1 if not found, else pointer to delim - if index+1: return string[:index] - return string - -######################################## -def newIpo(ipoName): #add a new Ipo object to the Blender scene - ipo=Blender.Ipo.New('Object',ipoName) - - ipo.addCurve('LocX') - ipo.addCurve('LocY') - ipo.addCurve('LocZ') - ipo.addCurve('RotX') - ipo.addCurve('RotY') - ipo.addCurve('RotZ') - return ipo - -######################################## -def makeUpaName(type,name): #i know this exists in Blender somewhere... - debug(90,'Making up a new %s name using %s as a basis.' % (type,name)) - name = (parse(name,'.')) - if type == 'Ipo': - ipoName = name # maybe we get lucky today - ext = 0 - extlen = 3 # 3 digit extensions, like hello.002 - success = False - while not(success): - try: - debug(100,'Trying %s' % ipoName) - ipo = Ipo.Get(ipoName) - #that one exists if we get here. add on extension and keep trying - ext +=1 - if ext>=10**extlen: extlen +=1 # go to more digits if 999 not found - ipoName = '%s.%s' % (name, str(ext).zfill(extlen)) - except: # could not find it - success = True - name=ipoName - else: - debug (0,'FATAL ERROR: I dont know how to make up a new %s name based on %s' % (type,ob)) - return None - return name - -######################################## -def createIpo(ob): #create an Ipo and curves and link them to this object - #first, we have to create a unique name - #try first with just the name of the object to keep things simple. - ipoName = makeUpaName('Ipo',ob.getName()) # make up a name for a new Ipo based on the object name - debug(20,'Ipo and LocRot curves called %s' % ipoName) - ipo=newIpo(ipoName) - ob.setIpo(ipo) #link them - return ipo - -######################################## -def getLocLocal(ob): - key = [ - ob.LocX, - ob.LocY, - ob.LocZ, - ob.RotX*R2D, #get the curves in this order - ob.RotY*R2D, - ob.RotZ*R2D - ] - return key - -######################################## -def getLocReal(ob): - obMatrix = ob.matrixWorld #Thank you IdeasMan42 - loc = obMatrix.translationPart() - rot = obMatrix.toEuler() - key = [ - loc.x, - loc.y, - loc.z, - rot.x/10, - rot.y/10, - rot.z/10 - ] - return key - -######################################## -def getLocRot(ob,space): - if space in xrange(len(COORDINATE_SYSTEMS)): - if space == COORD_LOCAL: - key = getLocLocal(ob) - return key - elif space == COORD_REAL: - key = getLocReal(ob) - return key - else: #hey, programmers make mistakes too. - debug(0,'Fatal Error: getLoc called with %i' % space) - return - -######################################## -def getCurves(ipo): - ipos = [ - ipo[Ipo.OB_LOCX], - ipo[Ipo.OB_LOCY], - ipo[Ipo.OB_LOCZ], - ipo[Ipo.OB_ROTX], #get the curves in this order - ipo[Ipo.OB_ROTY], - ipo[Ipo.OB_ROTZ] - ] - return ipos - -######################################## -def addPoint(time,keyLocRot,ipos): - if BLENDER_VERSION < 245: - debug(0,'WARNING: addPoint uses BezTriple') - for i in range(len(ipos)): - point = BezTriple.New() #this was new with Blender 2.45 API - point.pt = (time, keyLocRot[i]) - point.handleTypes = [1,1] - - ipos[i].append(point) - return ipos - -######################################## -def bakeFrames(ob,myipo): #bakes an object in a scene, returning the IPO containing the curves - myipoName = myipo.getName() - debug(20,'Baking frames for scene %s object %s to ipo %s' % (scn.getName(),ob.getName(),myipoName)) - ipos = getCurves(myipo) - #TODO: Gui setup idea: myOffset - # reset action to start at frame 1 or at location - myOffset=0 #=1-staframe - #loop through frames in the animation. Often, there is rollup and the mocap starts late - staframe,endframe,curframe = getRenderInfo() - for frame in range(staframe, endframe+1): - debug(80,'Baking Frame %i' % frame) - #tell Blender to advace to frame - Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects - if not BATCH: Blender.Redraw() # no secrets, let user see what we are doing - - #using the constrained Loc Rot of the object, set the location of the unconstrained clone. Yea! Clones are FreeMen - key = getLocRot(ob,usrCoord) #a key is a set of specifed exact channel values (LocRotScale) for a certain frame - key = [a+b for a,b in zip(key, usrDelta)] #offset to the new location - - myframe= frame+myOffset - Blender.Set(CURFRAME,myframe) - - time = Blender.Get('curtime') #for BezTriple - ipos = addPoint(time,key,ipos) #add this data at this time to the ipos - debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (myipoName, myframe, time, key[0], key[1], key[2], key[3], key[4], key[5])) - # eye-candy - smoothly rewind the animation, showing now how the clone match moves - if endframe-staframe <400 and not BATCH: - for frame in range (endframe,staframe,-1): #rewind - Blender.Set(CURFRAME,frame) # computes the constrained location of the 'real' objects - Blender.Redraw() - Blender.Set(CURFRAME,staframe) - Blender.Redraw() - - return ipos - -######################################## -def duplicateLinked(ob): - obType = ob.type - debug(10,'Duplicating %s Object named %s' % (obType,ob.getName())) - scn.objects.selected = [ob] -## rdw: simplified by just duplicating armature. kept code as reference for creating armatures -## disadvantage is that you cant have clone as stick and original as octahedron -## since they share the same Armature. User can click Make Single User button. -## if obType == ARMATURE: #build a copy from scratch -## myob= dupliArmature(ob) -## else: - Blender.Object.Duplicate() # Duplicate linked, including pose constraints. - myobs = Object.GetSelected() #duplicate is top on the list - myob = myobs[0] - if usrParent == False: - myob.clrParent(usrFreeze) - debug(20,'=myob= was created as %s' % myob.getName()) - return myob - -######################################## -def removeConstraints(ob): - for const in ob.constraints: - debug(90,'removed %s => %s' % (ob.name, const)) - ob.constraints.remove(const) - return - -######################################## -def removeConstraintsOb(ob): # from object or armature - debug(40,'Removing constraints from '+ob.getName()) - if BLENDER_VERSION > 241: #constraints module not available before 242 - removeConstraints(ob) - if ob.getType() == ARMATURE: - pose = ob.getPose() - for pbone in pose.bones.values(): - #bone = pose.bones[bonename] - removeConstraints(pbone) - #should also check if it is a deflector? - return - -######################################## -def deLinkOb(type,ob): #remove linkages - if type == 'Ipo': - success = ob.clearIpo() #true=there was one - if success: debug(80,'deLinked Ipo curve to %s' % ob.getName()) - return - -######################################## -def bakeObject(ob): #bakes the core object locrot and assigns the Ipo to a Clone - if ob != None: - # Clone the object - duplicate it, clean the clone, and create an ipo curve for the clone - myob = duplicateLinked(ob) #clone it - myob.setName(usrObjectNamePrefix + ob.getName()) - removeConstraintsOb(myob) #my object is a free man - deLinkOb('Ipo',myob) #kids, it's not nice to share. you've been lied to - if ob.getType() != ARMATURE: # baking armatures is based on bones, not object - myipo = createIpo(myob) #create own IPO and curves for the clone object - ipos = bakeFrames(ob,myipo) #bake the locrot for this obj for the scene frames - return myob - -######################################## -def bake(ob,par): #bakes an object of any type, linking it to parent - debug(0,'Baking %s object %s' % (ob.getType(), ob)) - clone = bakeObject(ob) #creates and bakes the object motion - if par!= None: - par.makeParent([clone]) - debug(20,"assigned object to parent %s" % par) - if ob.getType() == ARMATURE: -## error('Object baked. Continue with bones?') - bakeBones(ob,clone) #go into the bones and copy from -> to in frame range - #future idea: bakeMesh (net result of Shapekeys, Softbody, Cloth, Fluidsim,...) - return clone - -######################################## -def tstCreateArm(): #create a test armature in scene - # rip-off from http://www.blender.org/documentation/245PythonDoc/Pose-module.html - thank you! - - debug(0,'Making Test Armature') - # New Armature - arm_data= Armature.New('myArmature') - print arm_data - arm_ob = scn.objects.new(arm_data) - arm_data.makeEditable() - - # Add 4 bones - ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone(), Armature.Editbone()] - - # Name the editbones - ebones[0].name = 'Bone.001' - ebones[1].name = 'Bone.002' - ebones[2].name = 'Bone.003' - ebones[3].name = 'Bone.004' - - # Assign the editbones to the armature - for eb in ebones: - arm_data.bones[eb.name]= eb - - # Set the locations of the bones - ebones[0].head= Mathutils.Vector(0,0,0) - ebones[0].tail= Mathutils.Vector(0,0,1) #tip - ebones[1].head= Mathutils.Vector(0,0,1) - ebones[1].tail= Mathutils.Vector(0,0,2) - ebones[2].head= Mathutils.Vector(0,0,2) - ebones[2].tail= Mathutils.Vector(0,0,3) - ebones[3].head= Mathutils.Vector(0,0,3) - ebones[3].tail= Mathutils.Vector(0,0,4) - - ebones[1].parent= ebones[0] - ebones[2].parent= ebones[1] - ebones[3].parent= ebones[2] - - arm_data.update() - # Done with editing the armature - - # Assign the pose animation - arm_pose = arm_ob.getPose() - - act = arm_ob.getAction() - if not act: # Add a pose action if we dont have one - act = Armature.NLA.NewAction() - act.setActive(arm_ob) - - xbones=arm_ob.data.bones.values() - pbones = arm_pose.bones.values() - - frame = 1 - for pbone in pbones: # set bones to no rotation - pbone.quat[:] = 1.000,0.000,0.000,0.0000 - pbone.insertKey(arm_ob, frame, Object.Pose.ROT) - - # Set a different rotation at frame 25 - pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000 - pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000 - pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000 - pbones[3].quat[:] = 1.000,-0.2000,-0.3000,0.30000 - - frame = 25 - for i in xrange(4): - pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT) - - pbones[0].quat[:] = 1.000,0.000,0.000,0.0000 - pbones[1].quat[:] = 1.000,0.000,0.000,0.0000 - pbones[2].quat[:] = 1.000,0.000,0.000,0.0000 - pbones[3].quat[:] = 1.000,0.000,0.000,0.0000 - - frame = 50 - for pbone in pbones: # set bones to no rotation - pbone.quat[:] = 1.000,0.000,0.000,0.0000 - pbone.insertKey(arm_ob, frame, Object.Pose.ROT) - - return arm_ob - -######################################## -def tstMoveOb(ob): # makes a simple LocRot animation of object in the scene - anim = [ - #Loc Rot/10 - # - ( 0,0,0, 0, 0, 0), #frame 1 origin - ( 1,0,0, 0, 0, 0), #frame 2 - ( 1,1,0, 0, 0, 0), - ( 1,1,1, 0, 0, 0), - ( 1,1,1,4.5, 0, 0), - ( 1,1,1,4.5,4.5, 0), - ( 1,1,1,4.5,4.5,4.5) - ] - space = COORD_LOCAL - ipo = createIpo(ob) #create an Ipo and curves for this object - ipos = getCurves(ipo) - - # span this motion over the currently set anim range - # to set points, i need time but do not know how it is computed, so will have to advance the animation - staframe,endframe,curframe = getRenderInfo() - - frame = staframe #x position of new ipo datapoint. set to staframe if you want a match - frameDelta=(endframe-staframe)/(len(anim)) #accomplish the animation in frame range - for key in anim: #effectively does a getLocRot() - #tell Blender to advace to frame - Blender.Set('curframe',frame) # computes the constrained location of the 'real' objects - time = Blender.Get('curtime') - - ipos = addPoint(time,key,ipos) #add this data at this time to the ipos - - debug(100,'%s %i %.3f %.2f %.2f %.2f %.2f %.2f %.2f' % (ipo.name, frame, time, key[0], key[1], key[2], key[3], key[4], key[5])) - frame += frameDelta - Blender.Set(CURFRAME,curframe) # reset back to where we started - return -#================= -# Program Template -#================= -######################################## -def main(): - # return code set via rt button in Blender Buttons Scene Context Anim panel - if MODE == 1: #create test armature #1 - ob = tstCreateArm() # make test arm and select it - tstMoveOb(ob) - scn.objects.selected = [ob] - - obs= Blender.Object.GetSelected() #scn.objects.selected - obs= sortObjects(obs) - debug(0,'Baking %i objects' % len(obs)) - - if len(obs) >= 1: # user might have multiple objects selected - i= 0 - clones=[] # my clone army - for ob in obs: - par= ob.getParent() - if not usrParent: - if par in obs: - par= clones[obs.index(par)] - clones.append(bake(ob,par)) - scn.objects.selected = clones - else: - error('Please select at least one object') - return - -######################################## -def benchmark(): # This lets you benchmark (time) the script's running duration - Window.WaitCursor(1) - t = sys.time() - debug(60,'%s began at %.0f' %(__script__,sys.time())) - - # Run the function on the active scene - in_editmode = Window.EditMode() - if in_editmode: Window.EditMode(0) - - main() - - if in_editmode: Window.EditMode(1) - - # Timing the script is a good way to be aware on any speed hits when scripting - debug(0,'%s Script finished in %.2f seconds' % (__script__,sys.time()-t) ) - Window.WaitCursor(0) - return - -######################################## -# This lets you can import the script without running it -if __name__ == '__main__': - debug(0, "------------------------------------") - debug(0, "%s %s Script begins with mode=%i debug=%i batch=%s" % (__script__,__version__,MODE,DEBUG,BATCH)) - benchmark() diff --git a/release/scripts/animation_clean.py b/release/scripts/animation_clean.py deleted file mode 100644 index fc44f264ac1..00000000000 --- a/release/scripts/animation_clean.py +++ /dev/null @@ -1,192 +0,0 @@ -#!BPY - -""" -Name: 'Clean Animation Curves' -Blender: 249 -Group: 'Animation' -Tooltip: 'Remove unused keyframes for ipo curves' -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2008-2009: Blender Foundation -# -# 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, -# -------------------------------------------------------------------------- - -import bpy -from Blender import IpoCurve, Draw, Window - -def clean_ipos(ipos): - eul = 0.001 - - def isflat(vec): - prev_y = vec[0][1] - mid_y = vec[1][1] - next_y = vec[2][1] - - # flat status for prev and next - return abs(mid_y-prev_y) < eul, abs(mid_y-next_y) < eul - - - - X=0 - Y=1 - PREV=0 - MID=1 - NEXT=2 - - LEFT = 0 - RIGHT = 1 - - TOT = 0 - TOTBEZ = 0 - # for ipo in bpy.data.ipos: - for ipo in ipos: - if ipo.lib: - continue - # print ipo - for icu in ipo: - interp = icu.interpolation - extend = icu.extend - - bezierPoints = icu.bezierPoints - bezierVecs = [bez.vec for bez in bezierPoints] - - l = len(bezierPoints) - - TOTBEZ += l - - # our aim is to simplify this ipo as much as possible! - if interp == IpoCurve.InterpTypes.BEZIER or interp == interp == IpoCurve.InterpTypes.LINEAR: - #print "Not yet supported" - - if interp == IpoCurve.InterpTypes.BEZIER: - flats = [isflat(bez) for bez in bezierVecs] - else: - # A bit of a waste but fake the locations for these so they will always be flats - # IS better then too much duplicate code. - flats = [(True, True)] * l - for v in bezierVecs: - v[PREV][Y] = v[NEXT][Y] = v[MID][Y] - - - # remove middle points - if l>2: - done_nothing = False - - while not done_nothing and len(bezierVecs) > 2: - done_nothing = True - i = l-2 - - while i > 0: - #print i - #print i, len(bezierVecs) - if flats[i]==(True,True) and flats[i-1][RIGHT] and flats[i+1][LEFT]: - - if abs(bezierVecs[i][MID][Y] - bezierVecs[i-1][MID][Y]) < eul and abs(bezierVecs[i][MID][Y] - bezierVecs[i+1][MID][Y]) < eul: - done_nothing = False - - del flats[i] - del bezierVecs[i] - icu.delBezier(i) - TOT += 1 - l-=1 - i-=1 - - # remove endpoints - if extend == IpoCurve.ExtendTypes.CONST and len(bezierVecs) > 1: - #print l, len(bezierVecs) - # start - - while l > 2 and (flats[0][RIGHT] and flats[1][LEFT] and (abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul)): - print "\tremoving 1 point from start of the curve" - del flats[0] - del bezierVecs[0] - icu.delBezier(0) - TOT += 1 - l-=1 - - - # End - while l > 2 and flats[-2][RIGHT] and flats[-1][LEFT] and (abs(bezierVecs[-2][MID][Y] - bezierVecs[-1][MID][Y]) < eul): - print "\tremoving 1 point from end of the curve", l - del flats[l-1] - del bezierVecs[l-1] - icu.delBezier(l-1) - TOT += 1 - l-=1 - - - - if l==2: - if isflat( bezierVecs[0] )[RIGHT] and isflat( bezierVecs[1] )[LEFT] and abs(bezierVecs[0][MID][Y] - bezierVecs[1][MID][Y]) < eul: - # remove the second point - print "\tremoving 1 point from 2 point bez curve" - # remove the second point - del flats[1] - del bezierVecs[1] - icu.delBezier(1) - TOT+=1 - l-=1 - - # Change to linear for faster evaluation - ''' - if l==1: - print 'Linear' - icu.interpolation = IpoCurve.InterpTypes.LINEAR - ''' - - - - - if interp== IpoCurve.InterpTypes.CONST: - print "Not yet supported" - - print 'total', TOT, TOTBEZ - return TOT, TOTBEZ - -def main(): - ret = Draw.PupMenu('Clean Selected Objects Ipos%t|Object IPO%x1|Object Action%x2|%l|All IPOs (be careful!)%x3') - - sce = bpy.data.scenes.active - ipos = [] - - if ret == 3: - ipos.extend(list(bpy.data.ipos)) - else: - for ob in sce.objects.context: - if ret == 1: - ipo = ob.ipo - if ipo: - ipos.append(ipo) - - elif ret == 2: - action = ob.action - if action: - ipos.extend([ipo for ipo in action.getAllChannelIpos().values() if ipo]) - - - - if not ipos: - Draw.PupMenu('Error%t|No ipos found') - else: - total_removed, total = clean_ipos(ipos) - Draw.PupMenu('Done!%t|Removed ' + str(total_removed) + ' of ' + str(total) + ' points') - - Window.RedrawAll() - - -if __name__ == '__main__': - main() diff --git a/release/scripts/animation_trajectory.py b/release/scripts/animation_trajectory.py deleted file mode 100644 index 55a670b66b1..00000000000 --- a/release/scripts/animation_trajectory.py +++ /dev/null @@ -1,575 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: <- these words are ignored -Name: 'Trajectory' -Blender: 243 -Group: 'Animation' -Tip: 'See Trajectory of selected object' -""" - -__author__ = '3R - R3gis' -__version__ = '2.43' -__url__ = ["Script's site , http://blenderfrance.free.fr/python/Trajectory_en.htm","Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] -__email__=["3R, r3gis@free.fr"] - - -__bpydoc__ = """ - -Usage: - -* Launch with alt+P (or put it in .script folder) - -Allow to see in real time trajectory of selected object. - -On first run, it ask you -- If you want that actually selected object have they trajectory always shown -- If you want to use Space Handler or a Scriptlink in Redraw mode -- Future and Past : it is the frame in past and future -of the beggining and the end of the path -- Width of line that represent the trajectory - -Then the object's trajectory will be shown in all 3D areas. -When trajectory is red, you can modifiy it by moving object. -When trajectory is blue and you want to be able to modify it, inser a Key (I-Key) - -Points appears on trajectory : -- Left Clic to modify position -- Right Clic to go to the frame it represents - -Notes:
-In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on -In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory - - -""" - - -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004-2006: Regis Montoya -# -# 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 ***** -# -------------------------------------------------------------------------- -################################# -# by 3R - 26/08/05 -# for any problem : -# r3gis@free.fr -# ou sur le newsgroup: -# http://zoo-logique.org/3D.Blender/ -################################# -#Many thanks to cambo for his fixes -################################# - - - -import Blender - - -scene= Blender.Scene.GetCurrent() - - -#Writing -def write_script(name, script): - global scene - #List texts and their name - #write : type of writing : 1->New, 2->Overwrite - scripting= None - for text in Blender.Text.Get(): - if text.name==name and text.asLines()[1] != "#"+str(__version__): - scripting = text - scripting.clear() - scripting.write(script) - break - - if not scripting: - scripting= Blender.Text.New(name) - scripting.write(script) - -def link_script(name, type): - global scene - scriptlinks = scene.getScriptLinks(type) # none or list - if not scriptlinks or name not in scriptlinks: - scene.addScriptLink(name, type) - - -#Deleting of a text -def text_remove(name): - global scene - #try to delete text if already linked - try: - text= Blender.Text.Get(name) - # Texte.clear() - scene.clearScriptLinks([name]) - Blender.Text.unlink(text) - except: - print('---Initialisation of Trajectory_'+str(__version__)+'.py---') - -#Whether is already running, also check if it's the last version of the script : second line contain the version fo the script -ask_modif= 0 # Default -for text in Blender.Text.Get(): - if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__): - #We ask if script modify his seetings, keep it or stop script - ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|") - if ask_modif==-1: # user canceled. - ask_modif= 1 - break - -selection_mode= 0 -future= 35 -past= 20 -width= 2 - -#In modify case -if ask_modif==0: - handle_mode= Blender.Draw.Create(0) - selection_mode= Blender.Draw.Create(0) - future= Blender.Draw.Create(35) - past= Blender.Draw.Create(20) - width= Blender.Draw.Create(2) - - block= [] - block.append(("Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option... - block.append(("Always Draw", selection_mode, "Selected object will have their trajectory always shown")) - block.append(("Past :", past, 1, 900)) - block.append(("Futur:", future, 1, 900)) - block.append(("Width:", width, 1,5)) - - if not Blender.Draw.PupBlock("Trajectory seetings", block): - ask_modif=1 - - handle_mode= handle_mode.val - selection_mode= selection_mode.val - future= future.val - past= past.val - width= width.val - - -#put names of selected objects in objects_select if option choosen by user -if selection_mode==1: - objects_select= [ob.name for ob in scene.objects.context] -else: - objects_select= [] - - -try: - if handle_mode==1: - DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n" - else: - DrawPart="#!BPY\n" -except:DrawPart="#BadlyMade" - - -#Here is the script to write in Blender and to link, options are also written now -DrawPart=DrawPart+"#"+str(__version__)+""" -#This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode. -#Author : 3R - Regis Montoya -#It's better to use the Trajectory_"version_number".py -#You can modify the two following value to change the path settings -future="""+str(future)+""" -past="""+str(past)+""" -object_init_names="""+str(objects_select)+""" - - -import Blender, math -from Blender import BGL, Draw, Ipo -from Blender.BGL import * -from Blender.Draw import * -from math import * - -from Blender.Mathutils import Vector - -#take actual frame -frameC=Blender.Get('curframe') -scene = Blender.Scene.GetCurrent() -render_context=scene.getRenderingContext() -#ajust number of frames with NewMap and OldMapvalue values -k=1.00*render_context.oldMapValue()/render_context.newMapValue() -if k<1: - tr=-1*int(log(k*0.1, 10)) -else: - tr=-1*int(log(k, 10)) -#The real and integer frame to compare to ipos keys frames -frameCtr=round(frameC*k, tr) -frameCr=frameC*k -frameC=int(round(frameC*k, 0)) - - -#List objects that we have to show trajectory in $objects -# In this case, using a dict for unique objects is the fastest way. -object_dict= dict([(ob.name, ob) for ob in scene.objects.context]) -for obname in object_init_names: - if not object_dict.has_key(obname): - try: # Object may be removed. - object_dict[obname]= Blender.Object.Get(obname) - except: - pass # object was removed. - -#This fonction give the resulting matrix of all parents at a given frame -#parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object -def matrixForTraj(frame, parent_list): - DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]) - - for parent_data in parent_list: - parent_ob= parent_data[0] - - try: X= parent_data[5][frame]*pi/18 - except: X= parent_ob.RotX - try: Y= parent_data[6][frame]*pi/18 - except: Y= parent_ob.RotY - try: Z= parent_data[7][frame]*pi/18 - except: Z= parent_ob.RotZ - try: LX= parent_data[2][frame] - except: LX= parent_ob.LocX - try: LY= parent_data[3][frame] - except: LY= parent_ob.LocY - try: LZ= parent_data[4][frame] - except: LZ= parent_ob.LocZ - try: SX= parent_data[8][frame] - except: SX= parent_ob.SizeX - try: SY= parent_data[9][frame] - except: SY= parent_ob.SizeY - try: SZ= parent_data[10][frame] - except: SZ= parent_ob.SizeZ - - NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0], - [(-cos(X)*sin(Z)+sin(Y)*sin(X)*cos(Z))*SY,(sin(X)*sin(Y)*sin(Z)+cos(X)*cos(Z))*SY,sin(X)*cos(Y)*SY,0], - [(cos(X)*sin(Y)*cos(Z)+sin(X)*sin(Z))*SZ,(cos(X)*sin(Y)*sin(Z)-sin(X)*cos(Z))*SZ,SZ*cos(X)*cos(Y),0], - [LX,LY,LZ,1]) - DecMatC=DecMatC*parent_data[1]*NMat - return DecMatC - -##### -TestLIST=[] -matview=Blender.Window.GetPerspMatrix() -########### -#Fonction to draw trajectories -########### - -def Trace_Traj(ob): - global TestLIST, matview - #we draw trajectories for all objects in list - - LocX=[] - LocY=[] - LocZ=[] - #List with trajectories' vertexs - vertexX=[] - - contextIpo= ob.ipo - if contextIpo: - ipoLocX=contextIpo[Ipo.OB_LOCX] - ipoLocY=contextIpo[Ipo.OB_LOCY] - ipoLocZ=contextIpo[Ipo.OB_LOCZ] - ipoTime=contextIpo[Ipo.OB_TIME] - else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except) - ipoLocX= ipoLocY= ipoLocZ= ipoTime= None - - if ipoTime: - return 0 - - #Get all parents of ob - parent=ob.parent - backup_ob= ob - child= ob - parent_list= [] - - #Get parents's infos : - #list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z] - while parent: - Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise) - Init_Mat.invert() - Init_Mat=Init_Mat*child.getMatrix('localspace') - Init_Mat=parent.getMatrix()*Init_Mat - Init_Mat.invert() - - contextIpo= parent.ipo # None or IPO - if contextIpo: - ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX] - ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY] - ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ] - ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX] - ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY] - ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ] - ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX] - ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY] - ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ] - else: - ipo_Parent_LocX=ipo_Parent_LocY=ipo_Parent_LocZ=\ - ipo_Parent_RotX=ipo_Parent_RotY=ipo_Parent_RotZ=\ - ipo_Parent_SizeX=ipo_Parent_SizeY=ipo_Parent_SizeZ= None - - parent_list.append([parent, Init_Mat, ipo_Parent_LocX, ipo_Parent_LocY, ipo_Parent_LocZ, ipo_Parent_RotX, ipo_Parent_RotY, ipo_Parent_RotZ, ipo_Parent_SizeX, ipo_Parent_SizeY, ipo_Parent_SizeZ]) - - child=parent - parent=parent.parent - - #security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing - for parent in parent_list: - if parent[0].type == 'Curve': - if parent[0].data.flag & 1<<4: # Follow path, 4th bit - return 1 - - #ob >> re-assign obj and not parent - ob= backup_ob - ob= backup_ob - - - if ipoLocX: LXC= ipoLocX[frameC] - else: LXC= ob.LocX - if ipoLocY: LYC= ipoLocY[frameC] - else: LYC= ob.LocY - if ipoLocZ: LZC= ipoLocZ[frameC] - else: LZC= ob.LocZ - - vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1]) - color=[0, 1] - - #If trajectory is being modified and we are at a frame where a ipo key already exist - if round(ob.LocX, 5)!=round(LXC, 5): - for bez in ipoLocX.bezierPoints: - if round(bez.pt[0], tr)==frameCtr: - bez.pt = [frameCr, vect[0]] - ipoLocX.recalc() - if round(ob.LocY, 5)!=round(LYC, 5): - for bez in ipoLocY.bezierPoints: - if round(bez.pt[0], tr)==frameCtr: - bez.pt = [frameCr, vect[1]] - ipoLocY.recalc() - if round(ob.LocZ, 5)!=round(LZC, 5): - for bez in ipoLocZ.bezierPoints: - if round(bez.pt[0], tr)==frameCtr: - bez.pt = [frameCr, vect[2]] - ipoLocZ.recalc() - - #change trajectory color if at an ipoKey - VertexFrame=[] - bezier_Coord=0 - if ipoLocX: # FIXED like others it was just in case ipoLocX==None - for bez in ipoLocX.bezierPoints: - bezier_Coord=round(bez.pt[0], tr) - if bezier_Coord not in VertexFrame: - VertexFrame.append(bezier_Coord) - if bezier_Coord==frameCtr: - color=[1, color[1]-0.3] - if ipoLocY: # FIXED - for bez in ipoLocY.bezierPoints: - bezier_Coord=round(bez.pt[0], tr) - if bezier_Coord not in VertexFrame: - VertexFrame.append(bezier_Coord) - if round(bez.pt[0], tr)==frameCtr: - color=[1, color[1]-0.3] - if ipoLocZ: # FIXED - for bez in ipoLocZ.bezierPoints: - bezier_Coord=round(bez.pt[0], tr) - if bezier_Coord not in VertexFrame: - VertexFrame.append(bezier_Coord) - if round(bez.pt[0], tr)==frameCtr: - color=[1, color[1]-0.3] - - - #put in LocX, LocY and LocZ all points of trajectory - for frame in xrange(frameC-past, frameC+future): - DecMat=matrixForTraj(frame, parent_list) - - if ipoLocX: LX= ipoLocX[frame] - else: LX= ob.LocX - if ipoLocY: LY= ipoLocY[frame] - else: LY= ob.LocY - if ipoLocZ: LZ= ipoLocZ[frame] - else: LZ= ob.LocZ - - vect=Vector(LX, LY, LZ)*DecMat - LocX.append(vect[0]) - LocY.append(vect[1]) - LocZ.append(vect[2]) - - - #draw part : get current view - MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)] - - MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff) - - glLoadIdentity() - glMatrixMode(GL_PROJECTION) - glPushMatrix() - glLoadMatrixf(MatBuff) - - #draw trajectory line - glLineWidth("""+str(width)+""") - - glBegin(GL_LINE_STRIP) - for i in xrange(len(LocX)): - glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1]) - glVertex3f(LocX[i], LocY[i], LocZ[i]) - - glEnd() - - #draw trajectory's "vertexs" - if not Blender.Window.EditMode(): - glPointSize(5) - glBegin(GL_POINTS) - TestPOINTS=[] - TestFRAME=[] - i=0 - for frame in VertexFrame: - ix=int(frame)-frameC+past - if ix>=0 and ixpt[0]-4 and mouse_co[1]>pt[1]-4 and mouse_co[1]R and R>L can use the same code - def IS_XMIRROR_SOURCE(xval): - '''Source means is this the value we want to copy from''' - - if PREF_MODE_L2R: - if xval<0: return True - else: return False - else: # PREF_MODE_R2L - if xval<0: return False - else: return True - - if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2 - editbone2.head= VecXFlip(h1) - else: - ''' - assume h2.x<0 - not a big deal if were wrong, - its unlikely to ever happen because the bones would both be on the same side. - ''' - - # head bone 2s negative, so copy it to h1 - editbone1.head= VecXFlip(h2) - - # Same as above for tail - if IS_XMIRROR_SOURCE(t1.x): - editbone2.tail= VecXFlip(t1) - else: - editbone1.tail= VecXFlip(t2) - - # Copy roll from 1 bone to another, use the head's location to decide which side it's on. - if IS_XMIRROR_SOURCE(editbone1.head): - editbone2.roll= -editbone1.roll - else: - editbone1.roll= -editbone2.roll - - -def armature_symetry(\ - arm_ob,\ - PREF_MAX_DIST,\ - PREF_XMID_SNAP,\ - PREF_XZERO_THRESH,\ - PREF_MODE_L2R,\ - PREF_MODE_R2L,\ - PREF_SEL_ONLY): - - ''' - Main function that does all the work, - return the number of - ''' - arm_data= arm_ob.data - arm_data.makeEditable() - - # Get the bones - bones= [] - HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT - BONE_SELECTED= Blender.Armature.BONE_SELECTED - - if PREF_SEL_ONLY: - for eb in arm_data.bones.values(): - options= eb.options - if HIDDEN_EDIT not in options and BONE_SELECTED in options: - bones.append(eb) - else: - # All non hidden bones - for eb in arm_data.bones.values(): - options= eb.options - if HIDDEN_EDIT not in options: - bones.append(eb) - - del HIDDEN_EDIT # remove temp variables - del BONE_SELECTED - - # Store the numder of bones we have modified for a message - tot_editbones= len(bones) - tot_editbones_modified= 0 - - if PREF_XMID_SNAP: - # Remove bones that are in the middle (X Zero) - # reverse loop so we can remove items in the list. - for eb_idx in xrange(len(bones)-1, -1, -1): - edit_bone= bones[eb_idx] - if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2: - - # This is a center bone, clamp and remove from the bone list so we dont use again. - if edit_bone.tail.x or edit_bone.head.x: - tot_editbones_modified += 1 - - edit_bone.tail.x= edit_bone.head.x= 0 - del bones[eb_idx] - - - - - bone_comparisons= [] - - # Compare every bone with every other bone, shouldn't be too slow. - # These 2 "for" loops only compare once - for eb_idx_a in xrange(len(bones)-1, -1, -1): - edit_bone_a= bones[eb_idx_a] - for eb_idx_b in xrange(eb_idx_a-1, -1, -1): - edit_bone_b= bones[eb_idx_b] - # Error float the first value from editbone_mirror_diff() so we can sort the resulting list. - bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b)) - - - bone_comparisons.sort() # best matches first - - # Make a dict() of bone names that have been used so we dont mirror more then once - bone_mirrored= {} - - for error, editbone1, editbone2 in bone_comparisons: - # print 'Trying to merge at error %.3f' % error - if error > PREF_MAX_DIST: - # print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST - break - - if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name): - # Were not used, execute the mirror - editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L) - # print 'Merging bones' - - # Add ourselves so we aren't touched again - bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4 - bone_mirrored[editbone2.name] = None - - # If both options are enabled, then we have changed 2 bones - tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L - - arm_data.update() # get out of armature editmode - return tot_editbones, tot_editbones_modified - - -def main(): - ''' - User interface function that gets the options and calls armature_symetry() - ''' - - scn= bpy.data.scenes.active - arm_ob= scn.objects.active - - if not arm_ob or arm_ob.type!='Armature': - Blender.Draw.PupMenu('No Armature object selected.') - return - - # Cant be in editmode for armature.makeEditable() - is_editmode= Blender.Window.EditMode() - if is_editmode: Blender.Window.EditMode(0) - Draw= Blender.Draw - - # Defaults for the user input - PREF_XMID_SNAP= Draw.Create(1) - PREF_MAX_DIST= Draw.Create(0.4) - PREF_XZERO_THRESH= Draw.Create(0.02) - - PREF_MODE_L2R= Draw.Create(1) - PREF_MODE_R2L= Draw.Create(0) - PREF_SEL_ONLY= Draw.Create(1) - - pup_block = [\ - 'Left (-), Right (+)',\ - ('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\ - ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\ - '',\ - ('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\ - ('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\ - ('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ - ('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\ - ] - - # Popup, exit if the user doesn't click OK - if not Draw.PupBlock("X Mirror mesh tool", pup_block): - return - - # Replace the variables with their button values. - PREF_XMID_SNAP= PREF_XMID_SNAP.val - PREF_MAX_DIST= PREF_MAX_DIST.val - PREF_MODE_L2R= PREF_MODE_L2R.val - PREF_MODE_R2L= PREF_MODE_R2L.val - PREF_XZERO_THRESH= PREF_XZERO_THRESH.val - PREF_SEL_ONLY= PREF_SEL_ONLY.val - - # If both are off assume mid-point and enable both - if not PREF_MODE_R2L and not PREF_MODE_L2R: - PREF_MODE_R2L= PREF_MODE_L2R= True - - - tot_editbones, tot_editbones_modified = armature_symetry(\ - arm_ob,\ - PREF_MAX_DIST,\ - PREF_XMID_SNAP,\ - PREF_XZERO_THRESH,\ - PREF_MODE_L2R,\ - PREF_MODE_R2L,\ - PREF_SEL_ONLY) - - if is_editmode: Blender.Window.EditMode(1) - - # Redraw all views before popup - Blender.Window.RedrawAll() - - # Print results - if PREF_SEL_ONLY: - msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones) - else: - msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones) - - - Blender.Draw.PupMenu(msg) - -# Check for __main__ so this function can be imported by other scripts without running the script. -if __name__=='__main__': - main() diff --git a/release/scripts/bevel_center.py b/release/scripts/bevel_center.py deleted file mode 100644 index 637ed08127f..00000000000 --- a/release/scripts/bevel_center.py +++ /dev/null @@ -1,474 +0,0 @@ -#!BPY -# -*- coding: utf-8 -*- -""" Registration info for Blender menus -Name: 'Bevel Center' -Blender: 243 -Group: 'Mesh' -Tip: 'Bevel selected faces, edges, and vertices' -""" - -__author__ = "Loic BERTHE" -__url__ = ("blender", "blenderartists.org") -__version__ = "2.0" - -__bpydoc__ = """\ -This script implements vertex and edges bevelling in Blender. - -Usage: - -Select the mesh you want to work on, enter Edit Mode and select the edges -to bevel. Then run this script from the 3d View's Mesh->Scripts menu. - -You can control the thickness of the bevel with the slider -- redefine the -end points for bigger or smaller ranges. The thickness can be changed even -after applying the bevel, as many times as needed. - -For an extra smoothing after or instead of direct bevel, set the level of -recursiveness and use the "Recursive" button. - -This "Recursive" Button, won't work in face select mode, unless you choose -"faces" in the select mode menu. - -Notes:
- You can undo and redo your steps just like with normal mesh operations in -Blender. -""" - -###################################################################### -# Bevel Center v2.0 for Blender - -# This script lets you bevel the selected vertices or edges and control the -# thickness of the bevel - -# (c) 2004-2006 Loïc Berthe (loic+blender@lilotux.net) -# released under Blender Artistic License - -###################################################################### - -import Blender -from Blender import NMesh, Window, Scene -from Blender.Draw import * -from Blender.Mathutils import * -from Blender.BGL import * -import BPyMessages -#PY23 NO SETS# -''' -try: - set() -except: - from sets import set -''' - -###################################################################### -# Functions to handle the global structures of the script NF, NE and NC -# which contain informations about faces and corners to be created - -global E_selected -E_selected = NMesh.EdgeFlags['SELECT'] - -old_dist = None - -def act_mesh_ob(): - scn = Scene.GetCurrent() - ob = scn.objects.active - if ob == None or ob.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - if ob.getData(mesh=1).multires: - BPyMessages.Error_NoMeshMultiresEdit() - return - - return ob - -def make_sel_vert(*co): - v= NMesh.Vert(*co) - v.sel = 1 - me.verts.append(v) - return v - -def make_sel_face(verts): - f = NMesh.Face(verts) - f.sel = 1 - me.addFace(f) - -def add_to_NV(old,dir,new): - try: - NV[old][dir] = new - except: - NV[old] = {dir:new} - -def get_v(old, *neighbors): - # compute the direction of the new vert - if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize() - #dir - else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize() - - # look in NV if this vert already exists - key = tuple(dir) - if old in NV and key in NV[old] : return NV[old][key] - - # else, create it - new = old.co + dist.val*dir - v = make_sel_vert(new.x,new.y,new.z) - add_to_NV(old,key,v) - return v - -def make_faces(): - """ Analyse the mesh, make the faces corresponding to selected faces and - fill the structures NE and NC """ - - # make the differents flags consistent - for e in me.edges: - if e.flag & E_selected : - e.v1.sel = 1 - e.v2.sel = 1 - - NF =[] # NF : New faces - for f in me.faces: - V = f.v - nV = len(V) - enumV = range(nV) - E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV] - Esel = [x.flag & E_selected for x in E] - - # look for selected vertices and creates a list containing the new vertices - newV = V[:] - changes = False - for (i,v) in enumerate(V): - if v.sel : - changes = True - if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1]) - elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV]) - elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV]) - else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])] - - if changes: - # determine and store the face to be created - - lenV = [len(x) for x in newV] - if 2 not in lenV : - new_f = NMesh.Face(newV) - if sum(Esel) == nV : new_f.sel = 1 - NF.append(new_f) - - else : - nb2 = lenV.count(2) - - if nV == 4 : # f is a quad - if nb2 == 1 : - ind2 = lenV.index(2) - NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]])) - NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]])) - - elif nb2 == 2 : - # We must know if the tuples are neighbours - ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22') - - if ind2 != -1 : # They are - NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]])) - NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]])) - - else: # They aren't - ind2 = lenV.index(2) - NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]])) - NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]])) - NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]])) - - elif nb2 == 3 : - ind2 = lenV.index(3) - NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]])) - NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]])) - NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]])) - - else: - if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \ - < (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length : - ind2 = 0 - else : - ind2 = 1 - NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]])) - NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]])) - NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]])) - - else : # f is a tri - if nb2 == 1: - ind2 = lenV.index(2) - NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]])) - - elif nb2 == 2: - ind2 = lenV.index(3) - NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]])) - NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) - - else: - ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1] - NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]])) - NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) - - # Preparing the corners - for i in enumV: - if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i]) - - - old_faces.append(f) - - # Preparing the Edges - for i in enumV: - if Esel[i]: - verts = [newV[i],newV[(i+1) % nV]] - if V[i].index > V[(i+1) % nV].index : verts.reverse() - NE.setdefault(E[i],[]).append(verts) - - # Create the faces - for f in NF: me.addFace(f) - -def make_edges(): - """ Make the faces corresponding to selected edges """ - - for old,new in NE.iteritems() : - if len(new) == 1 : # This edge was on a border - oldv = [old.v1, old.v2] - if old.v1.index < old.v2.index : oldv.reverse() - - make_sel_face(oldv+new[0]) - - me.findEdge(*oldv).flag |= E_selected - me.findEdge(*new[0]).flag |= E_selected - - #PY23 NO SETS# for v in oldv : NV_ext.add(v) - for v in oldv : NV_ext[v]= None - - else: - make_sel_face(new[0] + new[1][::-1]) - - me.findEdge(*new[0]).flag |= E_selected - me.findEdge(*new[1]).flag |= E_selected - -def make_corners(): - """ Make the faces corresponding to corners """ - - for v in NV.iterkeys(): - V = NV[v].values() - nV = len(V) - - if nV == 1: pass - - elif nV == 2 : - #PY23 NO SETS# if v in NV_ext: - if v in NV_ext.iterkeys(): - make_sel_face(V+[v]) - me.findEdge(*V).flag |= E_selected - - else: - #PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V) - if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V) - - - else : - - # We need to know which are the edges around the corner. - # First, we look for the quads surrounding the corner. - eed = [] - for old, new in NE.iteritems(): - if v in (old.v1,old.v2) : - if v.index == min(old.v1.index,old.v2.index) : ind = 0 - else : ind = 1 - - if len(new) == 1: eed.append([v,new[0][ind]]) - else : eed.append([new[0][ind],new[1][ind]]) - - # We will add the edges coming from faces where only one vertice is selected. - # They are stored in NC. - if v in NC: eed = eed+NC[v] - - # Now we have to sort these vertices - hc = {} - for (a,b) in eed : - hc.setdefault(a,[]).append(b) - hc.setdefault(b,[]).append(a) - - for x0,edges in hc.iteritems(): - if len(edges) == 1 : break - - b = [x0] # b will contain the sorted list of vertices - - for i in xrange(len(hc)-1): - for x in hc[x0] : - if x not in b : break - b.append(x) - x0 = x - - b.append(b[0]) - - # Now we can create the faces - if len(b) == 5: make_sel_face(b[:4]) - - else: - New_V = Vector(0.0, 0.0,0.0) - New_d = [0.0, 0.0,0.0] - - for x in hc.iterkeys(): New_V += x.co - for dir in NV[v] : - for i in xrange(3): New_d[i] += dir[i] - - New_V *= 1./len(hc) - for i in xrange(3) : New_d[i] /= nV - - center = make_sel_vert(New_V.x,New_V.y,New_V.z) - add_to_NV(v,tuple(New_d),center) - - for k in xrange(len(b)-1): make_sel_face([center, b[k], b[k+1]]) - - if 2 < nV and v in NC : - for edge in NC[v] : me.findEdge(*edge).flag |= E_selected - -def clear_old(): - """ Erase old faces and vertices """ - - for f in old_faces: me.removeFace(f) - - for v in NV.iterkeys(): - #PY23 NO SETS# if v not in NV_ext : me.verts.remove(v) - if v not in NV_ext.iterkeys() : me.verts.remove(v) - - for e in me.edges: - if e.flag & E_selected : - e.v1.sel = 1 - e.v2.sel = 1 - - -###################################################################### -# Interface - -global dist - -dist = Create(0.2) -left = Create(0.0) -right = Create(1.0) -num = Create(2) - -# Events -EVENT_NOEVENT = 1 -EVENT_BEVEL = 2 -EVENT_UPDATE = 3 -EVENT_RECURS = 4 -EVENT_EXIT = 5 - -def draw(): - global dist, left, right, num, old_dist - global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT - - glClear(GL_COLOR_BUFFER_BIT) - Button("Bevel",EVENT_BEVEL,10,100,280,25) - - BeginAlign() - left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider') - dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \ - "Thickness of the bevel, can be changed even after bevelling") - right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider") - - EndAlign() - glRasterPos2d(8,40) - Text('To finish, you can use recursive bevel to smooth it') - - - if old_dist != None: - num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level') - Button("Recursive",EVENT_RECURS,55,10,100,16) - - Button("Exit",EVENT_EXIT,210,10,80,20) - -def event(evt, val): - if ((evt == QKEY or evt == ESCKEY) and not val): Exit() - -def bevent(evt): - if evt == EVENT_EXIT : Exit() - elif evt == EVENT_BEVEL : bevel() - elif evt == EVENT_UPDATE : - try: bevel_update() - except NameError : pass - elif evt == EVENT_RECURS : recursive() - -Register(draw, event, bevent) - -###################################################################### -def bevel(): - """ The main function, which creates the bevel """ - global me,NV,NV_ext,NE,NC, old_faces,old_dist - - ob = act_mesh_ob() - if not ob: return - - Window.WaitCursor(1) # Change the Cursor - t= Blender.sys.time() - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - - me = ob.data - - NV = {} - #PY23 NO SETS# NV_ext = set() - NV_ext= {} - NE = {} - NC = {} - old_faces = [] - - make_faces() - make_edges() - make_corners() - clear_old() - - old_dist = dist.val - print '\tbevel in %.6f sec' % (Blender.sys.time()-t) - me.update(1) - if is_editmode: Window.EditMode(1) - Window.WaitCursor(0) - Blender.Redraw() - -def bevel_update(): - """ Use NV to update the bevel """ - global dist, old_dist - - if old_dist == None: - # PupMenu('Error%t|Must bevel first.') - return - - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - - fac = dist.val - old_dist - old_dist = dist.val - - for old_v in NV.iterkeys(): - for dir in NV[old_v].iterkeys(): - for i in xrange(3): - NV[old_v][dir].co[i] += fac*dir[i] - - me.update(1) - if is_editmode: Window.EditMode(1) - Blender.Redraw() - -def recursive(): - """ Make a recursive bevel... still experimental """ - global dist - from math import pi, sin - - if num.val > 1: - a = pi/4 - ang = [] - for k in xrange(num.val): - ang.append(a) - a = (pi+2*a)/4 - - l = [2*(1-sin(x))/sin(2*x) for x in ang] - R = dist.val/sum(l) - l = [x*R for x in l] - - dist.val = l[0] - bevel_update() - - for x in l[1:]: - dist.val = x - bevel() - diff --git a/release/scripts/blenderLipSynchro.py b/release/scripts/blenderLipSynchro.py deleted file mode 100644 index c4815811512..00000000000 --- a/release/scripts/blenderLipSynchro.py +++ /dev/null @@ -1,729 +0,0 @@ -#!BPY -# coding: utf-8 -""" -Name: 'BlenderLipSynchro' -Blender: 242 -Group: 'Animation' -Tooltip: 'Import phonemes from Papagayo or JLipSync for lip synchronization' -""" - -__author__ = "Dienben: Benoit Foucque dienben_mail@yahoo.fr" -__url__ = ["blenderLipSynchro Blog, http://blenderlipsynchro.blogspot.com/", -"Papagayo (Python), http://www.lostmarble.com/papagayo/index.shtml", -"JLipSync (Java), http://jlipsync.sourceforge.net/"] -__version__ = "2.0" -__bpydoc__ = """\ -Description: - -This script imports Voice Export made by Papagayo or JLipSync and maps the export with your shapes. - -Usage: - -Import a Papagayo or JLipSync voice export file and link it with your shapes. - -Note:
-- Naturally, you need files exported from one of the supported lip synching -programs. Check their sites to learn more and download them. - -""" - -# -------------------------------------------------------------------------- -# BlenderLipSynchro -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - - - -#il y a 3 etapes -#la deuxieme on charge le dictionnaire de correspondance -#la troisieme on fait le choix des correpondance -#la quatrieme on construit les cles a partir du fichiers frame - -#there are 3 stages -#the second one load the mapping dictionnary -#the tird make the mapping -#the fourth make the key in the IPO Curve - -#voici mes differents imports -#the imports -import os -import Blender - -from Blender import Ipo -from Blender.Draw import * -from Blender.BGL import * -from Blender.sys import basename - - - -#ici commencent mes fonctions -#here begin my functions -#cette fonction trace l'interface graphique -#this functions draw the User interface -def trace(): - #voici mes variables pouvant etre modifie - #my variables - global nbr_phoneme, mon_fichier_dico - global let01, let02, let03, let04,let05, let06, let07, let08, let09, let10 - global let11, let12, let13, let14,let15, let16, let17, let18, let19, let20 - global let21, let22, let23, let24 - - global let01selectkey,let02selectkey,let03selectkey,let04selectkey,let05selectkey - global let06selectkey,let07selectkey,let08selectkey,let09selectkey,let10selectkey,let11selectkey - global let12selectkey,let13selectkey,let14selectkey,let15selectkey,let16selectkey,let17selectkey - global let18selectkey,let19selectkey,let20selectkey,let21selectkey,let22selectkey,let23selectkey - global let24selectkey - - glClearColor(0.4,0.5,0.6 ,0.0) - glClear(GL_COLOR_BUFFER_BIT) - - glColor3d(1,1,1) - glRasterPos2i(87, 375) - Text("Blendersynchro V 2.0") - glColor3d(1,1,1) - glRasterPos2i(84, 360) - Text("Programming: Dienben") - - glColor3d(0,0,0) - glRasterPos2i(13, 342) - Text("Lip Synchronization Tool") - glColor3d(0,0,0) - glRasterPos2i(13, 326) - Text("Thanks to Chris Clawson and Liubomir Kovatchev") - - glColor3d(1,1,1) - glRasterPos2i(5, 320) - Text("_______________________________________________________") - glColor3d(0,0,0) - glRasterPos2i(6, 318) - Text("_______________________________________________________") - - - if (etape==1): - #cette etape permet de choisi la correspondance entre les phonemes et les cles - #this stage offer the possibility to choose the mapping between phonems and shapes - - glColor3d(1,1,1) - glRasterPos2i(140, 300) - Text("Objet: "+Blender.Object.GetSelected()[0].getName() ) - - glColor3d(1,1,1) - glRasterPos2i(5, 215) - Text("Assign phonems to shapes:") - - #on mesure la taille de la liste de phonemes - #this is the lenght of the phonem list - nbr_phoneme=len(liste_phoneme) - - #on dessine les listes de choix - #we draw the choice list - - # - if (nbr_phoneme > 0): - let01 = String(" ", 4, 5, 185, 30, 16, liste_phoneme[0], 3) - glColor3d(0,0,0) - glRasterPos2i(40, 188) - Text("=") - let01selectkey = Menu(key_menu, 50, 50, 185, 70, 16, let01selectkey.val) - - # - if (nbr_phoneme > 1): - let02 = String(" ", 4, 150, 185, 30, 16, liste_phoneme[1], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 188) - Text("=") - let02selectkey = Menu(key_menu, 51, 195, 185, 70, 16, let02selectkey.val) - - # - if (nbr_phoneme > 2): - let03 = String(" ", 4, 5, 165, 30, 16, liste_phoneme[2], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 168) - Text("=") - let03selectkey = Menu(key_menu, 52, 50, 165, 70, 16, let03selectkey.val) - - # - if (nbr_phoneme > 3): - let04 = String(" ", 4, 150, 165, 30, 16, liste_phoneme[3], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 168) - Text("=") - let04selectkey = Menu(key_menu, 53, 195, 165, 70, 16, let04selectkey.val) - - # - if (nbr_phoneme > 4): - let05 = String(" ", 4, 5, 145, 30, 16, liste_phoneme[4], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 148) - Text("=") - let05selectkey = Menu(key_menu, 54, 50, 145, 70, 16, let05selectkey.val) - - # - if (nbr_phoneme > 5): - let06 = String(" ", 4, 150, 145, 30, 16, liste_phoneme[5], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 148) - Text("=") - let06selectkey = Menu(key_menu, 55, 195, 145, 70, 16, let06selectkey.val) - - # - if (nbr_phoneme > 6): - let07 = String(" ", 4, 5, 125, 30, 16, liste_phoneme[6], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 128) - Text("=") - let07selectkey = Menu(key_menu, 56, 50, 125, 70, 16, let07selectkey.val) - - # - if (nbr_phoneme > 7): - let08 = String(" ", 4, 150, 125, 30, 16, liste_phoneme[7], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 128) - Text("=") - let08selectkey = Menu(key_menu, 57, 195, 125, 70, 16,let08selectkey.val) - - # - if (nbr_phoneme > 8): - let09 = String(" ", 4, 5, 105, 30, 16, liste_phoneme[8], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 108) - Text("=") - let09selectkey = Menu(key_menu, 58, 50, 105, 70, 16,let09selectkey.val) - - # - if (nbr_phoneme > 9): - let10 = String(" ", 4, 150, 105, 30, 16, liste_phoneme[9], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 108) - Text("=") - let10selectkey = Menu(key_menu, 59, 195, 105, 70, 16, let10selectkey.val) - - # - if (nbr_phoneme > 10): - let11 = String(" ", 4, 5, 85, 30, 16, liste_phoneme[10], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 88) - Text("=") - let11selectkey = Menu(key_menu, 60, 50, 85, 70, 16, let11selectkey.val) - - # - if (nbr_phoneme > 11): - let12 = String(" ", 4, 150, 85, 30, 16, liste_phoneme[11], 2) - glColor3d(0,0,0) - Text("=") - let12selectkey = Menu(key_menu, 61, 195, 85, 70, 16, let12selectkey.val) - - # - if (nbr_phoneme > 12): - let13 = String(" ", 4, 5, 65, 30, 16, liste_phoneme[12], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 68) - Text("=") - let13selectkey = Menu(key_menu, 62, 50, 65, 70, 16, let13selectkey.val) - - # - if (nbr_phoneme > 13): - let14 = String(" ", 4, 150, 65, 30, 16, liste_phoneme[13], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 68) - Text("=") - let14selectkey = Menu(key_menu, 63, 195, 65, 70, 16, let14selectkey.val) - - # - if (nbr_phoneme > 14): - let15 = String(" ", 4, 5, 45, 30, 16, liste_phoneme[14], 2) - glColor3d(0,0,0) - glRasterPos2i(40, 48) - Text("=") - let15selectkey = Menu(key_menu, 64, 50, 45, 70, 16, let15selectkey.val) - - # - if (nbr_phoneme > 15): - let16 = String(" ", 4, 150, 45, 30, 16, liste_phoneme[15], 2) - glColor3d(0,0,0) - glRasterPos2i(185, 48) - Text("=") - let16selectkey = Menu(key_menu, 65, 195, 45, 70, 16, let16selectkey.val) - - # - if (nbr_phoneme > 16): - let17 = String(" ", 4, 295, 185, 30, 16, liste_phoneme[16], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 188) - Text("=") - let17selectkey = Menu(key_menu, 66, 340, 185, 70, 16, let17selectkey.val) - - # - if (nbr_phoneme > 17): - let18 = String(" ", 4, 440, 185, 70, 16, liste_phoneme[17], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 188) - Text("=") - let18selectkey = Menu(key_menu, 67, 525, 185, 70, 16, let18selectkey.val) - - # - if (nbr_phoneme > 18): - let19 = String(" ", 4, 295, 165, 30, 16, liste_phoneme[18], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 168) - Text("=") - let19selectkey = Menu(key_menu, 68, 340, 165, 70, 16, let19selectkey.val) - - # - if (nbr_phoneme > 19): - let20 = String(" ", 4, 440, 165, 70, 16, liste_phoneme[19], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 168) - Text("=") - let20selectkey = Menu(key_menu, 69, 525, 165, 70, 16, let20selectkey.val) - - # - if (nbr_phoneme > 20): - let21 = String(" ", 4, 295, 145, 30, 16, liste_phoneme[20], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 148) - Text("=") - let21selectkey = Menu(key_menu, 70, 340, 145, 70, 16, let21selectkey.val) - - # - if (nbr_phoneme > 21): - let22 = String(" ", 4, 440, 145, 70, 16, liste_phoneme[21], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 148) - Text("=") - let22selectkey = Menu(key_menu, 71, 525, 145, 70, 16, let22selectkey.val) - - # - if (nbr_phoneme > 22): - let23 = String(" ", 4, 295, 125, 30, 16, liste_phoneme[22], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 128) - Text("=") - let23selectkey = Menu(key_menu, 72, 340, 125, 70, 16,let23selectkey.val) - - # - if (nbr_phoneme > 23): - let24 = String(" ", 4, 440, 125, 70, 16, liste_phoneme[23], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 128) - Text("=") - let24selectkey = Menu(key_menu, 73, 525, 125, 70, 16, let24selectkey.val) - - # - if (nbr_phoneme > 24): - let25 = String(" ", 4, 295, 105, 30, 16, liste_phoneme[24], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 108) - Text("=") - let25selectkey = Menu(key_menu, 74, 340, 105, 70, 16, let25selectkey.val) - - # - if (nbr_phoneme > 25): - let26 = String(" ", 4, 440, 105, 70, 16, liste_phoneme[25], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 108) - Text("=") - let26selectkey = Menu(key_menu, 75, 525, 105, 70, 16,let26selectkey.val) - - # - if (nbr_phoneme > 26): - let27 = String(" ", 4, 295, 85, 30, 16, liste_phoneme[26], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 88) - Text("=") - let27selectkey = Menu(key_menu, 76, 340, 85, 70, 16, let27selectkey.val) - - # - if (nbr_phoneme > 27): - let28 = String(" ", 4, 440, 85, 70, 16, liste_phoneme[27], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 88) - Text("=") - let28selectkey = Menu(key_menu, 77, 525, 85, 70, 16,let28selectkey.val) - - # - if (nbr_phoneme > 28): - let29 = String(" ", 4, 295, 65, 30, 16, liste_phoneme[28], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 68) - Text("=") - let29selectkey = Menu(key_menu, 78, 340, 65, 70, 16, let29selectkey.val) - - # - if (nbr_phoneme > 29): - let30 = String(" ", 4, 440, 65, 70, 16, liste_phoneme[29], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 68) - Text("=") - let30selectkey = Menu(key_menu, 79, 525, 65, 70, 16, let30selectkey.val) - - # - if (nbr_phoneme > 30): - let31 = String(" ", 4, 295, 45, 30, 16, liste_phoneme[30], 2) - glColor3d(0,0,0) - glRasterPos2i(330, 48) - Text("=") - let31selectkey = Menu(key_menu, 80, 340, 45, 70, 16, let31selectkey.val) - - # - if (nbr_phoneme > 31): - let32 = String(" ", 4, 440, 45, 70, 16, liste_phoneme[31], 8) - glColor3d(0,0,0) - glRasterPos2i(515, 48) - Text("=") - let32selectkey = Menu(key_menu, 81, 525, 45, 70, 16, let32selectkey.val) - - Button("Go", 3, 155, 5, 145, 22) - - if (etape==2): - glColor3d(1,1,1) - glRasterPos2i(125, 200) - Text("Operation Completed") - - if (etape==0): - glColor3d(1,1,1) - glRasterPos2i(125, 200) - Text("Please select a Mesh'Object and Create all the IPO Curves for your Shapes") - - if (etape==3): - #this stage permits to load a custom dictionnary - load_file_text = "Load File" - if mon_fichier_dico: - Button("Import Loaded File", 2, 5, 5, 145, 22) - glColor3d(1,1,1) - glRasterPos2i(6, 50) - Text("loaded file: %s" % basename(mon_fichier_dico)) - load_file_text = "Choose Another File" - Button(load_file_text, 8, 125, 180, 145, 22) - - glRasterPos2i(6, 40) - Text("_______________________________________________________") - glColor3d(0,0,0) - glRasterPos2i(6, 38) - Text("_______________________________________________________") - - Button("Exit", 1, 305, 5, 80, 22) - - - -#cette fonction sur evenement quite en cas d'ESC -#this functions catch the ESC event and quit -def event(evt,val): - if (evt == ESCKEY and not val): Exit() - -#cette fonction gere les evenements -#the event functions -def bevent(evt): - global etape,soft_type,liste_phoneme,dico_phoneme_export - - if (evt == 1): - Exit() - - elif (evt == 2): - #c'est l'import du dictionnaire - #we create and import the dictionnary - lecture_chaine(mon_fichier_dico,dico_phoneme_export) - construction_dictionnaire_phoneme() - #we change the stage - etape=1 - - elif (evt == 3): - #c'est l'import - #we import - lecture_chaine(mon_fichier_export,dico_phoneme_export) - construction_dico_correspondance() - construction_lipsynchro() - #on change d'etape - #we change the stage - etape=2 - - elif (evt == 8): - #we choose the file - Blender.Window.FileSelector(selectionner_fichier,"Select File") - - Blender.Redraw() - -#cette fonction recupere le nom et le chemin du fichier dictionnaire -#we catch the name and the path of the dictionnary -def selectionner_fichier(filename): - global mon_fichier_dico,mon_fichier_export - mon_fichier_dico=filename - mon_fichier_export=filename - -#fonction de lecture de la liste frame phoneme -#we read the frame and phonems -def lecture_chaine(fichier,liste): - mon_fichier=open(fichier) - #je lis la premiere ligne qui contiens la version de moho - #first, we read the moho version - mon_fichier.readline() - - #je lis jusqu'a la fin - #then we read until the end of the file - while 1: - ma_ligne=mon_fichier.readline() - if ma_ligne=='': - break - decoup=ma_ligne.split() - liste[decoup[0]]=decoup[1] - print liste - - - - -#fonction qui construit la liste dictionnaire simple -#we make the dictionnary -def construction_dictionnaire_phoneme(): - global liste_phoneme - index_liste=0 - #je transforme mon dictionnaire en list de tulpes - #we transform the list in tulpes - ma_liste=dico_phoneme_export.items() - #je parcours ma liste a la recherche d'elements non existant - #we read the list to find non existing elements - print dico_phoneme - for index in range(len(ma_liste)): - if ma_liste[index][1] not in liste_phoneme: - liste_phoneme[index_liste:index_liste]=[ma_liste[index][1]] - index_liste=index_liste+1 - print liste_phoneme - - -#cette fonction recupere les courbes cible -#this functon catch the IPO curve -def recuperation_courbe(): - global key_menu,dico_key - - #on recupere le nom des shapes - #we catch the shapes - key=Blender.Object.GetSelected()[0].getData().getKey().getBlocks() - for n in range(len(key)): - #on vire la première cle (en effet basic n'est pas une cle en tant que telle) - #we threw away the basic shapes - if (n>0): - key_menu=key_menu+key[n].name + " %x" + str(n-1) + "|" - dico_key[str(n-1)]=Blender.Object.GetSelected()[0].getData().getKey().getIpo().getCurves()[n-1] - - - print "dico_key" - print dico_key - print 'end dico_key' - -#cette fonction construit un dictionnaire de correspondance entre les phonemes prononces et les cles a utiliser -#we make the dictionnary for the mapping between shapes and phonems -def construction_dico_correspondance(): - global dico_correspondance - #je parcours les phonemes - #we read the phonems - if (nbr_phoneme>0): - dico_correspondance[liste_phoneme[0]]=dico_key[str(let01selectkey.val)] - if (nbr_phoneme>1): - dico_correspondance[liste_phoneme[1]]=dico_key[str(let02selectkey.val)] - if (nbr_phoneme>2): - dico_correspondance[liste_phoneme[2]]=dico_key[str(let03selectkey.val)] - if (nbr_phoneme>3): - dico_correspondance[liste_phoneme[3]]=dico_key[str(let04selectkey.val)] - if (nbr_phoneme>4): - dico_correspondance[liste_phoneme[4]]=dico_key[str(let05selectkey.val)] - if (nbr_phoneme>5): - dico_correspondance[liste_phoneme[5]]=dico_key[str(let06selectkey.val)] - if (nbr_phoneme>6): - dico_correspondance[liste_phoneme[6]]=dico_key[str(let07selectkey.val)] - if (nbr_phoneme>7): - dico_correspondance[liste_phoneme[7]]=dico_key[str(let08selectkey.val)] - if (nbr_phoneme>8): - dico_correspondance[liste_phoneme[8]]=dico_key[str(let09selectkey.val)] - if (nbr_phoneme>9): - dico_correspondance[liste_phoneme[9]]=dico_key[str(let10selectkey.val)] - if (nbr_phoneme>10): - dico_correspondance[liste_phoneme[10]]=dico_key[str(let11selectkey.val)] - if (nbr_phoneme>11): - dico_correspondance[liste_phoneme[11]]=dico_key[str(let12selectkey.val)] - if (nbr_phoneme>12): - dico_correspondance[liste_phoneme[12]]=dico_key[str(let13selectkey.val)] - if (nbr_phoneme>13): - dico_correspondance[liste_phoneme[13]]=dico_key[str(let14selectkey.val)] - if (nbr_phoneme>14): - dico_correspondance[liste_phoneme[14]]=dico_key[str(let15selectkey.val)] - if (nbr_phoneme>15): - dico_correspondance[liste_phoneme[15]]=dico_key[str(let16selectkey.val)] - if (nbr_phoneme>16): - dico_correspondance[liste_phoneme[16]]=dico_key[str(let17selectkey.val)] - if (nbr_phoneme>17): - dico_correspondance[liste_phoneme[17]]=dico_key[str(let18selectkey.val)] - if (nbr_phoneme>18): - dico_correspondance[liste_phoneme[18]]=dico_key[str(let19selectkey.val)] - if (nbr_phoneme>19): - dico_correspondance[liste_phoneme[19]]=dico_key[str(let20selectkey.val)] - if (nbr_phoneme>20): - dico_correspondance[liste_phoneme[20]]=dico_key[str(let21selectkey.val)] - if (nbr_phoneme>21): - dico_correspondance[liste_phoneme[21]]=dico_key[str(let22selectkey.val)] - if (nbr_phoneme>22): - dico_correspondance[liste_phoneme[22]]=dico_key[str(let23selectkey.val)] - if (nbr_phoneme>23): - dico_correspondance[liste_phoneme[23]]=dico_key[str(let24selectkey.val)] - if (nbr_phoneme>24): - dico_correspondance[liste_phoneme[24]]=dico_key[str(let25selectkey.val)] - if (nbr_phoneme>25): - dico_correspondance[liste_phoneme[25]]=dico_key[str(let26selectkey.val)] - if (nbr_phoneme>26): - dico_correspondance[liste_phoneme[26]]=dico_key[str(let27selectkey.val)] - if (nbr_phoneme>27): - dico_correspondance[liste_phoneme[27]]=dico_key[str(let28selectkey.val)] - if (nbr_phoneme>28): - dico_correspondance[liste_phoneme[28]]=dico_key[str(let29selectkey.val)] - if (nbr_phoneme>29): - dico_correspondance[liste_phoneme[29]]=dico_key[str(let30selectkey.val)] - if (nbr_phoneme>30): - dico_correspondance[liste_phoneme[30]]=dico_key[str(let31selectkey.val)] - if (nbr_phoneme>31): - dico_correspondance[liste_phoneme[31]]=dico_key[str(let32selectkey.val)] - - print dico_correspondance - - -#cette fonction ajoute un points a la cle donnee a la frame donnee -#we add a point to the IPO curve Target -def ajoute_point(cle,frame,valeur): - cle.setInterpolation('Linear') - cle.append((frame,valeur)) - cle.Recalc() - -#cette fonction parcours le dictionnaire des frame à ajouter et construit les points -#we add all the point to the IPO Curve -def construction_lipsynchro(): - print "je construit" - doublet_old="" - #construction de la liste des frame - cpt=0 - liste_frame=[] - for frame in dico_phoneme_export: - liste_frame.append(int(frame)) - cpt=cpt+1 - liste_frame.sort() - print "listeframe" - print liste_frame - print "fini" - - for doublet in liste_frame: - ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],doublet,1) - if (doublet_old==""): - ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) - if (doublet_old!=''): - if (dico_correspondance[dico_phoneme_export[str(doublet)]]!=dico_correspondance[dico_phoneme_export[doublet_old]]): - print "doublet:"+str(doublet) - print "doublet old:"+doublet_old - ajoute_point(dico_correspondance[dico_phoneme_export[doublet_old]],(int(doublet_old)+2),0) - ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) - doublet_old=str(doublet) - - -#end of my functions we begin the execution -#je commence l execution----------------------------------------------------------------------------------------------- -#voici mes variables - -#declaration et instanciation -#decleration and instanciation - - -#voici mon objet de travail -objet_travail=Create(0) - -#my soft type -soft_type=1 - -#voici la liste des phoneme effectivement utilise -#the phonems'list -#liste_phoneme_papagayo=['AI','E','O','U','FV','L','WQ','MBP','etc','rest'] -#liste_phoneme_jlipsinch=['A','B','C','Closed','D','E','F','G','I','K','L','M','N','O','P','Q','R','S','SH','T','TH','U','V','W'] - -liste_phoneme=[] -#voici mon dictionnaire des frames o -dico_phoneme_export = Create(0) -dico_phoneme_export={} -dico_phoneme={} - - -#voici mes cle -key_menu="" -dico_key={} - -#voici mes ipo -dico_bloc={} -iponame = Create(0) - -#voici mon dictionnaire de correspondance -dico_correspondance={} - -try: - #on verifie est bien une mesh et qu'il a des courbes - if ((Blender.Object.GetSelected()[0].getType()=='Mesh')): - #on verifie que l'objet a bien toute ses Courbes - if (len(Blender.Object.GetSelected()[0].getData().getKey().getBlocks())-1==Blender.Object.GetSelected()[0].getData().getKey().getIpo().getNcurves()): - etape=3 - #on lance la creation du dictionnaire - recuperation_courbe() - else: - print "not the good number of IPO Curve" - etape = 0 - else: - print "error: bad object Type:" - print Blender.Object.GetSelected()[0].getType() - etape = 0 -except: - print 'error: exception' - etape = 0 - - -#voici le fichier dictionnaire -mon_fichier_dico="" - -#voici le fichier export pamela -mon_fichier_export="" - - -let01selectkey = Create(0) -let02selectkey = Create(0) -let03selectkey = Create(0) -let04selectkey = Create(0) -let05selectkey = Create(0) -let06selectkey = Create(0) -let07selectkey = Create(0) -let08selectkey = Create(0) -let09selectkey = Create(0) -let10selectkey = Create(0) -let11selectkey = Create(0) -let12selectkey = Create(0) -let13selectkey = Create(0) -let14selectkey = Create(0) -let15selectkey = Create(0) -let16selectkey = Create(0) -let17selectkey = Create(0) -let18selectkey = Create(0) -let19selectkey = Create(0) -let20selectkey = Create(0) -let21selectkey = Create(0) -let22selectkey = Create(0) -let23selectkey = Create(0) -let24selectkey = Create(0) - - -Register (trace,event,bevent) diff --git a/release/scripts/bpydata/KUlang.txt b/release/scripts/bpydata/KUlang.txt deleted file mode 100644 index 38605d69c9f..00000000000 --- a/release/scripts/bpydata/KUlang.txt +++ /dev/null @@ -1,121 +0,0 @@ -Version 3.233-2004 -****************** -Espanol -Sale del programa -Utilidades de...%t|Alinea objetos%x1|Creacion%x2|Edita mallas%x3|Edita objetos%x4 -11 -Mov -Esc -Encaja -Abarca -Separa -Alinea -Rota -Incr. -Crea nuevos objetos -Es+ -Es* -Separar entre:%t|Origenes%x1|Centros geometricos%x2|Minimos%x3|Maximos%x4|Baricentro%x5|Objetos%x6 -Crear%t|Arco (3 ptos.)%x1|Arco (interactivo)%x2|Circunferencia (3 ptos.)%x3 -12 -Puntos -Centro -Orden -Objeto -AngIni: -AngFin: -Angulo: -Radio: -Puntos: -Centro -Nombre: -Puntos -Modifica vertices%t|Subdivide%x1|Envia a un plano%x2|Aplica LocRotSize%x3 -Partes -Proyectar en el plano:%t|Coordenado global...%x1|Coordenado local...%x2 -Actuar sobre el plano%t|Yz%x1|Zx%x2|Xy%x3 -En la dirección%t|X%x1|Y%x2|Z%x3|Ortogonal al plano%x4 -Captura -Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacion%x3|Copia media LocRotSiz%x4|Ver buffer en consola%x5 -Transformar LocRotSize%t|Hacia el obj. activo%x1|Aleatoriamente%x2 -Poner a distancia fija%x1|Sumar (desp. absoluto)%x2|Multiplicar (desp. relativo)%x3 -******************** -English -Exit program -Utils about:%t|Align Objects%x1|Create%x2|Edit Meshes%x3|Edit Objects%x4 -11 -Mov -Sca -Fit -Embrace -Separate -Align -Rota -Incr. -Create new objects -Sc+ -Sc* -Separate between:%t|Origins%x1|Geometric centers%x2|Minimum%x3|Maximum%x4|Baricenter%x5|Objects%x6 -Create what%t|Arc (3 pts.)%x1|Arc (interactive)%x2|Circunference (3 pts.)%x3 -12 -Points -Centre -Sort -Object -AngIni: -AngEnd: -Angle: -Radius: -Points: -Centre -ObjName: -Points -Modify vertices%t|Subdivide edges%x1|Send to a plane%x2|Set LocRotSize%x3 -Parts -Project onto the plane:%t|Global coordinated...%x1|Local coordinated...%x2 -Act on plane%t|Yz%x1|Zx%x2|Xy%x3 -In direction%t|X%x1|Y%x2|Z%x3|Ortogonal to plane%x4 -Get -Buffer%t|Copy diference vector%x1|Copy distance%x2|Copy rot diference%x3|Copy LocRotSiz average%x4|Show Buffer in Console%x5 -Transform LocRotSize%t|Close to active%x1|Randomly%x2 -Set at fixed distance%x1|Add (absolute displ.)%x2|Multiply (relative displ.)%x3 -******************** -Catala -Surt del programa -Utilitats de...%t|Alinea objectes%x1|Creacio%x2|Edita malles%x3|Edita objetes%x4 -11 -Mov -Esc -Encaixa -Abarca -Separa -Alinea -Rotacio -Incr. -Crea objectes nous -Es+ -Es* -Separa entra:%t|Origens%x1|Centres geometrics%x2|Minims%x3|Maxims%x4|Baricentre%x5|Objectes%x6 -Crear%t|Arc (3 pts.)%x1|Arc (interactiu)%x2|Circumferencia (3 pts.)%x3 -12 -Punts -Centre -Ordre -Objecte -AngIni: -AngFi: -Angle: -Radi: -Punts: -Centre -Nom: -Punts -Modifica vertex%t|Subdivideix%x1|Envia a un pla%x2|Aplica LocRotSize%x3 -Parts -Projectar en el pla:%t|Coordenacio global...%x1|Coordenacio local...%x2 -Actuar sobre el pla%t|Yz%x1|Zx%x2|Xy%x3 -En la direccio%t|X%x1|Y%x2|Z%x3|Ortogonal al pla%x4 -Captura -Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacio%x3|Copia mitjana LocRotSiz%x4|Veure buffer en consola%x5 -Transformar LocRotSize%t|Cap al obj. actiu%x1|Aleatoriamente%x2 -Posar a distancia fixa%x1|Sumar (desp. absolut)%x2|Multiplicar (desp. relatiu)%x3 diff --git a/release/scripts/bpydata/config/readme.txt b/release/scripts/bpydata/config/readme.txt deleted file mode 100644 index 4b5cb61b063..00000000000 --- a/release/scripts/bpydata/config/readme.txt +++ /dev/null @@ -1,6 +0,0 @@ -This folder is for automatically saved scripts configuration data. - -To use this feature scripts just need to set a proper Blender.Registry key. - -To know more, check the API Reference doc (specifically the API_related and -Registry parts) and the documentation for the "Scripts Config Editor" script. diff --git a/release/scripts/bpydata/readme.txt b/release/scripts/bpydata/readme.txt deleted file mode 100644 index 3e640e27c4b..00000000000 --- a/release/scripts/bpydata/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This directory is the default place for scripts to put their data, -like internal files needed by the script and its saved configuration. - -Scripts can find the path to this dir using Blender.Get("datadir"). -Ex: - -import Blender -print Blender.Get("datadir") - diff --git a/release/scripts/bpymodules/BPyAddMesh.py b/release/scripts/bpymodules/BPyAddMesh.py deleted file mode 100644 index 901e68866cc..00000000000 --- a/release/scripts/bpymodules/BPyAddMesh.py +++ /dev/null @@ -1,159 +0,0 @@ -import Blender -from Blender.Window import EditMode, GetCursorPos, GetViewQuat -import bpy -import BPyMessages - -def add_mesh_simple(name, verts, edges, faces): - ''' - Adds a mesh from verts, edges and faces - - name - new object/mesh name - verts - list of 3d vectors - edges - list of int pairs - faces - list of int triplets/quads - ''' - - scn = bpy.data.scenes.active - if scn.lib: return - ob_act = scn.objects.active - - is_editmode = EditMode() - - cursor = GetCursorPos() - quat = None - if is_editmode or Blender.Get('add_view_align'): # Aligning seems odd for editmode, but blender does it, oh well - try: quat = Blender.Mathutils.Quaternion(GetViewQuat()) - except: pass - - # Exist editmode for non mesh types - if ob_act and ob_act.type != 'Mesh' and is_editmode: - EditMode(0) - - # We are in mesh editmode - if EditMode(): - me = ob_act.getData(mesh=1) - - if me.multires: - BPyMessages.Error_NoMeshMultiresEdit() - return - - # Add to existing mesh - # must exit editmode to modify mesh - EditMode(0) - - me.sel = False - - vert_offset = len(me.verts) - edge_offset = len(me.edges) - face_offset = len(me.faces) - - # transform the verts - txmat = Blender.Mathutils.TranslationMatrix(Blender.Mathutils.Vector(cursor)) - if quat: - mat = quat.toMatrix() - mat.invert() - mat.resize4x4() - txmat = mat * txmat - - txmat = txmat * ob_act.matrixWorld.copy().invert() - - - me.verts.extend(verts) - # Transform the verts by the cursor and view rotation - me.transform(txmat, selected_only=True) - - if vert_offset: - me.edges.extend([[i+vert_offset for i in e] for e in edges]) - me.faces.extend([[i+vert_offset for i in f] for f in faces]) - else: - # Mesh with no data, unlikely - me.edges.extend(edges) - me.faces.extend(faces) - else: - - # Object mode add new - - me = bpy.data.meshes.new(name) - me.verts.extend(verts) - me.edges.extend(edges) - me.faces.extend(faces) - me.sel = True - - # Object creation and location - scn.objects.selected = [] - ob_act = scn.objects.new(me, name) - scn.objects.active = ob_act - - if quat: - mat = quat.toMatrix() - mat.invert() - mat.resize4x4() - ob_act.setMatrix(mat) - - ob_act.loc = cursor - - me.calcNormals() - - if is_editmode or Blender.Get('add_editmode'): - EditMode(1) - - - - - -def write_mesh_script(filepath, me): - ''' - filepath - path to py file - me - mesh to write - ''' - - name = me.name - file = open(filepath, 'w') - - file.write('#!BPY\n') - file.write('"""\n') - file.write('Name: \'%s\'\n' % name) - file.write('Blender: 245\n') - file.write('Group: \'AddMesh\'\n') - file.write('"""\n\n') - file.write('import BPyAddMesh\n') - file.write('from Blender.Mathutils import Vector\n\n') - - file.write('verts = [\\\n') - for v in me.verts: - file.write('Vector(%f,%f,%f),\\\n' % tuple(v.co)) - file.write(']\n') - - file.write('edges = []\n') # TODO, write loose edges - - file.write('faces = [\\\n') - for f in me.faces: - file.write('%s,\\\n' % str(tuple([v.index for v in f]))) - file.write(']\n') - - file.write('BPyAddMesh.add_mesh_simple("%s", verts, edges, faces)\n' % name) - -# The script below can make a file from a mesh with teh above function... -''' -#!BPY -""" -Name: 'Mesh as AddMesh Script' -Blender: 242 -Group: 'Mesh' -Tip: '' -""" -import BPyAddMesh -reload(BPyAddMesh) - -import bpy - -def main(): - # Add error checking - scn = bpy.data.scenes.active - ob = scn.objects.active - me = ob.getData(mesh=1) - - BPyAddMesh.write_mesh_script('/test.py', me) - -main() -''' diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py deleted file mode 100644 index 63df02d080c..00000000000 --- a/release/scripts/bpymodules/BPyArmature.py +++ /dev/null @@ -1,152 +0,0 @@ -# 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 -# Version History: -# 1.0 original release bakes an armature into a matrix -# 1.1 optional params (ACTION_BAKE, ACTION_BAKE_FIRST_FRAME, direct function to key and return the Action - -import Blender -from Blender import sys -import bpy -def getBakedPoseData(ob_arm, start_frame, end_frame, ACTION_BAKE = False, ACTION_BAKE_FIRST_FRAME = True): - ''' - If you are currently getting IPO's this function can be used to - ACTION_BAKE==False: return a list of frame aligned bone dictionary's - ACTION_BAKE==True: return an action with keys aligned to bone constrained movement - if ACTION_BAKE_FIRST_FRAME is not supplied or is true: keys begin at frame 1 - - The data in these can be swaped in for the IPO loc and quat - - If you want to bake an action, this is not as hard and the ipo hack can be removed. - ''' - - # --------------------------------- Dummy Action! Only for this functon - backup_action = ob_arm.action - backup_frame = Blender.Get('curframe') - - DUMMY_ACTION_NAME = '~DONT_USE~' - # Get the dummy action if it has no users - try: - new_action = bpy.data.actions[DUMMY_ACTION_NAME] - if new_action.users: - new_action = None - except: - new_action = None - - if not new_action: - new_action = bpy.data.actions.new(DUMMY_ACTION_NAME) - new_action.fakeUser = False - # ---------------------------------- Done - - Matrix = Blender.Mathutils.Matrix - Quaternion = Blender.Mathutils.Quaternion - Vector = Blender.Mathutils.Vector - POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT] - - # Each dict a frame - bake_data = [{} for i in xrange(1+end_frame-start_frame)] - - pose= ob_arm.getPose() - armature_data= ob_arm.getData(); - pose_bones= pose.bones - - # --------------------------------- Build a list of arma data for reuse - armature_bone_data = [] - bones_index = {} - for bone_name, rest_bone in armature_data.bones.items(): - pose_bone = pose_bones[bone_name] - rest_matrix = rest_bone.matrix['ARMATURESPACE'] - rest_matrix_inv = rest_matrix.copy().invert() - armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ]) - bones_index[bone_name] = len(bones_index) - - # Set the parent ID's - for bone_name, pose_bone in pose_bones.items(): - parent = pose_bone.parent - if parent: - bone_index= bones_index[bone_name] - parent_index= bones_index[parent.name] - armature_bone_data[ bone_index ][1]= parent_index - # ---------------------------------- Done - - - - # --------------------------------- Main loop to collect IPO data - frame_index = 0 - NvideoFrames= end_frame-start_frame - for current_frame in xrange(start_frame, end_frame+1): - if frame_index==0: start=sys.time() - elif frame_index==15: print NvideoFrames*(sys.time()-start),"seconds estimated..." #slows as it grows *3 - elif frame_index >15: - percom= frame_index*100/NvideoFrames - print "Frame %i Overall %i percent complete\r" % (current_frame, percom), - ob_arm.action = backup_action - #pose.update() # not needed - Blender.Set('curframe', current_frame) - #Blender.Window.RedrawAll() - #frame_data = bake_data[frame_index] - ob_arm.action = new_action - ###for i,pose_bone in enumerate(pose_bones): - - for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data: - matrix= pose_bone.poseMatrix - parent_bone= rest_bone.parent - if parent_index != -1: - parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix - parent_bone_matrix_inv = armature_bone_data[parent_index][5] - matrix= matrix * parent_pose_matrix.copy().invert() - rest_matrix= rest_matrix * parent_bone_matrix_inv - - matrix=matrix * rest_matrix.copy().invert() - pose_bone.quat= matrix.toQuat() - pose_bone.loc= matrix.translationPart() - if ACTION_BAKE==False: - pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1 - - # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE - # - use a temp action and bake into that, always at the same frame - # so as not to make big IPO's, then collect the result from the IPOs - - # Now get the data from the IPOs - if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name) - - loc = Vector() - quat = Quaternion() - - for curve in ipo: - val = curve.evaluate(1) - curve_name= curve.name - if curve_name == 'LocX': loc[0] = val - elif curve_name == 'LocY': loc[1] = val - elif curve_name == 'LocZ': loc[2] = val - elif curve_name == 'QuatW': quat[3] = val - elif curve_name == 'QuatX': quat[0] = val - elif curve_name == 'QuatY': quat[1] = val - elif curve_name == 'QuatZ': quat[2] = val - - bake_data[frame_index][bone_name] = loc, quat - else: - if ACTION_BAKE_FIRST_FRAME: pose_bone.insertKey(ob_arm, frame_index+1, POSE_XFORM) - else: pose_bone.insertKey(ob_arm, current_frame , POSE_XFORM) - frame_index+=1 - print "\nBaking Complete." - ob_arm.action = backup_action - if ACTION_BAKE==False: - Blender.Set('curframe', backup_frame) - return bake_data - elif ACTION_BAKE==True: - return new_action - else: print "ERROR: Invalid ACTION_BAKE %i sent to BPyArmature" % ACTION_BAKE - - - diff --git a/release/scripts/bpymodules/BPyBlender.py b/release/scripts/bpymodules/BPyBlender.py deleted file mode 100644 index 681dff63cf8..00000000000 --- a/release/scripts/bpymodules/BPyBlender.py +++ /dev/null @@ -1,36 +0,0 @@ -# $Id$ -# -# -------------------------------------------------------------------------- -# BPyBlender.py version 0.3 Mar 20, 2005 -# -------------------------------------------------------------------------- -# helper functions to be used by other scripts -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - -# Basic set of modules Blender should have in all supported platforms. -# The second and third lines are the contents of the Python23.zip file -# included with Windows Blender binaries along with zlib.pyd. -# Other platforms are assumed to have Python installed. -basic_modules = [ -'Blender', -'chunk','colorsys','copy','copy_reg','gzip','os','random','repr','stat', -'string','StringIO','types','UserDict','webbrowser', 'zlib', 'math', -'BPyBlender', 'BPyRegistry' -] diff --git a/release/scripts/bpymodules/BPyCurve.py b/release/scripts/bpymodules/BPyCurve.py deleted file mode 100644 index 3dd5f1784f2..00000000000 --- a/release/scripts/bpymodules/BPyCurve.py +++ /dev/null @@ -1,79 +0,0 @@ -# -------------------------------------------------------------------------- -# BPyImage.py version 0.15 -# -------------------------------------------------------------------------- -# helper functions to be used by other scripts -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - -from Blender import * - -def curve2vecs(ob, WORLDSPACE= True): - ''' - Takes a curve object and retuirns a list of vec lists (polylines) - one list per curve - - This is usefull as a way to get a polyline per curve - so as not to have to deal with the spline types directly - ''' - if ob.type != 'Curve': - raise 'must be a curve object' - - me_dummy = Mesh.New() - me_dummy.getFromObject(ob) - - if WORLDSPACE: - me_dummy.transform(ob.matrixWorld) - - # build an edge dict - edges = {} # should be a set - - def sort_pair(i1, i2): - if i1 > i2: return i2, i1 - else: return i1, i2 - - for ed in me_dummy.edges: - edges[sort_pair(ed.v1.index,ed.v2.index)] = None # dummy value - - # now set the curves - first_time = True - - current_vecs = [] - vec_list = [current_vecs] - - for v in me_dummy.verts: - if first_time: - first_time = False - current_vecs.append(v.co.copy()) - last_index = v.index - else: - index = v.index - if edges.has_key(sort_pair(index, last_index)): - current_vecs.append( v.co.copy() ) - else: - current_vecs = [] - vec_list.append(current_vecs) - - last_index = index - - me_dummy.verts = None - - return vec_list - - diff --git a/release/scripts/bpymodules/BPyImage.py b/release/scripts/bpymodules/BPyImage.py deleted file mode 100644 index 504e4ee29ba..00000000000 --- a/release/scripts/bpymodules/BPyImage.py +++ /dev/null @@ -1,318 +0,0 @@ -# -------------------------------------------------------------------------- -# BPyImage.py version 0.15 -# -------------------------------------------------------------------------- -# helper functions to be used by other scripts -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - -#===========================================================================# -# Comprehensive image loader, will search and find the image # -# Will return a blender image or a new image if the image is missing # -#===========================================================================# -import bpy -from Blender import sys -try: - import os -except: - os=None - -#==============================================# -# Return directory, where the file is # -#==============================================# -def stripFile(path): - lastSlash = max(path.rfind('\\'), path.rfind('/')) - if lastSlash != -1: - path = path[:lastSlash] - newpath= '%s%s' % (path, sys.sep) - else: - newpath= path - return newpath - -#==============================================# -# Strips the slashes from the back of a string # -#==============================================# -def stripPath(path): - return path.split('/')[-1].split('\\')[-1] - -#====================================================# -# Strips the prefix off the name before writing # -#====================================================# -def stripExt(name): # name is a string - index = name.rfind('.') - if index != -1: - return name[ : index ] - else: - return name - -def getExt(name): - index = name.rfind('.') - if index != -1: - return name[index+1:] - return name - -#====================================================# -# Adds a slash to the end of a path if its not there # -#====================================================# -def addSlash(path): - if not path: - return '' - - elif path.endswith('\\') or path.endswith('/'): - return path - return path + sys.sep - - -def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False, CONVERT_CALLBACK=None): - ''' - imagePath: The image filename - If a path precedes it, this will be searched as well. - - filePath: is the directory where the image may be located - any file at teh end will be ignored. - - PLACE_HOLDER: if True a new place holder image will be created. - this is usefull so later you can relink the image to its original data. - - VERBOSE: If True debug info will be printed. - - RECURSIVE: If True, directories will be recursivly searched. - Be carefull with this if you have files in your root directory because it may take a long time. - - CASE_INSENSITIVE: for non win32 systems, find the correct case for the file. - - CONVERT_CALLBACK: a function that takes an existing path and returns a new one. - Use this when loading image formats blender may not support, the CONVERT_CALLBACK - can take the path for a GIF (for example), convert it to a PNG and return the PNG's path. - For formats blender can read, simply return the path that is given. - ''' - - # VERBOSE = True - - if VERBOSE: print 'img:', imagePath, 'file:', filePath - - if os == None and CASE_INSENSITIVE: - CASE_INSENSITIVE = True - - # When we have the file load it with this. try/except niceness. - def imageLoad(path): - #if path.endswith('\\') or path.endswith('/'): - # raise 'INVALID PATH' - - if CONVERT_CALLBACK: - path = CONVERT_CALLBACK(path) - - try: - img = bpy.data.images.new(filename=path) - if VERBOSE: print '\t\tImage loaded "%s"' % path - return img - except: - if VERBOSE: - if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path) - else: print '\t\tImage not found, making a place holder "%s"' % (path) - if PLACE_HOLDER: - img= bpy.data.images.new(stripPath(path),4,4) - img.filename= path - return img #blank image - else: - return None - - # Image formats blender can read - IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal - 'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try. - - imageFileName = stripPath(imagePath) # image path only - imageFileName_lower = imageFileName.lower() # image path only - - if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath - for i in bpy.data.images: - if stripPath(i.filename.lower()) == imageFileName_lower: - if VERBOSE: print '\t\tUsing existing image.' - return i - - - if VERBOSE: print '\tAttempting to load "%s"' % imagePath - if sys.exists(imagePath): - if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath - return imageLoad(imagePath) - - - - imageFileName_noext = stripExt(imageFileName) # With no extension. - imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension. - imageFilePath = stripFile(imagePath) - - # Remove relative path from image path - if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'): - imageFilePath = imageFilePath[2:] - - - # Attempt to load from obj path. - tmpPath = stripFile(filePath) + stripPath(imageFileName) - if sys.exists(tmpPath): - if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath - return imageLoad(tmpPath) - - - # os needed if we go any further. - if not os: - if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath - return imageLoad(imagePath) # Will jus treturn a placeholder. - - - # We have os. - # GATHER PATHS. - paths = {} # Store possible paths we may use, dict for no doubles. - tmpPath = addSlash(sys.expandpath('//')) # Blenders path - if sys.exists(tmpPath): - if VERBOSE: print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - else: - if VERBOSE: print '\tNo Path: "%s"' % tmpPath - - tmpPath = imageFilePath - if sys.exists(tmpPath): - if VERBOSE: print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - else: - if VERBOSE: print '\tNo Path: "%s"' % tmpPath - - tmpPath = stripFile(filePath) - if sys.exists(tmpPath): - if VERBOSE: print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - else: - if VERBOSE: print '\tNo Path: "%s"' % tmpPath - - tmpPath = addSlash(bpy.config.textureDir) - if tmpPath and sys.exists(tmpPath): - if VERBOSE: print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - else: - if VERBOSE: print '\tNo Path: "%s"' % tmpPath - - # Add path if relative image patrh was given. - tmp_paths= paths.keys() - for k in tmp_paths: - tmpPath = k + imageFilePath - if sys.exists(tmpPath): - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - else: - if VERBOSE: print '\tNo Path: "%s"' % tmpPath - # DONE - # - for path, files in paths.iteritems(): - if sys.exists(path + imageFileName): - if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName) - return imageLoad(path + imageFileName) - - # If the files not there then well do a case insensitive seek. - filesOrigCase = files[0] - filesLower = files[1] - filesLowerNoExt = files[2] - - # We are going to try in index the file directly, if its not there just keep on - - index = None - try: - # Is it just a case mismatch? - index = filesLower.index(imageFileName_lower) - except: - try: - # Have the extensions changed? - index = filesLowerNoExt.index(imageFileName_noext_lower) - - ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext. - - # Check that the ext is useable eg- not a 3ds file :) - if ext.lower() not in IMAGE_EXT: - index = None - - except: - index = None - - if index != None: - tmpPath = path + filesOrigCase[index] - img = imageLoad( tmpPath ) - if img != None: - if VERBOSE: print '\t\tImage Found "%s"' % tmpPath - return img - - if RECURSIVE: - # IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH. - if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search' - for path in paths.iterkeys(): - # Were not going to use files - if path == '/' or len(path) == 3 and path[1:] == ':\\': - continue - - # print path , 'ASS' - - #------------------ - # finds the file starting at the root. - # def findImage(findRoot, imagePath): - #W--------------- - - # ROOT, DIRS, FILES - pathWalk = os.walk(path) - pathList = [True] - - matchList = [] # Store a list of (match, size), choose the biggest. - while True: - try: - pathList = pathWalk.next() - except: - break - - for file in pathList[2]: - file_lower = file.lower() - # FOUND A MATCH - if (file_lower == imageFileName_lower) or\ - (stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT): - name = pathList[0] + sys.sep + file - size = os.path.getsize(name) - if VERBOSE: print '\t\t\tfound:', name - matchList.append( (name, size) ) - - if matchList: - # Sort by file size - matchList.sort(lambda A, B: cmp(B[1], A[1]) ) - - if VERBOSE: print '\t\tFound "%s"' % matchList[0][0] - - # Loop through all we have found - img = None - for match in matchList: - img = imageLoad(match[0]) # 0 - first, 0 - pathname - if img != None: - break - return img - - # No go. - if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath - return imageLoad(imagePath) # Will jus treturn a placeholder. diff --git a/release/scripts/bpymodules/BPyMathutils.py b/release/scripts/bpymodules/BPyMathutils.py deleted file mode 100644 index 4882e9aaf21..00000000000 --- a/release/scripts/bpymodules/BPyMathutils.py +++ /dev/null @@ -1,228 +0,0 @@ -# $Id$ -# -# -------------------------------------------------------------------------- -# helper functions to be used by other scripts -# -------------------------------------------------------------------------- -# ***** 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 Blender -from Blender.Mathutils import * - -# ------ Mersenne Twister - start - -# Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. -# Any feedback is very welcome. For any question, comments, -# see http://www.math.keio.ac.jp/matumoto/emt.html or email -# matumoto@math.keio.ac.jp - -# The link above is dead, this is the new one: -# http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/emt.html -# And here the license info, from Mr. Matsumoto's site: -# Until 2001/4/6, MT had been distributed under GNU Public License, -# but after 2001/4/6, we decided to let MT be used for any purpose, including -# commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered -# to be usable freely. -# -# So from the year above (1997), this code is under GPL. - -# Period parameters -N = 624 -M = 397 -MATRIX_A = 0x9908b0dfL # constant vector a -UPPER_MASK = 0x80000000L # most significant w-r bits -LOWER_MASK = 0x7fffffffL # least significant r bits - -# Tempering parameters -TEMPERING_MASK_B = 0x9d2c5680L -TEMPERING_MASK_C = 0xefc60000L - -def TEMPERING_SHIFT_U(y): - return (y >> 11) - -def TEMPERING_SHIFT_S(y): - return (y << 7) - -def TEMPERING_SHIFT_T(y): - return (y << 15) - -def TEMPERING_SHIFT_L(y): - return (y >> 18) - -mt = [] # the array for the state vector -mti = N+1 # mti==N+1 means mt[N] is not initialized - -# initializing the array with a NONZERO seed -def sgenrand(seed): - # setting initial seeds to mt[N] using - # the generator Line 25 of Table 1 in - # [KNUTH 1981, The Art of Computer Programming - # Vol. 2 (2nd Ed.), pp102] - - global mt, mti - - mt = [] - - mt.append(seed & 0xffffffffL) - for i in xrange(1, N + 1): - mt.append((69069 * mt[i-1]) & 0xffffffffL) - - mti = i -# end sgenrand - - -def genrand(): - global mt, mti - - mag01 = [0x0L, MATRIX_A] - # mag01[x] = x * MATRIX_A for x=0,1 - y = 0 - - if mti >= N: # generate N words at one time - if mti == N+1: # if sgenrand() has not been called, - sgenrand(4357) # a default initial seed is used - - for kk in xrange((N-M) + 1): - y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) - mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1] - - for kk in xrange(kk, N): - y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) - mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1] - - y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK) - mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1] - - mti = 0 - - y = mt[mti] - mti += 1 - y ^= TEMPERING_SHIFT_U(y) - y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B - y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C - y ^= TEMPERING_SHIFT_L(y) - - return ( float(y) / 0xffffffffL ) # reals - -#------ Mersenne Twister -- end - - - - -""" 2d convexhull -Based from Dinu C. Gherman's work, -modified for Blender/Mathutils by Campell Barton -""" -###################################################################### -# Public interface -###################################################################### -def convexHull(point_list_2d): - """Calculate the convex hull of a set of vectors - The vectors can be 3 or 4d but only the Xand Y are used. - returns a list of convex hull indicies to the given point list - """ - - ###################################################################### - # Helpers - ###################################################################### - - def _myDet(p, q, r): - """Calc. determinant of a special matrix with three 2D points. - - The sign, "-" or "+", determines the side, right or left, - respectivly, on which the point r lies, when measured against - a directed vector from p to q. - """ - return (q.x*r.y + p.x*q.y + r.x*p.y) - (q.x*p.y + r.x*q.y + p.x*r.y) - - def _isRightTurn((p, q, r)): - "Do the vectors pq:qr form a right turn, or not?" - #assert p[0] != q[0] and q[0] != r[0] and p[0] != r[0] - if _myDet(p[0], q[0], r[0]) < 0: - return 1 - else: - return 0 - - # Get a local list copy of the points and sort them lexically. - points = [(p, i) for i, p in enumerate(point_list_2d)] - - try: points.sort(key = lambda a: (a[0].x, a[0].y)) - except: points.sort(lambda a,b: cmp((a[0].x, a[0].y), (b[0].x, b[0].y))) - - # Build upper half of the hull. - upper = [points[0], points[1]] # cant remove these. - for i in xrange(len(points)-2): - upper.append(points[i+2]) - while len(upper) > 2 and not _isRightTurn(upper[-3:]): - del upper[-2] - - # Build lower half of the hull. - points.reverse() - lower = [points.pop(0), points.pop(1)] - for p in points: - lower.append(p) - while len(lower) > 2 and not _isRightTurn(lower[-3:]): - del lower[-2] - - # Concatenate both halfs and return. - return [p[1] for ls in (upper, lower) for p in ls] - - -def plane2mat(plane, normalize= False): - ''' - Takes a plane and converts to a matrix - points between 0 and 1 are up - 1 and 2 are right - assumes the plane has 90d corners - ''' - cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 - - - up= cent - ((plane[0]+plane[1])/2.0) - right= cent - ((plane[1]+plane[2])/2.0) - z= up.cross(right) - - if normalize: - up.normalize() - right.normalize() - z.normalize() - - mat= Matrix(up, right, z) - - # translate - mat.resize4x4() - tmat= Blender.Mathutils.TranslationMatrix(cent) - return mat * tmat - - -# Used for mesh_solidify.py and mesh_wire.py - -# returns a length from an angle -# Imaging a 2d space. -# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA) -# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB) -# This function returns the length of LINEB at the point it would intersect LINEA -# - Use this for working out how long to make the vector - differencing it from surrounding faces, -# import math -from math import pi, sin, cos, sqrt - -def angleToLength(angle): - # Alredy accounted for - if angle < 0.000001: return 1.0 - else: return abs(1.0 / cos(pi*angle/180)); diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py deleted file mode 100644 index 292f7a4b91e..00000000000 --- a/release/scripts/bpymodules/BPyMesh.py +++ /dev/null @@ -1,1326 +0,0 @@ -# ***** 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 Blender -import bpy -import BPyMesh_redux # seperated because of its size. -# reload(BPyMesh_redux) -redux= BPyMesh_redux.redux - -# python 2.3 has no reversed() iterator. this will only work on lists and tuples -try: - reversed -except: - def reversed(l): return l[::-1] - - -# If python version is less than 2.4, try to get set stuff from module -try: - set -except: - try: - from sets import Set as set - except: - set= None - - - - - -def meshWeight2List(me): - ''' Takes a mesh and return its group names and a list of lists, one list per vertex. - aligning the each vert list with the group names, each list contains float value for the weight. - These 2 lists can be modified and then used with list2MeshWeight to apply the changes. - ''' - - # Clear the vert group. - groupNames= me.getVertGroupNames() - len_groupNames= len(groupNames) - - if not len_groupNames: - # no verts? return a vert aligned empty list - return [[] for i in xrange(len(me.verts))], [] - - else: - vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))] - - for group_index, group in enumerate(groupNames): - for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. - vWeightList[vert_index][group_index]= weight - - # removed this because me may be copying teh vertex groups. - #for group in groupNames: - # me.removeVertGroup(group) - - return groupNames, vWeightList - - -def list2MeshWeight(me, groupNames, vWeightList): - ''' Takes a list of groups and a list of vertex Weight lists as created by meshWeight2List - and applys it to the mesh.''' - - if len(vWeightList) != len(me.verts): - raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' - - act_group = me.activeGroup - - # Clear the vert group. - currentGroupNames= me.getVertGroupNames() - for group in currentGroupNames: - me.removeVertGroup(group) # messes up the active group. - - # Add clean unused vert groupNames back - currentGroupNames= me.getVertGroupNames() - for group in groupNames: - me.addVertGroup(group) - - add_ = Blender.Mesh.AssignModes.ADD - - vertList= [None] - for i, v in enumerate(me.verts): - vertList[0]= i - for group_index, weight in enumerate(vWeightList[i]): - if weight: - try: - me.assignVertsToGroup(groupNames[group_index], vertList, min(1, max(0, weight)), add_) - except: - pass # vert group is not used anymore. - - try: me.activeGroup = act_group - except: pass - - me.update() - - - - -def meshWeight2Dict(me): - ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex. - using the group as a key and a float value for the weight. - These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. - ''' - - vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist. - - # Clear the vert group. - groupNames= me.getVertGroupNames() - - for group in groupNames: - for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. - vWeightDict[vert_index][group]= weight - - # removed this because me may be copying teh vertex groups. - #for group in groupNames: - # me.removeVertGroup(group) - - return groupNames, vWeightDict - - -def dict2MeshWeight(me, groupNames, vWeightDict): - ''' Takes a list of groups and a list of vertex Weight dicts as created by meshWeight2Dict - and applys it to the mesh.''' - - if len(vWeightDict) != len(me.verts): - raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' - - act_group = me.activeGroup - - # Clear the vert group. - currentGroupNames= me.getVertGroupNames() - for group in currentGroupNames: - if group not in groupNames: - me.removeVertGroup(group) # messes up the active group. - else: - me.removeVertsFromGroup(group) - - # Add clean unused vert groupNames back - currentGroupNames= me.getVertGroupNames() - for group in groupNames: - if group not in currentGroupNames: - me.addVertGroup(group) - - add_ = Blender.Mesh.AssignModes.ADD - - vertList= [None] - for i, v in enumerate(me.verts): - vertList[0]= i - for group, weight in vWeightDict[i].iteritems(): - try: - me.assignVertsToGroup(group, vertList, min(1, max(0, weight)), add_) - except: - pass # vert group is not used anymore. - - try: me.activeGroup = act_group - except: pass - - me.update() - -def dictWeightMerge(dict_weights): - ''' - Takes dict weight list and merges into 1 weight dict item and returns it - ''' - - if not dict_weights: - return {} - - keys= [] - for weight in dict_weights: - keys.extend([ (k, 0.0) for k in weight.iterkeys() ]) - - new_wdict = dict(keys) - - len_dict_weights= len(dict_weights) - - for weight in dict_weights: - for group, value in weight.iteritems(): - new_wdict[group] += value/len_dict_weights - - return new_wdict - - -FLIPNAMES=[\ -('Left','Right'),\ -('_L','_R'),\ -('-L','-R'),\ -('.L','.R'),\ -] - -def dictWeightFlipGroups(dict_weight, groupNames, createNewGroups): - ''' - Returns a weight with flip names - dict_weight - 1 vert weight. - groupNames - because we may need to add new group names. - dict_weight - Weather to make new groups where needed. - ''' - - def flipName(name): - for n1,n2 in FLIPNAMES: - for nA, nB in ( (n1,n2), (n1.lower(),n2.lower()), (n1.upper(),n2.upper()) ): - if createNewGroups: - newName= name.replace(nA,nB) - if newName!=name: - if newName not in groupNames: - groupNames.append(newName) - return newName - - newName= name.replace(nB,nA) - if newName!=name: - if newName not in groupNames: - groupNames.append(newName) - return newName - - else: - newName= name.replace(nA,nB) - if newName!=name and newName in groupNames: - return newName - - newName= name.replace(nB,nA) - if newName!=name and newName in groupNames: - return newName - - return name - - if not dict_weight: - return dict_weight, groupNames - - - new_wdict = {} - for group, weight in dict_weight.iteritems(): - flipname= flipName(group) - new_wdict[flipname]= weight - - return new_wdict, groupNames - - -def mesh2linkedFaces(me): - ''' - Splits the mesh into connected parts, - these parts are returned as lists of faces. - used for seperating cubes from other mesh elements in the 1 mesh - ''' - - # Build vert face connectivity - vert_faces= [[] for i in xrange(len(me.verts))] - for f in me.faces: - for v in f: - vert_faces[v.index].append(f) - - # sort faces into connectivity groups - face_groups= [[f] for f in me.faces] - face_mapping = range(len(me.faces)) # map old, new face location - - # Now clump faces iterativly - ok= True - while ok: - ok= False - - for i, f in enumerate(me.faces): - mapped_index= face_mapping[f.index] - mapped_group= face_groups[mapped_index] - - for v in f: - for nxt_f in vert_faces[v.index]: - if nxt_f != f: - nxt_mapped_index= face_mapping[nxt_f.index] - - # We are not a part of the same group - if mapped_index != nxt_mapped_index: - - ok= True - - # Assign mapping to this group so they all map to this group - for grp_f in face_groups[nxt_mapped_index]: - face_mapping[grp_f.index] = mapped_index - - # Move faces into this group - mapped_group.extend(face_groups[nxt_mapped_index]) - - # remove reference to the list - face_groups[nxt_mapped_index]= None - - - # return all face groups that are not null - # this is all the faces that are connected in their own lists. - return [fg for fg in face_groups if fg] - - -def getFaceLoopEdges(faces, seams=[]): - ''' - Takes me.faces or a list of faces and returns the edge loops - These edge loops are the edges that sit between quads, so they dont touch - 1 quad, not not connected will make 2 edge loops, both only containing 2 edges. - - return a list of edge key lists - [ [(0,1), (4, 8), (3,8)], ...] - - optionaly, seams are edge keys that will be removed - ''' - - OTHER_INDEX = 2,3,0,1 # opposite face index - - edges = {} - - for f in faces: - if len(f) == 4: - edge_keys = f.edge_keys - for i, edkey in enumerate(f.edge_keys): - edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]]) - - for edkey in seams: - edges[edkey] = [] - - # Collect edge loops here - edge_loops = [] - - for edkey, ed_adj in edges.iteritems(): - if 0 face indicies - face_edges[i] -> list referencs local faces v indicies 1,2,3 &| 4 - face_edges[i][j] -> list of faces that this edge uses. - crap this is tricky to explain :/ - ''' - face_edges= [ [-1] * len(f) for f in me.faces ] - - face_edges_dict= dict([(ed.key, []) for ed in me.edges]) - for fidx, f in enumerate(me.faces): - for i, edkey in enumerate(f.edge_keys): - edge_face_users= face_edges_dict[edkey] - edge_face_users.append(f) - face_edges[fidx][i]= edge_face_users - - return face_edges - - -def facesPlanerIslands(me): - - def roundvec(v): - return round(v[0], 4), round(v[1], 4), round(v[2], 4) - - face_props= [(cent, no, roundvec(no), cent.dot(no)) for f in me.faces for no, cent in ((f.no, f.cent),)] - - face_edge_users= face_edges(me) - islands= [] - - used_faces= [0] * len(me.faces) - while True: - new_island= False - for i, used_val in enumerate(used_faces): - if used_val==0: - island= [i] - new_island= True - used_faces[i]= 1 - break - - if not new_island: - break - - island_growing= True - while island_growing: - island_growing= False - for fidx1 in island[:]: - if used_faces[fidx1]==1: - used_faces[fidx1]= 2 - face_prop1= face_props[fidx1] - for ed in face_edge_users[fidx1]: - for f2 in ed: - fidx2= f2.index - if fidx1 != fidx2 and used_faces[fidx2]==0: - island_growing= True - face_prop2= face_props[fidx2] - # normals are the same? - if face_prop1[2]==face_prop2[2]: - if abs(face_prop1[3] - face_prop1[1].dot(face_prop2[0])) < 0.000001: - used_faces[fidx2]= 1 - island.append(fidx2) - islands.append([me.faces[i] for i in island]) - return islands - - - -def facesUvIslands(me, PREF_IMAGE_DELIMIT=True): - def roundvec(v): - return round(v[0], 4), round(v[1], 4) - - if not me.faceUV: - return [ list(me.faces), ] - - # make a list of uv dicts - face_uvs= [ [roundvec(uv) for uv in f.uv] for f in me.faces] - - # key - face uv || value - list of face idxs - uv_connect_dict= dict([ (uv, [] ) for f_uvs in face_uvs for uv in f_uvs]) - - for i, f_uvs in enumerate(face_uvs): - for uv in f_uvs: # loops through rounded uv values - uv_connect_dict[uv].append(i) - islands= [] - - used_faces= [0] * len(me.faces) - while True: - new_island= False - for i, used_val in enumerate(used_faces): - if used_val==0: - island= [i] - new_island= True - used_faces[i]= 1 - break - - if not new_island: - break - - island_growing= True - while island_growing: - island_growing= False - for fidx1 in island[:]: - if used_faces[fidx1]==1: - used_faces[fidx1]= 2 - for uv in face_uvs[fidx1]: - for fidx2 in uv_connect_dict[uv]: - if fidx1 != fidx2 and used_faces[fidx2]==0: - if not PREF_IMAGE_DELIMIT or me.faces[fidx1].image==me.faces[fidx2].image: - island_growing= True - used_faces[fidx2]= 1 - island.append(fidx2) - - islands.append([me.faces[i] for i in island]) - return islands - -#def faceUvBounds(me, faces= None): - - -def facesUvRotate(me, deg, faces= None, pivot= (0,0)): - ''' - Faces can be None an all faces will be used - pivot is just the x/y well rotated about - - positive deg value for clockwise rotation - ''' - if faces==None: faces= me.faces - pivot= Blender.Mathutils.Vector(pivot) - - rotmat= Blender.Mathutils.RotationMatrix(-deg, 2) - - for f in faces: - f.uv= [((uv-pivot)*rotmat)+pivot for uv in f.uv] - -def facesUvScale(me, sca, faces= None, pivot= (0,0)): - ''' - Faces can be None an all faces will be used - pivot is just the x/y well rotated about - sca can be wither an int/float or a vector if you want to - scale x/y seperately. - a sca or (1.0, 1.0) will do nothing. - ''' - def vecmulti(v1,v2): - '''V2 is unchanged''' - v1[:]= (v1.x*v2.x, v1.y*v2.y) - return v1 - - sca= Blender.Mathutils.Vector(sca) - if faces==None: faces= me.faces - pivot= Blender.Mathutils.Vector(pivot) - - for f in faces: - f.uv= [vecmulti(uv-pivot, sca)+pivot for uv in f.uv] - - -def facesUvTranslate(me, tra, faces= None, pivot= (0,0)): - ''' - Faces can be None an all faces will be used - pivot is just the x/y well rotated about - ''' - if faces==None: faces= me.faces - tra= Blender.Mathutils.Vector(tra) - - for f in faces: - f.uv= [uv+tra for uv in f.uv] - - - -def edgeFaceUserCount(me, faces= None): - ''' - Return an edge aligned list with the count for all the faces that use that edge. - - can spesify a subset of the faces, so only those will be counted. - ''' - if faces==None: - faces= me.faces - max_vert= len(me.verts) - else: - # find the lighest vert index - pass - - edge_users= [0] * len(me.edges) - - edges_idx_dict= dict([(ed.key, ed.index) for ed in me.edges]) - - for f in faces: - for edkey in f.edge_keys: - edge_users[edges_idx_dict[edkey]] += 1 - - return edge_users - - -#============================================================================# -# Takes a face, and a pixel x/y on the image and returns a worldspace x/y/z # -# will return none if the pixel is not inside the faces UV # -#============================================================================# -def getUvPixelLoc(face, pxLoc, img_size = None, uvArea = None): - TriangleArea= Blender.Mathutils.TriangleArea - Vector= Blender.Mathutils.Vector - - if not img_size: - w,h = face.image.size - else: - w,h= img_size - - scaled_uvs= [Vector(uv.x*w, uv.y*h) for uv in f.uv] - - if len(scaled_uvs)==3: - indicies= ((0,1,2),) - else: - indicies= ((0,1,2), (0,2,3)) - - for fidxs in indicies: - for i1,i2,i3 in fidxs: - # IS a point inside our triangle? - # UVArea could be cached? - uv_area = TriangleArea(scaled_uvs[i1], scaled_uvs[i2], scaled_uvs[i3]) - area0 = TriangleArea(pxLoc, scaled_uvs[i2], scaled_uvs[i3]) - area1 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i3]) - area2 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i2]) - if area0 + area1 + area2 > uv_area + 1: # 1 px bleed/error margin. - pass # if were a quad the other side may contain the pixel so keep looking. - else: - # We know the point is in the tri - area0 /= uv_area - area1 /= uv_area - area2 /= uv_area - - # New location - return Vector(\ - face.v[i1].co[0]*area0 + face.v[i2].co[0]*area1 + face.v[i3].co[0]*area2,\ - face.v[i1].co[1]*area0 + face.v[i2].co[1]*area1 + face.v[i3].co[1]*area2,\ - face.v[i1].co[2]*area0 + face.v[i2].co[2]*area1 + face.v[i3].co[2]*area2\ - ) - - return None - - -# Used for debugging ngon -""" -def draw_loops(loops): - - me= Blender.Mesh.New() - for l in loops: - #~ me= Blender.Mesh.New() - - - i= len(me.verts) - me.verts.extend([v[0] for v in l]) - try: - me.verts[0].sel= 1 - except: - pass - me.edges.extend([ (j-1, j) for j in xrange(i+1, len(me.verts)) ]) - # Close the edge? - me.edges.extend((i, len(me.verts)-1)) - - - #~ ob= Blender.Object.New('Mesh') - #~ ob.link(me) - #~ scn= Blender.Scene.GetCurrent() - #~ scn.link(ob) - #~ ob.Layers= scn.Layers - #~ ob.sel= 1 - - - - # Fill - #fill= Blender.Mathutils.PolyFill(loops) - #me.faces.extend(fill) - - - ob= Blender.Object.New('Mesh') - ob.link(me) - scn= Blender.Scene.GetCurrent() - scn.link(ob) - ob.Layers= scn.Layers - ob.sel= 1 - Blender.Window.RedrawAll() -""" - -def ngon(from_data, indices, PREF_FIX_LOOPS= True): - ''' - Takes a polyline of indices (fgon) - and returns a list of face indicie lists. - Designed to be used for importers that need indices for an fgon to create from existing verts. - - from_data: either a mesh, or a list/tuple of vectors. - indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. - PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. - ''' - - if not set: # Need sets for this, otherwise do a normal fill. - PREF_FIX_LOOPS= False - - Vector= Blender.Mathutils.Vector - if not indices: - return [] - - # return [] - def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) - def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length - - def vert_treplet(v, i): - return v, rvec(v), i, mlen(v) - - def ed_key_mlen(v1, v2): - if v1[3] > v2[3]: - return v2[1], v1[1] - else: - return v1[1], v2[1] - - - if not PREF_FIX_LOOPS: - ''' - Normal single concave loop filling - ''' - if type(from_data) in (tuple, list): - verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] - else: - verts= [from_data.verts[i].co for ii, i in enumerate(indices)] - - for i in xrange(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): - if verts[i][1]==verts[i-1][0]: - verts.pop(i-1) - - fill= Blender.Geometry.PolyFill([verts]) - - else: - ''' - Seperate this loop into multiple loops be finding edges that are used twice - This is used by lightwave LWO files a lot - ''' - - if type(from_data) in (tuple, list): - verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] - else: - verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] - - edges= [(i, i-1) for i in xrange(len(verts))] - if edges: - edges[0]= (0,len(verts)-1) - - if not verts: - return [] - - - edges_used= set() - edges_doubles= set() - # We need to check if any edges are used twice location based. - for ed in edges: - edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) - if edkey in edges_used: - edges_doubles.add(edkey) - else: - edges_used.add(edkey) - - # Store a list of unconnected loop segments split by double edges. - # will join later - loop_segments= [] - - v_prev= verts[0] - context_loop= [v_prev] - loop_segments= [context_loop] - - for v in verts: - if v!=v_prev: - # Are we crossing an edge we removed? - if ed_key_mlen(v, v_prev) in edges_doubles: - context_loop= [v] - loop_segments.append(context_loop) - else: - if context_loop and context_loop[-1][1]==v[1]: - #raise "as" - pass - else: - context_loop.append(v) - - v_prev= v - # Now join loop segments - - def join_seg(s1,s2): - if s2[-1][1]==s1[0][1]: # - s1,s2= s2,s1 - elif s1[-1][1]==s2[0][1]: - pass - else: - return False - - # If were stuill here s1 and s2 are 2 segments in the same polyline - s1.pop() # remove the last vert from s1 - s1.extend(s2) # add segment 2 to segment 1 - - if s1[0][1]==s1[-1][1]: # remove endpoints double - s1.pop() - - s2[:]= [] # Empty this segment s2 so we dont use it again. - return True - - joining_segments= True - while joining_segments: - joining_segments= False - segcount= len(loop_segments) - - for j in xrange(segcount-1, -1, -1): #reversed(xrange(segcount)): - seg_j= loop_segments[j] - if seg_j: - for k in xrange(j-1, -1, -1): # reversed(xrange(j)): - if not seg_j: - break - seg_k= loop_segments[k] - - if seg_k and join_seg(seg_j, seg_k): - joining_segments= True - - loop_list= loop_segments - - for verts in loop_list: - while verts and verts[0][1]==verts[-1][1]: - verts.pop() - - loop_list= [verts for verts in loop_list if len(verts)>2] - # DONE DEALING WITH LOOP FIXING - - - # vert mapping - vert_map= [None]*len(indices) - ii=0 - for verts in loop_list: - if len(verts)>2: - for i, vert in enumerate(verts): - vert_map[i+ii]= vert[2] - ii+=len(verts) - - fill= Blender.Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) - #draw_loops(loop_list) - #raise 'done loop' - # map to original indicies - fill= [[vert_map[i] for i in reversed(f)] for f in fill] - - - if not fill: - print 'Warning Cannot scanfill, fallback on a triangle fan.' - fill= [ [0, i-1, i] for i in xrange(2, len(indices)) ] - else: - # Use real scanfill. - # See if its flipped the wrong way. - flip= None - for fi in fill: - if flip != None: - break - for i, vi in enumerate(fi): - if vi==0 and fi[i-1]==1: - flip= False - break - elif vi==1 and fi[i-1]==0: - flip= True - break - - if not flip: - for i, fi in enumerate(fill): - fill[i]= tuple([ii for ii in reversed(fi)]) - - - - - return fill - - - -# EG -''' -scn= Scene.GetCurrent() -me = scn.getActiveObject().getData(mesh=1) -ind= [v.index for v in me.verts if v.sel] # Get indices - -indices = ngon(me, ind) # fill the ngon. - -# Extand the faces to show what the scanfill looked like. -print len(indices) -me.faces.extend([[me.verts[ii] for ii in i] for i in indices]) -''' - -def meshCalcNormals(me, vertNormals=None): - ''' - takes a mesh and returns very high quality normals 1 normal per vertex. - The normals should be correct, indipendant of topology - - vertNormals - a list of vectors at least as long as the number of verts in the mesh - ''' - Ang= Blender.Mathutils.AngleBetweenVecs - Vector= Blender.Mathutils.Vector - SMALL_NUM=0.000001 - # Weight the edge normals by total angle difference - # EDGE METHOD - - if not vertNormals: - vertNormals= [ Vector() for v in xrange(len(me.verts)) ] - else: - for v in vertNormals: - v.zero() - - edges={} - for f in me.faces: - f_v = f.v - for edkey in f.edge_keys: - edges.setdefault(edkey, []).append(f.no) - - # Weight the edge normals by total angle difference - for fnos in edges.itervalues(): - - len_fnos= len(fnos) - if len_fnos>1: - totAngDiff=0 - for j in xrange(len_fnos-1, -1, -1): # same as reversed(xrange(...)) - for k in xrange(j-1, -1, -1): # same as reversed(xrange(...)) - #print j,k - try: - totAngDiff+= (Ang(fnos[j], fnos[k])) # /180 isnt needed, just to keeop the vert small. - except: - pass # Zero length face - - # print totAngDiff - if totAngDiff > SMALL_NUM: - ''' - average_no= Vector() - for no in fnos: - average_no+=no - ''' - average_no= reduce(lambda a,b: a+b, fnos, Vector()) - fnos.append(average_no*totAngDiff) # average no * total angle diff - #else: - # fnos[0] - else: - fnos.append(fnos[0]) - - for ed, v in edges.iteritems(): - vertNormals[ed[0]]+= v[-1] - vertNormals[ed[1]]+= v[-1] - for i, v in enumerate(me.verts): - v.no= vertNormals[i] - - - - -def pointInsideMesh(ob, pt): - Intersect = Blender.Mathutils.Intersect # 2 less dict lookups. - Vector = Blender.Mathutils.Vector - - def ptInFaceXYBounds(f, pt): - f_v = f.v - co= f_v[0].co - xmax= xmin= co.x - ymax= ymin= co.y - - co= f_v[1].co - xmax= max(xmax, co.x) - xmin= min(xmin, co.x) - ymax= max(ymax, co.y) - ymin= min(ymin, co.y) - - co= f_v[2].co - xmax= max(xmax, co.x) - xmin= min(xmin, co.x) - ymax= max(ymax, co.y) - ymin= min(ymin, co.y) - - if len(f_v)==4: - co= f_v[3].co - xmax= max(xmax, co.x) - xmin= min(xmin, co.x) - ymax= max(ymax, co.y) - ymin= min(ymin, co.y) - - # Now we have the bounds, see if the point is in it. - if\ - pt.x < xmin or\ - pt.y < ymin or\ - pt.x > xmax or\ - pt.y > ymax: - return False # point is outside face bounds - else: - return True # point inside. - #return xmax, ymax, xmin, ymin - - def faceIntersect(f): - f_v = f.v - isect = Intersect(f_v[0].co, f_v[1].co, f_v[2].co, ray, obSpacePt, 1) # Clipped. - if not isect and len(f) == 4: - isect = Intersect(f_v[0].co, f_v[2].co, f_v[3].co, ray, obSpacePt, 1) # Clipped. - - if isect and isect.z > obSpacePt.z: # This is so the ray only counts if its above the point. - return True - else: - return False - - obSpacePt = pt*ob.matrixWorld.copy().invert() - ray = Vector(0,0,-1) - me= ob.getData(mesh=1) - - # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true. - return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2 - - -def faceAngles(f): - ''' - Returns the angle between all corners in a tri or a quad - - ''' - AngleBetweenVecs = Blender.Mathutils.AngleBetweenVecs - def Ang(a1,a2): - try: return AngleBetweenVecs(a1,a2) - except: return 180 - - if len(f) == 3: - if type(f) in (tuple, list): v1,v2,v3 = f - else: v1,v2,v3 = [v.co for v in f] - a1= Ang(v2-v1,v3-v1) - a2= Ang(v1-v2,v3-v2) - a3 = 180 - (a1+a2) # a3= Mathutils.AngleBetweenVecs(v2-v3,v1-v3) - return a1,a2,a3 - - else: - if type(f) in (tuple, list): v1,v2,v3,v4 = f - else: v1,v2,v3,v4 = [v.co for v in f] - a1= Ang(v2-v1,v4-v1) - a2= Ang(v1-v2,v3-v2) - a3= Ang(v2-v3,v4-v3) - a4= Ang(v3-v4,v1-v4) - return a1,a2,a3,a4 - -# NMesh wrapper -Vector= Blender.Mathutils.Vector -class NMesh(object): - __slots__= 'verts', 'faces', 'edges', 'faceUV', 'materials', 'realmesh' - def __init__(self, mesh): - ''' - This is an NMesh wrapper that - mesh is an Mesh as returned by Blender.Mesh.New() - This class wraps NMesh like access into Mesh - - Running NMesh.update() - with this wrapper, - Will update the realmesh. - ''' - self.verts= [] - self.faces= [] - self.edges= [] - self.faceUV= False - self.materials= [] - self.realmesh= mesh - - def addFace(self, nmf): - self.faces.append(nmf) - - def Face(self, v=[]): - return NMFace(v) - def Vert(self, x,y,z): - return NMVert(x,y,z) - - def hasFaceUV(self, flag): - if flag: - self.faceUV= True - else: - self.faceUV= False - - def addMaterial(self, mat): - self.materials.append(mat) - - def update(self, recalc_normals=False): # recalc_normals is dummy - mesh= self.realmesh - mesh.verts= None # Clears the - - # Add in any verts from faces we may have not added. - for nmf in self.faces: - for nmv in nmf.v: - if nmv.index==-1: - nmv.index= len(self.verts) - self.verts.append(nmv) - - - mesh.verts.extend([nmv.co for nmv in self.verts]) - for i, nmv in enumerate(self.verts): - nmv.index= i - mv= mesh.verts[i] - mv.sel= nmv.sel - - good_faces= [nmf for nmf in self.faces if len(nmf.v) in (3,4)] - #print len(good_faces), 'AAA' - - - #mesh.faces.extend([nmf.v for nmf in self.faces]) - mesh.faces.extend([[mesh.verts[nmv.index] for nmv in nmf.v] for nmf in good_faces]) - if len(mesh.faces): - if self.faceUV: - mesh.faceUV= 1 - - #for i, nmf in enumerate(self.faces): - for i, nmf in enumerate(good_faces): - mf= mesh.faces[i] - if self.faceUV: - if len(nmf.uv) == len(mf.v): - mf.uv= [Vector(uv[0], uv[1]) for uv in nmf.uv] - if len(nmf.col) == len(mf.v): - for c, i in enumerate(mf.col): - c.r, c.g, c.b= nmf.col[i].r, nmf.col[i].g, nmf.col[i].b - if nmf.image: - mf.image= nmf.image - - mesh.materials= self.materials[:16] - -class NMVert(object): - __slots__= 'co', 'index', 'no', 'sel', 'uvco' - def __init__(self, x,y,z): - self.co= Vector(x,y,z) - self.index= None # set on appending. - self.no= Vector(0,0,1) # dummy - self.sel= 0 - self.uvco= None -class NMFace(object): - __slots__= 'col', 'flag', 'hide', 'image', 'mat', 'materialIndex', 'mode', 'normal',\ - 'sel', 'smooth', 'transp', 'uv', 'v' - - def __init__(self, v=[]): - self.col= [] - self.flag= 0 - self.hide= 0 - self.image= None - self.mat= 0 # materialIndex needs support too. - self.mode= 0 - self.normal= Vector(0,0,1) - self.uv= [] - self.sel= 0 - self.smooth= 0 - self.transp= 0 - self.uv= [] - self.v= [] # a list of nmverts. - -class NMCol(object): - __slots__ = 'r', 'g', 'b', 'a' - def __init__(self): - self.r= 255 - self.g= 255 - self.b= 255 - self.a= 255 - - -''' -# -verts_split= [dict() for i in xrange(len(me.verts))] - -tot_verts= 0 -for f in me.faces: - f_uv= f.uv - for i, v in enumerate(f.v): - vert_index= v.index # mesh index - vert_dict= verts_split[vert_index] # get the dict for this vert - - uv= f_uv[i] - # now we have the vert and the face uv well make a unique dict. - - vert_key= v.x, v.y, v.x, uv.x, uv.y # ADD IMAGE NAME HETR IF YOU WANT TO SPLIT BY THAT TOO - value= vert_index, tot_verts # ADD WEIGHT HERE IF YOU NEED. - try: - vert_dict[vert_key] # if this is missing it will fail. - except: - # this stores a mapping between the split and orig vert indicies - vert_dict[vert_key]= value - tot_verts+= 1 - -# a flat list of split verts - can add custom weight data here too if you need -split_verts= [None]*tot_verts - -for vert_split_dict in verts_split: - for key, value in vert_split_dict.iteritems(): - local_index, split_index= value - split_verts[split_index]= key - -# split_verts - Now you have a list of verts split by their UV. -''' diff --git a/release/scripts/bpymodules/BPyMesh_redux.py b/release/scripts/bpymodules/BPyMesh_redux.py deleted file mode 100644 index 5955d696fbd..00000000000 --- a/release/scripts/bpymodules/BPyMesh_redux.py +++ /dev/null @@ -1,652 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# (C) Copyright 2006 MetaVR, Inc. -# http://www.metavr.com -# Written by Campbell Barton -# -# 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 Blender -import bpy -Vector= Blender.Mathutils.Vector -Ang= Blender.Mathutils.AngleBetweenVecs -MidpointVecs= Blender.Mathutils.MidpointVecs -import BPyMesh - -# If python version is less than 2.4, try to get set stuff from module - -try: - set -except: - try: - from sets import Set as set - except: - set= None - -def uv_key(uv): - return round(uv.x, 5), round(uv.y, 5) - -def uv_key_mix(uv1, uv2, w1, w2): - # Weighted mix. w1+w2==1.0 - return w1*uv1[0]+w2*uv2[0], w1*uv1[1]+w2*uv2[1] - -def col_key(col): - return col.r, col.g, col.b - -def col_key_mix(col1, col2, w1, w2): - # Weighted mix. w1+w2==1.0 - return int(w1*col1[0] + w2*col2[0]), int(w1*col1[1] + w2*col2[1]), int(w1*col1[2]+col2[2]*w2) - - -def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEIGHT=1.0, FACE_TRIANGULATE=True, DO_UV=True, DO_VCOL=True, DO_WEIGHTS=True, VGROUP_INF_REDUX= None, VGROUP_INF_WEIGHT=0.5): - """ - BOUNDRY_WEIGHT - 0 is no boundry weighting. 2.0 will make them twice as unlikely to collapse. - FACE_AREA_WEIGHT - 0 is no weight. 1 is normal, 2.0 is higher. - """ - - if REDUX<0 or REDUX>1.0: - raise 'Error, factor must be between 0 and 1.0' - elif not set: - raise 'Error, this function requires Python 2.4 or a full install of Python 2.3' - - BOUNDRY_WEIGHT= 1+BOUNDRY_WEIGHT - - """ # DEBUG! - if Blender.Get('rt') == 1000: - DEBUG=True - else: - DEBUG= False - """ - - me= ob.getData(mesh=1) - me.hide= False # unhide all data,. - if len(me.faces)<5: - return - - - - if FACE_TRIANGULATE or REMOVE_DOUBLES: - me.sel= True - - if FACE_TRIANGULATE: - me.quadToTriangle() - - if REMOVE_DOUBLES: - me.remDoubles(0.0001) - - vgroups= me.getVertGroupNames() - - if not me.getVertGroupNames(): - DO_WEIGHTS= False - - if (VGROUP_INF_REDUX!= None and VGROUP_INF_REDUX not in vgroups) or\ - VGROUP_INF_WEIGHT==0.0: - VGROUP_INF_REDUX= None - - try: - VGROUP_INF_REDUX_INDEX= vgroups.index(VGROUP_INF_REDUX) - except: - VGROUP_INF_REDUX_INDEX= -1 - - # del vgroups - len_vgroups= len(vgroups) - - - - OLD_MESH_MODE= Blender.Mesh.Mode() - Blender.Mesh.Mode(Blender.Mesh.SelectModes.VERTEX) - - if DO_UV and not me.faceUV: - DO_UV= False - - if DO_VCOL and not me.vertexColors: - DO_VCOL = False - - current_face_count= len(me.faces) - target_face_count= int(current_face_count * REDUX) - # % of the collapseable faces to collapse per pass. - #collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. - collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. - - """# DEBUG! - if DEBUG: - COUNT= [0] - def rd(): - if COUNT[0]< 330: - COUNT[0]+=1 - return - me.update() - Blender.Window.RedrawAll() - print 'Press key for next, count "%s"' % COUNT[0] - try: input() - except KeyboardInterrupt: - raise "Error" - except: - pass - - COUNT[0]+=1 - """ - - class collapseEdge(object): - __slots__ = 'length', 'key', 'faces', 'collapse_loc', 'v1', 'v2','uv1', 'uv2', 'col1', 'col2', 'collapse_weight' - def __init__(self, ed): - self.init_from_edge(ed) # So we can re-use the classes without using more memory. - - def init_from_edge(self, ed): - self.key= ed.key - self.length= ed.length - self.faces= [] - self.v1= ed.v1 - self.v2= ed.v2 - if DO_UV or DO_VCOL: - self.uv1= [] - self.uv2= [] - self.col1= [] - self.col2= [] - - # self.collapse_loc= None # new collapse location. - # Basic weighting. - #self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2)) - self.collapse_weight= 1.0 - - def collapse_locations(self, w1, w2): - ''' - Generate a smart location for this edge to collapse to - w1 and w2 are vertex location bias - ''' - - v1co= self.v1.co - v2co= self.v2.co - v1no= self.v1.no - v2no= self.v2.no - - # Basic operation, works fine but not as good as predicting the best place. - #between= ((v1co*w1) + (v2co*w2)) - #self.collapse_loc= between - - # normalize the weights of each vert - se we can use them as scalers. - wscale= w1+w2 - if not wscale: # no scale? - w1=w2= 0.5 - else: - w1/=wscale - w2/=wscale - - length= self.length - between= MidpointVecs(v1co, v2co) - - # Collapse - # new_location = between # Replace tricky code below. this code predicts the best collapse location. - - # Make lines at right angles to the normals- these 2 lines will intersect and be - # the point of collapsing. - - # Enlarge so we know they intersect: self.length*2 - cv1= v1no.cross(v1no.cross(v1co-v2co)) - cv2= v2no.cross(v2no.cross(v2co-v1co)) - - # Scale to be less then the edge lengths. - cv2.length = cv1.length = 1 - - cv1 = cv1 * (length* 0.4) - cv2 = cv2 * (length* 0.4) - - smart_offset_loc= between + (cv1 + cv2) - - # Now we need to blend between smart_offset_loc and w1/w2 - # you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend. - if w1 > 0.5: # between v1 and smart_offset_loc - #self.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5) - w2*=2 - w1= 1-w2 - new_loc_smart= v1co*w1 + smart_offset_loc*w2 - else: # w between v2 and smart_offset_loc - w1*=2 - w2= 1-w1 - new_loc_smart= v2co*w2 + smart_offset_loc*w1 - - if new_loc_smart.x != new_loc_smart.x: # NAN LOCATION, revert to between - new_loc_smart= None - - return new_loc_smart, between, v1co*0.99999 + v2co*0.00001, v1co*0.00001 + v2co*0.99999 - - - class collapseFace(object): - __slots__ = 'verts', 'normal', 'area', 'index', 'orig_uv', 'orig_col', 'uv', 'col' # , 'collapse_edge_count' - def __init__(self, f): - self.init_from_face(f) - - def init_from_face(self, f): - self.verts= f.v - self.normal= f.no - self.area= f.area - self.index= f.index - if DO_UV: - self.orig_uv= [uv_key(uv) for uv in f.uv] - self.uv= f.uv - if DO_VCOL: - self.orig_col= [col_key(col) for col in f.col] - self.col= f.col - - collapse_edges= collapse_faces= None - - # So meshCalcNormals can avoid making a new list all the time. - reuse_vertNormals= [ Vector() for v in xrange(len(me.verts)) ] - - while target_face_count <= len(me.faces): - BPyMesh.meshCalcNormals(me, reuse_vertNormals) - - if DO_WEIGHTS: - #groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) - groupNames, vWeightList= BPyMesh.meshWeight2List(me) - - # THIS CRASHES? Not anymore. - verts= list(me.verts) - edges= list(me.edges) - faces= list(me.faces) - - # THIS WORKS - #verts= me.verts - #edges= me.edges - #faces= me.faces - - # if DEBUG: DOUBLE_CHECK= [0]*len(verts) - me.sel= False - - if not collapse_faces: # Initialize the list. - collapse_faces= [collapseFace(f) for f in faces] - collapse_edges= [collapseEdge(ed) for ed in edges] - else: - for i, ed in enumerate(edges): - collapse_edges[i].init_from_edge(ed) - - # Strip the unneeded end off the list - collapse_edges[i+1:]= [] - - for i, f in enumerate(faces): - collapse_faces[i].init_from_face(f) - - # Strip the unneeded end off the list - collapse_faces[i+1:]= [] - - - collapse_edges_dict= dict( [(ced.key, ced) for ced in collapse_edges] ) - - # Store verts edges. - vert_ed_users= [[] for i in xrange(len(verts))] - for ced in collapse_edges: - vert_ed_users[ced.key[0]].append(ced) - vert_ed_users[ced.key[1]].append(ced) - - # Store face users - vert_face_users= [[] for i in xrange(len(verts))] - - # Have decieded not to use this. area is better. - #face_perim= [0.0]* len(me.faces) - - for ii, cfa in enumerate(collapse_faces): - for i, v1 in enumerate(cfa.verts): - vert_face_users[v1.index].append( (i,cfa) ) - - # add the uv coord to the vert - v2 = cfa.verts[i-1] - i1= v1.index - i2= v2.index - - if i1>i2: ced= collapse_edges_dict[i2,i1] - else: ced= collapse_edges_dict[i1,i2] - - ced.faces.append(cfa) - if DO_UV or DO_VCOL: - # if the edge is flipped from its order in the face then we need to flip the order indicies. - if cfa.verts[i]==ced.v1: i1,i2 = i, i-1 - else: i1,i2 = i-1, i - - if DO_UV: - ced.uv1.append( cfa.orig_uv[i1] ) - ced.uv2.append( cfa.orig_uv[i2] ) - - if DO_VCOL: - ced.col1.append( cfa.orig_col[i1] ) - ced.col2.append( cfa.orig_col[i2] ) - - - # PERIMITER - #face_perim[ii]+= ced.length - - - - # How weight the verts by the area of their faces * the normal difference. - # when the edge collapses, to vert weights are taken into account - - vert_weights= [0.5] * len(verts) - - for ii, vert_faces in enumerate(vert_face_users): - for f in vert_faces: - try: - no_ang= (Ang(verts[ii].no, f[1].normal)/180) * f[1].area - except: - no_ang= 1.0 - - vert_weights[ii] += no_ang - - # Use a vertex group as a weighting. - if VGROUP_INF_REDUX!=None: - - # Get Weights from a vgroup. - """ - vert_weights_map= [1.0] * len(verts) - for i, wd in enumerate(vWeightDict): - try: vert_weights_map[i]= 1+(wd[VGROUP_INF_REDUX] * VGROUP_INF_WEIGHT) - except: pass - """ - vert_weights_map= [1+(wl[VGROUP_INF_REDUX_INDEX]*VGROUP_INF_WEIGHT) for wl in vWeightList ] - - - # BOUNDRY CHECKING AND WEIGHT EDGES. CAN REMOVE - # Now we know how many faces link to an edge. lets get all the boundry verts - if BOUNDRY_WEIGHT > 0: - verts_boundry= [1] * len(verts) - #for ed_idxs, faces_and_uvs in edge_faces_and_uvs.iteritems(): - for ced in collapse_edges: - if len(ced.faces) < 2: - for key in ced.key: # only ever 2 key indicies. - verts_boundry[key]= 2 - - for ced in collapse_edges: - b1= verts_boundry[ced.key[0]] - b2= verts_boundry[ced.key[1]] - if b1 != b2: - # Edge has 1 boundry and 1 non boundry vert. weight higher - ced.collapse_weight= BOUNDRY_WEIGHT - #elif b1==b2==2: # if both are on a seam then weigh half as bad. - # ced.collapse_weight= ((BOUNDRY_WEIGHT-1)/2) +1 - # weight the verts by their boundry status - del b1 - del b2 - - for ii, boundry in enumerate(verts_boundry): - if boundry==2: - vert_weights[ii] *= BOUNDRY_WEIGHT - - vert_collapsed= verts_boundry - del verts_boundry - else: - vert_collapsed= [1] * len(verts) - - - - - # Best method, no quick hacks here, Correction. Should be the best but needs tweaks. - def ed_set_collapse_error(ced): - # Use the vertex weights to bias the new location. - new_locs= ced.collapse_locations(vert_weights[ced.key[0]], vert_weights[ced.key[1]]) - - - # Find the connecting faces of the 2 verts. - i1, i2= ced.key - test_faces= set() - for i in (i1,i2): # faster then LC's - for f in vert_face_users[i]: - test_faces.add(f[1].index) - for f in ced.faces: - test_faces.remove(f.index) - - - v1_orig= Vector(ced.v1.co) - v2_orig= Vector(ced.v2.co) - - def test_loc(new_loc): - ''' - Takes a location and tests the error without changing anything - ''' - new_weight= ced.collapse_weight - ced.v1.co= ced.v2.co= new_loc - - new_nos= [faces[i].no for i in test_faces] - - # So we can compare the befire and after normals - ced.v1.co= v1_orig - ced.v2.co= v2_orig - - # now see how bad the normals are effected - angle_diff= 1.0 - - for ii, i in enumerate(test_faces): # local face index, global face index - cfa= collapse_faces[i] # this collapse face - try: - # can use perim, but area looks better. - if FACE_AREA_WEIGHT: - # Psudo code for wrighting - # angle_diff= The before and after angle difference between the collapsed and un-collapsed face. - # ... devide by 180 so the value will be between 0 and 1.0 - # ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below) - # area_weight= The faces original area * the area weight - # ... add 1.0 so a small area face dosent make the angle_diff have no effect. - # - # Now multiply - (angle_diff * area_weight) - # ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting. - - angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area - else: - angle_diff+= (Ang(cfa.normal), new_nos[ii])/180 - - except: - pass - - - # This is very arbirary, feel free to modify - try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1 - except: no_ang= 2.0 - - # do *= because we face the boundry weight to initialize the weight. 1.0 default. - new_weight *= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1) - return new_weight - # End testloc - - - # Test the collapse locatons - collapse_loc_best= None - collapse_weight_best= 1000000000 - ii= 0 - for collapse_loc in new_locs: - if collapse_loc: # will only ever fail if smart loc is NAN - test_weight= test_loc(collapse_loc) - if test_weight < collapse_weight_best: - iii= ii - collapse_weight_best = test_weight - collapse_loc_best= collapse_loc - ii+=1 - - ced.collapse_loc= collapse_loc_best - ced.collapse_weight= collapse_weight_best - - - # are we using a weight map - if VGROUP_INF_REDUX: - v= vert_weights_map[i1]+vert_weights_map[i2] - ced.collapse_weight*= v - # End collapse Error - - # We can calculate the weights on __init__ but this is higher qualuity. - for ced in collapse_edges: - if ced.faces: # dont collapse faceless edges. - ed_set_collapse_error(ced) - - # Wont use the function again. - del ed_set_collapse_error - # END BOUNDRY. Can remove - - # sort by collapse weight - try: collapse_edges.sort(key = lambda ced: ced.collapse_weight) # edges will be used for sorting - except: collapse_edges.sort(lambda ced1, ced2: cmp(ced1.collapse_weight, ced2.collapse_weight)) # edges will be used for sorting - - - vert_collapsed= [0]*len(verts) - - collapse_edges_to_collapse= [] - - # Make a list of the first half edges we can collapse, - # these will better edges to remove. - collapse_count=0 - for ced in collapse_edges: - if ced.faces: - i1, i2= ced.key - # Use vert selections - if vert_collapsed[i1] or vert_collapsed[i2]: - pass - else: - # Now we know the verts havnyt been collapsed. - vert_collapsed[i2]= vert_collapsed[i1]= 1 # Dont collapse again. - collapse_count+=1 - collapse_edges_to_collapse.append(ced) - - # Get a subset of the entire list- the first "collapse_per_pass", that are best to collapse. - if collapse_count > 4: - collapse_count = int(collapse_count*collapse_per_pass) - else: - collapse_count = len(collapse_edges) - # We know edge_container_list_collapse can be removed. - for ced in collapse_edges_to_collapse: - """# DEBUG! - if DEBUG: - if DOUBLE_CHECK[ced.v1.index] or\ - DOUBLE_CHECK[ced.v2.index]: - raise 'Error' - else: - DOUBLE_CHECK[ced.v1.index]=1 - DOUBLE_CHECK[ced.v2.index]=1 - - tmp= (ced.v1.co+ced.v2.co)*0.5 - Blender.Window.SetCursorPos(tmp.x, tmp.y, tmp.z) - Blender.Window.RedrawAll() - """ - - # Chech if we have collapsed our quota. - collapse_count-=1 - if not collapse_count: - break - - current_face_count -= len(ced.faces) - - # Find and assign the real weights based on collapse loc. - - # Find the weights from the collapse error - if DO_WEIGHTS or DO_UV or DO_VCOL: - i1, i2= ced.key - # Dont use these weights since they may not have been used to make the collapse loc. - #w1= vert_weights[i1] - #w2= vert_weights[i2] - w1= (ced.v2.co-ced.collapse_loc).length - w2= (ced.v1.co-ced.collapse_loc).length - - # Normalize weights - wscale= w1+w2 - if not wscale: # no scale? - w1=w2= 0.5 - else: - w1/= wscale - w2/= wscale - - - # Interpolate the bone weights. - if DO_WEIGHTS: - - # add verts vgroups to eachother - wl1= vWeightList[i1] # v1 weight dict - wl2= vWeightList[i2] # v2 weight dict - for group_index in xrange(len_vgroups): - wl1[group_index]= wl2[group_index]= (wl1[group_index]*w1) + (wl2[group_index]*w2) - # Done finding weights. - - - - if DO_UV or DO_VCOL: - # Handel UV's and vert Colors! - for v, my_weight, other_weight, edge_my_uvs, edge_other_uvs, edge_my_cols, edge_other_cols in (\ - (ced.v1, w1, w2, ced.uv1, ced.uv2, ced.col1, ced.col2),\ - (ced.v2, w2, w1, ced.uv2, ced.uv1, ced.col2, ced.col1)\ - ): - uvs_mixed= [ uv_key_mix(edge_my_uvs[iii], edge_other_uvs[iii], my_weight, other_weight) for iii in xrange(len(edge_my_uvs)) ] - cols_mixed= [ col_key_mix(edge_my_cols[iii], edge_other_cols[iii], my_weight, other_weight) for iii in xrange(len(edge_my_cols)) ] - - for face_vert_index, cfa in vert_face_users[v.index]: - if len(cfa.verts)==3 and cfa not in ced.faces: # if the face is apart of this edge then dont bother finding the uvs since the face will be removed anyway. - - if DO_UV: - # UV COORDS - uvk= cfa.orig_uv[face_vert_index] - try: - tex_index= edge_my_uvs.index(uvk) - except: - tex_index= None - """ # DEBUG! - if DEBUG: - print 'not found', uvk, 'in', edge_my_uvs, 'ed index', ii, '\nwhat about', edge_other_uvs - """ - if tex_index != None: # This face uses a uv in the collapsing face. - do a merge - other_uv= edge_other_uvs[tex_index] - uv_vec= cfa.uv[face_vert_index] - uv_vec.x, uv_vec.y= uvs_mixed[tex_index] - - # TEXFACE COLORS - if DO_VCOL: - colk= cfa.orig_col[face_vert_index] - try: tex_index= edge_my_cols.index(colk) - except: pass - if tex_index != None: - other_col= edge_other_cols[tex_index] - col_ob= cfa.col[face_vert_index] - col_ob.r, col_ob.g, col_ob.b= cols_mixed[tex_index] - - # DEBUG! if DEBUG: rd() - - # Execute the collapse - ced.v1.sel= ced.v2.sel= True # Select so remove doubles removed the edges and faces that use it - ced.v1.co= ced.v2.co= ced.collapse_loc - - # DEBUG! if DEBUG: rd() - if current_face_count <= target_face_count: - break - - # Copy weights back to the mesh before we remove doubles. - if DO_WEIGHTS: - #BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) - BPyMesh.list2MeshWeight(me, groupNames, vWeightList) - - doubles= me.remDoubles(0.0001) - current_face_count= len(me.faces) - - if current_face_count <= target_face_count or not doubles: # not doubles shoule never happen. - break - - me.update() - Blender.Mesh.Mode(OLD_MESH_MODE) - - -# Example usage -def main(): - Blender.Window.EditMode(0) - scn= bpy.data.scenes.active - active_ob= scn.objects.active - t= Blender.sys.time() - redux(active_ob, 0.5) - print '%.4f' % (Blender.sys.time()-t) - -if __name__=='__main__': - main() diff --git a/release/scripts/bpymodules/BPyMessages.py b/release/scripts/bpymodules/BPyMessages.py deleted file mode 100644 index 8ee1aa6c707..00000000000 --- a/release/scripts/bpymodules/BPyMessages.py +++ /dev/null @@ -1,61 +0,0 @@ -from Blender import Draw, sys -def Error_NoMeshSelected(): - Draw.PupMenu('Error%t|No mesh objects selected') -def Error_NoActive(): - Draw.PupMenu('Error%t|No active object') -def Error_NoMeshActive(): - Draw.PupMenu('Error%t|Active object is not a mesh') -def Error_NoMeshUvSelected(): - Draw.PupMenu('Error%t|No mesh objects with texface selected') -def Error_NoMeshUvActive(): - Draw.PupMenu('Error%t|Active object is not a mesh with texface') -def Error_NoMeshMultiresEdit(): - Draw.PupMenu('Error%t|Unable to complete action with multires enabled') -def Error_NoMeshFaces(): - Draw.PupMenu('Error%t|Mesh has no faces') - -# File I/O messages -def Error_NoFile(path): - '''True if file missing, False if files there - - Use simply by doing... - if Error_NoFile(path): return - ''' - if not sys.exists(sys.expandpath(path)): - Draw.PupMenu("Error%t|Can't open file: " + path) - return True - return False - -def Error_NoDir(path): - '''True if dirs missing, False if dirs there - - Use simply by doing... - if Error_NoDir(path): return - ''' - if not sys.exists(sys.expandpath(path)): - Draw.PupMenu("Error%t|Path does not exist: " + path) - return True - return False - - -def Warning_MeshDistroyLayers(mesh): - '''Returns true if we can continue to edit the mesh, warn when using NMesh''' - if len(mesh.getUVLayerNames()) >1 and len(mesh.getColorLayerNames()) >1: - return True - - ret = Draw.PupMenu('Warning%t|This script will distroy inactive UV and Color layers, OK?') - if ret == -1: - return False - - return True - -def Warning_SaveOver(path): - '''Returns - True to save, False dont save''' - if sys.exists(sys.expandpath(path)): - ret= Draw.PupMenu('Save over%t|' + path) - if ret == -1: - return False - - return True - - diff --git a/release/scripts/bpymodules/BPyNMesh.py b/release/scripts/bpymodules/BPyNMesh.py deleted file mode 100644 index 043d8514db9..00000000000 --- a/release/scripts/bpymodules/BPyNMesh.py +++ /dev/null @@ -1,48 +0,0 @@ -# $Id$ -# -# -------------------------------------------------------------------------- -# BPyNMesh.py version 0.1 -# -------------------------------------------------------------------------- -# helper functions to be used by other scripts -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - - -# -------------------------------------------------------------------------- -# "Apply size and rotation" function by Jonas Petersen -# -------------------------------------------------------------------------- -# This function does (hopefully) exactly what the -# "Apply size and rotation" command does (CTRL-A in Object Mode). -def ApplySizeAndRotation(obj): - if obj.getType() != "Mesh": return - if obj.SizeX==1.0 and obj.SizeY==1.0 and obj.SizeZ==1.0 and obj.RotX == 0.0 and obj.RotY == 0.0 and obj.RotZ == 0.0: return - mesh = obj.getData() - matrix = obj.matrix - v = [0,0,0] - for vert in mesh.verts: - co = vert.co - v[0] = co[0]*matrix[0][0] + co[1]*matrix[1][0] + co[2]*matrix[2][0] - v[1] = co[0]*matrix[0][1] + co[1]*matrix[1][1] + co[2]*matrix[2][1] - v[2] = co[0]*matrix[0][2] + co[1]*matrix[1][2] + co[2]*matrix[2][2] - co[0], co[1], co[2] = v - obj.SizeX = obj.SizeY = obj.SizeZ = 1.0 - obj.RotX = obj.RotY = obj.RotZ = 0.0 - mesh.update() - diff --git a/release/scripts/bpymodules/BPyObject.py b/release/scripts/bpymodules/BPyObject.py deleted file mode 100644 index 54ff949218d..00000000000 --- a/release/scripts/bpymodules/BPyObject.py +++ /dev/null @@ -1,108 +0,0 @@ -import Blender - -def getObjectArmature(ob): - ''' - This returns the first armature the mesh uses. - remember there can be more then 1 armature but most people dont do that. - ''' - if ob.type != 'Mesh': - return None - - arm = ob.parent - if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE: - return arm - - for m in ob.modifiers: - if m.type== Blender.Modifier.Types.ARMATURE: - arm = m[Blender.Modifier.Settings.OBJECT] - if arm: - return arm - - return None - - -def getDerivedObjects(ob, PARTICLES= True): - ''' - Takes an objects and returnes a list of (ob, maxrix4x4) pairs - that are derived from this object - - This will include the object its self if it would be rendered. - all dupli's for eg are not rendered themselves. - - currently supports - * dupligroups - * dupliverts - * dupliframes - * static particles as a mesh - - it is possible this function will return an empty list. - ''' - - ob_mtx_pairs = ob.DupObjects - effects= ob.effects - - # Ignore self if were a dupli* or our parent is a duplivert. - if ob.enableDupFrames or ob.enableDupGroup or ob.enableDupVerts: - pass - else: - parent= ob.parent - if parent and parent.enableDupVerts: - pass - else: - if effects and (not effects[0].flag & Blender.Effect.Flags.EMESH): - # Particles mesh wont render - pass - else: - ob_mtx_pairs.append((ob, ob.matrixWorld)) - - - if PARTICLES: - type_vec= type(Blender.Mathutils.Vector()) - type_tp= type((0,0)) - type_ls= type([]) - - # TODO, particles per child object. - # TODO Support materials - me= Blender.Mesh.New() - for eff in effects: - par= eff.getParticlesLoc() - - if par: - type_par= type(par[0]) - - if type_par == type_vec: - # point particles - me.verts.extend(par) - - elif type_par == type_tp: - # edge pairs - start_index= len(me.verts) - me.verts.extend([v for p in par for v in p]) - me.edges.extend( [(i, i+1) for i in xrange(start_index, start_index + len(par) - 1 )] ) - - elif type_par == type_ls: - # lines of edges - start_index= len(me.verts) - me.verts.extend([v for line in par for v in line]) - - edges= [] - for line in par: - edges.extend( [(i,i+1) for i in xrange(start_index, start_index+len(line)-1) ] ) - start_index+= len(line) - - me.edges.extend(edges) - - if me.verts: - # If we have verts, then add the mesh - ob_par = Blender.Object.New('Mesh') - ob_par.link( me ) - - LOOSE= Blender.Mesh.EdgeFlags.LOOSE - for ed in me.edges: - ed.flag |= LOOSE - - # Particle's are in worldspace so an identity matrix is fine. - ob_mtx_pairs.append( (ob_par, Blender.Mathutils.Matrix()) ) - - return ob_mtx_pairs - - diff --git a/release/scripts/bpymodules/BPyRegistry.py b/release/scripts/bpymodules/BPyRegistry.py deleted file mode 100644 index 4d681e15937..00000000000 --- a/release/scripts/bpymodules/BPyRegistry.py +++ /dev/null @@ -1,267 +0,0 @@ -# -------------------------------------------------------------------------- -# Module BPyRegistry version 0.1 -# Helper functions to store / restore configuration data. -# -------------------------------------------------------------------------- -# $Id$ -# -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br -# -# 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, -# -------------------------------------------------------------------------- - -# The Registry is a Python dictionary that is kept in Blender for as long as -# the program is running, where scripts can store / restore persistent data -# (data that is not lost when the script exits). This module provides -# functions to save and restore Registry entries as config data in the -# bpydata/config folder. Scripts just need to give an extra parameter to -# the Blender.Registry.Get/Set() functions to have their data automatically -# saved and restored when needed. -# -# Note: entries starting with an underscore are not saved, so script authors -# can use that fact to define data that is not meant to be stored in a -# config file. Example: data to be passed to another script and references to -# invalid data, like Blender objects and any function or method. -# -# Check the Blender.Registry documentation for more information. - -import Blender -from Blender import Registry, sys as bsys - -_EXT = '.cfg' # file extension for saved config data - -# limits: -#MAX_ITEMS_NUM = 60 # max number of keys per dict and itens per list and tuple -#MAX_STR_LEN = 300 # max string length (remember this is just for config data) - -_CFG_DIR = '' -if Blender.Get('udatadir'): - _CFG_DIR = Blender.sys.join(Blender.Get('udatadir'), 'config') -if not _CFG_DIR or not bsys.exists(_CFG_DIR): - _CFG_DIR = Blender.sys.join(Blender.Get('datadir'), 'config') -if not bsys.exists(_CFG_DIR): - _CFG_DIR = '' - -# to compare against, so we don't write to a cvs tree: -_CVS_SUBPATH = 'release/scripts/bpydata/config/' -if bsys.dirsep == '\\': - _CVS_SUBPATH = _CVS_SUBPATH.replace('/', '\\') - -_KEYS = [k for k in Registry.Keys() if k[0] != '_'] - -# _ITEMS_NUM = 0 - -def _sanitize(o): - "Check recursively that all objects are valid, set invalid ones to None" - - # global MAX_ITEMS_NUM, MAX_STR_LEN, _ITEMS_NUM - - valid_types = [int, float, bool, long, type] - valid_checked_types = [str, unicode] - # Only very simple types are considered valid for configuration data, - # functions, methods and Blender objects (use their names instead) aren't. - - t = type(o) - - if t == dict: - ''' - _ITEMS_NUM += len(o) - if _ITEMS_NUM > MAX_ITEMS_NUM: - return None - ''' - for k, v in o.iteritems(): - o[k] = _sanitize(v) - elif t in [list, tuple]: - ''' - _ITEMS_NUM += len(o) - if _ITEMS_NUM > MAX_ITEMS_NUM: - return None - ''' - return [_sanitize(i) for i in o] - elif t in valid_types: - return o - elif t in valid_checked_types: - ''' - if len(o) > MAX_STR_LEN: - o = o[:MAX_STR_LEN] - ''' - return o - else: return None - - return o - - -def _dict_to_str(name, d): - "Return a pretty-print version of the passed dictionary" - if not d: return 'None' # d can be None if there was no config to pass - - if name: l = ['%s = {' % name] - else: l = ['{'] - #keys = d.keys() - for k,v in d.iteritems(): # .keys() - if type(v) == dict: - l.append("'%s': %s" % (k, _dict_to_str(None, v))) - else: - l.append("'%s': %s," % (k, repr(v))) - if name: l.append('}') - else: l.append('},') - return "\n".join(l) - -_HELP_MSG = """ -Please create a valid scripts config dir tree either by -copying release/scripts/ tree to your dir -or by copying release/scripts/bpydata/ tree to a user -defined scripts dir that you can set in the -User Preferences -> Paths tab -> Python path input box. -""" - -def _check_dir(): - global _CFG_DIR, _CVS_SUBPATH, _HELP_MSG - - if not _CFG_DIR: - errmsg = "scripts config dir not found!\n%s" % _HELP_MSG - raise IOError, errmsg - elif _CFG_DIR.find(_CVS_SUBPATH) > 0: - errmsg = """ -Your scripts config dir:\n%s -seems to reside in your local Blender's cvs tree.\n%s""" % (_CFG_DIR, _HELP_MSG) - raise SystemError, errmsg - else: return - - -# API: - -BPY_KEY_MISSING = 0 -BPY_KEY_IN_REGISTRY = 1 -BPY_KEY_IN_FILE = 2 - -def HasConfigData (key): - """ - Check if the given key exists, either already loaded in the Registry dict or - as a file in the script data config dir. - @type key: string - @param key: a given key name. - @returns: - - 0: key does not exist; - - 1: key exists in the Registry dict only; - - 2: key exists as a file only; - - 3: key exists in the Registry dict and also as a file. - @note: for readability it's better to check against the constant bitmasks - BPY_KEY_MISSING = 0, BPY_KEY_IN_REGISTRY = 1 and BPY_KEY_IN_FILE = 2. - """ - - fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) - - result = BPY_KEY_MISSING - if key in Registry.Keys(): result |= BPY_KEY_IN_REGISTRY - if bsys.exists(fname): result |= BPY_KEY_IN_FILE - - return result - - -def LoadConfigData (key = None): - """ - Load config data from file(s) to the Registry dictionary. - @type key: string - @param key: a given key name. If None (default), all available keys are - loaded. - @returns: None - """ - - _check_dir() - - import os - - if not key: - files = \ - [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] - else: - files = [] - fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) - if bsys.exists(fname): files.append(fname) - - for p in files: - try: - f = file(p, 'r') - lines = f.readlines() - f.close() - if lines: # Lines may be blank - mainkey = lines[0].split('=')[0].strip() - pysrc = "\n".join(lines) - exec(pysrc) - exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey)) - except Exception, e: - raise Warning(e) # Resend exception as warning - - -def RemoveConfigData (key = None): - """ - Remove this key's config file from the <(u)datadir>/config/ folder. - @type key: string - @param key: the name of the key to be removed. If None (default) all - available config files are deleted. - """ - - _check_dir() - - if not key: - files = \ - [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] - else: - files = [] - fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) - if bsys.exists(fname): files.append(fname) - - import os - - try: - for p in files: - os.remove(p) # remove the file(s) - except Exception, e: - raise Warning(e) # Resend exception as warning - - -def SaveConfigData (key = None): - """ - Save Registry key(s) as file(s) in the <(u)datadir>/config/ folder. - @type key: string - @param key: the name of the key to be saved. If None (default) all - available keys are saved. - """ - - global _KEYS, _CFG_DIR - - _check_dir() - - if key: keys = [key] - else: keys = _KEYS - - for mainkey in keys: - cfgdict = Registry.GetKey(mainkey).copy() - for k in cfgdict: # .keys() - if not k or k[0] == '_': - del cfgdict[k] - - if not cfgdict: continue - - try: - filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT)) - f = file(filename, 'w') - output = _dict_to_str(mainkey, _sanitize(cfgdict)) - if output!='None': - f.write(output) - f.close() - except Exception, e: - raise Warning(e) # Resend exception as warning diff --git a/release/scripts/bpymodules/BPyRender.py b/release/scripts/bpymodules/BPyRender.py deleted file mode 100644 index 951e1ae6300..00000000000 --- a/release/scripts/bpymodules/BPyRender.py +++ /dev/null @@ -1,633 +0,0 @@ -import Blender -from Blender import Scene, sys, Camera, Object, Image -from Blender.Scene import Render -Vector= Blender.Mathutils.Vector - - -def extFromFormat(format): - if format == Render.TARGA: return 'tga' - if format == Render.RAWTGA: return 'tga' - if format == Render.HDR: return 'hdr' - if format == Render.PNG: return 'png' - if format == Render.BMP: return 'bmp' - if format == Render.JPEG: return 'jpg' - if format == Render.HAMX: return 'ham' - if format == Render.TIFF: return 'tif' - if format == Render.CINEON: return 'cine' - if format == Render.DPX: return 'tif' - if format == Render.OPENEXR: return 'exr' - if format == Render.IRIS: return 'rgb' - return '' - - - -def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, camera_matrix= None, format=Render.PNG): - ''' - Takes any number of objects and renders them on the z axis, between x:y-0 and x:y-1 - Usefull for making images from a mesh without per pixel operations - - objects must be alredy placed - - smooth, anti alias True/False - - path renders to a PNG image - - alpha weather to render background as alpha - - returns the blender image - ''' - ext = '.' + extFromFormat(format) - print ext - # remove an extension if its alredy there - if path.lower().endswith(ext): - path= path[:-4] - - path_expand= sys.expandpath(path) + ext - - print path_expand, 'path' - - # Touch the path - try: - f= open(path_expand, 'w') - f.close() - except: - raise 'Error, could not write to path:' + path_expand - - - # RENDER THE FACES. - scn= Scene.GetCurrent() - render_scn= Scene.New() - render_scn.makeCurrent() - render_scn.Layers |= (1<<20)-1 # all layers enabled - - # Add objects into the current scene - for ob in objects: - render_scn.link(ob) - - render_context= render_scn.getRenderingContext() - render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. - - - render_context.imageSizeX(width) - render_context.imageSizeY(height) - - if smooth: - render_context.enableOversampling(True) - render_context.setOversamplingLevel(16) - else: - render_context.enableOversampling(False) - - render_context.setRenderWinSize(100) - render_context.setImageType(format) - render_context.enableExtensions(True) - #render_context.enableSky() # No alpha needed. - if alpha: - render_context.alphaMode= 1 - render_context.enableRGBAColor() - else: - render_context.alphaMode= 0 - render_context.enableRGBColor() - - render_context.displayMode= 0 # fullscreen - - # New camera and object - render_cam_data= Camera.New('ortho') - render_cam_ob= Object.New('Camera') - render_cam_ob.link(render_cam_data) - render_scn.link(render_cam_ob) - render_scn.objects.camera = render_cam_ob - - render_cam_data.type= 'ortho' - - - - # Position the camera - if camera_matrix: - render_cam_ob.setMatrix(camera_matrix) - # We need to take into account the matrix scaling when setting the size - # so we get the image bounds defined by the matrix - # first get the x and y factors from the matrix. - # To render the correct dimensions we must use the aspy and aspy to force the matrix scale to - # override the aspect enforced by the width and weight. - cent= Vector() * camera_matrix - xvec= Vector(1,0,0) * camera_matrix - yvec= Vector(0,1,0) * camera_matrix - # zvec= Vector(0,0,1) * camera_matrix - xlen = (cent-xvec).length # half height of the image - ylen = (cent-yvec).length # half width of the image - # zlen = (cent-zvec).length # dist to place the camera? - just use the loc for now. - - - # less then 1.0 portrate, 1.0 or more is portrate - asp_cam_mat= xlen/ylen # divide by zero? - possible but scripters fault. - asp_image_res= float(width)/height - #print 'asp quad', asp_cam_mat, 'asp_image', asp_image_res - #print 'xylen', xlen, ylen, 'w/h', width, height - # Setup the aspect - - if asp_cam_mat > asp_image_res: - # camera is wider then image res. - # to make the image wider, reduce the aspy - asp_diff= asp_image_res/asp_cam_mat - min_asp= asp_diff * 200 - #print 'X', min_asp - - elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res - # camera is narrower then image res - # to make the image narrower, reduce the aspx - asp_diff= asp_cam_mat/asp_image_res - min_asp= asp_diff * 200 - #print 'Y', min_asp - else: - min_asp= 200 - - # set the camera size - if xlen > ylen: - if asp_cam_mat > asp_image_res: - render_context.aspectX= 200 # get the greatest range possible - render_context.aspectY= min_asp # get the greatest range possible - else: - render_context.aspectY= 200 # get the greatest range possible - render_context.aspectX= min_asp # get the greatest range possible - #print "xlen bigger" - render_cam_data.scale= xlen * 2 - elif xlen < ylen:# ylen is bigger - if asp_cam_mat > asp_image_res: - render_context.aspectX= 200 # get the greatest range possible - render_context.aspectY= min_asp # get the greatest range possible - else: - render_context.aspectY= 200 # get the greatest range possible - render_context.aspectX= min_asp # get the greatest range possible - #print "ylen bigger" - render_cam_data.scale= ylen *2 - else: - # asppect 1:1 - #print 'NOLEN Bigger' - render_cam_data.scale= xlen * 2 - - #print xlen, ylen, 'xlen, ylen' - - else: - if width > height: - min_asp = int((float(height) / width) * 200) - render_context.aspectX= min_asp - render_context.aspectY= 200 - else: - min_asp = int((float(width) / height) * 200) - render_context.aspectX= 200 - render_context.aspectY= min_asp - - - render_cam_data.scale= 1.0 - render_cam_ob.LocZ= 1.0 - render_cam_ob.LocX= 0.5 - render_cam_ob.LocY= 0.5 - - Blender.Window.RedrawAll() - - render_context.render() - render_context.saveRenderedImage(path) - Render.CloseRenderWindow() - #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): - # raise 'Error!!!' - - scn.makeCurrent() - Scene.Unlink(render_scn) - - # NOW APPLY THE SAVED IMAGE TO THE FACES! - #print PREF_IMAGE_PATH_EXPAND - try: - target_image= Image.Load(path_expand) - return target_image - except: - raise 'Error: Could not render or load the image at path "%s"' % path_expand - return - - - -#-----------------------------------------------------------------------------# -# UV Baking functions, make a picture from mesh(es) uvs # -#-----------------------------------------------------------------------------# - -def mesh2uv(me_s, PREF_SEL_FACES_ONLY=False): - ''' - Converts a uv mapped mesh into a 2D Mesh from UV coords. - returns a triple - - (mesh2d, face_list, col_list) - "mesh" is the new mesh and... - "face_list" is the faces that were used to make the mesh, - "material_list" is a list of materials used by each face - These are in alligned with the meshes faces, so you can easerly copy data between them - - ''' - render_me= Blender.Mesh.New() - render_me.verts.extend( [Vector(0,0,0),] ) # 0 vert uv bugm dummy vert - face_list= [] - material_list= [] - for me in me_s: - me_materials= me.materials - if PREF_SEL_FACES_ONLY: - me_faces= [f for f in me.faces if f.sel] - else: - me_faces= me.faces - - face_list.extend(me_faces) - - # Dittro - if me_materials: - material_list.extend([me_materials[f.mat] for f in me_faces]) - else: - material_list.extend([None]*len(me_faces)) - - # Now add the verts - render_me.verts.extend( [ Vector(uv.x, uv.y, 0) for f in face_list for uv in f.uv ] ) - - # Now add the faces - tmp_faces= [] - vert_offset= 1 - for f in face_list: - tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) - vert_offset+= len(f) - - render_me.faces.extend(tmp_faces) - render_me.faceUV=1 - return render_me, face_list, material_list - - -def uvmesh_apply_normals(render_me, face_list): - '''Worldspace normals to vertex colors''' - for i, f in enumerate(render_me.faces): - face_orig= face_list[i] - f_col= f.col - for j, v in enumerate(face_orig): - c= f_col[j] - nx, ny, nz= v.no - c.r= int((nx+1)*128)-1 - c.g= int((ny+1)*128)-1 - c.b= int((nz+1)*128)-1 - -def uvmesh_apply_image(render_me, face_list): - '''Copy the image and uvs from the original faces''' - for i, f in enumerate(render_me.faces): - f.uv= face_list[i].uv - f.image= face_list[i].image - - -def uvmesh_apply_vcol(render_me, face_list): - '''Copy the vertex colors from the original faces''' - for i, f in enumerate(render_me.faces): - face_orig= face_list[i] - f_col= f.col - for j, c_orig in enumerate(face_orig.col): - c= f_col[j] - c.r= c_orig.r - c.g= c_orig.g - c.b= c_orig.b - -def uvmesh_apply_matcol(render_me, material_list): - '''Get the vertex colors from the original materials''' - for i, f in enumerate(render_me.faces): - mat_orig= material_list[i] - f_col= f.col - if mat_orig: - for c in f_col: - c.r= int(mat_orig.R*255) - c.g= int(mat_orig.G*255) - c.b= int(mat_orig.B*255) - else: - for c in f_col: - c.r= 255 - c.g= 255 - c.b= 255 - -def uvmesh_apply_col(render_me, color): - '''Get the vertex colors from the original materials''' - r,g,b= color - for i, f in enumerate(render_me.faces): - f_col= f.col - for c in f_col: - c.r= r - c.g= g - c.b= b - - -def vcol2image(me_s,\ - PREF_IMAGE_PATH,\ - PREF_IMAGE_SIZE,\ - PREF_IMAGE_BLEED,\ - PREF_IMAGE_SMOOTH,\ - PREF_IMAGE_WIRE,\ - PREF_IMAGE_WIRE_INVERT,\ - PREF_IMAGE_WIRE_UNDERLAY,\ - PREF_USE_IMAGE,\ - PREF_USE_VCOL,\ - PREF_USE_MATCOL,\ - PREF_USE_NORMAL,\ - PREF_USE_TEXTURE,\ - PREF_SEL_FACES_ONLY): - - - def rnd_mat(): - render_mat= Blender.Material.New() - mode= render_mat.mode - - # Dont use lights ever - mode |= Blender.Material.Modes.SHADELESS - - if PREF_IMAGE_WIRE: - # Set the wire color - if PREF_IMAGE_WIRE_INVERT: - render_mat.rgbCol= (1,1,1) - else: - render_mat.rgbCol= (0,0,0) - - mode |= Blender.Material.Modes.WIRE - if PREF_USE_VCOL or PREF_USE_MATCOL or PREF_USE_NORMAL: # both vcol and material color use vertex cols to avoid the 16 max limit in materials - mode |= Blender.Material.Modes.VCOL_PAINT - if PREF_USE_IMAGE: - mode |= Blender.Material.Modes.TEXFACE - - # Copy back the mode - render_mat.mode |= mode - return render_mat - - - render_me, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) - - # Normals exclude all others - if PREF_USE_NORMAL: - uvmesh_apply_normals(render_me, face_list) - else: - if PREF_USE_IMAGE: - uvmesh_apply_image(render_me, face_list) - uvmesh_apply_vcol(render_me, face_list) - - elif PREF_USE_VCOL: - uvmesh_apply_vcol(render_me, face_list) - - elif PREF_USE_MATCOL: - uvmesh_apply_matcol(render_me, material_list) - - elif PREF_USE_TEXTURE: - # if we have more then 16 materials across all the mesh objects were stuffed :/ - # get unique materials - tex_unique_materials= dict([(mat.name, mat) for mat in material_list]).values()[:16] # just incase we have more then 16 - tex_me= Blender.Mesh.New() - - # Backup the original shadless setting - tex_unique_materials_shadeless= [ mat.mode & Blender.Material.Modes.SHADELESS for mat in tex_unique_materials ] - - # Turn shadeless on - for mat in tex_unique_materials: - mat.mode |= Blender.Material.Modes.SHADELESS - - # Assign materials - render_me.materials= tex_unique_materials - - - - tex_material_indicies= dict([(mat.name, i) for i, mat in enumerate(tex_unique_materials)]) - - tex_me.verts.extend([Vector(0,0,0),]) # dummy - tex_me.verts.extend( [ Vector(v.co) for f in face_list for v in f ] ) - - # Now add the faces - tmp_faces= [] - vert_offset= 1 - for f in face_list: - tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) - vert_offset+= len(f) - - tex_me.faces.extend(tmp_faces) - - # Now we have the faces, put materials and normal, uvs into the mesh - if len(tex_me.faces) != len(face_list): - # Should never happen - raise "Error face length mismatch" - - # Copy data to the mesh that could be used as texture coords - for i, tex_face in enumerate(tex_me.faces): - orig_face= face_list[i] - - # Set the material index - try: - render_face.mat= tex_material_indicies[ material_list[i].name ] - except: - # more then 16 materials - pass - - - # set the uvs on the texmesh mesh - tex_face.uv= orig_face.uv - - orig_face_v= orig_face.v - # Set the normals - for j, v in enumerate(tex_face): - v.no= orig_face_v[j].no - - # Set the texmesh - render_me.texMesh= tex_me - # END TEXMESH - - - # Handel adding objects - render_ob= Blender.Object.New('Mesh') - render_ob.link(render_me) - - if not PREF_USE_TEXTURE: # textures use the original materials - render_me.materials= [rnd_mat()] - - - obs= [render_ob] - - - if PREF_IMAGE_WIRE_UNDERLAY: - # Make another mesh with the material colors - render_me_under, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) - - uvmesh_apply_matcol(render_me_under, material_list) - - # Handel adding objects - render_ob= Blender.Object.New('Mesh') - render_ob.link(render_me_under) - render_ob.LocZ= -0.01 - - # Add material and disable wire - mat= rnd_mat() - mat.rgbCol= 1,1,1 - mat.alpha= 0.5 - mat.mode &= ~Blender.Material.Modes.WIRE - mat.mode |= Blender.Material.Modes.VCOL_PAINT - - render_me_under.materials= [mat] - - obs.append(render_ob) - - elif PREF_IMAGE_BLEED and not PREF_IMAGE_WIRE: - # EVIL BLEEDING CODE!! - Just do copys of the mesh and place behind. Crufty but better then many other methods I have seen. - Cam - BLEED_PIXEL= 1.0/PREF_IMAGE_SIZE - z_offset= 0.0 - for i in xrange(PREF_IMAGE_BLEED): - for diag1, diag2 in ((-1,-1),(-1,1),(1,-1),(1,1), (1,0), (0,1), (-1,0), (0, -1)): # This line extends the object in 8 different directions, top avoid bleeding. - - render_ob= Blender.Object.New('Mesh') - render_ob.link(render_me) - - render_ob.LocX= (i+1)*diag1*BLEED_PIXEL - render_ob.LocY= (i+1)*diag2*BLEED_PIXEL - render_ob.LocZ= -z_offset - - obs.append(render_ob) - z_offset += 0.01 - - - - image= imageFromObjectsOrtho(obs, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_IMAGE_SIZE, PREF_IMAGE_SMOOTH) - - # Clear from memory as best as we can - render_me.verts= None - - if PREF_IMAGE_WIRE_UNDERLAY: - render_me_under.verts= None - - if PREF_USE_TEXTURE: - tex_me.verts= None - # Restire Shadeless setting - for i, mat in enumerate(tex_unique_materials): - # we know there all on so turn it off of its not set - if not tex_unique_materials_shadeless[i]: - mat.mode &= ~Blender.Material.Modes.SHADELESS - - return image - -def bakeToPlane(sce, ob_from, width, height, bakemodes, axis='z', margin=0, depth=32): - ''' - Bakes terrain onto a plane from one object - sce - scene to bake with - ob_from - mesh object - width/height - image size - bakemodes - list of baking modes to use, Blender.Scene.Render.BakeModes.NORMALS, Blender.Scene.Render.BakeModes.AO ... etc - axis - axis to allign the plane to. - margin - margin setting for baking. - depth - bit depth for the images to bake into, (32 or 128 for floating point images) - Example: - import Blender - from Blender import * - import BPyRender - sce = Scene.GetCurrent() - ob = Object.Get('Plane') - BPyRender.bakeToPlane(sce, ob, 512, 512, [Scene.Render.BakeModes.DISPLACEMENT, Scene.Render.BakeModes.NORMALS], 'z', 8 ) - ''' - - # Backup bake settings - rend = sce.render - BACKUP_bakeDist = rend.bakeDist - BACKUP_bakeBias = rend.bakeBias - BACKUP_bakeMode = rend.bakeMode - BACKUP_bakeClear = rend.bakeClear - BACKUP_bakeMargin = rend.bakeMargin - BACKUP_bakeToActive = rend.bakeToActive - BACKUP_bakeNormalize = rend.bakeNormalize - - # Backup object selection - BACKUP_obsel = list(sce.objects.selected) - BACKUP_obact = sce.objects.active - - # New bake settings - rend.bakeClear = True - rend.bakeMargin = margin - rend.bakeToActive = True - rend.bakeNormalize = True - - # Assume a mesh - me_from = ob_from.getData(mesh=1) - - xmin = ymin = zmin = 10000000000 - xmax = ymax = zmax =-10000000000 - - # Dont trust bounding boxes :/ - #bounds = ob_from.boundingBox - #for v in bounds: - # x,y,z = tuple(v) - mtx = ob_from.matrixWorld - for v in me_from.verts: - x,y,z = tuple(v.co*mtx) - - xmax = max(xmax, x) - ymax = max(ymax, y) - zmax = max(zmax, z) - - xmin = min(xmin, x) - ymin = min(ymin, y) - zmin = min(zmin, z) - - if axis=='x': - xmed = (xmin+xmax)/2.0 - co1 = (xmed, ymin, zmin) - co2 = (xmed, ymin, zmax) - co3 = (xmed, ymax, zmax) - co4 = (xmed, ymax, zmin) - rend.bakeDist = ((xmax-xmin)/2.0) + 0.000001 # we need a euler value for this since it - elif axis=='y': - ymed = (ymin+ymax)/2.0 - co1 = (xmin, ymed, zmin) - co2 = (xmin, ymed, zmax) - co3 = (xmax, ymed, zmax) - co4 = (xmax, ymed, zmin) - rend.bakeDist = ((ymax-ymin)/2.0) + 0.000001 - elif axis=='z': - zmed = (zmin+zmax)/2.0 - co1 = (xmin, ymin, zmed) - co2 = (xmin, ymax, zmed) - co3 = (xmax, ymax, zmed) - co4 = (xmax, ymin, zmed) - rend.bakeDist = ((zmax-zmin)/2.0) + 0.000001 - else: - raise "invalid axis" - me_plane = Blender.Mesh.New() - ob_plane = Blender.Object.New('Mesh') - ob_plane.link(me_plane) - sce.objects.link(ob_plane) - ob_plane.Layers = ob_from.Layers - - ob_from.sel = 1 # make active - sce.objects.active = ob_plane - ob_plane.sel = 1 - - me_plane.verts.extend([co4, co3, co2, co1]) - me_plane.faces.extend([(0,1,2,3)]) - me_plane.faceUV = True - me_plane_face = me_plane.faces[0] - uvs = me_plane_face.uv - uvs[0].x = 0.0; uvs[0].y = 0.0 - uvs[1].x = 0.0; uvs[1].y = 1.0 - uvs[2].x = 1.0; uvs[2].y = 1.0 - uvs[3].x = 1.0; uvs[3].y = 0.0 - - images_return = [] - - for mode in bakemodes: - img = Blender.Image.New('bake', width, height, depth) - - me_plane_face.image = img - rend.bakeMode = mode - rend.bake() - images_return.append( img ) - - # Restore bake settings - #''' - rend.bakeDist = BACKUP_bakeDist - rend.bakeBias = BACKUP_bakeBias - rend.bakeMode = BACKUP_bakeMode - rend.bakeClear = BACKUP_bakeClear - rend.bakeMargin = BACKUP_bakeMargin - rend.bakeToActive = BACKUP_bakeToActive - rend.bakeNormalize = BACKUP_bakeNormalize - - - # Restore obsel - sce.objects.selected = BACKUP_obsel - sce.objects.active = BACKUP_obact - - me_plane.verts = None - sce.objects.unlink(ob_plane) - #''' - - return images_return - diff --git a/release/scripts/bpymodules/BPySys.py b/release/scripts/bpymodules/BPySys.py deleted file mode 100644 index a2d2120ebff..00000000000 --- a/release/scripts/bpymodules/BPySys.py +++ /dev/null @@ -1,74 +0,0 @@ - -## This was used to make V, but faster not to do all that -##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' -##v = range(255) -##for c in valid: v.remove(ord(c)) -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]) -## del v, c, i, valid -del v, i - -def cleanName(name): - for ch in invalid: name = name.replace(ch, '_') - return name - -def caseInsensitivePath(path, RET_FOUND=False): - ''' - Get a case insensitive path on a case sensitive system - - RET_FOUND is for internal use only, to avoid too many calls to os.path.exists - # Example usage - getCaseInsensitivePath('/hOmE/mE/sOmEpAtH.tXt') - ''' - import os # todo, what happens with no os? - - if os==None: - if RET_FOUND: ret = path, True - else: ret = path - return ret - - if path=='' or os.path.exists(path): - if RET_FOUND: ret = path, True - else: ret = path - return ret - - f = os.path.basename(path) # f may be a directory or a file - d = os.path.dirname(path) - - suffix = '' - if not f: # dir ends with a slash? - if len(d) < len(path): - suffix = path[:len(path)-len(d)] - - f = os.path.basename(d) - d = os.path.dirname(d) - - if not os.path.exists(d): - d, found = caseInsensitivePath(d, True) - - if not found: - if RET_FOUND: ret = path, False - else: ret = path - return ret - - # at this point, the directory exists but not the file - - try: # we are expecting 'd' to be a directory, but it could be a file - files = os.listdir(d) - except: - if RET_FOUND: ret = path, False - else: ret = path - - f_low = f.lower() - - try: f_nocase = [fl for fl in files if fl.lower() == f_low][0] - except: f_nocase = None - - if f_nocase: - if RET_FOUND: ret = os.path.join(d, f_nocase) + suffix, True - else: ret = os.path.join(d, f_nocase) + suffix - return ret - else: - if RET_FOUND: ret = path, False - else: ret = path - return ret # cant find the right one, just return the path as is. \ No newline at end of file diff --git a/release/scripts/bpymodules/BPyTextPlugin.py b/release/scripts/bpymodules/BPyTextPlugin.py deleted file mode 100644 index cd5a085de37..00000000000 --- a/release/scripts/bpymodules/BPyTextPlugin.py +++ /dev/null @@ -1,814 +0,0 @@ -"""The BPyTextPlugin Module - -Use get_cached_descriptor(txt) to retrieve information about the script held in -the txt Text object. - -Use print_cache_for(txt) to print the information to the console. - -Use line, cursor = current_line(txt) to get the logical line and cursor position - -Use get_targets(line, cursor) to find out what precedes the cursor: - aaa.bbb.cc|c.ddd -> ['aaa', 'bbb', 'cc'] - -Use resolve_targets(txt, targets) to turn a target list into a usable object if -one is found to match. -""" - -import bpy, sys, os -import __builtin__, tokenize -from Blender.sys import time -from tokenize import generate_tokens, TokenError, \ - COMMENT, DEDENT, INDENT, NAME, NEWLINE, NL, STRING, NUMBER - -class Definition: - """Describes a definition or defined object through its name, line number - and docstring. This is the base class for definition based descriptors. - """ - - def __init__(self, name, lineno, doc=''): - self.name = name - self.lineno = lineno - self.doc = doc - -class ScriptDesc: - """Describes a script through lists of further descriptor objects (classes, - defs, vars) and dictionaries to built-in types (imports). If a script has - not been fully parsed, its incomplete flag will be set. The time of the last - parse is held by the time field and the name of the text object from which - it was parsed, the name field. - """ - - def __init__(self, name, imports, classes, defs, vars, incomplete=False): - self.name = name - self.imports = imports - self.classes = classes - self.defs = defs - self.vars = vars - self.incomplete = incomplete - self.parse_due = 0 - - def set_delay(self, delay): - self.parse_due = time() + delay - -class ClassDesc(Definition): - """Describes a class through lists of further descriptor objects (defs and - vars). The name of the class is held by the name field and the line on - which it is defined is held in lineno. - """ - - def __init__(self, name, parents, defs, vars, lineno, doc=''): - Definition.__init__(self, name, lineno, doc) - self.parents = parents - self.defs = defs - self.vars = vars - -class FunctionDesc(Definition): - """Describes a function through its name and list of parameters (name, - params) and the line on which it is defined (lineno). - """ - - def __init__(self, name, params, lineno, doc=''): - Definition.__init__(self, name, lineno, doc) - self.params = params - -class VarDesc(Definition): - """Describes a variable through its name and type (if ascertainable) and the - line on which it is defined (lineno). If no type can be determined, type - will equal None. - """ - - def __init__(self, name, type, lineno): - Definition.__init__(self, name, lineno) - self.type = type # None for unknown (supports: dict/list/str) - -# Context types -CTX_UNSET = -1 -CTX_NORMAL = 0 -CTX_SINGLE_QUOTE = 1 -CTX_DOUBLE_QUOTE = 2 -CTX_COMMENT = 3 - -# Python keywords -KEYWORDS = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', - 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield', - 'break', 'except', 'import', 'print', 'class', 'exec', 'in', - 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for', - 'lambda', 'try' ] - -# Module file extensions -MODULE_EXTS = ['.py', '.pyc', '.pyo', '.pyw', '.pyd'] - -ModuleType = type(__builtin__) -NoneScriptDesc = ScriptDesc('', dict(), dict(), dict(), dict(), True) - -_modules = {} -_modules_updated = 0 -_parse_cache = dict() - -def _load_module_names(): - """Searches the sys.path for module files and lists them, along with - sys.builtin_module_names, in the global dict _modules. - """ - - global _modules - - for n in sys.builtin_module_names: - _modules[n] = None - for p in sys.path: - if p == '': p = os.curdir - if not os.path.isdir(p): continue - for f in os.listdir(p): - for ext in MODULE_EXTS: - if f.endswith(ext): - _modules[f[:-len(ext)]] = None - break - -_load_module_names() - -def _trim_doc(doc): - """Trims the quotes from a quoted STRING token (eg. "'''text'''" -> "text") - """ - - l = len(doc) - i = 0 - while i < l/2 and (doc[i] == "'" or doc[i] == '"'): - i += 1 - return doc[i:-i] - -def resolve_targets(txt, targets): - """Attempts to return a useful object for the locally or externally defined - entity described by targets. If the object is local (defined in txt), a - Definition instance is returned. If the object is external (imported or - built in), the object itself is returned. If no object can be found, None is - returned. - """ - - count = len(targets) - if count==0: return None - - obj = None - local = None - i = 1 - - desc = get_cached_descriptor(txt) - b = targets[0].find('(') - if b==-1: b = None # Trick to let us use [:b] and get the whole string - - if desc.classes.has_key(targets[0][:b]): - local = desc.classes[targets[0][:b]] - elif desc.defs.has_key(targets[0]): - local = desc.defs[targets[0]] - elif desc.vars.has_key(targets[0]): - obj = desc.vars[targets[0]].type - - if local: - while i < count: - b = targets[i].find('(') - if b==-1: b = None - if hasattr(local, 'classes') and local.classes.has_key(targets[i][:b]): - local = local.classes[targets[i][:b]] - elif hasattr(local, 'defs') and local.defs.has_key(targets[i]): - local = local.defs[targets[i]] - elif hasattr(local, 'vars') and local.vars.has_key(targets[i]): - obj = local.vars[targets[i]].type - local = None - i += 1 - break - else: - local = None - break - i += 1 - - if local: return local - - if not obj: - if desc.imports.has_key(targets[0]): - obj = desc.imports[targets[0]] - else: - builtins = get_builtins() - if builtins.has_key(targets[0]): - obj = builtins[targets[0]] - - while obj and i < count: - if hasattr(obj, targets[i]): - obj = getattr(obj, targets[i]) - else: - obj = None - break - i += 1 - - return obj - -def get_cached_descriptor(txt, force_parse=0): - """Returns the cached ScriptDesc for the specified Text object 'txt'. If the - script has not been parsed in the last 'period' seconds it will be reparsed - to obtain this descriptor. - - Specifying TP_AUTO for the period (default) will choose a period based on the - size of the Text object. Larger texts are parsed less often. - """ - - global _parse_cache - - parse = True - key = hash(txt) - if not force_parse and _parse_cache.has_key(key): - desc = _parse_cache[key] - if desc.parse_due > time(): - parse = desc.incomplete - - if parse: - desc = parse_text(txt) - - return desc - -def parse_text(txt): - """Parses an entire script's text and returns a ScriptDesc instance - containing information about the script. - - If the text is not a valid Python script (for example if brackets are left - open), parsing may fail to complete. However, if this occurs, no exception - is thrown. Instead the returned ScriptDesc instance will have its incomplete - flag set and information processed up to this point will still be accessible. - """ - - start_time = time() - txt.reset() - tokens = generate_tokens(txt.readline) # Throws TokenError - - curl, cursor = txt.getCursorPos() - linen = curl + 1 # Token line numbers are one-based - - imports = dict() - imp_step = 0 - - classes = dict() - cls_step = 0 - - defs = dict() - def_step = 0 - - vars = dict() - var1_step = 0 - var2_step = 0 - var3_step = 0 - var_accum = dict() - var_forflag = False - - indent = 0 - prev_type = -1 - prev_text = '' - incomplete = False - - while True: - try: - type, text, start, end, line = tokens.next() - except StopIteration: - break - except (TokenError, IndentationError): - incomplete = True - break - - # Skip all comments and line joining characters - if type == COMMENT or type == NL: - continue - - ################# - ## Indentation ## - ################# - - if type == INDENT: - indent += 1 - elif type == DEDENT: - indent -= 1 - - ######################### - ## Module importing... ## - ######################### - - imp_store = False - - # Default, look for 'from' or 'import' to start - if imp_step == 0: - if text == 'from': - imp_tmp = [] - imp_step = 1 - elif text == 'import': - imp_from = None - imp_tmp = [] - imp_step = 2 - - # Found a 'from', create imp_from in form '???.???...' - elif imp_step == 1: - if text == 'import': - imp_from = '.'.join(imp_tmp) - imp_tmp = [] - imp_step = 2 - elif type == NAME: - imp_tmp.append(text) - elif text != '.': - imp_step = 0 # Invalid syntax - - # Found 'import', imp_from is populated or None, create imp_name - elif imp_step == 2: - if text == 'as': - imp_name = '.'.join(imp_tmp) - imp_step = 3 - elif type == NAME or text == '*': - imp_tmp.append(text) - elif text != '.': - imp_name = '.'.join(imp_tmp) - imp_symb = imp_name - imp_store = True - - # Found 'as', change imp_symb to this value and go back to step 2 - elif imp_step == 3: - if type == NAME: - imp_symb = text - else: - imp_store = True - - # Both imp_name and imp_symb have now been populated so we can import - if imp_store: - - # Handle special case of 'import *' - if imp_name == '*': - parent = get_module(imp_from) - imports.update(parent.__dict__) - - else: - # Try importing the name as a module - try: - if imp_from: - module = get_module(imp_from +'.'+ imp_name) - else: - module = get_module(imp_name) - except (ImportError, ValueError, AttributeError, TypeError): - # Try importing name as an attribute of the parent - try: - module = __import__(imp_from, globals(), locals(), [imp_name]) - imports[imp_symb] = getattr(module, imp_name) - except (ImportError, ValueError, AttributeError, TypeError): - pass - else: - imports[imp_symb] = module - - # More to import from the same module? - if text == ',': - imp_tmp = [] - imp_step = 2 - else: - imp_step = 0 - - ################### - ## Class parsing ## - ################### - - # If we are inside a class then def and variable parsing should be done - # for the class. Otherwise the definitions are considered global - - # Look for 'class' - if cls_step == 0: - if text == 'class': - cls_name = None - cls_lineno = start[0] - cls_indent = indent - cls_step = 1 - - # Found 'class', look for cls_name followed by '(' parents ')' - elif cls_step == 1: - if not cls_name: - if type == NAME: - cls_name = text - cls_sline = False - cls_parents = dict() - cls_defs = dict() - cls_vars = dict() - elif type == NAME: - if classes.has_key(text): - parent = classes[text] - cls_parents[text] = parent - cls_defs.update(parent.defs) - cls_vars.update(parent.vars) - elif text == ':': - cls_step = 2 - - # Found 'class' name ... ':', now check if it's a single line statement - elif cls_step == 2: - if type == NEWLINE: - cls_sline = False - else: - cls_sline = True - cls_doc = '' - cls_step = 3 - - elif cls_step == 3: - if not cls_doc and type == STRING: - cls_doc = _trim_doc(text) - if cls_sline: - if type == NEWLINE: - classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc) - cls_step = 0 - else: - if type == DEDENT and indent <= cls_indent: - classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc) - cls_step = 0 - - ################# - ## Def parsing ## - ################# - - # Look for 'def' - if def_step == 0: - if text == 'def': - def_name = None - def_lineno = start[0] - def_step = 1 - - # Found 'def', look for def_name followed by '(' - elif def_step == 1: - if type == NAME: - def_name = text - def_params = [] - elif def_name and text == '(': - def_step = 2 - - # Found 'def' name '(', now identify the parameters upto ')' - # TODO: Handle ellipsis '...' - elif def_step == 2: - if type == NAME: - def_params.append(text) - elif text == ':': - def_step = 3 - - # Found 'def' ... ':', now check if it's a single line statement - elif def_step == 3: - if type == NEWLINE: - def_sline = False - else: - def_sline = True - def_doc = '' - def_step = 4 - - elif def_step == 4: - if type == STRING: - def_doc = _trim_doc(text) - newdef = None - if def_sline: - if type == NEWLINE: - newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc) - else: - if type == NAME: - newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc) - if newdef: - if cls_step > 0: # Parsing a class - cls_defs[def_name] = newdef - else: - defs[def_name] = newdef - def_step = 0 - - ########################## - ## Variable assignation ## - ########################## - - if cls_step > 0: # Parsing a class - # Look for 'self.???' - if var1_step == 0: - if text == 'self': - var1_step = 1 - elif var1_step == 1: - if text == '.': - var_name = None - var1_step = 2 - else: - var1_step = 0 - elif var1_step == 2: - if type == NAME: - var_name = text - if cls_vars.has_key(var_name): - var_step = 0 - else: - var1_step = 3 - elif var1_step == 3: - if text == '=': - var1_step = 4 - elif text != ',': - var1_step = 0 - elif var1_step == 4: - var_type = None - if type == NUMBER: - close = end[1] - if text.find('.') != -1: var_type = float - else: var_type = int - elif type == STRING: - close = end[1] - var_type = str - elif text == '[': - close = line.find(']', end[1]) - var_type = list - elif text == '(': - close = line.find(')', end[1]) - var_type = tuple - elif text == '{': - close = line.find('}', end[1]) - var_type = dict - elif text == 'dict': - close = line.find(')', end[1]) - var_type = dict - if var_type and close+1 < len(line): - if line[close+1] != ' ' and line[close+1] != '\t': - var_type = None - cls_vars[var_name] = VarDesc(var_name, var_type, start[0]) - var1_step = 0 - - elif def_step > 0: # Parsing a def - # Look for 'global ???[,???]' - if var2_step == 0: - if text == 'global': - var2_step = 1 - elif var2_step == 1: - if type == NAME: - if not vars.has_key(text): - vars[text] = VarDesc(text, None, start[0]) - elif text != ',' and type != NL: - var2_step == 0 - - else: # In global scope - if var3_step == 0: - # Look for names - if text == 'for': - var_accum = dict() - var_forflag = True - elif text == '=' or (var_forflag and text == 'in'): - var_forflag = False - var3_step = 1 - elif type == NAME: - if prev_text != '.' and not vars.has_key(text): - var_accum[text] = VarDesc(text, None, start[0]) - elif not text in [',', '(', ')', '[', ']']: - var_accum = dict() - var_forflag = False - elif var3_step == 1: - if len(var_accum) != 1: - var_type = None - vars.update(var_accum) - else: - var_name = var_accum.keys()[0] - var_type = None - if type == NUMBER: - if text.find('.') != -1: var_type = float - else: var_type = int - elif type == STRING: var_type = str - elif text == '[': var_type = list - elif text == '(': var_type = tuple - elif text == '{': var_type = dict - vars[var_name] = VarDesc(var_name, var_type, start[0]) - var3_step = 0 - - ####################### - ## General utilities ## - ####################### - - prev_type = type - prev_text = text - - desc = ScriptDesc(txt.name, imports, classes, defs, vars, incomplete) - desc.set_delay(10 * (time()-start_time) + 0.05) - - global _parse_cache - _parse_cache[hash(txt)] = desc - return desc - -def get_modules(since=1): - """Returns the set of built-in modules and any modules that have been - imported into the system upto 'since' seconds ago. - """ - - global _modules, _modules_updated - - t = time() - if _modules_updated < t - since: - _modules.update(sys.modules) - _modules_updated = t - return _modules.keys() - -def suggest_cmp(x, y): - """Use this method when sorting a list of suggestions. - """ - - return cmp(x[0].upper(), y[0].upper()) - -def get_module(name): - """Returns the module specified by its name. The module itself is imported - by this method and, as such, any initialization code will be executed. - """ - - mod = __import__(name) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - -def type_char(v): - """Returns the character used to signify the type of a variable. Use this - method to identify the type character for an item in a suggestion list. - - The following values are returned: - 'm' if the parameter is a module - 'f' if the parameter is callable - 'v' if the parameter is variable or otherwise indeterminable - - """ - - if isinstance(v, ModuleType): - return 'm' - elif callable(v): - return 'f' - else: - return 'v' - -def get_context(txt): - """Establishes the context of the cursor in the given Blender Text object - - Returns one of: - CTX_NORMAL - Cursor is in a normal context - CTX_SINGLE_QUOTE - Cursor is inside a single quoted string - CTX_DOUBLE_QUOTE - Cursor is inside a double quoted string - CTX_COMMENT - Cursor is inside a comment - - """ - - l, cursor = txt.getCursorPos() - lines = txt.asLines(0, l+1) - - # FIXME: This method is too slow in large files for it to be called as often - # as it is. So for lines below the 1000th line we do this... (quorn) - if l > 1000: return CTX_NORMAL - - # Detect context (in string or comment) - in_str = CTX_NORMAL - for line in lines: - if l == 0: - end = cursor - else: - end = len(line) - l -= 1 - - # Comments end at new lines - if in_str == CTX_COMMENT: - in_str = CTX_NORMAL - - for i in range(end): - if in_str == 0: - if line[i] == "'": in_str = CTX_SINGLE_QUOTE - elif line[i] == '"': in_str = CTX_DOUBLE_QUOTE - elif line[i] == '#': in_str = CTX_COMMENT - else: - if in_str == CTX_SINGLE_QUOTE: - if line[i] == "'": - in_str = CTX_NORMAL - # In again if ' escaped, out again if \ escaped, and so on - for a in range(i-1, -1, -1): - if line[a] == '\\': in_str = 1-in_str - else: break - elif in_str == CTX_DOUBLE_QUOTE: - if line[i] == '"': - in_str = CTX_NORMAL - # In again if " escaped, out again if \ escaped, and so on - for a in range(i-1, -1, -1): - if line[i-a] == '\\': in_str = 2-in_str - else: break - - return in_str - -def current_line(txt): - """Extracts the Python script line at the cursor in the Blender Text object - provided and cursor position within this line as the tuple pair (line, - cursor). - """ - - lineindex, cursor = txt.getCursorPos() - lines = txt.asLines() - line = lines[lineindex] - - # Join previous lines to this line if spanning - i = lineindex - 1 - while i > 0: - earlier = lines[i].rstrip() - if earlier.endswith('\\'): - line = earlier[:-1] + ' ' + line - cursor += len(earlier) - i -= 1 - - # Join later lines while there is an explicit joining character - i = lineindex - while i < len(lines)-1 and lines[i].rstrip().endswith('\\'): - later = lines[i+1].strip() - line = line + ' ' + later[:-1] - i += 1 - - return line, cursor - -def get_targets(line, cursor): - """Parses a period separated string of valid names preceding the cursor and - returns them as a list in the same order. - """ - - brk = 0 - targets = [] - j = cursor - i = j-1 - while i >= 0: - if line[i] == ')': brk += 1 - elif brk: - if line[i] == '(': brk -= 1 - else: - if line[i] == '.': - targets.insert(0, line[i+1:j]); j=i - elif not (line[i].isalnum() or line[i] == '_' or line[i] == '.'): - break - i -= 1 - targets.insert(0, line[i+1:j]) - return targets - -def get_defs(txt): - """Returns a dictionary which maps definition names in the source code to - a list of their parameter names. - - The line 'def doit(one, two, three): print one' for example, results in the - mapping 'doit' : [ 'one', 'two', 'three' ] - """ - - return get_cached_descriptor(txt).defs - -def get_vars(txt): - """Returns a dictionary of variable names found in the specified Text - object. This method locates all names followed directly by an equal sign: - 'a = ???' or indirectly as part of a tuple/list assignment or inside a - 'for ??? in ???:' block. - """ - - return get_cached_descriptor(txt).vars - -def get_imports(txt): - """Returns a dictionary which maps symbol names in the source code to their - respective modules. - - The line 'from Blender import Text as BText' for example, results in the - mapping 'BText' : - - Note that this method imports the modules to provide this mapping as as such - will execute any initilization code found within. - """ - - return get_cached_descriptor(txt).imports - -def get_builtins(): - """Returns a dictionary of built-in modules, functions and variables.""" - - return __builtin__.__dict__ - - -################################# -## Debugging utility functions ## -################################# - -def print_cache_for(txt, period=sys.maxint): - """Prints out the data cached for a given Text object. If no period is - given the text will not be reparsed and the cached version will be returned. - Otherwise if the period has expired the text will be reparsed. - """ - - desc = get_cached_descriptor(txt, period) - print '================================================' - print 'Name:', desc.name, '('+str(hash(txt))+')' - print '------------------------------------------------' - print 'Defs:' - for name, ddesc in desc.defs.items(): - print ' ', name, ddesc.params, ddesc.lineno - print ' ', ddesc.doc - print '------------------------------------------------' - print 'Vars:' - for name, vdesc in desc.vars.items(): - print ' ', name, vdesc.type, vdesc.lineno - print '------------------------------------------------' - print 'Imports:' - for name, item in desc.imports.items(): - print ' ', name.ljust(15), item - print '------------------------------------------------' - print 'Classes:' - for clsnme, clsdsc in desc.classes.items(): - print ' *********************************' - print ' Name:', clsnme - print ' ', clsdsc.doc - print ' ---------------------------------' - print ' Defs:' - for name, ddesc in clsdsc.defs.items(): - print ' ', name, ddesc.params, ddesc.lineno - print ' ', ddesc.doc - print ' ---------------------------------' - print ' Vars:' - for name, vdesc in clsdsc.vars.items(): - print ' ', name, vdesc.type, vdesc.lineno - print ' *********************************' - print '================================================' diff --git a/release/scripts/bpymodules/BPyWindow.py b/release/scripts/bpymodules/BPyWindow.py deleted file mode 100644 index d3fd4fa88b5..00000000000 --- a/release/scripts/bpymodules/BPyWindow.py +++ /dev/null @@ -1,206 +0,0 @@ -import Blender -from Blender import Mathutils, Window, Scene, Draw, Mesh -from Blender.Mathutils import Matrix, Vector, Intersect - -# DESCRIPTION: -# screen_x, screen_y the origin point of the pick ray -# it is either the mouse location -# localMatrix is used if you want to have the returned values in an objects localspace. -# this is usefull when dealing with an objects data such as verts. -# or if useMid is true, the midpoint of the current 3dview -# returns -# Origin - the origin point of the pick ray -# Direction - the direction vector of the pick ray -# in global coordinates -epsilon = 1e-3 # just a small value to account for floating point errors - -def mouseViewRay(screen_x, screen_y, localMatrix=None, useMid = False): - - # Constant function variables - p = mouseViewRay.p - d = mouseViewRay.d - - for win3d in Window.GetScreenInfo(Window.Types.VIEW3D): # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example) - win_min_x, win_min_y, win_max_x, win_max_y = win3d['vertices'] - # calculate a few geometric extents for this window - - win_mid_x = (win_max_x + win_min_x + 1.0) * 0.5 - win_mid_y = (win_max_y + win_min_y + 1.0) * 0.5 - win_size_x = (win_max_x - win_min_x + 1.0) * 0.5 - win_size_y = (win_max_y - win_min_y + 1.0) * 0.5 - - #useMid is for projecting the coordinates when we subdivide the screen into bins - if useMid: # == True - screen_x = win_mid_x - screen_y = win_mid_y - - # if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one... - if (win_max_x > screen_x > win_min_x) and ( win_max_y > screen_y > win_min_y): - # first we handle all pending events for this window (otherwise the matrices might come out wrong) - Window.QHandle(win3d['id']) - - # now we get a few matrices for our window... - # sorry - i cannot explain here what they all do - # - if you're not familiar with all those matrices take a look at an introduction to OpenGL... - pm = Window.GetPerspMatrix() # the prespective matrix - pmi = Matrix(pm); pmi.invert() # the inverted perspective matrix - - if (1.0 - epsilon < pmi[3][3] < 1.0 + epsilon): - # pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5) - hms = mouseViewRay.hms - ortho_d = mouseViewRay.ortho_d - - # ortho mode: is a bit strange - actually there's no definite location of the camera ... - # but the camera could be displaced anywhere along the viewing direction. - - ortho_d.x, ortho_d.y, ortho_d.z = Window.GetViewVector() - ortho_d.w = 0 - - # all rays are parallel in ortho mode - so the direction vector is simply the viewing direction - #hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 - hms[:] = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 - - # these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1 - p=(hms*pmi) + (1000*ortho_d) - p.resize3D() - d[:] = ortho_d[:3] - - - # Finally we shift the position infinitely far away in - # the viewing direction to make sure the camera if outside the scene - # (this is actually a hack because this function - # is used in sculpt_mesh to initialize backface culling...) - else: - # PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location - vmi = Matrix(Window.GetViewMatrix()); vmi.invert() # the inverse viewing matrix - fp = mouseViewRay.fp - - dx = pm[3][3] * (((screen_x-win_min_x)/win_size_x)-1.0) - pm[3][0] - dy = pm[3][3] * (((screen_y-win_min_y)/win_size_y)-1.0) - pm[3][1] - - fp[:] = \ - pmi[0][0]*dx+pmi[1][0]*dy,\ - pmi[0][1]*dx+pmi[1][1]*dy,\ - pmi[0][2]*dx+pmi[1][2]*dy - - # fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y) - #- figuring out how to calculate this took me quite some time. - # The calculation of dxy and fp are simplified versions of my original code - #- so it's almost impossible to explain what's going on geometrically... sorry - - p[:] = vmi[3][:3] - - # the camera's location in global 3dcoords can be read directly from the inverted viewmatrix - #d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp)) - d[:] = p.x-fp.x, p.y-fp.y, p.z-fp.z - - #print 'd', d, 'p', p, 'fp', fp - - - # the direction vector is simply the difference vector from the virtual camera's position - #to the unprojected (screenspace) point fp - - # Do we want to return a direction in object's localspace? - - if localMatrix: - localInvMatrix = Matrix(localMatrix) - localInvMatrix.invert() - localInvMatrix_notrans = localInvMatrix.rotationPart() - p = p * localInvMatrix - d = d * localInvMatrix # normalize_v3 - - # remove the translation from d - d.x -= localInvMatrix[3][0] - d.y -= localInvMatrix[3][1] - d.z -= localInvMatrix[3][2] - - - d.normalize() - ''' - # Debugging - me = Blender.Mesh.New() - me.verts.extend([p[0:3]]) - me.verts.extend([(p-d)[0:3]]) - me.edges.extend([0,1]) - ob = Blender.Scene.GetCurrent().objects.new(me) - ''' - return True, p, d # Origin, Direction - - # Mouse is not in any view, return None. - return False, None, None - -# Constant function variables -mouseViewRay.d = Vector(0,0,0) # Perspective, 3d -mouseViewRay.p = Vector(0,0,0) -mouseViewRay.fp = Vector(0,0,0) - -mouseViewRay.hms = Vector(0,0,0,0) # ortho only 4d -mouseViewRay.ortho_d = Vector(0,0,0,0) # ortho only 4d - - -LMB= Window.MButs['L'] -def mouseup(): - # Loop until click - mouse_buttons = Window.GetMouseButtons() - while not mouse_buttons & LMB: - Blender.sys.sleep(10) - mouse_buttons = Window.GetMouseButtons() - while mouse_buttons & LMB: - Blender.sys.sleep(10) - mouse_buttons = Window.GetMouseButtons() - - -if __name__=='__main__': - mouseup() - x,y= Window.GetMouseCoords() - isect, point, dir= mouseViewRay(x,y) - if isect: - scn= Blender.Scene.GetCurrent() - me = Blender.Mesh.New() - ob= Blender.Object.New('Mesh') - ob.link(me) - scn.link(ob) - ob.sel= 1 - me.verts.extend([point, dir]) - me.verts[0].sel= 1 - - print isect, point, dir - - - -def spaceRect(): - ''' - Returns the space rect - xmin,ymin,width,height - ''' - - __UI_RECT__ = Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4) - Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, __UI_RECT__) - __UI_RECT__ = __UI_RECT__.list - __UI_RECT__ = int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2])-1, int(__UI_RECT__[3]) - - return __UI_RECT__ - -def mouseRelativeLoc2d(__UI_RECT__= None): - if not __UI_RECT__: - __UI_RECT__ = spaceRect() - - mco = Window.GetMouseCoords() - if mco[0] > __UI_RECT__[0] and\ - mco[1] > __UI_RECT__[1] and\ - mco[0] < __UI_RECT__[0] + __UI_RECT__[2] and\ - mco[1] < __UI_RECT__[1] + __UI_RECT__[3]: - - return (mco[0] - __UI_RECT__[0], mco[1] - __UI_RECT__[1]) - - else: - return None - - - - - - - - - \ No newline at end of file diff --git a/release/scripts/bpymodules/blend2renderinfo.py b/release/scripts/bpymodules/blend2renderinfo.py deleted file mode 100644 index 1b9dec58d55..00000000000 --- a/release/scripts/bpymodules/blend2renderinfo.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/python - -# -------------------------------------------------------------------------- -# ***** 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 struct - -# In Blender, selecting scenes in the databrowser (shift+f4) will tag for rendering. - -# This struct wont change according to ton. -# Note that the size differs on 32/64bit -''' -typedef struct BHead { - int code, len; - void *old; - int SDNAnr, nr; -} BHead; -''' - - -def read_blend_rend_chunk(path): - file = open(path, 'rb') - - if file.read(len('BLENDER')) != 'BLENDER': - return [] - - # - if file.read(1) == '-': - is64bit = True - else: # '_' - is64bit = False - - if file.read(1) == 'V': - isBigEndian = True # ppc - else: # 'V' - isBigEndian = False # x86 - - - # Now read the bhead chunk!!! - file.read(3) # skip the version - - scenes = [] - - while file.read(4) == 'REND': - - if is64bit: sizeof_bhead = sizeof_bhead_left = 24 # 64bit - else: sizeof_bhead = sizeof_bhead_left = 20 # 32bit - - sizeof_bhead_left -= 4 - - if isBigEndian: rend_length = struct.unpack('>i', file.read(4))[0] - else: rend_length = struct.unpack('2i', file.read(8)) - else: start_frame, end_frame = struct.unpack('<2i', file.read(8)) - - scene_name = file.read(24) - scene_name = scene_name[ : scene_name.index('\0') ] - - scenes.append( (start_frame, end_frame, scene_name) ) - return scenes - -def main(): - import sys - for arg in sys.argv[1:]: - if arg.lower().endswith('.blend'): - print read_blend_rend_chunk(arg) - -if __name__ == '__main__': - main() - diff --git a/release/scripts/bpymodules/defaultdoodads.py b/release/scripts/bpymodules/defaultdoodads.py deleted file mode 100644 index 987b8b8ae71..00000000000 --- a/release/scripts/bpymodules/defaultdoodads.py +++ /dev/null @@ -1,941 +0,0 @@ -# Default Doodad Set for Discombobulator -# by Evan J. Rosky, 2005 -# GPL- http://www.gnu.org/copyleft/gpl.html -# -# $Id$ -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2005: Evan J. Rosky -# -# 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 ***** -# -------------------------------------------------------------------------- - - -#Run discombobulator.py, not this. - -import Blender -from Blender import NMesh,Object,Material -from Blender.NMesh import Vert,Face -from Blender.Mathutils import * - -import BPyMathutils -from BPyMathutils import genrand -a = BPyMathutils.sgenrand(4859) - -#Create random numbers -def randnum(low,high): - num = genrand() - num = num*(high-low) - num = num+low - return num - -face = Face() -xmin = Vector([0,0,0]) -xmax = Vector([0,0,0]) -ymin = Vector([0,0,0]) -ymax = Vector([0,0,0]) -mxmin = Vector([0,0,0]) -mxmax = Vector([0,0,0]) -mymin = Vector([0,0,0]) -mymax = Vector([0,0,0]) -doodadCenter = Vector([0,0,0]) -orientation = 0 -center = Vector([0,0,0]) -tosel = 0 -seltopsonly = 0 -tempx = [] -doodadMesh = NMesh.GetRaw() - -global materialArray -global reassignMats -global thereAreMats -global currmat -global doodSideMat -global doodTopMat - -#face is the face to add the doodad to. -#sizeX and sizeY are values from 0.0 to 1.0 that represents a percentage the face that is covered by the doodad. -#height is how tall the doodad is. - -def settings(seltops,matArr,reasMats,therMats,sidemat,topmat): - global seltopsonly - global materialArray - global reassignMats - global thereAreMats - global currmat - global doodSideMat - global doodTopMat - materialArray = matArr - reassignMats = reasMats - thereAreMats = therMats - seltopsonly = seltops - doodSideMat = sidemat - doodTopMat = topmat - -def setCurrMat(curma): - global currmat - currmat = curma - -#Find center and orientation of doodad -def findDoodadCenter(sizeX, sizeY): - #globalizing junk - global face - global xmin - global xmax - global ymin - global ymax - global orientation - global doodadCenter - global center - global tosel - global mxmin - global mxmax - global mymin - global mymax - global tempx - global seltopsonly - - #Find the center of the face - center = Vector([0,0,0]) - for pt in face.v: - center = center + pt.co - center = divideVectorByInt(center,len(face.v)) - - #Find Temp Location Range by looking at the sizes - txmin = ((divideVectorByInt((face.v[0].co + face.v[3].co),2)) - center)*(1-sizeX) + center - txmax = ((divideVectorByInt((face.v[1].co + face.v[2].co),2)) - center)*(1-sizeX) + center - tymin = ((divideVectorByInt((face.v[0].co + face.v[1].co),2)) - center)*(1-sizeY) + center - tymax = ((divideVectorByInt((face.v[2].co + face.v[3].co),2)) - center)*(1-sizeY) + center - - #Find Center of doodad - amtx = randnum(0.0,1.0) - amty = randnum(0.0,1.0) - thepoint = (((((txmin - txmax)*amtx + txmax) - ((tymin - tymax)*amty + tymax))*.5 + ((tymin - tymax)*amty + tymax)) - center)*2 + center - doodadCenter = Vector([thepoint[0],thepoint[1],thepoint[2]]) - - #Find Main Range by looking at the sizes - mxmin = divideVectorByInt((face.v[0].co + face.v[3].co),2) - mxmax = divideVectorByInt((face.v[1].co + face.v[2].co),2) - mymin = divideVectorByInt((face.v[0].co + face.v[1].co),2) - mymax = divideVectorByInt((face.v[2].co + face.v[3].co),2) - - #Find x/y equivs for whole face - ve1 = (txmin - txmax)*amtx + txmax - ve1 = ve1 - mxmax - nax = ve1.length - ve1 = (mxmin - mxmax) - nax = nax/ve1.length - - ve1 = (tymin - tymax)*amty + tymax - ve1 = ve1 - mymax - nay = ve1.length - ve1 = (mymin - mymax) - nay = nay/ve1.length - - #Find new box thing - tempx = [] - amtx = nax-sizeX/2 - amty = nay-sizeY/2 - tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) - - amtx = nax-sizeX/2 - amty = nay+sizeY/2 - tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) - - amtx = nax+sizeX/2 - amty = nay+sizeY/2 - tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) - - amtx = nax+sizeX/2 - amty = nay-sizeY/2 - tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) - - #Find New Location Range by looking at the sizes - xmin = divideVectorByInt((tempx[0] + tempx[3]),2) - xmax = divideVectorByInt((tempx[1] + tempx[2]),2) - ymin = divideVectorByInt((tempx[0] + tempx[1]),2) - ymax = divideVectorByInt((tempx[2] + tempx[3]),2) - -#Make a point -def makePoint(x,y,z=0): - global xmin - global xmax - global ymin - global ymax - global doodadCenter - global tosel - global seltopsonly - global face - - amtx = x - amty = y - thepoint = (((((xmin - xmax)*amtx + xmax) - ((ymin - ymax)*amty + ymax))*.5 + ((ymin - ymax)*amty + ymax)) - doodadCenter)*2 + doodadCenter - thepoint = thepoint + z*Vector(face.no) - tver = Vert(thepoint[0],thepoint[1],thepoint[2]) - if tosel == 1 and seltopsonly == 0 and z == 0: - tver.sel = 1 - return tver - -#extrude ground-plane(s) -def extrudedoodad(vArray,heig): - global face - global doodadMesh - global tosel - - topVArray = [] - - doodadMesh.verts.extend(vArray) - - #Create array for extruded verts - for ind in range(0,(len(vArray))): - point = vArray[ind].co + heig*Vector(face.no) - ver = Vert(point[0],point[1],point[2]) - if tosel == 1: - ver.sel = 1 - topVArray.append(ver) - doodadMesh.verts.append(topVArray[ind]) - - #make faces around sides - for ind in range(0,(len(vArray) - 1)): - face = Face() - face.v.extend([vArray[ind],vArray[ind+1],topVArray[ind+1],topVArray[ind]]) - if tosel == 1 and seltopsonly == 0: face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodSideMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vArray[len(vArray) - 1],vArray[0],topVArray[0],topVArray[len(topVArray) - 1]]) - if tosel == 1 and seltopsonly == 0: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodSideMat-1 - doodadMesh.faces.append(face) - - return topVArray - -#For switching face vertices -def fixvertindex(ind): - if ind > 3: - indx = ind - 4 - else: - indx = ind - return indx - -#runs doodads -def createDoodad(indexArray,facec,minsi,maxsi,minhei,maxhei,selec,amtmin,amtmax,facpercent): - global doodadMesh - global seltopsonly - global tosel - - doodadMesh = NMesh.GetRaw() - - theamt = round(randnum(amtmin,amtmax),0) - theamt = int(theamt) - tosel = selec - - for i in range(0,(theamt)): - if randnum(0,1) <= facpercent: - index = round(randnum(1,len(indexArray)),0) - index = indexArray[(int(index) - 1)] - - Xsi = randnum(minsi,maxsi) - Ysi = randnum(minsi,maxsi) - hei = randnum(minhei,maxhei) - - #Determine orientation - orient = int(round(randnum(0.0,3.0))) - - #face to use as range - facer = Face() - facer.v.extend([facec.v[orient],facec.v[fixvertindex(1+orient)],facec.v[fixvertindex(2+orient)],facec.v[fixvertindex(3+orient)]]) - - if index == 1: - singleBox(facer,Xsi,Ysi,hei) - if index == 2: - doubleBox(facer,Xsi,Ysi,hei) - if index == 3: - tripleBox(facer,Xsi,Ysi,hei) - if index == 4: - LShape(facer,Xsi,Ysi,hei) - if index == 5: - TShape(facer,Xsi,Ysi,hei) - if index == 6: - if randnum(0.0,1.0) > .5: - SShape(facer,Xsi,Ysi,hei) - else: - ZShape(facer,Xsi,Ysi,hei) - - return doodadMesh - -def divideVectorByInt(thevect,theint): - thevect.x = thevect.x/theint - thevect.y = thevect.y/theint - thevect.z = thevect.z/theint - return thevect - -#Single Box Doodad -def singleBox(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - vertArray = [] - - #place four points - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,1)) - vertArray.append(makePoint(1,1)) - vertArray.append(makePoint(1,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -#Double Box Doodad -def doubleBox(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - vertArray = [] - - #place first box - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,1)) - vertArray.append(makePoint(0.45,1)) - vertArray.append(makePoint(0.45,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - vertArray = [] - - #place second box - vertArray.append(makePoint(0.55,0)) - vertArray.append(makePoint(0.55,1)) - vertArray.append(makePoint(1,1)) - vertArray.append(makePoint(1,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -#Triple Box Doodad -def tripleBox(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - vertArray = [] - - #place first box - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,1)) - vertArray.append(makePoint(0.3,1)) - vertArray.append(makePoint(0.3,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - vertArray = [] - - #place second box - vertArray.append(makePoint(0.35,0)) - vertArray.append(makePoint(0.35,1)) - vertArray.append(makePoint(0.65,1)) - vertArray.append(makePoint(0.65,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - vertArray = [] - - #place third box - vertArray.append(makePoint(0.7,0)) - vertArray.append(makePoint(0.7,1)) - vertArray.append(makePoint(1,1)) - vertArray.append(makePoint(1,0)) - topVertArray = extrudedoodad(vertArray,height) - - face = Face() - face.v.extend(vertArray) - face.v.reverse() - doodadMesh.faces.append(face) - face = Face() - face.v.extend(topVertArray) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -#The "L" Shape -def LShape(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - rcon1 = randnum(0.2,0.8) - rcon2 = randnum(0.2,0.8) - - vertArray = [] - - #place L shape - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,rcon1)) - vertArray.append(makePoint(0,1)) - vertArray.append(makePoint(rcon2,1)) - vertArray.append(makePoint(rcon2,rcon1)) - vertArray.append(makePoint(1,rcon1)) - vertArray.append(makePoint(1,0)) - vertArray.append(makePoint(rcon2,0)) - topVertArray = extrudedoodad(vertArray,height) - - #This fills in the bottom of doodad with faceness - face = Face() - face.v.extend([vertArray[0],vertArray[1],vertArray[4],vertArray[7]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[4]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - #This fills in the top with faceness - face = Face() - face.v.extend([topVertArray[0],topVertArray[1],topVertArray[4],topVertArray[7]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[4]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -#The "T" Shape -def TShape(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - rcony = randnum(0.25,0.75) - rconx1 = randnum(0.1,0.49) - rconx2 = randnum(0.51,0.9) - - vertArray = [] - - #place T shape - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,rcony)) - vertArray.append(makePoint(rconx1,rcony)) - vertArray.append(makePoint(rconx1,1)) - vertArray.append(makePoint(rconx2,1)) - vertArray.append(makePoint(rconx2,rcony)) - vertArray.append(makePoint(1,rcony)) - vertArray.append(makePoint(1,0)) - vertArray.append(makePoint(rconx2,0)) - vertArray.append(makePoint(rconx1,0)) - topVertArray = extrudedoodad(vertArray,height) - - #fills bottom with faceness - face = Face() - face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[9]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[2],vertArray[3],vertArray[4],vertArray[5]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[8],vertArray[9],vertArray[2],vertArray[5]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - #fills top with faceness - face = Face() - face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[9]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[2],topVertArray[3],topVertArray[4],topVertArray[5]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[8],topVertArray[9],topVertArray[2],topVertArray[5]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -#The "S" or "Z" Shapes -def SShape(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - rcony1 = randnum(0.1,0.49) - rcony2 = randnum(0.51,0.9) - rconx1 = randnum(0.1,0.49) - rconx2 = randnum(0.51,0.9) - - vertArray = [] - - #place S shape - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,rcony1)) - vertArray.append(makePoint(rconx1,rcony1)) - vertArray.append(makePoint(rconx1,rcony2)) - vertArray.append(makePoint(rconx1,1)) - vertArray.append(makePoint(rconx2,1)) - vertArray.append(makePoint(1,1)) - vertArray.append(makePoint(1,rcony2)) - vertArray.append(makePoint(rconx2,rcony2)) - vertArray.append(makePoint(rconx2,rcony1)) - vertArray.append(makePoint(rconx2,0)) - vertArray.append(makePoint(rconx1,0)) - topVertArray = extrudedoodad(vertArray,height) - - #fills bottom with faceness - face = Face() - face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[11]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[2],vertArray[9],vertArray[10],vertArray[11]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[2],vertArray[3],vertArray[8],vertArray[9]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[3],vertArray[4],vertArray[5],vertArray[8]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - #fills top with faceness - face = Face() - face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[11]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[2],topVertArray[9],topVertArray[10],topVertArray[11]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[2],topVertArray[3],topVertArray[8],topVertArray[9]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[3],topVertArray[4],topVertArray[5],topVertArray[8]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - -def ZShape(facel, Xsize, Ysize, height): - #globaling junk - global face - global tosel - global doodadMesh - - face = Face() - face = facel - - findDoodadCenter(Xsize, Ysize) - - rcony1 = randnum(0.1,0.49) - rcony2 = randnum(0.51,0.9) - rconx1 = randnum(0.1,0.49) - rconx2 = randnum(0.51,0.9) - - vertArray = [] - - #place Z shape - vertArray.append(makePoint(0,0)) - vertArray.append(makePoint(0,rcony1)) - vertArray.append(makePoint(0,rcony2)) - vertArray.append(makePoint(rconx1,rcony2)) - vertArray.append(makePoint(rconx2,rcony2)) - vertArray.append(makePoint(rconx2,1)) - vertArray.append(makePoint(1,1)) - vertArray.append(makePoint(1,rcony2)) - vertArray.append(makePoint(1,rcony1)) - vertArray.append(makePoint(rconx2,rcony1)) - vertArray.append(makePoint(rconx1,rcony1)) - vertArray.append(makePoint(rconx1,0)) - topVertArray = extrudedoodad(vertArray,height) - - #fills bottom with faceness - face = Face() - face.v.extend([vertArray[0],vertArray[1],vertArray[10],vertArray[11]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[10]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[3],vertArray[4],vertArray[9],vertArray[10]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[4],vertArray[7],vertArray[8],vertArray[9]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - - #fills top with faceness - face = Face() - face.v.extend([topVertArray[0],topVertArray[1],topVertArray[10],topVertArray[11]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[10]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[3],topVertArray[4],topVertArray[9],topVertArray[10]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[4],topVertArray[7],topVertArray[8],topVertArray[9]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - face = Face() - face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or doodTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = doodTopMat-1 - doodadMesh.faces.append(face) - diff --git a/release/scripts/bpymodules/dxfColorMap.py b/release/scripts/bpymodules/dxfColorMap.py deleted file mode 100644 index 66c0bd4e9a2..00000000000 --- a/release/scripts/bpymodules/dxfColorMap.py +++ /dev/null @@ -1,282 +0,0 @@ -# dictionary mapping AutoCAD color indexes with Blender colors - -# -------------------------------------------------------------------------- -# color_map.py Final by Ed Blake (AKA Kitsu) -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - -color_map = { - 0:[0.0, 0.0, 0.0], - 1:[0.99609375, 0.0, 0.0], - 2:[0.99609375, 0.99609375, 0.0], - 3:[0.0, 0.99609375, 0.0], - 4:[0.0, 0.99609375, 0.99609375], - 5:[0.0, 0.0, 0.99609375], - 6:[0.99609375, 0.0, 0.99609375], - 7:[0.99609375, 0.99609375, 0.99609375], - 8:[0.25390625, 0.25390625, 0.25390625], - 9:[0.5, 0.5, 0.5], - 10:[0.99609375, 0.0, 0.0], - 11:[0.99609375, 0.6640625, 0.6640625], - 12:[0.73828125, 0.0, 0.0], - 13:[0.73828125, 0.4921875, 0.4921875], - 14:[0.50390625, 0.0, 0.0], - 15:[0.50390625, 0.3359375, 0.3359375], - 16:[0.40625, 0.0, 0.0], - 17:[0.40625, 0.26953125, 0.26953125], - 18:[0.30859375, 0.0, 0.0], - 19:[0.30859375, 0.20703125, 0.20703125], - 20:[0.99609375, 0.24609375, 0.0], - 21:[0.99609375, 0.74609375, 0.6640625], - 22:[0.73828125, 0.1796875, 0.0], - 23:[0.73828125, 0.55078125, 0.4921875], - 24:[0.50390625, 0.12109375, 0.0], - 25:[0.50390625, 0.375, 0.3359375], - 26:[0.40625, 0.09765625, 0.0], - 27:[0.40625, 0.3046875, 0.26953125], - 28:[0.30859375, 0.07421875, 0.0], - 29:[0.30859375, 0.23046875, 0.20703125], - 30:[0.99609375, 0.49609375, 0.0], - 31:[0.99609375, 0.828125, 0.6640625], - 32:[0.73828125, 0.3671875, 0.0], - 33:[0.73828125, 0.61328125, 0.4921875], - 34:[0.50390625, 0.25, 0.0], - 35:[0.50390625, 0.41796875, 0.3359375], - 36:[0.40625, 0.203125, 0.0], - 37:[0.40625, 0.3359375, 0.26953125], - 38:[0.30859375, 0.15234375, 0.0], - 39:[0.30859375, 0.2578125, 0.20703125], - 40:[0.99609375, 0.74609375, 0.0], - 41:[0.99609375, 0.9140625, 0.6640625], - 42:[0.73828125, 0.55078125, 0.0], - 43:[0.73828125, 0.67578125, 0.4921875], - 44:[0.50390625, 0.375, 0.0], - 45:[0.50390625, 0.4609375, 0.3359375], - 46:[0.40625, 0.3046875, 0.0], - 47:[0.40625, 0.37109375, 0.26953125], - 48:[0.30859375, 0.23046875, 0.0], - 49:[0.30859375, 0.28515625, 0.20703125], - 50:[0.99609375, 0.99609375, 0.0], - 51:[0.99609375, 0.99609375, 0.6640625], - 52:[0.73828125, 0.73828125, 0.0], - 53:[0.73828125, 0.73828125, 0.4921875], - 54:[0.50390625, 0.50390625, 0.0], - 55:[0.50390625, 0.50390625, 0.3359375], - 56:[0.40625, 0.40625, 0.0], - 57:[0.40625, 0.40625, 0.26953125], - 58:[0.30859375, 0.30859375, 0.0], - 59:[0.30859375, 0.30859375, 0.20703125], - 60:[0.74609375, 0.99609375, 0.0], - 61:[0.9140625, 0.99609375, 0.6640625], - 62:[0.55078125, 0.73828125, 0.0], - 63:[0.67578125, 0.73828125, 0.4921875], - 64:[0.375, 0.50390625, 0.0], - 65:[0.4609375, 0.50390625, 0.3359375], - 66:[0.3046875, 0.40625, 0.0], - 67:[0.37109375, 0.40625, 0.26953125], - 68:[0.23046875, 0.30859375, 0.0], - 69:[0.28515625, 0.30859375, 0.20703125], - 70:[0.49609375, 0.99609375, 0.0], - 71:[0.828125, 0.99609375, 0.6640625], - 72:[0.3671875, 0.73828125, 0.0], - 73:[0.61328125, 0.73828125, 0.4921875], - 74:[0.25, 0.50390625, 0.0], - 75:[0.41796875, 0.50390625, 0.3359375], - 76:[0.203125, 0.40625, 0.0], - 77:[0.3359375, 0.40625, 0.26953125], - 78:[0.15234375, 0.30859375, 0.0], - 79:[0.2578125, 0.30859375, 0.20703125], - 80:[0.24609375, 0.99609375, 0.0], - 81:[0.74609375, 0.99609375, 0.6640625], - 82:[0.1796875, 0.73828125, 0.0], - 83:[0.55078125, 0.73828125, 0.4921875], - 84:[0.12109375, 0.50390625, 0.0], - 85:[0.375, 0.50390625, 0.3359375], - 86:[0.09765625, 0.40625, 0.0], - 87:[0.3046875, 0.40625, 0.26953125], - 88:[0.07421875, 0.30859375, 0.0], - 89:[0.23046875, 0.30859375, 0.20703125], - 90:[0.0, 0.99609375, 0.0], - 91:[0.6640625, 0.99609375, 0.6640625], - 92:[0.0, 0.73828125, 0.0], - 93:[0.4921875, 0.73828125, 0.4921875], - 94:[0.0, 0.50390625, 0.0], - 95:[0.3359375, 0.50390625, 0.3359375], - 96:[0.0, 0.40625, 0.0], - 97:[0.26953125, 0.40625, 0.26953125], - 98:[0.0, 0.30859375, 0.0], - 99:[0.20703125, 0.30859375, 0.20703125], - 100:[0.0, 0.99609375, 0.24609375], - 101:[0.6640625, 0.99609375, 0.74609375], - 102:[0.0, 0.73828125, 0.1796875], - 103:[0.4921875, 0.73828125, 0.55078125], - 104:[0.0, 0.50390625, 0.12109375], - 105:[0.3359375, 0.50390625, 0.375], - 106:[0.0, 0.40625, 0.09765625], - 107:[0.26953125, 0.40625, 0.3046875], - 108:[0.0, 0.30859375, 0.07421875], - 109:[0.20703125, 0.30859375, 0.23046875], - 110:[0.0, 0.99609375, 0.49609375], - 111:[0.6640625, 0.99609375, 0.828125], - 112:[0.0, 0.73828125, 0.3671875], - 113:[0.4921875, 0.73828125, 0.61328125], - 114:[0.0, 0.50390625, 0.25], - 115:[0.3359375, 0.50390625, 0.41796875], - 116:[0.0, 0.40625, 0.203125], - 117:[0.26953125, 0.40625, 0.3359375], - 118:[0.0, 0.30859375, 0.15234375], - 119:[0.20703125, 0.30859375, 0.2578125], - 120:[0.0, 0.99609375, 0.74609375], - 121:[0.6640625, 0.99609375, 0.9140625], - 122:[0.0, 0.73828125, 0.55078125], - 123:[0.4921875, 0.73828125, 0.67578125], - 124:[0.0, 0.50390625, 0.375], - 125:[0.3359375, 0.50390625, 0.4609375], - 126:[0.0, 0.40625, 0.3046875], - 127:[0.26953125, 0.40625, 0.37109375], - 128:[0.0, 0.30859375, 0.23046875], - 129:[0.20703125, 0.30859375, 0.28515625], - 130:[0.0, 0.99609375, 0.99609375], - 131:[0.6640625, 0.99609375, 0.99609375], - 132:[0.0, 0.73828125, 0.73828125], - 133:[0.4921875, 0.73828125, 0.73828125], - 134:[0.0, 0.50390625, 0.50390625], - 135:[0.3359375, 0.50390625, 0.50390625], - 136:[0.0, 0.40625, 0.40625], - 137:[0.26953125, 0.40625, 0.40625], - 138:[0.0, 0.30859375, 0.30859375], - 139:[0.20703125, 0.30859375, 0.30859375], - 140:[0.0, 0.74609375, 0.99609375], - 141:[0.6640625, 0.9140625, 0.99609375], - 142:[0.0, 0.55078125, 0.73828125], - 143:[0.4921875, 0.67578125, 0.73828125], - 144:[0.0, 0.375, 0.50390625], - 145:[0.3359375, 0.4609375, 0.50390625], - 146:[0.0, 0.3046875, 0.40625], - 147:[0.26953125, 0.37109375, 0.40625], - 148:[0.0, 0.23046875, 0.30859375], - 149:[0.20703125, 0.28515625, 0.30859375], - 150:[0.0, 0.49609375, 0.99609375], - 151:[0.6640625, 0.828125, 0.99609375], - 152:[0.0, 0.3671875, 0.73828125], - 153:[0.4921875, 0.61328125, 0.73828125], - 154:[0.0, 0.25, 0.50390625], - 155:[0.3359375, 0.41796875, 0.50390625], - 156:[0.0, 0.203125, 0.40625], - 157:[0.26953125, 0.3359375, 0.40625], - 158:[0.0, 0.15234375, 0.30859375], - 159:[0.20703125, 0.2578125, 0.30859375], - 160:[0.0, 0.24609375, 0.99609375], - 161:[0.6640625, 0.74609375, 0.99609375], - 162:[0.0, 0.1796875, 0.73828125], - 163:[0.4921875, 0.55078125, 0.73828125], - 164:[0.0, 0.12109375, 0.50390625], - 165:[0.3359375, 0.375, 0.50390625], - 166:[0.0, 0.09765625, 0.40625], - 167:[0.26953125, 0.3046875, 0.40625], - 168:[0.0, 0.07421875, 0.30859375], - 169:[0.20703125, 0.23046875, 0.30859375], - 170:[0.0, 0.0, 0.99609375], - 171:[0.6640625, 0.6640625, 0.99609375], - 172:[0.0, 0.0, 0.73828125], - 173:[0.4921875, 0.4921875, 0.73828125], - 174:[0.0, 0.0, 0.50390625], - 175:[0.3359375, 0.3359375, 0.50390625], - 176:[0.0, 0.0, 0.40625], - 177:[0.26953125, 0.26953125, 0.40625], - 178:[0.0, 0.0, 0.30859375], - 179:[0.20703125, 0.20703125, 0.30859375], - 180:[0.24609375, 0.0, 0.99609375], - 181:[0.74609375, 0.6640625, 0.99609375], - 182:[0.1796875, 0.0, 0.73828125], - 183:[0.55078125, 0.4921875, 0.73828125], - 184:[0.12109375, 0.0, 0.50390625], - 185:[0.375, 0.3359375, 0.50390625], - 186:[0.09765625, 0.0, 0.40625], - 187:[0.3046875, 0.26953125, 0.40625], - 188:[0.07421875, 0.0, 0.30859375], - 189:[0.23046875, 0.20703125, 0.30859375], - 190:[0.49609375, 0.0, 0.99609375], - 191:[0.828125, 0.6640625, 0.99609375], - 192:[0.3671875, 0.0, 0.73828125], - 193:[0.61328125, 0.4921875, 0.73828125], - 194:[0.25, 0.0, 0.50390625], - 195:[0.41796875, 0.3359375, 0.50390625], - 196:[0.203125, 0.0, 0.40625], - 197:[0.3359375, 0.26953125, 0.40625], - 198:[0.15234375, 0.0, 0.30859375], - 199:[0.2578125, 0.20703125, 0.30859375], - 200:[0.74609375, 0.0, 0.99609375], - 201:[0.9140625, 0.6640625, 0.99609375], - 202:[0.55078125, 0.0, 0.73828125], - 203:[0.67578125, 0.4921875, 0.73828125], - 204:[0.375, 0.0, 0.50390625], - 205:[0.4609375, 0.3359375, 0.50390625], - 206:[0.3046875, 0.0, 0.40625], - 207:[0.37109375, 0.26953125, 0.40625], - 208:[0.23046875, 0.0, 0.30859375], - 209:[0.28515625, 0.20703125, 0.30859375], - 210:[0.99609375, 0.0, 0.99609375], - 211:[0.99609375, 0.6640625, 0.99609375], - 212:[0.73828125, 0.0, 0.73828125], - 213:[0.73828125, 0.4921875, 0.73828125], - 214:[0.50390625, 0.0, 0.50390625], - 215:[0.50390625, 0.3359375, 0.50390625], - 216:[0.40625, 0.0, 0.40625], - 217:[0.40625, 0.26953125, 0.40625], - 218:[0.30859375, 0.0, 0.30859375], - 219:[0.30859375, 0.20703125, 0.30859375], - 220:[0.99609375, 0.0, 0.74609375], - 221:[0.99609375, 0.6640625, 0.9140625], - 222:[0.73828125, 0.0, 0.55078125], - 223:[0.73828125, 0.4921875, 0.67578125], - 224:[0.50390625, 0.0, 0.375], - 225:[0.50390625, 0.3359375, 0.4609375], - 226:[0.40625, 0.0, 0.3046875], - 227:[0.40625, 0.26953125, 0.37109375], - 228:[0.30859375, 0.0, 0.23046875], - 229:[0.30859375, 0.20703125, 0.28515625], - 230:[0.99609375, 0.0, 0.49609375], - 231:[0.99609375, 0.6640625, 0.828125], - 232:[0.73828125, 0.0, 0.3671875], - 233:[0.73828125, 0.4921875, 0.61328125], - 234:[0.50390625, 0.0, 0.25], - 235:[0.50390625, 0.3359375, 0.41796875], - 236:[0.40625, 0.0, 0.203125], - 237:[0.40625, 0.26953125, 0.3359375], - 238:[0.30859375, 0.0, 0.15234375], - 239:[0.30859375, 0.20703125, 0.2578125], - 240:[0.99609375, 0.0, 0.24609375], - 241:[0.99609375, 0.6640625, 0.74609375], - 242:[0.73828125, 0.0, 0.1796875], - 243:[0.73828125, 0.4921875, 0.55078125], - 244:[0.50390625, 0.0, 0.12109375], - 245:[0.50390625, 0.3359375, 0.375], - 246:[0.40625, 0.0, 0.09765625], - 247:[0.40625, 0.26953125, 0.3046875], - 248:[0.30859375, 0.0, 0.07421875], - 249:[0.30859375, 0.20703125, 0.23046875], - 250:[0.19921875, 0.19921875, 0.19921875], - 251:[0.3125, 0.3125, 0.3125], - 252:[0.41015625, 0.41015625, 0.41015625], - 253:[0.5078125, 0.5078125, 0.5078125], - 254:[0.7421875, 0.7421875, 0.7421875], - 255:[0.99609375, 0.99609375, 0.99609375], -} diff --git a/release/scripts/bpymodules/dxfLibrary.py b/release/scripts/bpymodules/dxfLibrary.py deleted file mode 100644 index ccd8ef9b625..00000000000 --- a/release/scripts/bpymodules/dxfLibrary.py +++ /dev/null @@ -1,880 +0,0 @@ -#dxfLibrary.py : provides functions for generating DXF files -# -------------------------------------------------------------------------- -__version__ = "v1.33 - 2009.06.16" -__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" -__license__ = "GPL" -__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" -__bpydoc__ ="""The library to export geometry data to DXF format r12 version. - -Copyright %s -Version %s -License %s -Homepage %s - -See the homepage for documentation. -Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439 - -IDEAs: -- - -TODO: -- add support for DXFr14 (needs extended file header) -- add support for SPLINEs (possible first in DXFr14 version) -- add user preset for floating point precision (3-16?) - -History -v1.33 - 2009.06.16 by migius - - modif _point(): converts all coords to floats - - modif LineType class: implement elements - - added VPORT class, incl. defaults - - fix Insert class -v1.32 - 2009.06.06 by migius - - modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0 - - modif Text class: alignment parameter reactivated -v1.31 - 2009.06.02 by migius - - modif _Entity class: added paperspace,elevation -v1.30 - 2009.05.28 by migius - - bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0 -v1.29 - 2008.12.28 by Yorik - - modif POLYLINE to support bulge segments -v1.28 - 2008.12.13 by Steeve/BlenderArtists - - bugfix for EXTMIN/EXTMAX to suit Cycas-CAD -v1.27 - 2008.10.07 by migius - - beautifying output code: keys whitespace prefix - - refactoring DXF-strings format: NewLine moved to the end of -v1.26 - 2008.10.05 by migius - - modif POLYLINE to support POLYFACE -v1.25 - 2008.09.28 by migius - - modif FACE class for r12 -v1.24 - 2008.09.27 by migius - - modif POLYLINE class for r12 - - changing output format from r9 to r12(AC1009) -v1.1 (20/6/2005) by www.stani.be/python/sdxf - - Python library to generate dxf drawings -______________________________________________________________ -""" % (__author__,__version__,__license__,__url__) - -# -------------------------------------------------------------------------- -# DXF Library: copyright (C) 2005 by Stani Michiels (AKA Stani) -# 2008/2009 modif by Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** 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 Blender -#from Blender import Mathutils, Window, Scene, sys, Draw -#import BPyMessages - -try: - import copy - #from struct import pack -except: - copy = None - -####1) Private (only for developpers) -_HEADER_POINTS=['insbase','extmin','extmax'] - -#---helper functions----------------------------------- -def _point(x,index=0): - """Convert tuple to a dxf point""" - #print 'deb: _point=', x #------------- - return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))]) - -def _points(plist): - """Convert a list of tuples to dxf points""" - out = '\n'.join([_point(plist[i],i)for i in range(len(plist))]) - return out - -#---base classes---------------------------------------- -class _Call: - """Makes a callable class.""" - def copy(self): - """Returns a copy.""" - return copy.deepcopy(self) - - def __call__(self,**attrs): - """Returns a copy with modified attributes.""" - copied=self.copy() - for attr in attrs:setattr(copied,attr,attrs[attr]) - return copied - -#------------------------------------------------------- -class _Entity(_Call): - """Base class for _common group codes for entities.""" - def __init__(self,paperspace=None,color=None,layer='0', - lineType=None,lineTypeScale=None,lineWeight=None, - extrusion=None,elevation=None,thickness=None, - parent=None): - """None values will be omitted.""" - self.paperspace = paperspace - self.color = color - self.layer = layer - self.lineType = lineType - self.lineTypeScale = lineTypeScale - self.lineWeight = lineWeight - self.extrusion = extrusion - self.elevation = elevation - self.thickness = thickness - #self.visible = visible - self.parent = parent - - def _common(self): - """Return common group codes as a string.""" - if self.parent:parent=self.parent - else:parent=self - result ='' - if parent.paperspace==1: result+=' 67\n1\n' - if parent.layer!=None: result+=' 8\n%s\n'%parent.layer - if parent.color!=None: result+=' 62\n%s\n'%parent.color - if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType - # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight - # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible - if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale - if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation - if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness - if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) - return result - -#-------------------------- -class _Entities: - """Base class to deal with composed objects.""" - def __dxf__(self): - return [] - - def __str__(self): - return ''.join([str(x) for x in self.__dxf__()]) - -#-------------------------- -class _Collection(_Call): - """Base class to expose entities methods to main object.""" - def __init__(self,entities=[]): - self.entities=copy.copy(entities) - #link entities methods to drawing - for attr in dir(self.entities): - if attr[0]!='_': - attrObject=getattr(self.entities,attr) - if callable(attrObject): - setattr(self,attr,attrObject) - -####2) Constants -#---color values -BYBLOCK=0 -BYLAYER=256 - -#---block-type flags (bit coded values, may be combined): -ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application -NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) -XREF =4 # This block is an external reference (xref) -XREF_OVERLAY =8 # This block is an xref overlay -EXTERNAL =16 # This block is externally dependent -RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) -REFERENCED =64 # This definition is a referenced external reference (ignored on input) - -#---mtext flags -#attachment point -TOP_LEFT = 1 -TOP_CENTER = 2 -TOP_RIGHT = 3 -MIDDLE_LEFT = 4 -MIDDLE_CENTER = 5 -MIDDLE_RIGHT = 6 -BOTTOM_LEFT = 7 -BOTTOM_CENTER = 8 -BOTTOM_RIGHT = 9 -#drawing direction -LEFT_RIGHT = 1 -TOP_BOTTOM = 3 -BY_STYLE = 5 #the flow direction is inherited from the associated text style -#line spacing style (optional): -AT_LEAST = 1 #taller characters will override -EXACT = 2 #taller characters will not override - -#---polyline flags -CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) -CURVE_FIT =2 # Curve-fit vertices have been added -SPLINE_FIT =4 # Spline-fit vertices have been added -POLYLINE_3D =8 # This is a 3D polyline -POLYGON_MESH =16 # This is a 3D polygon mesh -CLOSED_N =32 # The polygon mesh is closed in the N direction -POLYFACE_MESH =64 # The polyline is a polyface mesh -CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline - -#---text flags -#horizontal -LEFT = 0 -CENTER = 1 -RIGHT = 2 -ALIGNED = 3 #if vertical alignment = 0 -MIDDLE = 4 #if vertical alignment = 0 -FIT = 5 #if vertical alignment = 0 -#vertical -BASELINE = 0 -BOTTOM = 1 -MIDDLE = 2 -TOP = 3 - -####3) Classes -#---entitities ----------------------------------------------- -#-------------------------- -class Arc(_Entity): - """Arc, angles in degrees.""" - def __init__(self,center=(0,0,0),radius=1, - startAngle=0.0,endAngle=90,**common): - """Angles in degrees.""" - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - self.startAngle=startAngle - self.endAngle=endAngle - def __str__(self): - return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\ - (self._common(),_point(self.center), - self.radius,self.startAngle,self.endAngle) - -#----------------------------------------------- -class Circle(_Entity): - """Circle""" - def __init__(self,center=(0,0,0),radius=1,**common): - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - def __str__(self): - return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\ - (self._common(),_point(self.center),self.radius) - -#----------------------------------------------- -class Face(_Entity): - """3dface""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - while len(points)<4: #fix for r12 format - points.append(points[-1]) - self.points=points - - def __str__(self): - out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points)) - #print 'deb:out=', out #------------------- - return out - -#----------------------------------------------- -class Insert(_Entity): - """Block instance.""" - def __init__(self,name,point=(0,0,0), - xscale=None,yscale=None,zscale=None, - cols=None,colspacing=None,rows=None,rowspacing=None, - rotation=None, - **common): - _Entity.__init__(self,**common) - self.name=name - self.point=point - self.xscale=xscale - self.yscale=yscale - self.zscale=zscale - self.cols=cols - self.colspacing=colspacing - self.rows=rows - self.rowspacing=rowspacing - self.rotation=rotation - - def __str__(self): - result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\ - (self.name,self._common(),_point(self.point)) - if self.xscale!=None:result+=' 41\n%s\n'%self.xscale - if self.yscale!=None:result+=' 42\n%s\n'%self.yscale - if self.zscale!=None:result+=' 43\n%s\n'%self.zscale - if self.rotation:result+=' 50\n%s\n'%self.rotation - if self.cols!=None:result+=' 70\n%s\n'%self.cols - if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing - if self.rows!=None:result+=' 71\n%s\n'%self.rows - if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing - return result - -#----------------------------------------------- -class Line(_Entity): - """Line""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nLINE\n%s%s\n' %( - self._common(), _points(self.points)) - - -#----------------------------------------------- -class PolyLine(_Entity): - def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common): - #width = number, or width = list [width_start=None, width_end=None] - #for 2d-polyline: points = [ [x, y, z, width_start=None, width_end=None, bulge=0 or None], ...] - #for 3d-polyline: points = [ [x, y, z], ...] - #for polyface: points = [points_list, faces_list] - _Entity.__init__(self,**common) - self.points=points - self.org_point=org_point - self.flag=flag - self.polyface = False - self.polyline2d = False - self.faces = [] # dummy value - self.width= None # dummy value - if self.flag & POLYFACE_MESH: - self.polyface=True - self.points=points[0] - self.faces=points[1] - self.p_count=len(self.points) - self.f_count=len(self.faces) - elif not self.flag & POLYLINE_3D: - self.polyline2d = True - if width: - if type(width)!='list': - width=[width,width] - self.width=width - - def __str__(self): - result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag) - result+=' 66\n1\n' - result+='%s\n' %_point(self.org_point) - if self.polyface: - result+=' 71\n%s\n' %self.p_count - result+=' 72\n%s\n' %self.f_count - elif self.polyline2d: - if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) - for point in self.points: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - if self.polyface: - result+='%s\n' %_point(point[0:3]) - result+=' 70\n192\n' - elif self.polyline2d: - result+='%s\n' %_point(point[0:2]) - if len(point)>4: - width1, width2 = point[3], point[4] - if width1!=None: result+=' 40\n%s\n' %width1 - if width2!=None: result+=' 41\n%s\n' %width2 - if len(point)==6: - bulge = point[5] - if bulge: result+=' 42\n%s\n' %bulge - else: - result+='%s\n' %_point(point[0:3]) - for face in self.faces: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - result+='%s\n' %_point(self.org_point) - result+=' 70\n128\n' - result+=' 71\n%s\n' %face[0] - result+=' 72\n%s\n' %face[1] - result+=' 73\n%s\n' %face[2] - if len(face)==4: result+=' 74\n%s\n' %face[3] - result+=' 0\nSEQEND\n' - result+=' 8\n%s\n' %self.layer - return result - -#----------------------------------------------- -class Point(_Entity): - """Point.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): # TODO: - return ' 0\nPOINT\n%s%s\n' %(self._common(), - _points(self.points) - ) - -#----------------------------------------------- -class Solid(_Entity): - """Colored solid fill.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nSOLID\n%s%s\n' %(self._common(), - _points(self.points[:2]+[self.points[3],self.points[2]]) - ) - - -#----------------------------------------------- -class Text(_Entity): - """Single text line.""" - def __init__(self,text='',point=(0,0,0),alignment=None, - flag=None,height=1,justifyhor=None,justifyver=None, - rotation=None,obliqueAngle=None,style=None,xscale=None,**common): - _Entity.__init__(self,**common) - self.text=text - self.point=point - self.alignment=alignment - self.flag=flag - self.height=height - self.justifyhor=justifyhor - self.justifyver=justifyver - self.rotation=rotation - self.obliqueAngle=obliqueAngle - self.style=style - self.xscale=xscale - def __str__(self): - result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\ - (self._common(),_point(self.point),self.height,self.text) - if self.rotation: result+=' 50\n%s\n'%self.rotation - if self.xscale: result+=' 41\n%s\n'%self.xscale - if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle - if self.style: result+=' 7\n%s\n'%self.style - if self.flag: result+=' 71\n%s\n'%self.flag - if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor - if self.alignment: result+='%s\n'%_point(self.alignment,1) - if self.justifyver: result+=' 73\n%s\n'%self.justifyver - return result - -#----------------------------------------------- -class Mtext(Text): - """Surrogate for mtext, generates some Text instances.""" - def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options): - Text.__init__(self,text=text,point=point,**options) - if down:spacingFactor*=-1 - self.spacingFactor=spacingFactor - self.spacingWidth=spacingWidth - self.width=width - self.down=down - def __str__(self): - texts=self.text.replace('\r\n','\n').split('\n') - if not self.down:texts.reverse() - result='' - x=y=0 - if self.spacingWidth:spacingWidth=self.spacingWidth - else:spacingWidth=self.height*self.spacingFactor - for text in texts: - while text: - result+='%s\n'%Text(text[:self.width], - point=(self.point[0]+x*spacingWidth, - self.point[1]+y*spacingWidth, - self.point[2]), - alignment=self.alignment,flag=self.flag,height=self.height, - justifyhor=self.justifyhor,justifyver=self.justifyver, - rotation=self.rotation,obliqueAngle=self.obliqueAngle, - style=self.style,xscale=self.xscale,parent=self - ) - text=text[self.width:] - if self.rotation:x+=1 - else:y+=1 - return result[1:] - -#----------------------------------------------- -##class _Mtext(_Entity): -## """Mtext not functioning for minimal dxf.""" -## def __init__(self,text='',point=(0,0,0),attachment=1, -## charWidth=None,charHeight=1,direction=1,height=100,rotation=0, -## spacingStyle=None,spacingFactor=None,style=None,width=100, -## xdirection=None,**common): -## _Entity.__init__(self,**common) -## self.text=text -## self.point=point -## self.attachment=attachment -## self.charWidth=charWidth -## self.charHeight=charHeight -## self.direction=direction -## self.height=height -## self.rotation=rotation -## self.spacingStyle=spacingStyle -## self.spacingFactor=spacingFactor -## self.style=style -## self.width=width -## self.xdirection=xdirection -## def __str__(self): -## input=self.text -## text='' -## while len(input)>250: -## text+='3\n%s\n'%input[:250] -## input=input[250:] -## text+='1\n%s\n'%input -## result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\ -## (self._common(),_point(self.point),self.charHeight,self.width, -## self.attachment,self.direction,text, -## self.height, -## self.rotation) -## if self.style:result+='7\n%s\n'%self.style -## if self.xdirection:result+='%s\n'%_point(self.xdirection,1) -## if self.charWidth:result+='42\n%s\n'%self.charWidth -## if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle -## if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor -## return result - -#---tables --------------------------------------------------- -#----------------------------------------------- -class Block(_Collection): - """Use list methods to add entities, eg append.""" - def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]): - self.entities=copy.copy(entities) - _Collection.__init__(self,entities) - self.layer=layer - self.name=name - self.flag=0 - self.base=base - def __str__(self): # TODO: - e=''.join([str(x)for x in self.entities]) - return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ - (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e) - -#----------------------------------------------- -class Layer(_Call): - """Layer""" - def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64): - self.name=name - self.color=color - self.lineType=lineType - self.flag=flag - def __str__(self): - return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\ - (self.name.upper(),self.flag,self.color,self.lineType) - -#----------------------------------------------- -class LineType(_Call): - """Custom linetype""" - def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0): - self.name=name - self.description=description - self.elements=copy.copy(elements) - self.flag=flag - def __str__(self): - result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ - (self.name.upper(),self.flag,self.description) - if self.elements: - elements = ' 73\n%s\n' %(len(self.elements)-1) - elements += ' 40\n%s\n' %(self.elements[0]) - for e in self.elements[1:]: - elements += ' 49\n%s\n' %e - result += elements - return result - - -#----------------------------------------------- -class Style(_Call): - """Text style""" - def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, - mirror=0,lastHeight=1,font='arial.ttf',bigFont=''): - self.name=name - self.flag=flag - self.height=height - self.widthFactor=widthFactor - self.obliqueAngle=obliqueAngle - self.mirror=mirror - self.lastHeight=lastHeight - self.font=font - self.bigFont=bigFont - def __str__(self): - return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\ - (self.name.upper(),self.flag,self.flag,self.widthFactor, - self.obliqueAngle,self.mirror,self.lastHeight, - self.font.upper(),self.bigFont.upper()) - -#----------------------------------------------- -class VPort(_Call): - def __init__(self,name,flag=0, - leftBottom=(0.0,0.0), - rightTop=(1.0,1.0), - center=(0.5,0.5), - snap_base=(0.0,0.0), - snap_spacing=(0.1,0.1), - grid_spacing=(0.1,0.1), - direction=(0.0,0.0,1.0), - target=(0.0,0.0,0.0), - height=1.0, - ratio=1.0, - lens=50, - frontClipping=0, - backClipping=0, - snap_rotation=0, - twist=0, - mode=0, - circle_zoom=100, - fast_zoom=1, - ucsicon=1, - snap_on=0, - grid_on=0, - snap_style=0, - snap_isopair=0 - ): - self.name=name - self.flag=flag - self.leftBottom=leftBottom - self.rightTop=rightTop - self.center=center - self.snap_base=snap_base - self.snap_spacing=snap_spacing - self.grid_spacing=grid_spacing - self.direction=direction - self.target=target - self.height=float(height) - self.ratio=float(ratio) - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.snap_rotation=float(snap_rotation) - self.twist=float(twist) - self.mode=mode - self.circle_zoom=circle_zoom - self.fast_zoom=fast_zoom - self.ucsicon=ucsicon - self.snap_on=snap_on - self.grid_on=grid_on - self.snap_style=snap_style - self.snap_isopair=snap_isopair - def __str__(self): - output = [' 0', 'VPORT', - ' 2', self.name, - ' 70', self.flag, - _point(self.leftBottom), - _point(self.rightTop,1), - _point(self.center,2), # View center point (in DCS) - _point(self.snap_base,3), - _point(self.snap_spacing,4), - _point(self.grid_spacing,5), - _point(self.direction,6), #view direction from target (in WCS) - _point(self.target,7), - ' 40', self.height, - ' 41', self.ratio, - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.snap_rotation, - ' 51', self.twist, - ' 71', self.mode, - ' 72', self.circle_zoom, - ' 73', self.fast_zoom, - ' 74', self.ucsicon, - ' 75', self.snap_on, - ' 76', self.grid_on, - ' 77', self.snap_style, - ' 78', self.snap_isopair - ] - - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str - - - -#----------------------------------------------- -class View(_Call): - def __init__(self,name,flag=0, - width=1, - height=1, - center=(0.5,0.5), - direction=(0,0,1), - target=(0,0,0), - lens=50, - frontClipping=0, - backClipping=0, - twist=0,mode=0 - ): - self.name=name - self.flag=flag - self.width=float(width) - self.height=float(height) - self.center=center - self.direction=direction - self.target=target - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.twist=float(twist) - self.mode=mode - def __str__(self): - output = [' 0', 'VIEW', - ' 2', self.name, - ' 70', self.flag, - ' 40', self.height, - _point(self.center), - ' 41', self.width, - _point(self.direction,1), - _point(self.target,2), - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.twist, - ' 71', self.mode - ] - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str - -#----------------------------------------------- -def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options): - width=abs(rightTop[0]-leftBottom[0]) - height=abs(rightTop[1]-leftBottom[1]) - center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5) - return View(name=name,width=width,height=height,center=center,**options) - -#---drawing -#----------------------------------------------- -class Drawing(_Collection): - """Dxf drawing. Use append or any other list methods to add objects.""" - def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0), - layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], - views=[],vports=[],entities=None,fileName='test.dxf'): - # TODO: replace list with None,arial - if not entities: - entities=[] - _Collection.__init__(self,entities) - self.insbase=insbase - self.extmin=extmin - self.extmax=extmax - self.layers=copy.copy(layers) - self.linetypes=copy.copy(linetypes) - self.styles=copy.copy(styles) - self.views=copy.copy(views) - self.vports=copy.copy(vports) - self.blocks=copy.copy(blocks) - self.fileName=fileName - #private - #self.acadver='9\n$ACADVER\n1\nAC1006\n' - self.acadver=' 9\n$ACADVER\n 1\nAC1009\n' - """DXF AutoCAD-Release format codes - AC1021 2008, 2007 - AC1018 2006, 2005, 2004 - AC1015 2002, 2000i, 2000 - AC1014 R14,14.01 - AC1012 R13 - AC1009 R12,11 - AC1006 R10 - AC1004 R9 - AC1002 R2.6 - AC1.50 R2.05 - """ - - def _name(self,x): - """Helper function for self._point""" - return ' 9\n$%s\n' %x.upper() - - def _point(self,name,x): - """Point setting from drawing like extmin,extmax,...""" - return '%s%s' %(self._name(name),_point(x)) - - def _section(self,name,x): - """Sections like tables,blocks,entities,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr) - - def _table(self,name,x): - """Tables like ltype,layer,style,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr) - - def __str__(self): - """Returns drawing as dxf string.""" - header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] - header=self._section('header',header) - - tables=[self._table('vport',[str(x) for x in self.vports]), - self._table('ltype',[str(x) for x in self.linetypes]), - self._table('layer',[str(x) for x in self.layers]), - self._table('style',[str(x) for x in self.styles]), - self._table('view',[str(x) for x in self.views]), - ] - tables=self._section('tables',tables) - - blocks=self._section('blocks',[str(x) for x in self.blocks]) - - entities=self._section('entities',[str(x) for x in self.entities]) - - all=''.join([header,tables,blocks,entities,' 0\nEOF\n']) - return all - - def saveas(self,fileName): - self.fileName=fileName - self.save() - - def save(self): - test=open(self.fileName,'w') - test.write(str(self)) - test.close() - - -#---extras -#----------------------------------------------- -class Rectangle(_Entity): - """Rectangle, creates lines.""" - def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common): - _Entity.__init__(self,**common) - self.point=point - self.width=width - self.height=height - self.solid=solid - self.line=line - def __str__(self): - result='' - points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]), - (self.point[0]+self.width,self.point[1]+self.height,self.point[2]), - (self.point[0],self.point[1]+self.height,self.point[2]),self.point] - if self.solid: - result+= Solid(points=points[:-1],parent=self.solid) - if self.line: - for i in range(4): - result+= Line(points=[points[i],points[i+1]],parent=self) - return result[1:] - -#----------------------------------------------- -class LineList(_Entity): - """Like polyline, but built of individual lines.""" - def __init__(self,points=[],org_point=[0,0,0],closed=0,**common): - _Entity.__init__(self,**common) - self.closed=closed - self.points=copy.copy(points) - def __str__(self): - if self.closed:points=self.points+[self.points[0]] - else: points=self.points - result='' - for i in range(len(points)-1): - result+= Line(points=[points[i],points[i+1]],parent=self) - return result[1:] - -#----------------------------------------------------- -def test(): - #Blocks - b=Block('test') - b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1)) - b.append(Arc(center=(1,0,0),color=2)) - - #Drawing - d=Drawing() - #tables - d.blocks.append(b) #table blocks - d.styles.append(Style()) #table styles - d.views.append(View('Normal')) #table view - d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem - - #entities - d.append(Circle(center=(1,1,0),color=3)) - d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4)) - d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2)) - d.append(Line(points=[(0,0,0),(1,1,1)])) - d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90)) - d.append(Text('Please donate!',point=(3,0,1))) - #d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2))) - d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3)) - #d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],flag=1,color=1)) - - #d.saveas('c:\\test.dxf') - d.saveas('test.dxf') - -#----------------------------------------------------- -if __name__=='__main__': - if not copy: - Draw.PupMenu('Error%t|This script requires a full python install') - else: test() - \ No newline at end of file diff --git a/release/scripts/bpymodules/dxfReader.py b/release/scripts/bpymodules/dxfReader.py deleted file mode 100644 index df4ebc309e4..00000000000 --- a/release/scripts/bpymodules/dxfReader.py +++ /dev/null @@ -1,381 +0,0 @@ -"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data. - - The convert function is called by the readDXF fuction to convert dxf strings into the correct data based - on their type code. readDXF expects a (full path) file name as input. -""" - -# -------------------------------------------------------------------------- -# DXF Reader v0.9 by Ed Blake (AKA Kitsu) -# 2008.05.08 modif.def convert() by Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - - -#from dxfImportObjects import * - -class Object: - """Empty container class for dxf objects""" - - def __init__(self, _type='', block=False): - """_type expects a string value.""" - self.type = _type - self.name = '' - self.data = [] - - def __str__(self): - if self.name: - return self.name - else: - return self.type - - def __repr__(self): - return str(self.data) - - def get_type(self, kind=''): - """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" - if type: - objects = [] - for item in self.data: - if type(item) != list and item.type == kind: - # we want this type of object - objects.append(item) - elif type(item) == list and item[0] == kind: - # we want this type of data - objects.append(item[1]) - return objects - - -class InitializationError(Exception): pass - -class StateMachine: - """(finite) State Machine from the great David Mertz's great Charming Python article.""" - - def __init__(self): - self.handlers = [] - self.startState = None - self.endStates = [] - - def add_state(self, handler, end_state=0): - """All states and handlers are functions which return - a state and a cargo.""" - self.handlers.append(handler) - if end_state: - self.endStates.append(handler) - def set_start(self, handler): - """Sets the starting handler function.""" - self.startState = handler - - - def run(self, cargo=None): - if not self.startState: - raise InitializationError,\ - "must call .set_start() before .run()" - if not self.endStates: - raise InitializationError, \ - "at least one state must be an end_state" - handler = self.startState - while 1: - (newState, cargo) = handler(cargo) - #print cargo - if newState in self.endStates: - return newState(cargo) - #break - elif newState not in self.handlers: - raise RuntimeError, "Invalid target %s" % newState - else: - handler = newState - -def get_name(data): - """Get the name of an object from its object data. - - Returns a pair of (data_item, name) where data_item is the list entry where the name was found - (the data_item can be used to remove the entry from the object data). Be sure to check - name not None before using the returned values! - """ - value = None - for item in data: - if item[0] == 2: - value = item[1] - break - return item, value - -def get_layer(data): - """Expects object data as input. - - Returns (entry, layer_name) where entry is the data item that provided the layer name. - """ - value = None - for item in data: - if item[0] == 8: - value = item[1] - break - return item, value - - -def convert(code, value): - """Convert a string to the correct Python type based on its dxf code. - code types: - ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070 - longs = 90-99, 420-429, 440-459, 1071 - floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059 - hex = 105, 310-379, 390-399 - strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009 - """ - if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071: - value = int(float(value)) - elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: - value = long(float(value)) - elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060: - value = float(value) - elif code == 105 or 309 < code < 380 or 389 < code < 400: - value = int(value, 16) # should be left as string? - else: # it's already a string so do nothing - pass - return value - - -def findObject(infile, kind=''): - """Finds the next occurance of an object.""" - obj = False - while 1: - line = infile.readline() - if not line: # readline returns '' at eof - return False - if not obj: # We're still looking for our object code - if line.lower().strip() == '0': - obj = True # found it - else: # we are in an object definition - if kind: # if we're looking for a particular kind - if line.lower().strip() == kind: - obj = Object(line.lower().strip()) - break - else: # otherwise take anything non-numeric - if line.lower().strip() not in string.digits: - obj = Object(line.lower().strip()) - break - obj = False # whether we found one or not it's time to start over - return obj - -def handleObject(infile): - """Add data to an object until end of object is found.""" - line = infile.readline() - if line.lower().strip() == 'section': - return 'section' # this would be a problem - elif line.lower().strip() == 'endsec': - return 'endsec' # this means we are done with a section - else: # add data to the object until we find a new object - obj = Object(line.lower().strip()) - obj.name = obj.type - done = False - data = [] - while not done: - line = infile.readline() - if not data: - if line.lower().strip() == '0': - #we've found an object, time to return - return obj - else: - # first part is always an int - data.append(int(line.lower().strip())) - else: - data.append(convert(data[0], line.strip())) - obj.data.append(data) - data = [] - -def handleTable(table, infile): - """Special handler for dealing with nested table objects.""" - item, name = get_name(table.data) - if name: # We should always find a name - table.data.remove(item) - table.name = name.lower() - # This next bit is from handleObject - # handleObject should be generalized to work with any section like object - while 1: - obj = handleObject(infile) - if obj.type == 'table': - print "Warning: previous table not closed!" - return table - elif obj.type == 'endtab': - return table # this means we are done with the table - else: # add objects to the table until one of the above is found - table.data.append(obj) - - - - -def handleBlock(block, infile): - """Special handler for dealing with nested table objects.""" - item, name = get_name(block.data) - if name: # We should always find a name - block.data.remove(item) - block.name = name - # This next bit is from handleObject - # handleObject should be generalized to work with any section like object - while 1: - obj = handleObject(infile) - if obj.type == 'block': - print "Warning: previous block not closed!" - return block - elif obj.type == 'endblk': - return block # this means we are done with the table - else: # add objects to the table until one of the above is found - block.data.append(obj) - - - - -"""These are the states/functions used in the State Machine. -states: - start - find first section - start_section - add data, find first object - object - add obj-data, watch for next obj (called directly by start_section) - end_section - look for next section or eof - end - return results -""" - -def start(cargo): - """Expects the infile as cargo, initializes the cargo.""" - #print "Entering start state!" - infile = cargo - drawing = Object('drawing') - section = findObject(infile, 'section') - if section: - return start_section, (infile, drawing, section) - else: - return error, (infile, "Failed to find any sections!") - -def start_section(cargo): - """Expects [infile, drawing, section] as cargo, builds a nested section object.""" - #print "Entering start_section state!" - infile = cargo[0] - drawing = cargo[1] - section = cargo[2] - # read each line, if it is an object declaration go to object mode - # otherwise create a [index, data] pair and add it to the sections data. - done = False - data = [] - while not done: - line = infile.readline() - - if not data: # if we haven't found a dxf code yet - if line.lower().strip() == '0': - # we've found an object - while 1: # no way out unless we find an end section or a new section - obj = handleObject(infile) - if obj == 'section': # shouldn't happen - print "Warning: failed to close previous section!" - return end_section, (infile, drawing) - elif obj == 'endsec': # This section is over, look for the next - drawing.data.append(section) - return end_section, (infile, drawing) - elif obj.type == 'table': # tables are collections of data - obj = handleTable(obj, infile) # we need to find all there contents - section.data.append(obj) # before moving on - elif obj.type == 'block': # the same is true of blocks - obj = handleBlock(obj, infile) # we need to find all there contents - section.data.append(obj) # before moving on - else: # found another sub-object - section.data.append(obj) - else: - data.append(int(line.lower().strip())) - else: # we have our code, now we just need to convert the data and add it to our list. - data.append(convert(data[0], line.strip())) - section.data.append(data) - data = [] -def end_section(cargo): - """Expects (infile, drawing) as cargo, searches for next section.""" - #print "Entering end_section state!" - infile = cargo[0] - drawing = cargo[1] - section = findObject(infile, 'section') - if section: - return start_section, (infile, drawing, section) - else: - return end, (infile, drawing) - -def end(cargo): - """Expects (infile, drawing) as cargo, called when eof has been reached.""" - #print "Entering end state!" - infile = cargo[0] - drawing = cargo[1] - #infile.close() - return drawing - -def error(cargo): - """Expects a (infile, string) as cargo, called when there is an error during processing.""" - #print "Entering error state!" - infile = cargo[0] - err = cargo[1] - infile.close() - print "There has been an error:" - print err - return False - -def readDXF(filename, objectify): - """Given a file name try to read it as a dxf file. - - Output is an object with the following structure - drawing - header - header data - classes - class data - tables - table data - blocks - block data - entities - entity data - objects - object data - where foo data is a list of sub-objects. True object data - is of the form [code, data]. -""" - infile = open(filename) - - sm = StateMachine() - sm.add_state(error, True) - sm.add_state(end, True) - sm.add_state(start_section) - sm.add_state(end_section) - sm.add_state(start) - sm.set_start(start) - try: - drawing = sm.run(infile) - if drawing: - drawing.name = filename - for obj in drawing.data: - item, name = get_name(obj.data) - if name: - obj.data.remove(item) - obj.name = name.lower() - setattr(drawing, name.lower(), obj) - # Call the objectify function to cast - # raw objects into the right types of object - obj.data = objectify(obj.data) - #print obj.name - finally: - infile.close() - return drawing -if __name__ == "__main__": - filename = r".\examples\block-test.dxf" - drawing = readDXF(filename) - for item in drawing.entities.data: - print item diff --git a/release/scripts/bpymodules/mesh_gradient.py b/release/scripts/bpymodules/mesh_gradient.py deleted file mode 100644 index e582a30152b..00000000000 --- a/release/scripts/bpymodules/mesh_gradient.py +++ /dev/null @@ -1,229 +0,0 @@ -# This is not to be used directly, vertexGradientPick can be used externaly - -import Blender -import BPyMesh -import BPyWindow - -mouseViewRay= BPyWindow.mouseViewRay -from Blender import Mathutils, Window, Scene, Draw, sys -from Blender.Mathutils import Vector, Intersect, LineIntersect, AngleBetweenVecs -LMB= Window.MButs['L'] - -def mouseup(): - # Loop until click - mouse_buttons = Window.GetMouseButtons() - while not mouse_buttons & LMB: - sys.sleep(10) - mouse_buttons = Window.GetMouseButtons() - while mouse_buttons & LMB: - sys.sleep(10) - mouse_buttons = Window.GetMouseButtons() - -def mousedown_wait(): - # If the menu has just been pressed dont use its mousedown, - mouse_buttons = Window.GetMouseButtons() - while mouse_buttons & LMB: - mouse_buttons = Window.GetMouseButtons() - -eps= 0.0001 -def vertexGradientPick(ob, MODE): - #MODE 0 == VWEIGHT, 1 == VCOL - - me= ob.getData(mesh=1) - if not me.faceUV: me.faceUV= True - - Window.DrawProgressBar (0.0, '') - - mousedown_wait() - - if MODE==0: - act_group= me.activeGroup - if act_group == None: - mousedown_wait() - Draw.PupMenu('Error, mesh has no active group.') - return - - # Loop until click - Window.DrawProgressBar (0.25, 'Click to set gradient start') - mouseup() - - obmat= ob.matrixWorld - screen_x, screen_y = Window.GetMouseCoords() - mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) - if not mouseInView or not OriginA: - return - - # get the mouse weight - - if MODE==0: - pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA) - if MODE==1: - pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA) - - Window.DrawProgressBar (0.75, 'Click to set gradient end') - mouseup() - - TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT - - screen_x, screen_y = Window.GetMouseCoords() - mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat) - if not mouseInView or not OriginB: - return - - if not TOALPHA: # Only get a second opaque value if we are not blending to alpha - if MODE==0: pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB) - else: - pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB) - else: - if MODE==0: pickValB= 0.0 - else: pickValB= [0.0, 0.0, 0.0] # Dummy value - - # Neither points touched a face - if pickValA == pickValB == None: - return - - # clicking on 1 non face is fine. just set the weight to 0.0 - if pickValA==None: - pickValA= 0.0 - - # swap A/B - OriginA, OriginB= OriginB, OriginA - DirectionA, DirectionB= DirectionB, DirectionA - pickValA, pickValB= pickValA, pickValB - - TOALPHA= True - - if pickValB==None: - pickValB= 0.0 - TOALPHA= True - - # set up 2 lines so we can measure their distances and calc the gradient - - # make a line 90d to the grad in screenspace. - if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction - cross_grad= DirectionA.cross(DirectionB) - ORTHO= False - - else: # Ortho - Same direction, different origin - cross_grad= DirectionA.cross(OriginA-OriginB) - ORTHO= True - - cross_grad.normalize() - cross_grad= cross_grad * 100 - - lineA= (OriginA, OriginA+(DirectionA*100)) - lineB= (OriginB, OriginB+(DirectionB*100)) - - if not ORTHO: - line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2 - line_mid= (lineA[1]+lineB[1])*0.5 - - VSEL= [False] * (len(me.verts)) - - # Get the selected faces and apply the selection to the verts. - for f in me.faces: - if f.sel: - for v in f.v: - VSEL[v.index]= True - groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) - - - - def grad_weight_from_co(v): - ''' - Takes a vert and retuens its gradient radio between A and B - ''' - - if not VSEL[v.index]: # Not bart of a selected face? - return None, None - - v_co= v.co - # make a line 90d to the 2 lines the user clicked. - vert_line= (v_co - cross_grad, v_co + cross_grad) - - xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1]) - xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1]) - - if not xA or not xB: # Should never happen but support it anyhow - return None, None - - wA= (xA[0]-xA[1]).length - wB= (xB[0]-xB[1]).length - - wTot= wA+wB - if not wTot: # lines are on the same point. - return None, None - - ''' - Get the length of the line between both intersections on the - 2x view lines. - if the dist between lineA+VertLine and lineB+VertLine is - greater then the lenth between lineA and lineB intersection points, it means - that the verts are not inbetween the 2 lines. - ''' - lineAB_length= (xA[1]-xB[1]).length - - # normalzie - wA= wA/wTot - wB= wB/wTot - - if ORTHO: # Con only use line length method with parelelle lines - if wTot > lineAB_length+eps: - # vert is outside the range on 1 side. see what side of the grad - if wA>wB: wA, wB= 1.0, 0.0 - else: wA, wB= 0.0, 1.0 - else: - # PERSP, lineA[0] is the same origin as lineB[0] - - # Either xA[0] or xB[0] can be used instead of a possible x_mid between the 2 - # as long as the point is inbetween lineA and lineB it dosent matter. - a= AngleBetweenVecs(lineA[0]-xA[0], line_mid) - if a>line_angle: - # vert is outside the range on 1 side. see what side of the grad - if wA>wB: wA, wB= 1.0, 0.0 - else: wA, wB= 0.0, 1.0 - - return wA, wB - - - grad_weights= [grad_weight_from_co(v) for v in me.verts] - - - if MODE==0: - for v in me.verts: - i= v.index - if VSEL[i]: - wA, wB = grad_weights[i] - if wA != None: # and wB - if TOALPHA: - # Do alpha by using the exiting weight for - try: pickValB= vWeightDict[i][act_group] - except: pickValB= 0.0 # The weights not there? assume zero - # Mix2 2 opaque weights - vWeightDict[i][act_group]= pickValB*wA + pickValA*wB - - else: # MODE==1 VCol - for f in me.faces: - if f.sel: - f_v= f.v - for i in xrange(len(f_v)): - v= f_v[i] - wA, wB = grad_weights[v.index] - - c= f.col[i] - - if TOALPHA: - pickValB= c.r, c.g, c.b - - c.r = int(pickValB[0]*wA + pickValA[0]*wB) - c.g = int(pickValB[1]*wA + pickValA[1]*wB) - c.b = int(pickValB[2]*wA + pickValA[2]*wB) - - - - - # Copy weights back to the mesh. - BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) - Window.DrawProgressBar (1.0, '') - - diff --git a/release/scripts/bpymodules/meshtools.py b/release/scripts/bpymodules/meshtools.py deleted file mode 100644 index 274a12ea6da..00000000000 --- a/release/scripts/bpymodules/meshtools.py +++ /dev/null @@ -1,355 +0,0 @@ -# $Id$ -# -# +---------------------------------------------------------+ -# | Copyright (c) 2001 Anthony D'Agostino | -# | http://www.redrival.com/scorpius | -# | scorpius@netzero.com | -# | September 28, 2002 | -# +---------------------------------------------------------+ -# | Common Functions & Global Variables For All IO Modules | -# +---------------------------------------------------------+ - -# ***** 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 Blender -import sys - -show_progress = 1 # Set to 0 for faster performance -average_vcols = 1 # Off for per-face, On for per-vertex -overwrite_mesh_name = 0 # Set to 0 to increment object-name version - -blender_version = Blender.Get('version') -blender_version_str = `blender_version`[0] + '.' + `blender_version`[1:] - -try: - import operator -except: - msg = "Error: you need a full Python install to run this script." - meshtools.print_boxed(msg) - Blender.Draw.PupMenu("ERROR%t|"+msg) - -# ================================= -# === Append Faces To Face List === -# ================================= -def append_faces(mesh, faces, facesuv, uvcoords): - for i in xrange(len(faces)): - if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces") - numfaceverts=len(faces[i]) - if numfaceverts == 2: #This is not a face is an edge - if mesh.edges == None: #first run - mesh.addEdgeData() - #rev_face = revert(cur_face) - i1 = faces[i][0] - i2 = faces[i][1] - ee = mesh.addEdge(mesh.verts[i1],mesh.verts[i2]) - ee.flag |= Blender.NMesh.EdgeFlags.EDGEDRAW - ee.flag |= Blender.NMesh.EdgeFlags.EDGERENDER - elif numfaceverts in [3,4]: # This face is a triangle or quad - face = Blender.NMesh.Face() - for j in xrange(numfaceverts): - index = faces[i][j] - face.v.append(mesh.verts[index]) - if len(uvcoords) > 1: - uvidx = facesuv[i][j] - face.uv.append(uvcoords[uvidx]) - face.mode = 0 - face.col = [Blender.NMesh.Col()]*4 - mesh.faces.append(face) - else: # Triangulate n-sided convex polygon. - a, b, c = 0, 1, 2 # Indices of first triangle. - for j in xrange(numfaceverts-2): # Number of triangles in polygon. - face = Blender.NMesh.Face() - face.v.append(mesh.verts[faces[i][a]]) - face.v.append(mesh.verts[faces[i][b]]) - face.v.append(mesh.verts[faces[i][c]]) - b = c; c += 1 - mesh.faces.append(face) - #face.smooth = 1 - -# =================================== -# === Append Verts to Vertex List === -# =================================== -def append_verts(mesh, verts, normals): - #print "Number of normals:", len(normals) - #print "Number of verts :", len(verts) - for i in xrange(len(verts)): - if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(verts), "Generating Verts") - x, y, z = verts[i] - mesh.verts.append(Blender.NMesh.Vert(x, y, z)) - if normals: - mesh.verts[i].no[0] = normals[i][0] - mesh.verts[i].no[1] = normals[i][1] - mesh.verts[i].no[2] = normals[i][2] - -# =========================== -# === Create Blender Mesh === -# =========================== -def create_mesh(verts, faces, objname, facesuv=[], uvcoords=[], normals=[]): - if normals: normal_flag = 0 - else: normal_flag = 1 - mesh = Blender.NMesh.GetRaw() - append_verts(mesh, verts, normals) - append_faces(mesh, faces, facesuv, uvcoords) - if not overwrite_mesh_name: - objname = versioned_name(objname) - ob= Blender.NMesh.PutRaw(mesh, objname, normal_flag) # Name the Mesh - ob.name= objname # Name the Object - Blender.Redraw() - -# ============================== -# === Increment Name Version === -# ============================== -def versioned_name(objname): - existing_names = [] - for object in Blender.Object.Get(): - existing_names.append(object.name) - existing_names.append(object.getData(name_only=1)) - if objname in existing_names: # don't over-write other names - try: - name, ext = objname.split('.') - except ValueError: - name, ext = objname, '' - try: - num = int(ext) - root = name - except ValueError: - root = objname - for i in xrange(1, 1000): - objname = "%s.%03d" % (root, i) - if objname not in existing_names: - break - return objname - -# =========================== -# === Print Text In A Box === -# =========================== -def print_boxed(text): - lines = text.splitlines() - maxlinelen = max(map(len, lines)) - if sys.platform[:3] == "win": - print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191) - for line in lines: - print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179) - print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217) - else: - print '+-' + '-'*maxlinelen + '-+' - for line in lines: print '| ' + line.ljust(maxlinelen) + ' |' - print '+-' + '-'*maxlinelen + '-+' - print '\a\r', # beep when done - -# =============================================== -# === Get euler angles from a rotation matrix === -# =============================================== -def mat2euler(mat): - angle_y = -math.asin(mat[0][2]) - c = math.cos(angle_y) - if math.fabs(c) > 0.005: - angle_x = math.atan2(mat[1][2]/c, mat[2][2]/c) - angle_z = math.atan2(mat[0][1]/c, mat[0][0]/c) - else: - angle_x = 0.0 - angle_z = -math.atan2(mat[1][0], mat[1][1]) - return (angle_x, angle_y, angle_z) - -# ========================== -# === Transpose A Matrix === -# ========================== -def transpose(A): - S = len(A) - T = len(A[0]) - B = [[None]*S for i in xrange(T)] - for i in xrange(T): - for j in xrange(S): - B[i][j] = A[j][i] - return B - -# ======================= -# === Apply Transform === -# ======================= -def apply_transform(vertex, matrix): - x, y, z = vertex - xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2] - xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc - ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc - zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc - vertex = [xcomponent, ycomponent, zcomponent] - return vertex - -# ========================= -# === Has Vertex Colors === -# ========================= -def has_vertex_colors(mesh): - # My replacement/workaround for hasVertexColours() - # The docs say: - # "Warning: If a mesh has both vertex colours and textured faces, - # this function will return False. This is due to the way Blender - # deals internally with the vertex colours array (if there are - # textured faces, it is copied to the textured face structure and - # the original array is freed/deleted)." - try: - return mesh.faces[0].col[0] - except: - return 0 - -# =========================== -# === Generate Edge Table === -# =========================== -def generate_edgetable(mesh): - edge_table = {} - numfaces = len(mesh.faces) - - for i in xrange(numfaces): - if not i%100 and show_progress: - Blender.Window.DrawProgressBar(float(i)/numfaces, "Generating Edge Table") - if len(mesh.faces[i].v) == 4: # Process Quadrilaterals - generate_entry_from_quad(mesh, i, edge_table) - elif len(mesh.faces[i].v) == 3: # Process Triangles - generate_entry_from_tri(mesh, i, edge_table) - else: # Skip This Face - print "Face #", i, "was skipped." - - # === Sort Edge_Table Keys & Add Edge Indices === - i = 0 - keys = edge_table.keys() - keys.sort() - for key in keys: - edge_table[key][6] = i - i += 1 - - # === Replace Tuples With Indices === - for key in keys: - for i in [2,3,4,5]: - if edge_table.has_key(edge_table[key][i]): - edge_table[key][i] = edge_table[edge_table[key][i]][6] - else: - keyrev = (edge_table[key][i][1], edge_table[key][i][0]) - edge_table[key][i] = edge_table[keyrev][6] - - return edge_table - -# ================================ -# === Generate Entry From Quad === -# ================================ -def generate_entry_from_quad(mesh, i, edge_table): - vertex4, vertex3, vertex2, vertex1 = mesh.faces[i].v - - if has_vertex_colors(mesh): - vcolor4, vcolor3, vcolor2, vcolor1 = mesh.faces[i].col - Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) - Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) - Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) - Dcol = (vcolor4.r/255.0, vcolor4.g/255.0, vcolor4.b/255.0) - - # === verts are upper case, edges are lower case === - A, B, C, D = vertex1.index, vertex2.index, vertex3.index, vertex4.index - a, b, c, d = (A, B), (B, C), (C, D), (D, A) - - if edge_table.has_key((B, A)): - edge_table[(B, A)][1] = i - edge_table[(B, A)][4] = d - edge_table[(B, A)][5] = b - if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol - else: - if has_vertex_colors(mesh): - edge_table[(A, B)] = [i, None, d, b, None, None, None, Bcol, None] - else: - edge_table[(A, B)] = [i, None, d, b, None, None, None] - - if edge_table.has_key((C, B)): - edge_table[(C, B)][1] = i - edge_table[(C, B)][4] = a - edge_table[(C, B)][5] = c - if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol - else: - if has_vertex_colors(mesh): - edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] - else: - edge_table[(B, C)] = [i, None, a, c, None, None, None] - - if edge_table.has_key((D, C)): - edge_table[(D, C)][1] = i - edge_table[(D, C)][4] = b - edge_table[(D, C)][5] = d - if has_vertex_colors(mesh): edge_table[(D, C)][8] = Dcol - else: - if has_vertex_colors(mesh): - edge_table[(C, D)] = [i, None, b, d, None, None, None, Dcol, None] - else: - edge_table[(C, D)] = [i, None, b, d, None, None, None] - - if edge_table.has_key((A, D)): - edge_table[(A, D)][1] = i - edge_table[(A, D)][4] = c - edge_table[(A, D)][5] = a - if has_vertex_colors(mesh): edge_table[(A, D)][8] = Acol - else: - if has_vertex_colors(mesh): - edge_table[(D, A)] = [i, None, c, a, None, None, None, Acol, None] - else: - edge_table[(D, A)] = [i, None, c, a, None, None, None] - -# ==================================== -# === Generate Entry From Triangle === -# ==================================== -def generate_entry_from_tri(mesh, i, edge_table): - vertex3, vertex2, vertex1 = mesh.faces[i].v - - if has_vertex_colors(mesh): - vcolor3, vcolor2, vcolor1, _vcolor4_ = mesh.faces[i].col - Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) - Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) - Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) - - # === verts are upper case, edges are lower case === - A, B, C = vertex1.index, vertex2.index, vertex3.index - a, b, c = (A, B), (B, C), (C, A) - - if edge_table.has_key((B, A)): - edge_table[(B, A)][1] = i - edge_table[(B, A)][4] = c - edge_table[(B, A)][5] = b - if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol - else: - if has_vertex_colors(mesh): - edge_table[(A, B)] = [i, None, c, b, None, None, None, Bcol, None] - else: - edge_table[(A, B)] = [i, None, c, b, None, None, None] - - if edge_table.has_key((C, B)): - edge_table[(C, B)][1] = i - edge_table[(C, B)][4] = a - edge_table[(C, B)][5] = c - if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol - else: - if has_vertex_colors(mesh): - edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] - else: - edge_table[(B, C)] = [i, None, a, c, None, None, None] - - if edge_table.has_key((A, C)): - edge_table[(A, C)][1] = i - edge_table[(A, C)][4] = b - edge_table[(A, C)][5] = a - if has_vertex_colors(mesh): edge_table[(A, C)][8] = Acol - else: - if has_vertex_colors(mesh): - edge_table[(C, A)] = [i, None, b, a, None, None, None, Acol, None] - else: - edge_table[(C, A)] = [i, None, b, a, None, None, None] - diff --git a/release/scripts/bpymodules/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py deleted file mode 100644 index 6eb5023a8d4..00000000000 --- a/release/scripts/bpymodules/paths_ai2obj.py +++ /dev/null @@ -1,506 +0,0 @@ -# -*- coding: latin-1 -*- -""" -paths_ai2obj.py -# --------------------------------------------------------------- -Copyright (c) jm soler juillet/novembre 2004-april 2007, -# --------------------------------------------------------------- - released under GNU Licence - for the Blender 2.45 Python Scripts Bundle. -Ce programme est libre, vous pouvez le redistribuer et/ou -le modifier selon les termes de la Licence Publique Générale GNU -publiée par la Free Software Foundation (version 2 ou bien toute -autre version ultérieure choisie par vous). - -Ce programme est distribué car potentiellement utile, mais SANS -AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties -de commercialisation ou d'adaptation dans un but spécifique. -Reportez-vous à la Licence Publique Générale GNU pour plus de détails. - -Vous devez avoir reçu une copie de la Licence Publique Générale GNU -en même temps que ce programme ; si ce n'est pas le cas, écrivez à la -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, -MA 02111-1307, États-Unis. - - -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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# --------------------------------------------------------------- -#---------------------------------------------- -# -# Page officielle : -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai_en.htm -# Communiquer les problemes et erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -#---------------------------------------------- - -#Changelog -#---------------------------------------------- -# 0.1.1 : 2004/08/03, bug in boundingbox reading when Value are negative -# 0.1.2 : 2005/06/12, gmove tranformation properties -# 0.1.3 : 2005/06/25, added a __name__ test to use the script alone -# 0.1.4 : 2005/06/25, closepath improvements -# 0.1.5 : 2005/06/25, ... -# 0.1.6 : 2005/06/26, warning for compacted file - compatibility increased up to AI 10.0 plain text -# 0.1.7 : 2005/06/25, two more closepath improvements -# -# 0.1.8 : 2006/07/03, two more closepath improvements -# 0.1.9 : 2007/05/06, modif on the method that gets the last object on - the list data -# 2008/03/12, Added character encoding line so french text -# does not break python interpreters. - -""" -SHARP_IMPORT=0 -SCALE=1 -NOTHING_TODO=1 -AI_VERSION='' - -GSTACK = [] -GSCALE = [] -GTRANSLATE = [] - -import sys -#oldpath=sys.path -import Blender -BLversion=Blender.Get('version') - -try: - import nt - os=nt - os.sep='\\' - -except: - import posix - os=posix - os.sep='/' - -def isdir(path): - try: - st = os.stat(path) - return 1 - except: - return 0 - -def split(pathname): - if pathname.find(os.sep)!=-1: - k0=pathname.split(os.sep) - else: - if os.sep=='/': - k0=pathname.split('\\') - else: - k0=pathname.split('/') - - directory=pathname.replace(k0[len(k0)-1],'') - Name=k0[len(k0)-1] - return directory, Name - -def join(l0,l1): - return l0+os.sep+l1 - -os.isdir=isdir -os.split=split -os.join=join - -def filtreFICHIER(nom): - f=open(nom,'rU') - t=f.readlines() - f.close() - - if len(t)>1 and t[0].find('EPSF')==-1: - return t - else: - name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 - result = Blender.Draw.PupMenu(name) - - return 'false' - -#=============================== -# Data -#=============================== -#=============================== -# Blender Curve Data -#=============================== -objBEZIER=0 -objSURFACE=5 -typBEZIER3D=1 #3D -typBEZIER2D=9 #2D - -class Bez: - def __init__(self): - self.co=[] - self.ha=[0,0] - self.tag='' - -class ITEM: - def __init__(self): - self.type = typBEZIER3D, - self.pntsUV = [0,0] - self.resolUV = [32,0] - self.orderUV = [0,0] - self.flagUV = [0,0] - self.Origine = [0.0,0.0] - self.beziers_knot = [] - -class COURBE: - def __init__(self): - self.magic_number='3DG3' - self.type = objBEZIER - self.number_of_items = 0 - self.ext1_ext2 = [0,0] - self.matrix = """0.0 0.0 1.0 0.0 -0.0 1.0 0.0 0.0 -0.0 0.0 1.0 0.0 -0.0 0.0 0.0 1.0 """ - self.ITEM = {} - -courbes=COURBE() - -PATTERN={} - -BOUNDINGBOX={'rec':[],'coef':1.0} -npat=0 -#===================================================================== -#======== name of the curve in teh courbes dictionnary =============== -#===================================================================== -n0=0 - -#===================================================================== -#====================== current Point ================================ -#===================================================================== -CP=[0.0,0.0] #currentPoint - - -# modifs 12/06/2005 -#===================================================================== -#====================== current transform ============================ -#===================================================================== -class transform: - def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): - self.matrix=matrix[:] - self.xy=[x,y] - -def G_move(l,a): - global GSCALE, GTRANSLATE, GSTACK - #print GSCALE, GTRANSLATE, GSTACK - return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) -# modifs 12/06/2005 - - -#===================================================================== -#===== to compare last position to the original move to displacement = -#===== needed for cyclic efinition ================================= -#===================================================================== -def test_egalitedespositions(f1,f2): - if f1[0]==f2[0] and f1[1]==f2[1]: - return Blender.TRUE - else: - return Blender.FALSE - - -def Open_GEOfile(dir,nom): - if BLversion>=233: - in_editmode = Blender.Window.EditMode() - if in_editmode: Blender.Window.EditMode(0) - Blender.Load(dir+nom+'OOO.obj', 1) - BO=Blender.Scene.GetCurrent().objects.active - BO.RotY=0.0 - BO.RotX=1.57 - BO.makeDisplayList() - Blender.Window.RedrawAll() - else: - print "Not yet implemented" - -def create_GEOtext(courbes): - global SCALE, B, BOUNDINGBOX - r=BOUNDINGBOX['rec'] - - if SCALE==1: - SCALE=1.0 - elif SCALE==2: - SCALE=r[2]-r[0] - elif SCALE==3: - SCALE=r[3]-r[1] - - t=[] - t.append(courbes.magic_number+'\n') - t.append(str(courbes.type)+'\n') - t.append(str(courbes.number_of_items)+'\n') - t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') - t.append(courbes.matrix+'\n') - - for k in courbes.ITEM.keys(): - if len(courbes.ITEM[k].beziers_knot)>1 : - t.append("%s\n"%courbes.ITEM[k].type) - t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) - - flag =courbes.ITEM[k].flagUV[0] - - for k2 in range(len(courbes.ITEM[k].beziers_knot)): - #print k2 - k1 =courbes.ITEM[k].beziers_knot[k2] - t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) - - t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') - return t - -def save_GEOfile(dir,nom,t): - f=open(dir+nom+'OOO.obj','w') - f.writelines(t) - f.close() - #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" - #result = Blender.Draw.PupMenu(warning) - - -#===================================================================== -#===== AI format : DEBUT ========================= -#===================================================================== -def mouvement_vers(l,n0,CP): - if n0 in courbes.ITEM.keys(): - n0+=1 - - CP=[l[-3].replace('d',''),l[-2]] - courbes.ITEM[n0]=ITEM() - courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] - - B=Bez() - B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] - B.ha=[0,0] - B.tag=l[-1] - - courbes.ITEM[n0].beziers_knot.append(B) - - return courbes,n0,CP - -def courbe_vers_c(l,l2, n0,CP): #c,C - - B=Bez() - B.co=[l[4],l[5],l[2],l[3],l[4],l[5]] - B.tag=l[-1] - B.ha=[0,0] - - BP=courbes.ITEM[n0].beziers_knot[-1] - - BP.co[0]=l[0] - BP.co[1]=l[1] - - courbes.ITEM[n0].beziers_knot.append(B) - - CP=[B.co[4],B.co[5]] - return courbes,n0,CP - - -def courbe_vers_v(l,n0,CP): #v-V - - B=Bez() - B.tag=l[-1] - B.co=[l[2],l[3],l[0],l[1],l[2],l[3]] - B.ha=[0,0] - - courbes.ITEM[n0].beziers_knot.append(B) - - CP=[B.co[4],B.co[5]] - return courbes,n0,CP - -def courbe_vers_y(l,n0,CP): #y - B=Bez() - B.tag=l[-1] - B.co=[l[2],l[3],l[2],l[3],l[2],l[3]] - B.ha=[0,0] - - BP=courbes.ITEM[n0].beziers_knot[-1] - BP.co[0]=l[0] - BP.co[1]=l[1] - - courbes.ITEM[n0].beziers_knot.append(B) - CP=[B.co[4],B.co[5]] - return courbes,n0,CP - - -def ligne_tracee_l(l,n0,CP): - B=Bez() - B.tag=l[-1] - B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] - B.ha=[0,0] - - BP=courbes.ITEM[n0].beziers_knot[-1] - - courbes.ITEM[n0].beziers_knot.append(B) - CP=[B.co[4],B.co[5]] - return courbes,n0,CP - -def ligne_fermee(l,n0,CP): - courbes.ITEM[n0].flagUV[0]=1 - - if len(courbes.ITEM[n0].beziers_knot)>1: - BP=courbes.ITEM[n0].beziers_knot[-1] - BP0=courbes.ITEM[n0].beziers_knot[0] - - if BP.tag not in ['l','L']: - BP.co[0]=BP0.co[0] #4-5 point prec - BP.co[1]=BP0.co[1] - - del courbes.ITEM[n0].beziers_knot[0] - return courbes,n0,CP - -def passe(l,n0,CP): - return courbes,n0,CP - -Actions= { "C" : courbe_vers_c, - "c" : courbe_vers_c, - "V" : courbe_vers_v, - "v" : courbe_vers_v, - "Y" : courbe_vers_y, - "y" : courbe_vers_y, - "m" : mouvement_vers, - "l" : ligne_tracee_l, - "L" : ligne_tracee_l, - "F" : passe, - "f" : ligne_fermee, - "B" : passe, - "b" : ligne_fermee, - "S" : passe, - "s" : ligne_fermee, - "N" : ligne_fermee, - "n" : passe, - } - -TAGcourbe=Actions.keys() - -def pik_pattern(t,l): - global npat, PATTERN, BOUNDINGBOX, AI_VERSION - while t[l].find('%%EndSetup')!=0: - if t[l].find('%%Creator: Adobe Illustrator(R)')!=-1: - print t[l] - AI_VERSION=t[l].split()[-1] - print AI_VERSION - - if t[l].find('%%BoundingBox:')!=-1: - t[l]=t[l][t[l].find(':')+1:] - l0=t[l].split() - BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] - r=BOUNDINGBOX['rec'] - BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) - #print l, - if t[l].find('BeginPattern')!=-1: - nomPattern=t[l][t[l].find('(')+1:t[l].find(')')] - PATTERN[nomPattern]={} - - if t[l].find('BeginPatternLayer')!=-1: - npat+=1 - PATTERN[nomPattern][npat]=[] - while t[l].find('EndPatternLayer')==-1: - #print t[l] - PATTERN[nomPattern][npat].append(l) - l+=1 - if l+10: - if len(PATTERN.keys() )>0: - #print len(PATTERN.keys() ) - warning = "Pattern list (for info not used): %t| " - p0=1 - for P in PATTERN.keys(): - warning+="%s %%x%s|"%(P,p0) - p0+=1 - Padd = Blender.Draw.PupMenu(warning) - - t=create_GEOtext(courbes) - save_GEOfile(dir,name[0],t) - - # 0.1.8 --------------------------------- - # [O.select(0) for O in Blender.Scene.getCurrent().getChildren()] - # 0.1.8 --------------------------------- - - Open_GEOfile(dir,name[0]) - - # 0.1.8 --------------------------------- - Blender.Object.Get()[-1].setName(name[0]) - # 0.1.8 --------------------------------- - - else: - pass -#===================================================================== -#====================== AI format mouvements ========================= -#===================================================================== -#========================================================= -# une sorte de contournement qui permet d'utiliser la fonction -# et de documenter les variables Window.FileSelector -#========================================================= -def fonctionSELECT(nom): - global NOTHING_TODO,AI_VERSION - scan_FILE(nom) - if NOTHING_TODO==1: - warning = "AI %s compatible file "%AI_VERSION+" but nothing to do ? %t| Perhaps a compacted file ... " - NOTHING = Blender.Draw.PupMenu(warning) - -if __name__=="__main__": - Blender.Window.FileSelector (fonctionSELECT, 'SELECT AI FILE') -#sys.path=oldpath diff --git a/release/scripts/bpymodules/paths_eps2obj.py b/release/scripts/bpymodules/paths_eps2obj.py deleted file mode 100644 index e1643c3bf40..00000000000 --- a/release/scripts/bpymodules/paths_eps2obj.py +++ /dev/null @@ -1,452 +0,0 @@ -#---------------------------------------------- -# (c) jm soler juillet 2004-juin 2005 , released under Blender Artistic Licence -# for the Blender 2.34-2.37 Python Scripts Bundle. -# -# last update: 06/05/2007 -#---------------------------------------------- -# Page officielle : -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_eps.htm -# Communiquer les problemes et erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -#---------------------------------------------- -SHARP_IMPORT = 0 -SCALE = 1.0 -scale = 1 - -import sys -#oldpath=sys.path - -import Blender -from Blender import Draw -BLversion=Blender.Get('version') - -try: - import nt - os=nt - os.sep='\\' - -except: - import posix - os=posix - os.sep='/' - -def isdir(path): - try: - st = os.stat(path) - return 1 - except: - return 0 - -def split(pathname): - if pathname.find(os.sep)!=-1: - k0=pathname.split(os.sep) - else: - if os.sep=='/': - k0=pathname.split('\\') - else: - k0=pathname.split('/') - - directory=pathname.replace(k0[len(k0)-1],'') - Name=k0[len(k0)-1] - return directory, Name - -def join(l0,l1): - return l0+os.sep+l1 - -os.isdir=isdir -os.split=split -os.join=join - -def filtreFICHIER(nom): - f=open(nom,'rU') - t=f.readlines() - f.close() - if len(t)==1 and t[0].find('\r'): - t=t[0].split('\r') - if len(t)>1 and t[0].find('PS-Adobe-3.0')==-1 and t[0].find('EPSF')==-1: - return t - else: - name = "OK?%t| Not a valid file or an empty file or... %x1| not a pure PS-Adobe-2.0 file %x2 " - result = Blender.Draw.PupMenu(name) - return 'false' - -#=============================== -# Data -#=============================== -#=============================== -# Blender Curve Data -#=============================== -objBEZIER=0 -objSURFACE=5 -typBEZIER3D=1 #3D -typBEZIER2D=9 #2D - -class Bez: - def __init__(self): - self.co=[] - self.ha=[0,0] - -class ITEM: - def __init__(self): - self.type = typBEZIER3D, - self.pntsUV = [0,0] - self.resolUV = [32,0] - self.orderUV = [0,0] - self.flagUV = [0,0] - self.Origine = [0.0,0.0] - self.beziers_knot = [] - -class COURBE: - def __init__(self): - self.magic_number='3DG3' - self.type = objBEZIER - self.number_of_items = 0 - self.ext1_ext2 = [0,0] - self.matrix = """0.0 0.0 1.0 0.0 -0.0 1.0 0.0 0.0 -0.0 0.0 1.0 0.0 -0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size - self.ITEM = {} - -courbes=COURBE() -PATTERN={} -BOUNDINGBOX={'rec':[],'coef':1.0} -npat=0 -#===================================================================== -#======== name of the curve in teh courbes dictionnary =============== -#===================================================================== -n0=0 - -#===================================================================== -#====================== current Point ================================ -#===================================================================== -CP=[0.0,0.0] #currentPoint - -# modifs 12/06/2005 -#===================================================================== -#====================== current transform ============================ -#===================================================================== -class transform: - def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): - self.matrix=matrix[:] - self.xy=[x,y] - -GSTACK = [] -stack=transform() -GSTACK.append(stack) - -GSCALE = [1.0,1.0] -GTRANSLATE = [0.0,0.0] - -def G_move(l,a): - global GSCALE, GTRANSLATE, GSTACK - #print GSCALE, GTRANSLATE, GSTACK - return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) -# modifs 12/06/2005 - -#===================================================================== -#===== to compare last position to the original move to displacement = -#===== needed for cyclic efinition ================================= -#===================================================================== -def test_egalitedespositions(f1,f2): - if f1[0]==f2[0] and f1[1]==f2[1]: - return Blender.TRUE - else: - return Blender.FALSE - - -def Open_GEOfile(dir,nom): - global SCALE,BOUNDINGBOX, scale - if BLversion>=233: - Blender.Load(dir+nom+'OOO.obj', 1) - BO=Blender.Scene.GetCurrent().objects.active - BO.RotY=3.1416 - BO.RotZ=3.1416 - BO.RotX=3.1416/2.0 - if scale==1: - BO.LocY+=BOUNDINGBOX['rec'][3] - else: - BO.LocY+=BOUNDINGBOX['rec'][3]/SCALE - - BO.makeDisplayList() - Blender.Window.RedrawAll() - else: - print "Not yet implemented" - -def create_GEOtext(courbes): - global SCALE, B, BOUNDINGBOX,scale - r=BOUNDINGBOX['rec'] - - if scale==1: - SCALE=1.0 - elif scale==2: - SCALE=r[2]-r[0] - elif scale==3: - SCALE=r[3]-r[1] - - t=[] - t.append(courbes.magic_number+'\n') - t.append(str(courbes.type)+'\n') - t.append(str(courbes.number_of_items)+'\n') - t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') - t.append(courbes.matrix+'\n') - - for k in courbes.ITEM.keys(): - t.append("%s\n"%courbes.ITEM[k].type) - t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) - - flag =courbes.ITEM[k].flagUV[0] - - for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): - k1 =courbes.ITEM[k].beziers_knot[k2] - t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) - t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') - return t - -def save_GEOfile(dir,nom,t): - f=open(dir+nom+'OOO.obj','w') - f.writelines(t) - f.close() - - #name = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" - #result = Blender.Draw.PupMenu(name) - - -#===================================================================== -#===== EPS format : DEBUT ========================= -#===================================================================== -def mouvement_vers(l,n0,CP): - if n0 in courbes.ITEM.keys(): - #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): - # courbes.ITEM[n0].flagUV[0]=1 - n0+=1 - CP=[l[-3].replace('d',''),l[-2]] - else: - CP=[l[-3].replace('d',''),l[-2]] - #i= - courbes.ITEM[n0]=ITEM() - courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] - - B=Bez() - B.co=[G_move(CP[0],0), - G_move(CP[1],1), - G_move(CP[0],0), - G_move(CP[1],1), - G_move(CP[0],0), - G_move(CP[1],1)] - - B.ha=[0,0] - courbes.ITEM[n0].beziers_knot.append(B) - - return courbes,n0,CP - -def rmouvement_vers(l,n0,CP): - if n0 in courbes.ITEM.keys(): - #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): - # courbes.ITEM[n0].flagUV[0]=1 - n0+=1 - CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] - else: - CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] - #i= - courbes.ITEM[n0]=ITEM() - courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] - - B=Bez() - B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] - B.ha=[0,0] - courbes.ITEM[n0].beziers_knot.append(B) - return courbes,n0,CP - -def courbe_vers_c(l, l2, n0,CP): #c,C - """ - B=Bez() - B.co=[l[0],l[1],l[2],l[3],l[4],l[5]] - B.ha=[0,0] - - courbes.ITEM[n0].beziers_knot.append(B) - """ - B=Bez() - B.co=[G_move(l[2],0), - G_move(l[3],1), - G_move(l[4],0), - G_move(l[5],1), - G_move(l[0],0), - G_move(l[1],1)] - if len(courbes.ITEM[n0].beziers_knot)==1: - CP=[l[0],l[1]] - courbes.ITEM[n0].Origine=[l[0],l[1]] - if l[-1]=='C': - B.ha=[2,2] - else: - B.ha=[0,0] - courbes.ITEM[n0].beziers_knot.append(B) - if len(l2)>1 and l2[-1] in Actions.keys(): - B.co[-2]=G_move(l2[0],0) - B.co[-1]=G_move(l2[1],1) - else: - B.co[-2]=G_move(CP[0],0) - B.co[-1]=G_move(CP[1],1) - return courbes,n0,CP - -def ligne_tracee_l(l,n0,CP): - B=Bez() - B.co=[G_move(l[0],0), - G_move(l[1],1), - G_move(l[0],0), - G_move(l[1],1), - G_move(l[0],0), - G_move(l[1],1)] - B.ha=[0,0] - courbes.ITEM[n0].beziers_knot.append(B) - CP=[l[0],l[1]] - return courbes,n0,CP - -def rligne_tracee_l(l,n0,CP): - B=Bez() - B.co=["%4f"%(float(l[0])+float(CP[0])), - "%4f"%(float(l[1])+float(CP[1])), - "%4f"%(float(l[0])+float(CP[0])), - "%4f"%(float(l[1])+float(CP[1])), - "%4f"%(float(l[0])+float(CP[0])), - "%4f"%(float(l[1])+float(CP[1]))] - B.ha=[0,0] - courbes.ITEM[n0].beziers_knot.append(B) - CP=[l[0],l[1]] - return courbes,n0,CP - -Actions= { "curveto" : courbe_vers_c, - "curveto" : courbe_vers_c, - "moveto" : mouvement_vers, - "rmoveto" : mouvement_vers, - "lineto" : ligne_tracee_l, - "rlineto" : rligne_tracee_l -} - -TAGcourbe=Actions.keys() - -""" -def pik_pattern(t,l): - global npat, PATTERN, BOUNDINGBOX - while t[l].find('%%EndSetup')!=0: - if t[l].find('%%BoundingBox:')!=-1: - l0=t[l].split() - BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] - r=BOUNDINGBOX['rec'] - BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) - print l, - if t[l].find('BeginPatternLayer')!=-1: - npat+=1 - PATTERN[npat]=[] - while t[l].find('EndPatternLayer')==-1: - print t[l] - PATTERN[npat].append(l) - l+=1 - if l+10: - if len(PATTERN.keys() )>0: - #print len(PATTERN.keys() ) - pass - t=create_GEOtext(courbes) - save_GEOfile(dir,name[0],t) - Open_GEOfile(dir,name[0]) - - # 03 juillet 2006 ---------------------- - Blender.Object.Get()[-1].setName(name[0]) - # 03 juillet 2006 ---------------------- - - else: - pass - - -#===================================================================== -#====================== EPS format mouvements ========================= -#===================================================================== -#========================================================= -# une sorte de contournement qui permet d'utiliser la fonction -# et de documenter les variables Window.FileSelector -#========================================================= -def fonctionSELECT(nom): - scan_FILE(nom) - -if __name__=="__main__": - Blender.Window.FileSelector (fonctionSELECT, 'SELECT EPS FILE') - - diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py deleted file mode 100644 index c2ce9718c71..00000000000 --- a/release/scripts/bpymodules/paths_gimp2obj.py +++ /dev/null @@ -1,363 +0,0 @@ -# -*- coding: latin-1 -*- -""" -#---------------------------------------------- -# (c) jm soler juillet 2004, -#---------------------------------------------- - released under GNU Licence - for the Blender 2.45 Python Scripts Bundle. -Ce programme est libre, vous pouvez le redistribuer et/ou -le modifier selon les termes de la Licence Publique Générale GNU -publiée par la Free Software Foundation (version 2 ou bien toute -autre version ultérieure choisie par vous). - -Ce programme est distribué car potentiellement utile, mais SANS -AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties -de commercialisation ou d'adaptation dans un but spécifique. -Reportez-vous à la Licence Publique Générale GNU pour plus de détails. - -Vous devez avoir reçu une copie de la Licence Publique Générale GNU -en même temps que ce programme ; si ce n'est pas le cas, écrivez à la -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, -MA 02111-1307, États-Unis. - - -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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -""" - -# --------------------------------------------------------------- -# last update : 07/05/2007 -#---------------------------------------------- -# Page officielle : -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm -# Communiquer les problemes et erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -# Modification History: -# 2008-03-12 Added character encoding line so french text does not break -# python interpreters. -#--------------------------------------------- - -SHARP_IMPORT=0 -SCALE=1 - -import sys -#oldpath=sys.path - -import Blender -BLversion=Blender.Get('version') - -try: - import nt - os=nt - os.sep='\\' - -except: - import posix - os=posix - os.sep='/' - -def isdir(path): - try: - st = os.stat(path) - return 1 - except: - return 0 - -def split(pathname): - if pathname.find(os.sep)!=-1: - k0=pathname.split(os.sep) - else: - if os.sep=='/': - k0=pathname.split('\\') - else: - k0=pathname.split('/') - - directory=pathname.replace(k0[len(k0)-1],'') - Name=k0[len(k0)-1] - return directory, Name - -def join(l0,l1): - return l0+os.sep+l1 - -os.isdir=isdir -os.split=split -os.join=join - -def filtreFICHIER(nom): - f=open(nom,'r') - t=f.readlines() - f.close() - if len(t)==1 and t[0].find('\r'): - t=t[0].split('\r') - if len(t)>1 and t[1].find('#POINTS:')==0: - return t - else: - warning = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 - result = Blender.Draw.PupMenu(warning) - return "false" - -#=============================== -# Data -#=============================== -#=============================== -# Blender Curve Data -#=============================== -objBEZIER=0 -objSURFACE=5 -typBEZIER3D=1 #3D -typBEZIER2D=9 #2D - -class Bez: - def __init__(self): - self.co=[] - self.ha=[0,0] - - def echo(self): - #print 'co = ', self.co - #print 'ha = ', self.ha - pass - -class ITEM: - def __init__(self): - self.type = typBEZIER3D, - self.pntsUV = [0,0] - self.resolUV = [32,0] - self.orderUV = [0,0] - self.flagUV = [0,0] - self.Origine = [0.0,0.0] - self.beziers_knot = [] - -class COURBE: - def __init__(self): - self.magic_number='3DG3' - self.type = objBEZIER - self.number_of_items = 0 - self.ext1_ext2 = [0,0] - self.matrix = """0.0 0.0 1.0 0.0 -0.0 1.0 0.0 0.0 -0.0 0.0 1.0 0.0 -0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size - self.ITEM = {} - -courbes=COURBE() -PATTERN={} -BOUNDINGBOX={'rec':[],'coef':1.0} -npat=0 -#===================================================================== -#======== name of the curve in the courbes dictionnary =============== -#===================================================================== -n0=0 - -#===================================================================== -#====================== current Point ================================ -#===================================================================== -CP=[0.0,0.0] #currentPoint - -def MINMAX(b): - global BOUNDINGBOX - r=BOUNDINGBOX['rec'] - for m in range(0,len(b)-2,2): - #print m, m+1 , len(b)-1 - #print b[m], r, r[0] - if float(b[m])r[2]: r[2]=float(b[m]) - - if float(b[m+1])r[3]: r[3]=float(b[m+1]) - -#===================================================================== -#===== to compare last position to the original move to displacement = -#===== needed for cyclic efinition ================================= -#===================================================================== -def test_egalitedespositions(f1,f2): - if f1[0]==f2[0] and f1[1]==f2[1]: - return Blender.TRUE - else: - return Blender.FALSE - - -def Open_GEOfile(dir,nom): - if BLversion>=233: - Blender.Load(dir+nom+'OOO.obj', 1) - BO=Blender.Scene.GetCurrent().objects.active - BO.LocZ=1.0 - BO.makeDisplayList() - Blender.Window.RedrawAll() - else: - print "Not yet implemented" - -def create_GEOtext(courbes): - global SCALE, B, BOUNDINGBOX - r=BOUNDINGBOX['rec'] - if SCALE==1: - SCALE=1.0 - elif SCALE==2: - SCALE=r[2]-r[0] - elif SCALE==3: - SCALE=r[3]-r[1] - - t=[] - t.append(courbes.magic_number+'\n') - t.append(str(courbes.type)+'\n') - t.append(str(courbes.number_of_items)+'\n') - t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') - t.append(courbes.matrix+'\n') - - for k in courbes.ITEM.keys(): - - t.append("%s\n"%courbes.ITEM[k].type) - - t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) - t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) - - flag =0#courbes.ITEM[k].flagUV[0] - - for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): - k1 =courbes.ITEM[k].beziers_knot[k2] - t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) - t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) - t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') - return t - -def save_GEOfile(dir,nom,t): - f=open(dir+nom+'OOO.obj','w') - f.writelines(t) - f.close() - #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" - #result = Blender.Draw.PupMenu(warning) - - -#===================================================================== -#===== GIMP format : DEBUT ========================= -#===================================================================== -CLOSED=0 - -def mouvement_vers(l,l1,l2,n0): - global BOUNDINGBOX, CP - if l[1] == '3' : - n0+=1 - courbes.ITEM[n0]=ITEM() - courbes.ITEM[n0].Origine=[l[-3],l[-1],] - courbes.ITEM[n0-1].beziers_knot[0].co[0]=CP[0] - courbes.ITEM[n0-1].beziers_knot[0].co[1]=CP[1] - CP=[l2[-3], l2[-1]] - - elif l[1]=='1' and (n0 not in courbes.ITEM.keys()): - courbes.ITEM[n0]=ITEM() - courbes.ITEM[n0].Origine=[l[-3],l[-1],] - CP=[l2[-3], l2[-1]] - - B=Bez() - B.co=[ CP[0],CP[1], - l1[-3], l1[-1], - l[-3], l[-1]] - - CP=[l2[-3], l2[-1]] - - if BOUNDINGBOX['rec']==[]: - BOUNDINGBOX['rec']=[float(l2[-3]), float(l2[-1]), float(l[-3]), float(l[-1])] - B.ha=[0,0] - - """ - if len( courbes.ITEM[n0].beziers_knot)>=1: - courbes.ITEM[n0].beziers_knot[-1].co[2]=l1[-3] - courbes.ITEM[n0].beziers_knot[-1].co[3]=l1[-1] - """ - - MINMAX(B.co) - courbes.ITEM[n0].beziers_knot.append(B) - return courbes,n0 - -Actions= { "1" : mouvement_vers, - "3" : mouvement_vers } - -TAGcourbe=Actions.keys() - -def scan_FILE(nom): - global CP, courbes, SCALE, MAX, MIN, CLOSED - dir,name=split(nom) - name=name.split('.') - #print name - n0=0 - result=0 - t=filtreFICHIER(nom) - if t!="false": - if not SHARP_IMPORT: - warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" - SCALE = Blender.Draw.PupMenu(warning) - npat=0 - l=0 - while l 0: - t=create_GEOtext(courbes) - save_GEOfile(dir,name[0],t) - Open_GEOfile(dir,name[0]) - # 0.1.8 --------------------------------- - Blender.Object.Get()[-1].setName(name[0]) - # 0.1.8 --------------------------------- - - else: - pass - -#===================================================================== -#====================== GIMP Path format mouvements ========================= -#===================================================================== -#========================================================= -# une sorte de contournement qui permet d'utiliser la fonction -# et de documenter les variables Window.FileSelector -#========================================================= -def fonctionSELECT(nom): - scan_FILE(nom) - -if __name__=="__main__": - Blender.Window.FileSelector (fonctionSELECT, 'SELECT GIMP FILE') - diff --git a/release/scripts/bpymodules/paths_svg2obj.py b/release/scripts/bpymodules/paths_svg2obj.py deleted file mode 100644 index 6bab6dcbfd8..00000000000 --- a/release/scripts/bpymodules/paths_svg2obj.py +++ /dev/null @@ -1,1651 +0,0 @@ -# -*- coding: latin-1 -*- -""" -SVG 2 OBJ translater, 0.5.9o -Copyright (c) jm soler juillet/novembre 2004-april 2009, -# --------------------------------------------------------------- - released under GNU Licence - for the Blender 2.42 Python Scripts Bundle. -Ce programme est libre, vous pouvez le redistribuer et/ou -le modifier selon les termes de la Licence Publique Générale GNU -publiée par la Free Software Foundation (version 2 ou bien toute -autre version ultérieure choisie par vous). - -Ce programme est distribué car potentiellement utile, mais SANS -AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties -de commercialisation ou d'adaptation dans un but spécifique. -Reportez-vous à la Licence Publique Générale GNU pour plus de détails. - -Vous devez avoir reçu une copie de la Licence Publique Générale GNU -en même temps que ce programme ; si ce n'est pas le cas, écrivez à la -Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, -MA 02111-1307, États-Unis. - -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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# --------------------------------------------------------------- -# -#--------------------------------------------------------------------------- -# Page officielle : -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg.htm -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg_en.htm -# Communiquer les problemes et erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -#--------------------------------------------------------------------------- - ---Old Concept : translate SVG file in GEO .obj file and try to load it. - was removed for the Blender 2.4x release. - .-- Curiousity : the original matrix must be : - | - | 0.0 0.0 1.0 0.0 - | 0.0 1.0 0.0 0.0 - | 0.0 0.0 1.0 0.0 - | 0.0 0.0 0.0 1.0 - | - | and not: - | 1.0 0.0 0.0 0.0 - | 0.0 1.0 0.0 0.0 - | 0.0 0.0 1.0 0.0 - | 0.0 0.0 0.0 1.0 - | - '-- Possible bug : sometime, the new curves object's RotY value - jumps to -90.0 degrees without any reason. - ---Options : - SHARP_IMPORT = 0 - choise between "As is", "Devide by height" and "Devide by width" - SHARP_IMPORT = 1 - no choise - - - -All commands are managed: - M : absolute move to - Z : close path - L : absolute line to - C : absolute curve to - S : absolute curve to with only one handle - H : absolute horizontal line to - V : absolute vertical line to - - l : relative line to 2004/08/03 - c : relative curve to 2004/08/03 - s : relative curve to with only one handle - h : relative horizontal line to - v : relative vertical line to - - A : curve_to_a, - V : draw_line_v, - H : draw_line_h, - Z : close_z, - Q : curve_to_q, - T : curve_to_t, - a : curve_to_a, - v : draw_line_v, - h : draw_line_h, - z : close_z, - q : curve_to_q, - - transfrom for tag - transform for tag - -The circle, rectangle closed or open polygons lines are managed too. - -Changelog: - 0.1.1 : - control file without extension - 0.2.0 : - improved reading of several data of the same type - following the same command (for gimp import) - 0.2.1 : - better choice for viewboxing ( takes the viewbox if found, - instead of x,y,width and height - 0.2.2 : - read compact path data from Illustrator 10 - 0.2.3 : - read a few new relative displacements - 0.2.4 : - better hash for command followed by a lone data - (h,v) or uncommun number (a) - 0.2.5 : - correction for gimp import - 0.2.6 : - correction for illustrator 10 SVG - 0.2.7 : - correction for inskape 0.40 cvs SVG - 0.2.8 : - correction for inskape plain SVG - 0.3 : - reading of the transform properties added : - translate - 0.3.1 : - compatibility restored with gimp - 0.3.2 : - transform properties added (june, 15-16): - scale, - rotate, - matrix, - skew - - added a test on __name__ to load the script - outside from the blender menu - 0.3.3 : - matrix transform content control - 0.3.4 : - paths data reading rewritten (19/06/05) - 0.3.5 : - test on empty curve (22/06/05) - - removed overlayed points - 0.3.6 : - rewriting of the bezier point contruction to correct - a problem in the connection between L type point and - C or S type point - 0.3.7 : - code correction for bezier knot in Curveto command when - the command close a path - 0.3.8 : - code was aded to manage quadratic bezier, - Q,q command and T,t commands, as a normal blender's bezier point - - The last modications does not work with gimp 2.0 svg export . - corrected too . - 0.3.9 : - Path's A,a command for ellipse's arc . - 0.4.0 : - To speed up the function filter_DATA was removed and text - variables are changed into numeric variables - 0.4.1 : - svg, groups and shapes hierarchy added - - now transform properties are computed using a stack with all - parented groups - - removed or replaced useless functions : - - skewY, skewX transforms - - radians in rotate transform - 0.4.2 : - Added functon to translate others shapes in path - rect, line, polyline, polygon - 0.4.3 : - various corrections - text font (id property exported by Adobe Illustrator are between coma) - function to code s tag has been rewritten - 0.4.4 : - various corrections - to oblige the script to understand a line feed just after - a tag . Rarely encountered problem, but it exits in a svg file - format exported by a outliner script for mesh . - 0.4.5 : - update for CVS only, at least blender 2.38 and upper - no BezTriple module in older version - added a createCURVES function to avoid to use - the OBJ format export/import . - Perhaps problems with cyclic curves . If a closed curve - does not appear closed in blender, enter edit mode select - all knot with Akey, do a Hkey to set handle type (without - this the knot are recalculated) , and finally use the Ckey - to close the curve . - Should work ... not guaranted . - 0.4.6 : - cyclic flag ... - 0.4.7 : - Management of the svgz files . the complete python or the - gzip.py file is needed . - Little improvement of the curve drawing using the createCURVES - function - 0.4.8 : - short modif for a fantasy font case in the OOo svg format - ('viewbox' is written 'viewBox', for instance) . - Note that (at this time, 2006/05/01, 1OOo exports in svg - but does not read its own export - 0.4.9 : - skipped version : private test - 0.5.0 : - the script worked perfectly with Blender 2.41 but in Blender - 2.42, use the original svg name file + 'OOO.obj' to - write a videoscape file made blender crash under window XP when - the script loaded it . Curiously, use a more simple - name with a sole 'O' solved this problem . - - script returned errors on open path : corrected - - in b2.42, several successive imports seem to be added to - the same original curve . So now the script automaticaly - renames the last group of imported curve with the original - name file . - 0.5.1 : - without join option in the internal curve creation function - 0.5.2 : - the createCURVES() function has been cleanded . Now it works - fine but all bezier curves are joined in the same curve object . - 0.5.3 : - removed two things : - 1/ the ajustement function to increase speed . 35 % faster : - 5690 curves and 30254 points in 11 seconds . User should do - a ctrl-a on the object . - 2/ the import method menu . No reason to choose between the - old extern curve creat and the new intern curve creation - this last one is largely faster . - 0.5.4 : - translation of the functions' name + improvment in the dict lookup . - Quite 15% faster . 9.75 seconds instead of 11 to load the file test . - A test was also added to find the fill style so now the script closes - these curves even if they are not defined as closed in the strict path - commands . - The old non used functions have been completely removed . - 0.5.5 : - Modifs for architect users . - 0.5.6 : - Exec was removed from the collect_ATTRIBUTS function . - Other uses was evaluated. - 0.5.7 : - Wash down of some handle problems. - - 0.5.8 : - 2007/3/9 - Wash down of the last exec and correction of a - problem with the curve's first beztriple handle - which was not recorded at first time . - - Added some units managements - - Correction of the rotate matrix - - Correction of the skew matrix - - change in the wash_DATA function suggested by cambo - - added __slot__ in class Bez, ITEM and CURVE suggested by cambo - - remove unused properties in class ITEM and CURVE - - 0.5.9 : - 2007/3/28 - - many improvements for faster and clearer code suggested by cambo and martin. - replacement of "%s" statement by str function. - - correction of an error in the scale transform management - - correction in the management of the stack transformation that rise an error - under python 2.5 but curiously not with python 2.4 - - 0.5.9a : - 2007/3/29 - - Again a lot of minors corrections - - Backward to 0.5.8 of the function that manages float numbers exported - by the Adobe Illustrator's SVG. After a lot of tests it seems that this oldest - version is also faster too . - - correction (bad) on handle management with V and H commands. - - 0.5.9b : - 2007/3/31 - - one or two minor corrections - - now the new object curve is added in the current layer. - - short modif in the scale menu... - - 0.5.9d : - 2007/4/5 - - when a svg file containts several curves they can be imported in - separate object. - - managment of paths' name when paths are imported as separate curves. - - a menu was added to select between separate or joined curves - - management of colors - - 0.5.9e : - 2007/4/7 - - corrected a scale problem that only appears when one uses beveldepth - - in separate curve option, name is also given to the curve data - - added the list of svg's color names (147) and modified the color's method - to work with. - - 0.5.9h : - 2007/5/2 - - script was updated with the modifs by cambo - - removed all debug statements - - correction of a zero division error in the calc_arc function. - - 0.5.9f: - 2007/15/7 - - Correction de plusieurs bugs sur l'attributions des couleurs et le nommage - des courbes - - 0.5.9i : - ??/??/?? - - Patch externe réalisé sur blender.org project. - - 0.5.9j : - 08/11/2008 - 0.5.9k : - 14/01/2009 - 0.5.9l : - 31/01/2009 - 0.5.9n : - 01/02/2009 - 0.5.9o : - 04/04/2009, remove pattern if it made with path. - - -================================================================================== -==================================================================================""" -SHARP_IMPORT=0 -SCALE=1 -scale_=1 -DEBUG = 0 -DEVELOPPEMENT=0 -TESTCOLOR=0 - -LAST_ID='' -LAST_COLOR=[0.0,0.0,0.0,0.0] -SEPARATE_CURVES=0 -USE_COLORS=0 -PATTERN=0 - -SVGCOLORNAMELIST={ 'aliceblue':[240, 248, 255] ,'antiquewhite':[250, 235, 215] -,'aqua':[ 0, 255, 255], 'aquamarine':[127, 255, 212] -,'azure':[240, 255, 255], 'beige':[245, 245, 220] -,'bisque':[255, 228, 196], 'black':[ 0, 0, 0] -,'blanchedalmond':[255, 235, 205] ,'blue':[ 0, 0, 255] -,'blueviolet':[138, 43, 226],'brown':[165, 42, 42] -,'burlywood':[222, 184, 135],'cadetblue':[ 95, 158, 160] -,'chartreuse':[127, 255, 0] ,'chocolate':[210, 105, 30] -,'coral':[255, 127, 80],'cornflowerblue':[100, 149, 237] -,'cornsilk':[255, 248, 220],'crimson':[220, 20, 60] -,'cyan':[ 0, 255, 255],'darkblue':[ 0, 0, 139] -,'darkcyan':[ 0, 139, 139],'darkgoldenrod':[184, 134, 11] -,'darkgray':[169, 169, 169],'darkgreen':[ 0, 100, 0] -,'darkgrey':[169, 169, 169],'darkkhaki':[189, 183, 107] -,'darkmagenta':[139, 0, 139],'darkolivegreen':[ 85, 107, 47] -,'darkorange':[255, 140, 0],'darkorchid':[153, 50, 204] -,'darkred':[139, 0, 0],'darksalmon':[233, 150, 122] -,'darkseagreen':[143, 188, 143],'darkslateblue':[ 72, 61, 139] -,'darkslategray':[ 47, 79, 79],'darkslategrey':[ 47, 79, 79] -,'darkturquoise':[ 0, 206, 209],'darkviolet':[148, 0, 211] -,'deeppink':[255, 20, 147],'deepskyblue':[ 0, 191, 255] -,'dimgray':[105, 105, 105],'dimgrey':[105, 105, 105] -,'dodgerblue':[ 30, 144, 255],'firebrick':[178, 34, 34] -,'floralwhite':[255, 250, 240],'forestgreen':[ 34, 139, 34] -,'fuchsia':[255, 0, 255],'gainsboro':[220, 220, 220] -,'ghostwhite':[248, 248, 255],'gold':[255, 215, 0] -,'goldenrod':[218, 165, 32],'gray':[128, 128, 128] -,'grey':[128, 128, 128],'green':[ 0, 128, 0] -,'greenyellow':[173, 255, 47],'honeydew':[240, 255, 240] -,'hotpink':[255, 105, 180],'indianred':[205, 92, 92] -,'indigo':[ 75, 0, 130],'ivory':[255, 255, 240] -,'khaki':[240, 230, 140],'lavender':[230, 230, 250] -,'lavenderblush':[255, 240, 245],'lawngreen':[124, 252, 0] -,'lemonchiffon':[255, 250, 205],'lightblue':[173, 216, 230] -,'lightcoral':[240, 128, 128],'lightcyan':[224, 255, 255] -,'lightgoldenrodyellow':[250, 250, 210],'lightgray':[211, 211, 211] -,'lightgreen':[144, 238, 144],'lightgrey':[211, 211, 211] -,'lightpink':[255, 182, 193],'lightsalmon':[255, 160, 122] -,'lightseagreen':[ 32, 178, 170],'lightskyblue':[135, 206, 250] -,'lightslategray':[119, 136, 153],'lightslategrey':[119, 136, 153] -,'lightsteelblue':[176, 196, 222],'lightyellow':[255, 255, 224] -,'lime':[ 0, 255, 0],'limegreen':[ 50, 205, 50] -,'linen':[250, 240, 230],'magenta':[255, 0, 255] -,'maroon':[128, 0, 0],'mediumaquamarine':[102, 205, 170] -,'mediumblue':[ 0, 0, 205],'mediumorchid':[186, 85, 211] -,'mediumpurple':[147, 112, 219],'mediumseagreen':[ 60, 179, 113] -,'mediumslateblue':[123, 104, 238],'mediumspringgreen':[ 0, 250, 154] -,'mediumturquoise':[ 72, 209, 204],'mediumvioletred':[199, 21, 133] -,'midnightblue':[ 25, 25, 112],'mintcream':[245, 255, 250] -,'mistyrose':[255, 228, 225],'moccasin':[255, 228, 181] -,'navajowhite':[255, 222, 173],'navy':[ 0, 0, 128] -,'oldlace':[253, 245, 230],'olive':[128, 128, 0] -,'olivedrab':[107, 142, 35],'orange':[255, 165, 0] -,'orangered':[255, 69, 0],'orchid':[218, 112, 214] -,'palegoldenrod':[238, 232, 170],'palegreen':[152, 251, 152] -,'paleturquoise':[175, 238, 238],'palevioletred':[219, 112, 147] -,'papayawhip':[255, 239, 213],'peachpuff':[255, 218, 185] -,'peru':[205, 133, 63],'pink':[255, 192, 203] -,'plum':[221, 160, 221],'powderblue':[176, 224, 230] -,'purple':[128, 0, 128],'red':[255, 0, 0] -,'rosybrown':[188, 143, 143],'royalblue':[ 65, 105, 225] -,'saddlebrown':[139, 69, 19],'salmon':[250, 128, 114] -,'sandybrown':[244, 164, 96],'seagreen':[ 46, 139, 87] -,'seashell':[255, 245, 238],'sienna':[160, 82, 45] -,'silver':[192, 192, 192],'skyblue':[135, 206, 235] -,'slateblue':[106, 90, 205],'slategray':[112, 128, 144] -,'slategrey':[112, 128, 144],'snow':[255, 250, 250] -,'springgreen':[ 0, 255, 127],'steelblue':[ 70, 130, 180] -,'tan':[210, 180, 140],'teal':[ 0, 128, 128] -,'thistle':[216, 191, 216],'tomato':[255, 99, 71] -,'turquoise':[ 64, 224, 208],'violet':[238, 130, 238] -,'wheat':[245, 222, 179],'white':[255, 255, 255] -,'whitesmoke':[245, 245, 245],'yellow':[255, 255, 0] -,'yellowgreen':[154, 205, 50]} - - -import sys -from math import cos,sin,tan, atan2, pi, ceil -PI=pi -import Blender -from Blender import Mathutils - -try: - import nt - os=nt - os.sep='\\' - -except: - import posix - os=posix - os.sep='/' - -def isdir(path): - try: - st = os.stat(path) - return 1 - except: - return 0 - -def split(pathname): - if os.sep in pathname: - k0=pathname.split(os.sep) - else: - if os.sep=='/': - k0=pathname.split('\\') - else: - k0=pathname.split('/') - directory=pathname.replace(k0[len(k0)-1],'') - Name=k0[len(k0)-1] - return directory, Name - -def join(l0,l1): - return l0+os.sep+l1 - -os.isdir=isdir -os.split=split -os.join=join - -def filterFILE(nom): - """ - Function filterFILE - - in : string nom , filename - out : string t , if correct filecontaint - - read the file's content and try to see if the format - is correct . - - Lit le contenu du fichier et en fait une pre-analyse - pour savoir s'il merite d'etre traite . - """ - # ---------- - # 0.4.7 - # ---------- - if nom.upper().endswith('.SVGZ'): - try : - import gzip - tz=gzip.GzipFile(nom) - t=tz.read() - except: - name = "ERROR: fail to import gzip module or gzip error ... " - result = Blender.Draw.PupMenu(name) - return "false" - else: - f=open(nom,'rU') - t=f.read() - f.close() - # ---------- - # 0.4.7 : end - # ---------- - # ----------------- - # pre-format ... - # ----------------- - # -------------------- - # 0.4.4 '\r','' --> '\r',' ' - # '\n','' --> '\n',' ' - #-------------------- - t=t.replace('\r',' ') - t=t.replace('\n',' ') - t=t.replace('svg:','') - #-------------------- - # may be needed in some import case when the - # file is saved from a mozilla display - #-------------------- - t=t.replace(chr(0),'') - if not '= 0.0\ - and abs(f1[5])-abs(f2[5])< EPSILON and abs(f1[5])-abs(f2[5])>= 0.0 : - return 1 - else: - return 0 - - -#-------------------- -# 0.4.5 : for blender cvs 2.38 .... -#-------------------- -def createCURVES(curves, name): - """ - internal curves creation - """ - global SCALE, B, BOUNDINGBOX,scale_, SEPARATE_CURVES - global USE_COLORS - from Blender import Curve, Object, Scene, BezTriple - HANDLE={'C':BezTriple.HandleTypes.FREE,'L':BezTriple.HandleTypes.VECT} - r=BOUNDINGBOX['rec'] - - if scale_==3: - SCALE=1.0 - elif scale_==1: - SCALE=r[2]-r[0] - elif scale_==2: - SCALE=r[3]-r[1] - - scene = Scene.GetCurrent() - scene.objects.selected = [] - - if not SEPARATE_CURVES: - c = Curve.New() - c.setResolu(24) - - MATNAME=[] - nloc=0.0 - - def new_MATERIAL(val): - # ----------------------- - # have to create a material - #------------------------ - if val.matname and val.matname in MATNAME: - mat = Blender.Material.Get(val.matname) - elif val.matname: - mat = Blender.Material.New(val.matname) - mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] - else: - mat = Blender.Material.New(val.id) - mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] - return [mat] - - for I,val in curves.ITEM.iteritems(): - if SEPARATE_CURVES: - c = Curve.New() - c.setResolu(24) - if USE_COLORS and val.mat: - c.materials=new_MATERIAL(val) - - bzn=0 - if val.beziers_knot[-1].tag in ['L','l','V','v','H','h'] and\ - test_samelocations(val.beziers_knot[-1].co,val.beziers_knot[0].co): - del val.beziers_knot[-1] - - for k2 in xrange(0,len(val.beziers_knot)): - bz= [co for co in val.beziers_knot[k2].co] - if bzn==0: - cp1 = bz[4]/SCALE, bz[5]/-SCALE,0.0, bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0, - beztriple1 = BezTriple.New(cp1) - bez = c.appendNurb(beztriple1) - bez[0].handleTypes=(HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) - bzn = 1 - else: - cp2 = bz[4]/SCALE,bz[5]/-SCALE,0.0 , bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0 - beztriple2 = BezTriple.New(cp2) - beztriple2.handleTypes= (HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) - bez.append(beztriple2) - - if val.flagUV[0]==1 or val.fill==1: - #-------------------- - # 0.4.6 : cyclic flag ... - #-------------------- - bez.flagU += 1 - - if SEPARATE_CURVES: - ob = scene.objects.new(c,val.id) - scene.objects.active = ob - ob.setLocation(0.0,0.0,nloc) - nloc+=0.0001 - c.update() - - if not SEPARATE_CURVES: - ob = scene.objects.new(c,name) - scene.objects.active = ob - c.update() - -#===================================================================== -#===== SVG format : DEBUT ========================= -#===================================================================== -#-------------------- -# 0.5.8, needed with the new -# tranform evaluation -#-------------------- -pxUNIT={'pt':1.25, - 'pc':15.0, - 'mm':3.543307, - 'cm':35.43307, - 'in':90.0, - 'em':1.0, # should be taken from font size - # but not currently managed - 'ex':1.0, # should be taken from font size - # but not currently managed - '%':1.0, - } - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def rect(prp): - """ - build rectangle paths - """ - D=[] - if 'x' not in prp: x=0.0 - else : x=float(prp['x']) - if 'y' not in prp: y=0.0 - else : y=float(prp['y']) - #-------------------- - # 0.5.8 - #-------------------- - try: - height=float(prp['height']) - except: - pxUNIT['%']=(BOUNDINGBOX['rec'][3]-BOUNDINGBOX['rec'][1])/100.0 - for key in pxUNIT:#.keys(): - if key in prp['height']: - height=float(prp['height'].replace(key,''))*pxUNIT[key] - try: - width=float(prp['width']) - except: - pxUNIT['%']=(BOUNDINGBOX['rec'][2]-BOUNDINGBOX['rec'][0])/100.0 - for key in pxUNIT:#.keys(): - if key in prp['width']: - width=float(prp['width'].replace(key,''))*pxUNIT[key] - #-------------------- - # 0.5.8, end - #-------------------- - """ - normal rect - x,y - h1 - *----------* - | | - | | - | | - *----------* v1 - h2 - """ - if 'rx' not in prp or 'rx' not in prp: - D=['M',str(x),str(y),'h',str(width),'v',str(height),'h',str(-width),'z'] - else : - rx=float(prp['rx']) - if 'ry' not in prp : - ry=float(prp['rx']) - else : ry=float(prp['ry']) - if 'rx' in prp and prp['rx']<0.0: rx*=-1 - if 'ry' in prp and prp['ry']<0.0: ry*=-1 - """ - rounded corner - - x,y M h1 - ---*----------* - / \ - / \ - v2 * * c1 - | | - | | - | | - c3 * * v2 - \ / - \ / - *----------* - h2 c2 - """ - - D=['M',str(x+rx),str(y), - 'h',str(width-2*rx), - 'c',str(rx),'0.0',str(rx),str(ry),str(rx),str(ry), - 'v',str(height-ry), - 'c','0.0',str(ry),str(-rx),str(ry),str(-rx),str(ry), - 'h',str(-width+2*rx), - 'c',str(-rx),'0.0',str(-rx),str(-ry),str(-rx),str(-ry), - 'v',str(-height+ry), - 'c','0.0','0.0','0.0',str(-ry),str(rx),str(-ry), - 'z'] - - return D - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def circle(prp): - if 'cx' not in prp: cx=0.0 - else : cx =float(prp['cx']) - if 'cy' not in prp: cy=0.0 - else : cy =float(prp['cy']) - r = float(prp['r']) - D=['M',str(cx),str(cy+r), - 'C',str(cx-r), str(cy+r*0.552),str(cx-0.552*r),str(cy+r), str(cx),str(cy+r), - 'C',str(cx+r*0.552), str(cy+r), str(cx+r), str(cy+r*0.552), str(cx+r),str(cy), - 'C',str(cx+r), str(cy-r*0.552),str(cx+r*0.552),str(cy-r),str(cx), str(cy-r), - 'C',str(cx-r*0.552), str(cy-r), str(cx-r), str(cy-r*0.552),str(cx-r),str(cy), - 'Z'] - return D - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def ellipse(prp): - if 'cx' not in prp: cx=0.0 - else : cx =float(prp['cx']) - if 'cy' not in prp: cy=0.0 - else : cy =float(prp['cy']) - ry = float(prp['rx']) - rx = float(prp['ry']) - D=['M',str(cx),str(cy+rx), - 'C',str(cx-ry),str(cy+rx*0.552),str(cx-0.552*ry),str(cy+rx),str(cx),str(cy+rx), - 'C',str(cx+ry*0.552),str(cy+rx),str(cx+ry),str(cy+rx*0.552),str(cx+ry),str(cy), - 'C',str(cx+ry),str(cy-rx*0.552),str(cx+ry*0.552),str(cy-rx),str(cx),str(cy-rx), - 'C',str(cx-ry*0.552),str(cy-rx),str(cx-ry),str(cy-rx*0.552),str(cx-ry),str(cy), - 'z'] - return D - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def line(prp): - D=['M',str(prp['x1']),str(prp['y1']), - 'L',str(prp['x2']),str(prp['y2'])] - return D - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def polyline(prp): - if 'points' in prp: - points=prp['points'].split(' ') - np=0 - for p in points: - if p!='': - p=p.split(',') - if np==0: - D=['M',str(p[0]),str(p[1])] - np+=1 - else: - D.append('L'); D.append(str(p[0])); D.append(str(p[1])) - return D - else: - return [] - -#-------------------- -# 0.4.2 -# 0.5.8, to remove exec -#-------------------- -def polygon(prp): - D=polyline(prp) - if D!=[]: - D.append('Z') - return D - - -#-------------------- -# 0.5.8, to remove exec -#-------------------- -OTHERSSHAPES={ 'rect' : rect, - 'line' : line, - 'polyline': polyline, - 'polygon' : polygon, - 'circle' : circle, - 'ellipse' : ellipse} - -#-------------------- -# 0.3.9 -#-------------------- -def calc_arc (cpx,cpy, rx, ry, ang, fa , fs , x, y) : - """ - Calc arc paths - """ - rx=abs(rx) - ry=abs(ry) - px=abs((cos(ang)*(cpx-x)+sin(ang)*(cpy-y))*0.5)**2.0 - py=abs((cos(ang)*(cpy-y)-sin(ang)*(cpx-x))*0.5)**2.0 - rpx=rpy=0.0 - if abs(rx)>0.0: rpx=px/(rx**2.0) - if abs(ry)>0.0: rpy=py/(ry**2.0) - pl=rpx+rpy - if pl>1.0: - pl=pl**0.5;rx*=pl;ry*=pl - carx=sarx=cary=sary=0.0 - if abs(rx)>0.0: - carx=cos(ang)/rx;sarx=sin(ang)/rx - if abs(ry)>0.0: - cary=cos(ang)/ry;sary=sin(ang)/ry - x0=(carx)*cpx+(sarx)*cpy - y0=(-sary)*cpx+(cary)*cpy - x1=(carx)*x+(sarx)*y - y1=(-sary)*x+(cary)*y - d=(x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) - if abs(d)>0.0 :sq=1.0/d-0.25 - else: sq=-0.25 - if sq<0.0 :sq=0.0 - sf=sq**0.5 - if fs==fa :sf=-sf - xc=0.5*(x0+x1)-sf*(y1-y0) - yc=0.5*(y0+y1)+sf*(x1-x0) - ang_0=atan2(y0-yc,x0-xc) - ang_1=atan2(y1-yc,x1-xc) - ang_arc=ang_1-ang_0; - if (ang_arc < 0.0 and fs==1) : - ang_arc += 2.0 * PI - elif (ang_arc>0.0 and fs==0) : - ang_arc-=2.0*PI - n_segs=int(ceil(abs(ang_arc*2.0/(PI*0.5+0.001)))) - P=[] - for i in xrange(n_segs): - ang0=ang_0+i*ang_arc/n_segs - ang1=ang_0+(i+1)*ang_arc/n_segs - ang_demi=0.25*(ang1-ang0) - t=2.66666*sin(ang_demi)*sin(ang_demi)/sin(ang_demi*2.0) - x1=xc+cos(ang0)-t*sin(ang0) - y1=yc+sin(ang0)+t*cos(ang0) - x2=xc+cos(ang1) - y2=yc+sin(ang1) - x3=x2+t*sin(ang1) - y3=y2-t*cos(ang1) - P.append([[(cos(ang)*rx)*x1+(-sin(ang)*ry)*y1, - (sin(ang)*rx)*x1+(cos(ang)*ry)*y1], - [(cos(ang)*rx)*x3+(-sin(ang)*ry)*y3, - (sin(ang)*rx)*x3+(cos(ang)*ry)*y3], - [(cos(ang)*rx)*x2+(-sin(ang)*ry)*y2, - (sin(ang)*rx)*x2+(cos(ang)*ry)*y2]]) - return P - -#-------------------- -# 0.3.9 -#-------------------- -def curve_to_a(curves, c,D,n0,CP): #A,a - global SCALE - l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), - int(D[c[1]+4]),int(D[c[1]+5]),float(D[c[1]+6]),float(D[c[1]+7])] - if c[0]=='a': - l[5]=l[5] + CP[0] - l[6]=l[6] + CP[1] - B=Bez() - B.co=[ CP[0], CP[1], CP[0], CP[1], CP[0], CP[1] ] - B.ha=['C','C'] - B.tag=c[0] - POINTS= calc_arc (CP[0],CP[1], - l[0], l[1], l[2]*(PI / 180.0), - l[3], l[4], - l[5], l[6] ) - for p in POINTS : - B=Bez() - B.co=[ p[2][0],p[2][1], p[0][0],p[0][1], p[1][0],p[1][1]] - B.ha=['C','C'] - B.tag='C' - BP=curves.ITEM[n0].beziers_knot[-1] - BP.co[2]=B.co[2] - BP.co[3]=B.co[3] - curves.ITEM[n0].beziers_knot.append(B) - BP=curves.ITEM[n0].beziers_knot[-1] - BP.co[2]=BP.co[0] - BP.co[3]=BP.co[1] - CP=[l[5], l[6]] - #---------- 059m------------ - if len(D)>c[1]+7 and D[c[1]+8] not in TAGcourbe : - c[1]+=7 - curves,n0,CP=curve_to_a(curves, c, D, n0,CP) - #---------- 059m------------ - return curves,n0,CP - -def move_to(curves, c, D, n0,CP, proprietes): - global DEBUG,TAGcourbe, LAST_ID - global USE_COLORS - - l=[float(D[c[1]+1]),float(D[c[1]+2])] - - if c[0]=='m': - l=[l[0]+CP[0], - l[1] + CP[1]] - - if n0 in curves.ITEM: - n0+=1 - CP=[l[0],l[1]] - curves.ITEM[n0]=ITEM() - - if 'id' in proprietes: - curves.ITEM[n0].id=proprietes['id'] - else: - curves.ITEM[n0].id=LAST_ID - - proprietes['n'].append(n0) - if USE_COLORS: - pr= proprietes.get('fill') # None or the property - if pr != None: - if '#' in pr: - i=1 - curves.ITEM[n0].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] - curves.ITEM[n0].mat=1 - elif pr in SVGCOLORNAMELIST: - Courbe[n].color=SVGCOLORNAMELIST[pr] - Courbe[n].mat=1 - - B=Bez() - B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] - B.ha=['L','C'] - B.tag=c[0] - curves.ITEM[n0].beziers_knot.append(B) - return curves,n0,CP - -def close_z(curves, c,D,n0,CP): #Z,z - curves.ITEM[n0].flagUV[0]=1 - if len(curves.ITEM[n0].beziers_knot)>1: - BP=curves.ITEM[n0].beziers_knot[-1] - BP0=curves.ITEM[n0].beziers_knot[0] - if BP.tag in ['c','C','s','S',]: - BP.co[2]=BP0.co[2] #4-5 point prec - BP.co[3]=BP0.co[3] - del curves.ITEM[n0].beziers_knot[0] - else: - del curves.ITEM[n0] - n0-=1 - return curves,n0,CP - -def curve_to_q(curves, c,D,n0,CP): #Q,q - l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]),float(D[c[1]+4])] - if c[0]=='q': - l=[l[0]+CP[0], l[1]+CP[1], l[2]+CP[0], l[3]+CP[1]] - B=Bez() - B.co=[l[2], l[3], l[2], l[3], l[0], l[1]] #plus toucher au 2-3 - B.ha=['C','C'] - B.tag=c[0] - BP=curves.ITEM[n0].beziers_knot[-1] - BP.co[2]=BP.co[0] - BP.co[3]=BP.co[1] - curves.ITEM[n0].beziers_knot.append(B) - CP=[l[2],l[3]] - #if DEBUG==1: pass - if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : - c[1]+=4 - curves,n0,CP=curve_to_q(curves, c, D, n0,CP) - return curves,n0,CP - -def curve_to_t(curves, c,D,n0,CP): #T,t - l=[float(D[c[1]+1]),float(D[c[1]+2])] - if c[0]=='t': - l=[l[0]+CP[0], l[1]+CP[1]] - B=Bez() - B.co=[l[0], l[1], l[0], l[1], l[0], l[1]] #plus toucher au 2-3 - B.ha=['C','C'] - B.tag=c[0] - BP=curves.ITEM[n0].beziers_knot[-1] - l0=build_SYMETRIC([BP.co[0],BP.co[1],BP.co[4],BP.co[5]]) - if BP.tag in ['q','Q','t','T','m','M']: - BP.co[2]=l0[2] - BP.co[3]=l0[3] - curves.ITEM[n0].beziers_knot.append(B) - CP=[l[0],l[1]] - if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : - c[1]+=4 - curves,n0,CP=curve_to_t(curves, c, D, n0,CP) - return curves,n0,CP - -#-------------------- -# 0.4.3 : rewritten -#-------------------- -def build_SYMETRIC(l): - X=l[2]-(l[0]-l[2]) - Y=l[3]-(l[1]-l[3]) - return X,Y - -def curve_to_s(curves, c,D,n0,CP): #S,s - l=[float(D[c[1]+1]), - float(D[c[1]+2]), - float(D[c[1]+3]), - float(D[c[1]+4])] - if c[0]=='s': - l=[l[0]+CP[0], l[1]+CP[1], - l[2]+CP[0], l[3]+CP[1]] - B=Bez() - B.co=[l[2],l[3],l[2],l[3],l[0],l[1]] #plus toucher au 2-3 - B.ha=['C','C'] - B.tag=c[0] - BP=curves.ITEM[n0].beziers_knot[-1] - #-------------------- - # 0.4.3 - #-------------------- - BP.co[2],BP.co[3]=build_SYMETRIC([BP.co[4],BP.co[5],BP.co[0],BP.co[1]]) - curves.ITEM[n0].beziers_knot.append(B) - #-------------------- - # 0.4.3 - #-------------------- - CP=[l[2],l[3]] - if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : - c[1]+=4 - curves,n0,CP=curve_to_c(curves, c, D, n0,CP) - return curves,n0,CP - -def curve_to_c(curves, c, D, n0,CP): #c,C - l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), - float(D[c[1]+4]),float(D[c[1]+5]),float(D[c[1]+6])] - if c[0]=='c': - l=[l[0]+CP[0], - l[1]+CP[1], - l[2]+CP[0], - l[3]+CP[1], - l[4]+CP[0], - l[5]+CP[1]] - B=Bez() - B.co=[l[4], - l[5], - l[4], - l[5], - l[2], - l[3]] #plus toucher au 2-3 - - - B.ha=['C','C'] - B.tag=c[0] - BP=curves.ITEM[n0].beziers_knot[-1] - BP.co[2]=l[0] - BP.co[3]=l[1] - BP.ha[1]='C' - curves.ITEM[n0].beziers_knot.append(B) - CP=[l[4],l[5]] - if len(D)>c[1]+7 and D[c[1]+7] not in TAGcourbe : - c[1]+=6 - curves,n0,CP=curve_to_c(curves, c, D, n0,CP) - return curves,n0,CP - -def draw_line_l(curves, c, D, n0,CP): #L,l - - l=[float(D[c[1]+1]),float(D[c[1]+2])] - if c[0]=='l': - l=[l[0]+CP[0], - l[1]+CP[1]] - B=Bez() - B.co=[l[0],l[1], - l[0],l[1], - l[0],l[1]] - - B.ha=['L','L'] - B.tag=c[0] - BP=curves.ITEM[n0].beziers_knot[-1] - BP.ha[1]='L' - - curves.ITEM[n0].beziers_knot.append(B) - CP=[B.co[4],B.co[5]] - - if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : - c[1]+=2 - curves,n0,CP=draw_line_l(curves, c, D, n0,CP) #L - - return curves,n0,CP - -def draw_line_h(curves, c,D,n0,CP): #H,h - if c[0]=='h': - l=[float(D[c[1]+1])+float(CP[0]),CP[1]] - else: - l=[float(D[c[1]+1]),CP[1]] - B=Bez() - B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] - B.ha=['L','L'] - B.tag=c[0] - #BP=curves.ITEM[n0].beziers_knot[-1] - #BP.ha[0]='L' - curves.ITEM[n0].beziers_knot.append(B) - CP=[l[0],l[1]] - return curves,n0,CP - -def draw_line_v(curves, c,D,n0,CP): #V, v - if c[0]=='v': - l=[CP[0], float(D[c[1]+1])+CP[1]] - else: - l=[CP[0], float(D[c[1]+1])] - - B=Bez() - B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] - B.ha=['L','L'] - B.tag=c[0] - #BP=curves.ITEM[n0].beziers_knot[-1] - #BP.ha[0]='L' - curves.ITEM[n0].beziers_knot.append(B) - CP=[l[0],l[1]] - return curves,n0,CP - -Actions= { "C" : curve_to_c, - "A" : curve_to_a, - "S" : curve_to_s, - "M" : move_to, - "V" : draw_line_v, - "L" : draw_line_l, - "H" : draw_line_h, - "Z" : close_z, - "Q" : curve_to_q, - "T" : curve_to_t, - - "c" : curve_to_c, - "a" : curve_to_a, - "s" : curve_to_s, - "m" : move_to, - "v" : draw_line_v, - "l" : draw_line_l, - "h" : draw_line_h, - "z" : close_z, - "q" : curve_to_q, - "T" : curve_to_t -} - -TAGcourbe=Actions.keys() -TAGtransform=['M','L','C','S','H','V','T','Q'] -tagTRANSFORM=0 - -def wash_DATA(ndata): - if ndata: - ndata = ndata.strip() - - if ndata[0]==',':ndata=ndata[1:] - if ndata[-1]==',':ndata=ndata[:-1] - - #-------------------- - # 0.4.0 : 'e' - #-------------------- - ni=0 - i = ndata.find('-',ni) - if i != -1: - while i>-1 : - i = ndata.find('-',ni) - # 059l ------ - if i>0 : - if ndata[i-1] not in [' ',',','e']: - ndata=ndata[:i]+','+ndata[i:] - ni=i+2 - else: - ni=i+1 - elif i>-1: - ni=1 - # 059l ------ - - ndata=ndata.replace(',,',',') - ndata=ndata.replace(' ',',') - ndata=ndata.split(',') - ndata=[i for i in ndata if i] #059a - - return ndata - -#-------------------- -# 0.3.4 : - read data rewrittten -#-------------------- -def list_DATA(DATA): - """ - This function translate a text in a list of - correct commandswith the right number of waited - values for each of them . For example : - d="'M0,14.0 z" becomes ['M','0.0','14.0','z'] - """ - # ---------------------------------------- - # borner les differents segments qui devront etre - # traites - # pour cela construire une liste avec chaque - # position de chaque emplacement tag de type - # commande path... - # ---------------------------------------- - tagplace=[] - for d in Actions: - b1=0 - while True: - i = DATA.find(d,b1) - if i==-1: break - tagplace.append(i) - b1=i+1 - #------------------------------------------ - # cette liste doit etre traites dans l'ordre - # d'apparition des tags - #------------------------------------------ - tagplace.sort() - - tpn=range(len(tagplace)) - - - #-------------------- - # 0.3.5 :: short data, only one tag - #-------------------- - if len(tagplace)-1>0: - DATA2=[] - for t in tpn[:-1]: - DATA2.append(DATA[tagplace[t]:tagplace[t]+1]) - ndata=DATA[tagplace[t]+1:tagplace[t+1]] - - if DATA2[-1] not in ['z','Z'] : - ndata=wash_DATA(ndata) - DATA2.extend(ndata) - - DATA2.append(DATA[tagplace[t+1]:tagplace[t+1]+1]) - - if DATA2[-1] not in ['z','Z'] and len(DATA)-1>=tagplace[t+1]+1: - ndata=DATA[tagplace[t+1]+1:] - ndata=wash_DATA(ndata) - DATA2.extend(ndata) #059a - - else: - #-------------------- - # 0.3.5 : short data,only one tag - #-------------------- - DATA2=[] - DATA2.append(DATA[tagplace[0]:tagplace[0]+1]) - ndata=DATA[tagplace[0]+1:] - ndata=wash_DATA(ndata) - DATA2.extend(ndata) - return DATA2 - -#---------------------------------------------- -# 0.3 -# 0.5.8, to remove exec -#---------------------------------------------- -def translate(t): - tx=t[0] - ty=t[1] - return [1, 0, tx], [0, 1, ty],[0,0,1] - -#---------------------------------------------- -# 0.3.2 -# 0.5.8, to remove exec -#---------------------------------------------- -def scale(s): - sx=s[0] - if len(s)>1: sy=s[1] - else: sy=sx - return [sx, 0, 0], [0, sy, 0],[0,0,1] - -#---------------------------------------------- -# 0.4.1 : transslate a in radians -# 0.5.8, to remove exec -#---------------------------------------------- -def rotate(t): - a=t[0] - return [cos(a*3.1416/180.0), -sin(a*3.1416/180.0), 0], [sin(a*3.1416/180.0), cos(a*3.1416/180.0),0],[0,0,1] - -#---------------------------------------------- -# 0.3.2 -# 0.5.8, to remove exec -#---------------------------------------------- -def skewx(t): - a=t[0] - return [1, tan(a*3.1416/180.0), 0], [0, 1, 0],[0,0,1] - -#---------------------------------------------- -# 0.4.1 -# 0.5.8, to remove exec -#---------------------------------------------- -def skewy(t): - a=t[0] - return [1, 0, 0], [tan(a*3.1416/180.0), 1 , 0],[0,0,1] - -#---------------------------------------------- -# 0.3.2 -# 0.5.8, to remove exec -#---------------------------------------------- -def matrix(t): - a,b,c,d,e,f=t - return [a,c,e],[b,d,f],[0,0,1] - -#-------------------- -# 0.5.8, to remove exec -#-------------------- -matrixTRANSFORM={ 'translate':translate, - 'scale':scale, - 'rotate':rotate, - 'skewx':skewx, - 'skewy':skewy, - 'matrix':matrix - } - -#---------------------------------------------- -# 0.4.2 : rewritten -# 0.5.8 : to remove exec uses. -#---------------------------------------------- -def control_CONTAINT(txt): - """ - the transforms' descriptions can be sole or several - and separators might be forgotten - """ - t0=0 - tlist=[] - while txt.count(')',t0)>0: - t1=txt.find(')',t0) - nt0=txt[t0:t1+1] - t2=nt0[nt0.find('(')+1:-1] - val=nt0[:nt0.find('(')] - - while t2.find(' ')!=-1: - t2=t2.replace(' ',' ') - while t2.find(', ')!=-1: #059l - t2=t2.replace(', ',',') #059l - - t2=t2.replace(' ',',') - t2=[float(t) for t in t2.split(',')] - - if val=='rotate' : - t3=t2 - if len(t3)==3: - tlist.append(['translate',[t3[1],t3[2]]]) - tlist.append(['rotate',[t3[0]/180.0*3.1416]]) - tlist.append(['translate',[-t3[1],-t3[2]]]) - else: - tlist.append(['rotate',[t3[0]]]) - else: - tlist.append([val,t2]) - t0=t1+1 - return tlist - - -def curve_FILL(Courbe,proprietes): - global USE_COLORS - for n in proprietes['n']: - pr = proprietes['style'] - if n in Courbe and 'fill:' in pr: - if not 'fill:none' in pr: - Courbe[n].fill=1 - if USE_COLORS: - i= pr.find('fill:#') - if i != -1: - i= i+6 - Courbe[n].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] - Courbe[n].mat=1 - elif ';fill-opacity' in pr: - if pr.find('fill:url')==-1: - i= pr.find('fill:')+5 - i2= pr.find(';',i) - COLORNAME= pr[i:i2] - Courbe[n].color=SVGCOLORNAMELIST[COLORNAME] - Courbe[n].mat=1 - elif 'color:' in pr: - i= pr.find('color:')+6 - i2= pr.find(';',i) - COLORNAME= pr[i:i2] - Courbe[n].color=SVGCOLORNAMELIST[COLORNAME] - Courbe[n].mat=1 - else : - COLORNAME= 'white' - Courbe[n].color=SVGCOLORNAMELIST[COLORNAME] - Courbe[n].mat=1 - -#---------------------------------------------- -# 0.4.1 : apply transform stack -#---------------------------------------------- -def curve_TRANSFORM(Courbe,proprietes): - # 1/ unpack the STACK - # create a matrix for each transform - ST=[] - for st in proprietes['stack'] : - if st and type(st)==list: - for t in st: - code = control_CONTAINT(t) - a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) - T=Mathutils.Matrix(a,b,c) - ST.append(T) - elif st : - code = control_CONTAINT(st) - a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) - T=Mathutils.Matrix(a,b,c) - ST.append(T) - if 'transform' in proprietes: - for trans in control_CONTAINT(proprietes['transform']): - #-------------------- - # 0.5.8, to remove exec - #-------------------- - a,b,c=matrixTRANSFORM[trans[0].strip()](trans[1][:]) #059 - T=Mathutils.Matrix(a,b,c) - ST.append(T) - ST.reverse() - for n in proprietes['n']: - if n in Courbe: - for bez0 in Courbe[n].beziers_knot: - bez=bez0.co - for b in [0,2,4]: - for t in ST: - v=t * Mathutils.Vector([bez[b],bez[b+1],1.0]) #059a - bez[b]=v[0] - bez[b+1]=v[1] - -def filter(d): - for nn in d: - if nn not in '0123456789.': #059a - d=d.replace(nn,"") - return d - -def get_BOUNDBOX(BOUNDINGBOX,SVG): - if 'viewbox' not in SVG: - h=float(filter(SVG['height'])) - - w=float(filter(SVG['width'])) - BOUNDINGBOX['rec']=[0.0,0.0,w,h] - r=BOUNDINGBOX['rec'] - BOUNDINGBOX['coef']=w/h - else: - viewbox=SVG['viewbox'].split() - BOUNDINGBOX['rec']=[float(viewbox[0]),float(viewbox[1]),float(viewbox[2]),float(viewbox[3])] - r=BOUNDINGBOX['rec'] - BOUNDINGBOX['coef']=(r[2]-r[0])/(r[3]-r[1]) - return BOUNDINGBOX - -#---------------------------------------------- -# 0.4.1 : attributs ex : 'id=', 'transform=', 'd=' ... -#---------------------------------------------- -def collect_ATTRIBUTS(data): - #---------------------------------------------- - # 0.4.8 : short modif for a fantasy font case - # in the OOo svg format ('viewbox' is - # written 'viewBox', for instance) - #---------------------------------------------- - data=data.replace(' ',' ').lower() - ELEM={'TYPE':data[1:data.find(' ')]} - t1=len(data) - t2=0 - ct=data.count('="') - while ct>0: - t0=data.find('="',t2) - t2=data.find(' ',t2)+1 - id=data[t2:t0] - t2=data.find('"',t0+2) - if id!='d': - ELEM[id]=data[t0+2:t2].replace('\\','/') - else: - ELEM[id]=[] - ELEM[id].append(t0+2) - ELEM[id].append(t2) - ct=data.count('="',t2) - return ELEM - -# -------------------------------------------- -# 0.4.1 : to avoid to use sax and ths xml -# tools of the complete python -# -------------------------------------------- -def build_HIERARCHY(t): - global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM - global LAST_ID, PATTERN - TRANSFORM=0 - t=t.replace('\t',' ') - while t.find(' ')!=-1: t=t.replace(' ',' ') - n0=0 - t0=t1=0 - #baliste=[] - balisetype=['?','?','/','/','!','!'] - BALISES=['D', #DECL_TEXTE', - 'D', #DECL_TEXTE', - 'F', #FERMANTE', - 'E', #ELEM_VIDE', - 'd', #DOC', - 'R', #REMARQUES', - 'C', #CONTENU', - 'O' #OUVRANTE' - ] - STACK=[] - while t1-1: - t0=t.find('<',t0) - t1=t.find('>',t0) - ouvrante=0 - #-------------------- - # 0.4.4 , add 'else:' and 'break' to the 'if' statement - #-------------------- - if t0>-1 and t1>-1: - if t[t0+1] in balisetype: - b=balisetype.index(t[t0+1]) - - if t[t0+2]=='-': - b=balisetype.index(t[t0+1])+1 - - balise=BALISES[b] - - if b==2: - parent=STACK.pop(-1) - if parent!=None and TRANSFORM>0: - TRANSFORM-=1 - - elif t[t1-1] in balisetype: - balise=BALISES[balisetype.index(t[t1-1])+1] - - else: - t2=t.find(' ',t0) - if t2>t1: t2=t1 - ouvrante=1 - NOM=t[t0+1:t2] - - - if '-1: - balise=BALISES[-1] - if NOM=='pattern' and not PATTERN: - t1=t.find('',t0)+len('') - balise=BALISES[-3] - else: - balise=BALISES[-2] - - if balise=='E' or balise=='O': - - proprietes=collect_ATTRIBUTS(t[t0:t1+ouvrante]) - - if 'id' in proprietes: - LAST_ID=proprietes['id'] - - if balise=='O' and 'transform' in proprietes: - STACK.append(proprietes['transform']) - TRANSFORM+=1 - elif balise=='O' : - STACK.append(None) - - proprietes['stack']=STACK[:] - D=[] - - if proprietes['TYPE'] in ['path'] and (proprietes['d'][1]-proprietes['d'][0]>1): - D=list_DATA(t[proprietes['d'][0]+t0:proprietes['d'][1]+t0]) - - elif proprietes['TYPE'] in OTHERSSHAPES: - #-------------------- - # 0.5.8, to remove exec - #-------------------- - D=OTHERSSHAPES[proprietes['TYPE']](proprietes) - - #elif proprietes['TYPE'] in ['pattern']: - # print 'pattern' - # D='' - - CP=[0.0,0.0] - if len(D)>0: - cursor=0 - proprietes['n']=[] - for cell in D: - - if len(cell)>=1 and cell[0] in TAGcourbe: - #-------------------- - # 0.5.8, to remove exec - #-------------------- - if cell[0] in ['m','M']: - curves,n0,CP=Actions[cell](curves, [cell,cursor], D, n0,CP,proprietes) - else: - curves,n0,CP=Actions[cell](curves, [cell,cursor], D, n0,CP) - - cursor+=1 - if TRANSFORM>0 or 'transform' in proprietes : - curve_TRANSFORM(curves.ITEM,proprietes) - - if 'style' in proprietes : - curve_FILL(curves.ITEM,proprietes) - - - elif proprietes['TYPE'] == 'svg': - BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,proprietes) - else: - #-------------------- - # 0.4.4 - #-------------------- - break - t1+=1 - t0=t1 - -def scan_FILE(nom): - global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM - global SEPARATE_CURVES, USE_COLORS, PATTERN - - dir,name=split(nom) - name=name.split('.') - result=0 - #Choise=1 - t1=Blender.sys.time() - t=filterFILE(nom) - if t!='false': - Blender.Window.EditMode(0) - if not SHARP_IMPORT: - togH = Blender.Draw.Create(1) - togW = Blender.Draw.Create(0) - togAS = Blender.Draw.Create(0) - togSP = Blender.Draw.Create(0) - togCOL = Blender.Draw.Create(0) - Pattern= Blender.Draw.Create(0) - block=[\ - ("Clamp Width 1", togW, "Rescale the import with a Width of one unit"),\ - ("Clamp Height 1", togH, "Rescale the import with a Heightof one unit"),\ - ("No Rescaling", togAS, "No rescaling, the result can be very large"),\ - ("Separate Curves", togSP, "Create an object for each curve, Slower. May manage colors"),\ - ("Import Colors", togCOL, "try to import color if the path is set as 'fill'. Only With separate option"),\ - ("Import Patterns", Pattern, "import pattern content if it is made with paths.")] - retval = Blender.Draw.PupBlock("Import Options", block) - if togW.val: scale_=1 - elif togH.val: scale_=2 - elif togAS.val: scale_=3 - - if togSP.val: SEPARATE_CURVES=1 - - if togCOL.val and SEPARATE_CURVES : USE_COLORS=1 - - if Pattern.val : PATTERN =1 - - t1=Blender.sys.time() - # 0.4.1 : to avoid to use sax and the xml - # tools of the complete python - build_HIERARCHY(t) - r=BOUNDINGBOX['rec'] - curves.number_of_items=len(curves.ITEM) - for k, val in curves.ITEM.iteritems(): - val.pntsUV[0] =len(val.beziers_knot) - if curves.number_of_items>0 : #and Choise==1 : - #-------------------- - # 0.4.5 and 0.4.9 - #-------------------- - createCURVES(curves, name[0]) - else: - pass - print ' elapsed time : ',Blender.sys.time()-t1 - Blender.Redraw() - -#===================================================================== -#====================== SVG format mouvements ======================== -#===================================================================== -def functionSELECT(nom): - scan_FILE(nom) - - -if __name__=='__main__': - Blender.Window.FileSelector (functionSELECT, 'SELECT an .SVG FILE', '*.svg') \ No newline at end of file diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py deleted file mode 100644 index 4134503c511..00000000000 --- a/release/scripts/bvh_import.py +++ /dev/null @@ -1,757 +0,0 @@ -#!BPY - -""" -Name: 'Motion Capture (.bvh)...' -Blender: 242 -Group: 'Import' -Tip: 'Import a (.bvh) motion capture file' -""" - -__author__ = "Campbell Barton" -__url__ = ("blender.org", "blenderartists.org") -__version__ = "1.90 06/08/01" - -__bpydoc__ = """\ -This script imports BVH motion capture data to Blender. -as empties or armatures. -""" - -# -------------------------------------------------------------------------- -# BVH Import v2.0 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 Blender -import bpy -import BPyMessages -Vector= Blender.Mathutils.Vector -Euler= Blender.Mathutils.Euler -Matrix= Blender.Mathutils.Matrix -RotationMatrix = Blender.Mathutils.RotationMatrix -TranslationMatrix= Blender.Mathutils.TranslationMatrix - -DEG2RAD = 0.017453292519943295 - -class bvh_node_class(object): - __slots__=(\ - 'name',# bvh joint name - 'parent',# bvh_node_class type or None for no parent - 'children',# a list of children of this type. - 'rest_head_world',# worldspace rest location for the head of this node - 'rest_head_local',# localspace rest location for the head of this node - 'rest_tail_world',# # worldspace rest location for the tail of this node - 'rest_tail_local',# # worldspace rest location for the tail of this node - 'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple - 'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation. - 'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz) - 'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1) - 'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1) - 'temp')# use this for whatever you want - - def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order): - self.name= name - self.rest_head_world= rest_head_world - self.rest_head_local= rest_head_local - self.rest_tail_world= None - self.rest_tail_local= None - self.parent= parent - self.channels= channels - self.rot_order= rot_order - - # convenience functions - self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1 - self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1 - - - self.children= [] - - # list of 6 length tuples: (lx,ly,lz, rx,ry,rz) - # even if the channels arnt used they will just be zero - # - self.anim_data= [(0,0,0,0,0,0)] - - - def __repr__(self): - return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\ - (self.name,\ - self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\ - self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z) - - - -# Change the order rotation is applied. -MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1]) -MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) - -def eulerRotate(x,y,z, rot_order): - # Clamp all values between 0 and 360, values outside this raise an error. - mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')] - # print rot_order - # Standard BVH multiplication order, apply the rotation in the order Z,X,Y - return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler() - -def read_bvh(file_path, GLOBAL_SCALE=1.0): - # File loading stuff - # Open the file for importing - file = open(file_path, 'rU') - - # Seperate into a list of lists, each line a list of words. - file_lines = file.readlines() - # Non standard carrage returns? - if len(file_lines) == 1: - file_lines = file_lines[0].split('\r') - - # Split by whitespace. - file_lines =[ll for ll in [ l.split() for l in file_lines] if ll] - - - # Create Hirachy as empties - - if file_lines[0][0].lower() == 'hierarchy': - #print 'Importing the BVH Hierarchy for:', file_path - pass - else: - raise 'ERROR: This is not a BVH file' - - bvh_nodes= {None:None} - bvh_nodes_serial = [None] - - channelIndex = -1 - - - lineIdx = 0 # An index for the file. - while lineIdx < len(file_lines) -1: - #... - if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint': - - # Join spaces into 1 word with underscores joining it. - if len(file_lines[lineIdx]) > 2: - file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:]) - file_lines[lineIdx] = file_lines[lineIdx][:2] - - # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.?? - - # Make sure the names are unique- Object names will match joint names exactly and both will be unique. - name = file_lines[lineIdx][1] - - #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1]) - - lineIdx += 2 # Incriment to the next line (Offset) - rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) - lineIdx += 1 # Incriment to the next line (Channels) - - # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation] - # newChannel references indecies to the motiondata, - # if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended - # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value. - my_channel = [-1, -1, -1, -1, -1, -1] - my_rot_order= [None, None, None] - rot_count= 0 - for channel in file_lines[lineIdx][2:]: - channel= channel.lower() - channelIndex += 1 # So the index points to the right channel - if channel == 'xposition': my_channel[0] = channelIndex - elif channel == 'yposition': my_channel[1] = channelIndex - elif channel == 'zposition': my_channel[2] = channelIndex - - elif channel == 'xrotation': - my_channel[3] = channelIndex - my_rot_order[rot_count]= 0 - rot_count+=1 - elif channel == 'yrotation': - my_channel[4] = channelIndex - my_rot_order[rot_count]= 1 - rot_count+=1 - elif channel == 'zrotation': - my_channel[5] = channelIndex - my_rot_order[rot_count]= 2 - rot_count+=1 - - channels = file_lines[lineIdx][2:] - - my_parent= bvh_nodes_serial[-1] # account for none - - - # Apply the parents offset accumletivly - if my_parent==None: - rest_head_world= Vector(rest_head_local) - else: - rest_head_world= my_parent.rest_head_world + rest_head_local - - bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order) - - # If we have another child then we can call ourselves a parent, else - bvh_nodes_serial.append(bvh_node) - - # Account for an end node - if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it. - lineIdx += 2 # Incriment to the next line (Offset) - rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) - - bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail - bvh_nodes_serial[-1].rest_tail_local= rest_tail - - - # Just so we can remove the Parents in a uniform way- End end never has kids - # so this is a placeholder - bvh_nodes_serial.append(None) - - if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}'] - bvh_nodes_serial.pop() # Remove the last item - - if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion': - #print '\nImporting motion data' - lineIdx += 3 # Set the cursor to the first frame - break - - lineIdx += 1 - - - # Remove the None value used for easy parent reference - del bvh_nodes[None] - # Dont use anymore - del bvh_nodes_serial - - bvh_nodes_list= bvh_nodes.values() - - while lineIdx < len(file_lines): - line= file_lines[lineIdx] - for bvh_node in bvh_nodes_list: - #for bvh_node in bvh_nodes_serial: - lx= ly= lz= rx= ry= rz= 0.0 - channels= bvh_node.channels - anim_data= bvh_node.anim_data - if channels[0] != -1: - lx= GLOBAL_SCALE * float( line[channels[0]] ) - - if channels[1] != -1: - ly= GLOBAL_SCALE * float( line[channels[1]] ) - - if channels[2] != -1: - lz= GLOBAL_SCALE * float( line[channels[2]] ) - - if channels[3] != -1 or channels[4] != -1 or channels[5] != -1: - rx, ry, rz = eulerRotate(float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] ), bvh_node.rot_order) - #x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d - - # Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling. - # Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation. - - while anim_data[-1][3] - rx > 180: rx+=360 - while anim_data[-1][3] - rx < -180: rx-=360 - - while anim_data[-1][4] - ry > 180: ry+=360 - while anim_data[-1][4] - ry < -180: ry-=360 - - while anim_data[-1][5] - rz > 180: rz+=360 - while anim_data[-1][5] - rz < -180: rz-=360 - - # Done importing motion data # - anim_data.append( (lx, ly, lz, rx, ry, rz) ) - lineIdx += 1 - - # Assign children - for bvh_node in bvh_nodes.itervalues(): - bvh_node_parent= bvh_node.parent - if bvh_node_parent: - bvh_node_parent.children.append(bvh_node) - - # Now set the tip of each bvh_node - for bvh_node in bvh_nodes.itervalues(): - - if not bvh_node.rest_tail_world: - if len(bvh_node.children)==0: - # could just fail here, but rare BVH files have childless nodes - bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world) - bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local) - elif len(bvh_node.children)==1: - bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world) - bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local) - else: - # allow this, see above - #if not bvh_node.children: - # raise 'error, bvh node has no end and no children. bad file' - - # Removed temp for now - rest_tail_world= Vector(0,0,0) - rest_tail_local= Vector(0,0,0) - for bvh_node_child in bvh_node.children: - rest_tail_world += bvh_node_child.rest_head_world - rest_tail_local += bvh_node_child.rest_head_local - - bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children)) - bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children)) - - # Make sure tail isnt the same location as the head. - if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE: - - bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10 - bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10 - - - - return bvh_nodes - - - -def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): - - if IMPORT_START_FRAME<1: - IMPORT_START_FRAME= 1 - - scn= bpy.data.scenes.active - scn.objects.selected = [] - - objects= [] - - def add_ob(name): - ob = scn.objects.new('Empty') - objects.append(ob) - return ob - - # Add objects - for name, bvh_node in bvh_nodes.iteritems(): - bvh_node.temp= add_ob(name) - - # Parent the objects - for bvh_node in bvh_nodes.itervalues(): - bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast. - - # Offset - for bvh_node in bvh_nodes.itervalues(): - # Make relative to parents offset - bvh_node.temp.loc= bvh_node.rest_head_local - - # Add tail objects - for name, bvh_node in bvh_nodes.iteritems(): - if not bvh_node.children: - ob_end= add_ob(name + '_end') - bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast. - ob_end.loc= bvh_node.rest_tail_local - - - # Animate the data, the last used bvh_node will do since they all have the same number of frames - for current_frame in xrange(len(bvh_node.anim_data)): - Blender.Set('curframe', current_frame+IMPORT_START_FRAME) - - for bvh_node in bvh_nodes.itervalues(): - lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame] - - rest_head_local= bvh_node.rest_head_local - bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz - - bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD - - bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) - - scn.update(1) - return objects - - - -def bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): - - if IMPORT_START_FRAME<1: - IMPORT_START_FRAME= 1 - - - # Add the new armature, - scn = bpy.data.scenes.active - scn.objects.selected = [] - - arm_data= bpy.data.armatures.new() - arm_ob = scn.objects.new(arm_data) - scn.objects.context = [arm_ob] - scn.objects.active = arm_ob - - # Put us into editmode - arm_data.makeEditable() - - # Get the average bone length for zero length bones, we may not use this. - average_bone_length= 0.0 - nonzero_count= 0 - for bvh_node in bvh_nodes.itervalues(): - l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length - if l: - average_bone_length+= l - nonzero_count+=1 - - # Very rare cases all bones couldbe zero length??? - if not average_bone_length: - average_bone_length = 0.1 - else: - # Normal operation - average_bone_length = average_bone_length/nonzero_count - - - - ZERO_AREA_BONES= [] - for name, bvh_node in bvh_nodes.iteritems(): - # New editbone - bone= bvh_node.temp= Blender.Armature.Editbone() - - bone.name= name - arm_data.bones[name]= bone - - bone.head= bvh_node.rest_head_world - bone.tail= bvh_node.rest_tail_world - - # ZERO AREA BONES. - if (bone.head-bone.tail).length < 0.001: - if bvh_node.parent: - ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local - if ofs.length: # is our parent zero length also?? unlikely - bone.tail= bone.tail+ofs - else: - bone.tail.y= bone.tail.y+average_bone_length - else: - bone.tail.y= bone.tail.y+average_bone_length - - ZERO_AREA_BONES.append(bone.name) - - - for bvh_node in bvh_nodes.itervalues(): - if bvh_node.parent: - # bvh_node.temp is the Editbone - - # Set the bone parent - bvh_node.temp.parent= bvh_node.parent.temp - - # Set the connection state - if not bvh_node.has_loc and\ - bvh_node.parent and\ - bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ - bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: - bvh_node.temp.options= [Blender.Armature.CONNECTED] - - # Replace the editbone with the editbone name, - # to avoid memory errors accessing the editbone outside editmode - for bvh_node in bvh_nodes.itervalues(): - bvh_node.temp= bvh_node.temp.name - - arm_data.update() - - # Now Apply the animation to the armature - - # Get armature animation data - pose= arm_ob.getPose() - pose_bones= pose.bones - - action = Blender.Armature.NLA.NewAction("Action") - action.setActive(arm_ob) - #xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ] - - # Replace the bvh_node.temp (currently an editbone) - # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) - for bvh_node in bvh_nodes.itervalues(): - bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. - pose_bone= pose_bones[bone_name] - rest_bone= arm_data.bones[bone_name] - bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart() - - bone_rest_matrix_inv= Matrix(bone_rest_matrix) - bone_rest_matrix_inv.invert() - - bone_rest_matrix_inv.resize4x4() - bone_rest_matrix.resize4x4() - bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) - - - # Make a dict for fast access without rebuilding a list all the time. - xformConstants_dict={ - (True,True): [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\ - (False,True): [Blender.Object.Pose.ROT],\ - (True,False): [Blender.Object.Pose.LOC],\ - (False,False): [],\ - } - - - # KEYFRAME METHOD, SLOW, USE IPOS DIRECT - - # Animate the data, the last used bvh_node will do since they all have the same number of frames - for current_frame in xrange(len(bvh_node.anim_data)-1): # skip the first frame (rest frame) - # print current_frame - - #if current_frame==40: # debugging - # break - - # Dont neet to set the current frame - for bvh_node in bvh_nodes.itervalues(): - pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp - lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1] - - if bvh_node.has_rot: - # Set the rotation, not so simple - bone_rotation_matrix= Euler(rx,ry,rz).toMatrix() - bone_rotation_matrix.resize4x4() - pose_bone.quat= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat() - - if bvh_node.has_loc: - # Set the Location, simple too - pose_bone.loc= (\ - TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) *\ - bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works - - # Get the transform - xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] - - - if xformConstants: - # Insert the keyframe from the loc/quat - pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True ) - - # First time, set the IPO's to linear - if current_frame==0: - for ipo in action.getAllChannelIpos().itervalues(): - if ipo: - for cur in ipo: - cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - if IMPORT_LOOP: - cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC - - - - - # END KEYFRAME METHOD - - - """ - # IPO KEYFRAME SETTING - # Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/ - for bvh_node in bvh_nodes.itervalues(): - pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp - - # Get the transform - xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] - if xformConstants: - pose_bone.loc[:]= 0,0,0 - pose_bone.quat[:]= 0,0,1,0 - # Insert the keyframe from the loc/quat - pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants) - - - action_ipos= action.getAllChannelIpos() - - - for bvh_node in bvh_nodes.itervalues(): - has_loc= bvh_node.has_loc - has_rot= bvh_node.has_rot - - if not has_rot and not has_loc: - # No animation data - continue - - ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key - - if has_loc: - curve_xloc= ipo[Blender.Ipo.PO_LOCX] - curve_yloc= ipo[Blender.Ipo.PO_LOCY] - curve_zloc= ipo[Blender.Ipo.PO_LOCZ] - - curve_xloc.interpolation= \ - curve_yloc.interpolation= \ - curve_zloc.interpolation= \ - Blender.IpoCurve.InterpTypes.LINEAR - - - if has_rot: - curve_wquat= ipo[Blender.Ipo.PO_QUATW] - curve_xquat= ipo[Blender.Ipo.PO_QUATX] - curve_yquat= ipo[Blender.Ipo.PO_QUATY] - curve_zquat= ipo[Blender.Ipo.PO_QUATZ] - - curve_wquat.interpolation= \ - curve_xquat.interpolation= \ - curve_yquat.interpolation= \ - curve_zquat.interpolation= \ - Blender.IpoCurve.InterpTypes.LINEAR - - # Get the bone - pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp - - - def pose_rot(anim_data): - bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix() - bone_rotation_matrix.resize4x4() - return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz - - def pose_loc(anim_data): - return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart()) - - - last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1 - - if has_loc: - pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data] - - # Add the start at the end, we know the start is just 0,0,0 anyway - curve_xloc.append((last_frame, pose_locations[-1][0])) - curve_yloc.append((last_frame, pose_locations[-1][1])) - curve_zloc.append((last_frame, pose_locations[-1][2])) - - if len(pose_locations) > 1: - ox,oy,oz= pose_locations[0] - x,y,z= pose_locations[1] - - for i in xrange(1, len(pose_locations)-1): # from second frame to second last frame - - nx,ny,nz= pose_locations[i+1] - xset= yset= zset= True # we set all these by default - if abs((ox+nx)/2 - x) < 0.00001: xset= False - if abs((oy+ny)/2 - y) < 0.00001: yset= False - if abs((oz+nz)/2 - z) < 0.00001: zset= False - - if xset: curve_xloc.append((i+IMPORT_START_FRAME, x)) - if yset: curve_yloc.append((i+IMPORT_START_FRAME, y)) - if zset: curve_zloc.append((i+IMPORT_START_FRAME, z)) - - # Set the old and use the new - ox,oy,oz= x,y,z - x,y,z= nx,ny,nz - - - if has_rot: - pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data] - - # Add the start at the end, we know the start is just 0,0,0 anyway - curve_wquat.append((last_frame, pose_rotations[-1][0])) - curve_xquat.append((last_frame, pose_rotations[-1][1])) - curve_yquat.append((last_frame, pose_rotations[-1][2])) - curve_zquat.append((last_frame, pose_rotations[-1][3])) - - - if len(pose_rotations) > 1: - ow,ox,oy,oz= pose_rotations[0] - w,x,y,z= pose_rotations[1] - - for i in xrange(1, len(pose_rotations)-1): # from second frame to second last frame - - nw, nx,ny,nz= pose_rotations[i+1] - wset= xset= yset= zset= True # we set all these by default - if abs((ow+nw)/2 - w) < 0.00001: wset= False - if abs((ox+nx)/2 - x) < 0.00001: xset= False - if abs((oy+ny)/2 - y) < 0.00001: yset= False - if abs((oz+nz)/2 - z) < 0.00001: zset= False - - if wset: curve_wquat.append((i+IMPORT_START_FRAME, w)) - if xset: curve_xquat.append((i+IMPORT_START_FRAME, x)) - if yset: curve_yquat.append((i+IMPORT_START_FRAME, y)) - if zset: curve_zquat.append((i+IMPORT_START_FRAME, z)) - - # Set the old and use the new - ow,ox,oy,oz= w,x,y,z - w,x,y,z= nw,nx,ny,nz - - # IPO KEYFRAME SETTING - """ - pose.update() - return arm_ob - - -#=============# -# TESTING # -#=============# - -#('/metavr/mocap/bvh/boxer.bvh') -#('/d/staggered_walk.bvh') -#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF -#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings. -#('/metavr/mocap/bvh/walk4.bvh') # 0 channels - -''' -import os -DIR = '/metavr/mocap/bvh/' -for f in ('/d/staggered_walk.bvh',): - #for f in os.listdir(DIR)[5:6]: - #for f in os.listdir(DIR): - if f.endswith('.bvh'): - s = Blender.Scene.New(f) - s.makeCurrent() - #file= DIR + f - file= f - print f - bvh_nodes= read_bvh(file, 1.0) - bvh_node_dict2armature(bvh_nodes, 1) -''' - -def load_bvh_ui(file, PREF_UI= True): - - if BPyMessages.Error_NoFile(file): - return - - Draw= Blender.Draw - - IMPORT_SCALE = Draw.Create(0.1) - IMPORT_START_FRAME = Draw.Create(1) - IMPORT_AS_ARMATURE = Draw.Create(1) - IMPORT_AS_EMPTIES = Draw.Create(0) - IMPORT_LOOP = Draw.Create(0) - - # Get USER Options - if PREF_UI: - pup_block = [\ - ('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\ - ('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\ - ('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\ - ('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\ - ('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\ - ] - - if not Draw.PupBlock('BVH Import...', pup_block): - return - - print 'Attempting import BVH', file - - IMPORT_SCALE = IMPORT_SCALE.val - IMPORT_START_FRAME = IMPORT_START_FRAME.val - IMPORT_AS_ARMATURE = IMPORT_AS_ARMATURE.val - IMPORT_AS_EMPTIES = IMPORT_AS_EMPTIES.val - IMPORT_LOOP = IMPORT_LOOP.val - - if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES: - Blender.Draw.PupMenu('No import option selected') - return - Blender.Window.WaitCursor(1) - # Get the BVH data and act on it. - t1= Blender.sys.time() - print '\tparsing bvh...', - bvh_nodes= read_bvh(file, IMPORT_SCALE) - print '%.4f' % (Blender.sys.time()-t1) - t1= Blender.sys.time() - print '\timporting to blender...', - if IMPORT_AS_ARMATURE: bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) - if IMPORT_AS_EMPTIES: bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) - - print 'Done in %.4f\n' % (Blender.sys.time()-t1) - Blender.Window.WaitCursor(0) - -def main(): - Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh') - -if __name__ == '__main__': - #def foo(): - main() - ''' - scn = bpy.data.scenes.active - for ob in list(scn.objects): - if ob.name!='arm__': - scn.objects.unlink(ob) - load_bvh_ui('/test.bvh', False) - ''' \ No newline at end of file diff --git a/release/scripts/c3d_import.py b/release/scripts/c3d_import.py deleted file mode 100644 index 98f643cbab9..00000000000 --- a/release/scripts/c3d_import.py +++ /dev/null @@ -1,1244 +0,0 @@ -#!BPY -# -*- coding: latin-1 -*- -""" -Name: 'Motion Capture (.c3d)...' -Blender: 246 -Group: 'Import' -Tooltip: 'Import a C3D Motion Capture file' -""" -__script__ = "C3D Motion Capture file import" -__author__ = " Jean-Baptiste PERIN, Roger D. Wickes (rogerwickes@yahoo.com)" -__version__ = "0.9" -__url__ = ["Communicate problems and errors, BlenderArtists.org, Python forum"] -__email__= ["rogerwickes@yahoo.com", "c3d script"] -__bpydoc__ = """\ -c3d_import.py v0.8 - -Script loading Graphics Lab Motion Capture file, -Usage:
- - Run the script
- - Choose the file to open
- - Press Import C3D button
- -Version History: - 0.4: PERIN Released under Blender Artistic Licence - 0.5: WICKES used marker names, fixed 2.45 depricated call - 0.6: WICKES creates armature for each subject - 0.7: WICKES constrains armature to follow the empties (markers). Verified for shake hands s - 0.8: WICKES resolved DEC support issue - 0.9: BARTON removed scene name change, whitespace edits. WICKES added IK layers -""" - -#---------------------------------------------- -# (c) Jean-Baptiste PERIN december 2005, released under Blender Artistic Licence -# for the Blender 2.40 Python Scripts Bundle. -#---------------------------------------------- - -###################################################### -# This script imports a C3D file into blender. -# Loader is based on MATLAB C3D loader from -# Alan Morris, Toronto, October 1998 -# Jaap Harlaar, Amsterdam, april 2002 -###################################################### - -import string -import Blender -from Blender import * -import bpy -import struct -import BPyMessages -Vector= Blender.Mathutils.Vector -Euler= Blender.Mathutils.Euler -Matrix= Blender.Mathutils.Matrix -RotationMatrix = Blender.Mathutils.RotationMatrix -TranslationMatrix= Blender.Mathutils.TranslationMatrix - -#================= -# Global Variables, Constants, Defaults, and Shorthand References -#================= -# set senstitivity for displaying debug/console messages. 0=few, 100=max, including clicks at major steps -# debug(num,string) to conditionally display status/info in console window -DEBUG=Blender.Get('rt') - -# marker sets known in the world -HUMAN_CMU= "HumanRTKm.mkr" # The Human Real-Time capture marker set used by CMU -HUMAN_CMU2="HumanRT.mkr" # found in another file, seems same as others in that series -MARKER_SETS = [ HUMAN_CMU, HUMAN_CMU2 ] # marker sets that this program supports (can make an armature for) -XYZ_LIMIT= 10000 #max value for coordinates if in integer format - -# what layers to put stuff on in scene. 1 is selected, so everything goes there -# selecting only layer 2 shows only the armature moving, 12 shows only the empties -LAYERS_ARMOB= [1,2] -LAYERS_MARKER=[1,12] -LAYERS_IK=[1,11] -IK_PREFIX="ik_" # prefix in empty name: ik_prefix+subject prefix+bone name - -CLEAN=True # Should program ignore markers at (0,0,0) and beyond the outer limits? - -scn = Blender.Scene.GetCurrent() - -BCS=Blender.Constraint.Settings # shorthand dictionary - define with brace, reference with bracket -trackto={"+x":BCS.TRACKX, "+y":BCS.TRACKY, "+z":BCS.TRACKZ, "-x":BCS.TRACKNEGX, "-y":BCS.TRACKNEGY, "-z":BCS.TRACKNEGZ} -trackup={"x":BCS.UPX, "y":BCS.UPY, "z":BCS.UPZ} - -#=============================# -# Classes -#=============================# -class Marker: - def __init__(self, x, y, z): - self.x=0.0 - self.y=0.0 - self.z=0.0 - - def __repr__(self): #report on self, as in if just printed - return str("[x = "+str(self.x) +" y = " + str(self.y)+" z = "+ str(self.z)+"]") - -class ParameterGroup: - def __init__(self, nom, description, parameter): - self.name = nom - self.description = description - self.parameter = parameter - - def __repr__(self): - return self.name, " ", self.description, " ", self.parameter - -class Parameter: - def __init__(self, name, datatype, dim, data, description): - self.name = name - self.datatype = datatype - self.dim = dim - self.data = data - self.description = description - - def __repr__(self): - return self.name, " ", self.description, " ", self.dim - -class MyVector: - def __init__(self, fx,fy,fz): - self.x=fx - self.y=fy - self.z=fz - -class Mybone: - "information structure for bone generation and posing" - def __init__(self, name,vec,par,head,tail,const): - self.name=name # name of this bone. must be unique within armature - self.vec=vec # edit bone vector it points - self.parent=par # name of parent bone to locate head and form a chain - self.headMark=head # list of 0+ markers where the head of this non-parented bone should be placed - self.tailMark=tail # list of 0+ markers where the tip should be placed - self.const=const # list of 0+ constraint tuples to control posing - self.head=MyVector(0,0,0) #T-pose location - self.tail=MyVector(0,0,0) - def __repr__(self): - return '[Mybone "%s"]' % self.name - - -#=============================# -# functions/modules -#=============================# -def error(str): - Draw.PupMenu('ERROR%t|'+str) - return -def status(str): - Draw.PupMenu('STATUS%t|'+str+"|Continue?") - return -def debug(num,msg): #use log4j or just console here. - if DEBUG >= num: - print 'debug:', (' '*num), msg - #TODO: if level 0, make a text file in Blender file to record major stuff - return - -def names(ob): return ob.name - - -######### -# Cette fonction renvoie la liste des empties -# in : -# out : emp_list (List of Object) la liste des objets de type "Empty" -######### -def getEmpty(name): - obs = [ob for ob in scn.objects if ob.type=="Empty" and ob.name==name] - if len(obs)==0: - return None - elif len(obs)==1: - return obs[0] - else: - error("FATAL ERROR: %i empties %s in file" % (len(obs),ob[0])) -######### -# Cette fonction renvoie un empty -# in : objname : le nom de l'empty recherche -# out : myobj : l'empty cree ou retrouve -######### -def getOrCreateEmpty(objname): - myobj= getEmpty(objname) - if myobj==None: - myobj = scn.objects.new("Empty",objname) - debug(50,'Marker/Empty created %s' % myobj) - return myobj - -def getOrCreateCurve(ipo, curvename): - """ - Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo - - >>> import mylib - - >>> lIpo = GetOrCreateIPO("Une IPO") - >>> laCurve = getOrCreateCurve(lIpo, "RotX") - - Either an ipo curve named C{curvename} exists before the call then this curve is returned, - Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned - - @type ipo: Blender Ipo - @param ipo: the Ipo in which the curve must be retrieved or created. - @type curvename: string - @param curvename: name of the IPO. - @rtype: Blender Curve - @return: a Blender Curve named C{curvename} in the C{ipo} Ipo - """ - try: - mycurve = ipo.getCurve(curvename) - if mycurve != None: - pass - else: - mycurve = ipo.addCurve(curvename) - except: - mycurve = ipo.addCurve(curvename) - return mycurve - -def eraseIPO (objectname): - object = Blender.Object.Get(objectname) - lIpo = object.getIpo() - if lIpo != None: - nbCurves = lIpo.getNcurves() - for i in range(nbCurves): - nbBezPoints = lIpo.getNBezPoints(i) - for j in range(nbBezPoints): - lIpo.delBezPoint(i) - -def comp_loc(emptyNameList): - myloc=Vector(0,0,0) - for emName in emptyNameList: - myobj = Blender.Object.Get(emName) - for i in range(3): - myloc[i]= myloc[i]+(myobj.loc[i]/len(emptyNameList)) #take the average loc of all marks - return myloc - -def comp_len(head, tail): # computes the length of a bone - headvec=comp_loc(head) - tailvec=comp_loc(tail) - netvec=headvec-tailvec - return netvec.length - -def createHumanCMU(): # human bone structure, makes a node set for CMU MoCap Lab - # order of bones: "spine","chest","neck","head",...face toward you in front view - # pose constraints are tuples of (type,target,influence,other-as-needed) - # constraint stack order is important. for proper bone pointing and orinetation: - # IK, then TT +YZ in world space. then LR XZ to 0 in world space, this points the bone, twists it, but then - # limits the rotation to the sidebar enpty with the Z facing it, and Y pointing along the bone. - nodes=[] # bonename, vector, parent, head targets, tail targets, constraint list - for i in range(23): nodes.append(Mybone("name","vec","par",[],[],[])) - nodes[0]= Mybone("root", "-Y","",["RBWT", "LBWT"],["RFWT", "LFWT", "RBWT", "LBWT"],[("LOC","RBWT",1.0),("LOC","LBWT",0.5),("IK","RFWT",1.0),("IK","LFWT",0.5),("TT","RBWT",1,"+YZ"),("LR","XZ",1)]) - nodes[1]= Mybone("spine","+Z","root",[],["STRN","T10"],[("IK","STRN",1.0),("IK","T10",0.5),("TT","STRN",1,"+YZ"),("LR","XZ",1)]) - nodes[2]= Mybone("chest","+Z","spine",[],["CLAV","C7"],[("IK","CLAV",1.0),("IK","C7",0.5),("TT","CLAV",1,"+YZ"),("LR","XZ",1)]) - nodes[3]= Mybone("neck", "+Z","chest",[],["RBHD","LBHD"],[("IK","RBHD",1.0),("IK","LBHD",0.5),("TT","LBHD",1,"+YZ"),("LR","XZ",1)]) - nodes[4]= Mybone("head" ,"-Y","neck",[],["RFHD","LFHD"],[("IK","RFHD",1.0),("IK","LFHD",0.5),("TT","LFHD",1,"+YZ"),("LR","XZ",1)]) - - nodes[5]= Mybone("shoulder.R","-X","chest",[],["RSHO"],[("IK","RSHO",1.0)]) - nodes[6]= Mybone("toparm.R", "-X","shoulder.R",[],["RELB"],[("IK","RELB",1.0),("TT","RUPA",1,"+YZ"),("LR","XZ",1)]) - nodes[7]= Mybone("lowarm.R", "-X","toparm.R",[],["RWRA","RWRB"],[("IK","RWRA",1.0),("IK","RWRB",0.5),("TT","RFRM",1,"+YZ"),("LR","XZ",1)]) - nodes[8]= Mybone("hand.R", "-X","lowarm.R",[],["RFIN"],[("IK","RFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"RTHM" - - nodes[9]= Mybone("hip.R", "-X","root",[],["RFWT","RBWT"],[("IK","RFWT",1.0),("IK","RBWT",0.5)]) - nodes[10]=Mybone("topleg.R","-Z","hip.R",[],["RKNE"],[("IK","RKNE",1),("TT","RTHI",1,"+YZ"),("LR","XZ",1)]) - nodes[11]=Mybone("lowleg.R","-Z","topleg.R",[],["RANK","RHEE"],[("IK","RHEE",1.0),("TT","RSHN",1,"+YZ"),("LR","XZ",1)]) - nodes[12]=Mybone("foot.R", "-Y","lowleg.R",[],["RTOE","RMT5"],[("IK","RTOE",1.0),("IK","RMT5",0.2),("TT","RMT5",1,"+YZ")]) - nodes[13]=Mybone("toes.R", "-Y","foot.R",[],["RTOE"],[("IK","RTOE",1.0)]) - - nodes[14]=Mybone("shoulder.L","+X","chest",[],["LSHO"],[("IK","LSHO",1.0)]) - nodes[15]=Mybone("toparm.L", "+X","shoulder.L",[],["LELB"],[("IK","LELB",1.0),("TT","LUPA",1,"+YZ"),("LR","XZ",1)]) - nodes[16]=Mybone("lowarm.L", "+X","toparm.L",[],["LWRA","LWRB"],[("IK","LWRA",1.0),("IK","LWRB",0.5),("TT","LFRM",1,"+YZ"),("LR","XZ",1)]) - nodes[17]=Mybone("hand.L", "+X","lowarm.L",[],["LFIN"],[("IK","LFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"LTHM" - - nodes[18]=Mybone("hip.L", "+X","root",[],["LFWT","LBWT"],[("IK","LFWT",1.0),("IK","LBWT",0.5)]) - nodes[19]=Mybone("topleg.L","-Z","hip.L",[],["LKNE"],[("IK","LKNE",1),("TT","LTHI",1,"+YZ"),("LR","XZ",1)]) - nodes[20]=Mybone("lowleg.L","-Z","topleg.L",[],["LANK","LHEE"],[("IK","LHEE",1.0),("TT","LSHN",1,"+YZ"),("LR","XZ",1)]) - nodes[21]=Mybone("foot.L", "-Y","lowleg.L",[],["LTOE","LMT5"],[("IK","LTOE",1.0),("IK","LMT5",0.2),("TT","LMT5",1,"+YZ"),("LR","XZ",1)]) - nodes[22]=Mybone("toes.L", "-Y","foot.L",[],["LTOE"],[("IK","LTOE",1.0)]) - return nodes - -def createNodes(marker_set): # make a list of bone name, parent, edit head loc, edit tail loc, pose constraints - #ultimately, I want to read in an XML file here that specifies the node trees for various marker sets - if marker_set==HUMAN_CMU: nodes= createHumanCMU() #load up and verify the file has the CMU marker set - elif marker_set==HUMAN_CMU2: nodes= createHumanCMU() - else: nodes=[] - return nodes -def findEntry(item,list): - for i in range(len(list)): - if item==list[i]: break - debug(100,"findEtnry %s is %i in list of %i items" % (item,i,len(list))) - return i -def makeNodes(prefix, markerList, empties, marker_set): #make sure the file has the nodes selected - nodes= createNodes(marker_set) # list has generic marker names; replace them with the actual object names created - #each entry in markerlist has a corresponding entry in empties in the same order - errList=[] - for i in range(len(nodes)): - node= nodes[i] - debug(60,"Adapting node %s to prefix %s" % (node,prefix)) - - #replace generic head markers with actual empty names - for im in range(len(node.headMark)): - marker= node.headMark[im] - mark= prefix+marker - imn= findEntry(mark,markerList) - if imn < len(markerList): - debug(90,"Adapating head marker %s to %s" % (marker,empties[imn].name)) - nodes[i].headMark[im]= empties[imn].name - else: errList.append([node.name,"head location",mark,node,2]) - - #replace generic tail markers with actual empty names - for im in range(len(node.tailMark)): - marker= node.tailMark[im] - mark= prefix+marker - imn= findEntry(mark,markerList) - if imn < len(markerList): - debug(90,"Adapating marker %s to %s" % (marker,empties[imn].name)) - nodes[i].tailMark[im]= empties[imn].name - else: errList.append([node.name,"tail location",mark,node,2]) - - #replace generic constraint markers (if the constraint references a marker) with empty name - for im in range(len(node.const)): - const=node.const[im] - if const[0] in ("LOC","IK","TT"): - marker=const[1] - mark= prefix+marker - imn= findEntry(mark,markerList) - if imn < len(markerList): - debug(90,"Adapating %s constraint marker %s to %s" % (const[0],marker,empties[imn].name)) - if const[0] in ("IK","LR","LOC"): - nodes[i].const[im]=(const[0], empties[imn].name, const[2]) - else: nodes[i].const[im]=(const[0], empties[imn].name, const[2], const[3]) - else: errList.append([node.name,const[0]+" constraint",mark,node,4]) - - if errList!=[]: #we have issues. - for err in errList: - debug(0,"Bone "+err[0]+" specifies "+err[2]+" as "+err[1]+"which was not specified in file.") - #need a popup here to ignore/cleanup node tree, or add the marker(?) or abort - usrOption= 1 - if usrOption==0: #ignore this marker (remove it) - for node in nodes: #find the bone in error - if node.name==err[0]: - print "Before",node - if err[3] in range(2,3): - node[err[3]].remove(err[2]) #find the marker in error and remove it - elif err[3]==4: #find the constraint and remove it - for const in node.const: - if const[1]==err[2]: node.const.remove(const) - print "After",node - elif usrOption==1: #add these markers as static empties, and user will automate them later - #and the bones will be keyed to them, so it will all be good. - #file may have just mis-named the empty, or the location can be derived based on other markers - em= getOrCreateEmpty(err[2]) - em.layers= LAYERS_MARKER - else: abort() #abend - if DEBUG==100: status("Nodes Updated") - return nodes #nodes may be updated - -def makeBones(arm,nodes): - debug(20,"Making %i edit bones" % len(nodes)) - for node in nodes: - bone= Blender.Armature.Editbone() - bone.name= node.name - arm.bones[bone.name]= bone #add it to the armature - debug(50,"Bone added: %s" % bone) - if bone.name <> node.name: - debug(0,"ERROR: duplicate node % name specified" % node.name) - node.name= bone.name #you may not get what you asked for - if node.parent!="": #parent - debug(60,"Bone parent: %s"%node.parent) - bone.parent= arm.bones[node.parent] - bone.options = [Armature.CONNECTED] - #compute head = average of the reference empties - if node.headMark==[]: # no head explicitly stated, must be tail of parent - for parnode in nodes: - if node.parent==parnode.name: break - node.headMark= parnode.tailMark - node.head= parnode.tail - else: node.head= comp_loc(node.headMark) #node head is specified, probably only for root. - - bone.head= node.head - debug(60,"%s bone head: (%0.2f, %0.2f, %0.2f)" % (bone.name,bone.head.x, bone.head.y, bone.head.z)) - mylen=comp_len(node.headMark,node.tailMark) # length of the bone as it was recorded for that person - # for our T position, compute the bone length, add it to the head vector component to get the tail - if node.vec[0]=="-": mylen=-mylen - debug(80,"Bone vector %s length %0.2f" %(node.vec,mylen)) - node.tail= Vector(node.head) - myvec=node.vec[1].lower() - if myvec=="x": node.tail.x+=mylen - elif myvec=="y": node.tail.y+=mylen - elif myvec=="z": node.tail.z+=mylen - else: - debug(0,"%s %s %s %s" % (node.vec,myvec,node.vec[0],node.vec[1])) - error("ERROR IN BONE SPEC ") - bone.tail= node.tail - debug(60,"Bone tail: (%i,%i,%i)" %(bone.tail.x, bone.tail.y, bone.tail.z)) - #Armature created in the T postion, but with bone lengths to match the marker set and subject - #when this is constrained to the markers, the recorded action will be relative to a know Rotation - #so that all recorded actions should be interchangeable. wooot! - #Only have to adjust starting object loc when matching up actions. - return #arm #updated - -def makeConstLoc(pbone,const): - const_new= pbone.constraints.append(Constraint.Type.COPYLOC) - const_new.name = const[0]+"-"+const[1] - const_target=Blender.Object.Get(const[1]) - const_new[BCS.TARGET]= const_target - const_new.influence = const[2] - return - -def makeConstLimRot(pbone,const): - const_new= pbone.constraints.append(Constraint.Type.LIMITROT) - const_new.name = const[0]+"-"+const[1] - for axis in const[1]: - if axis.lower()=="x": const_new[BCS.LIMIT] |= BCS.LIMIT_XROT #set - if axis.lower()=="y": const_new[BCS.LIMIT] |= BCS.LIMIT_YROT #set - if axis.lower()=="z": const_new[BCS.LIMIT] |= BCS.LIMIT_ZROT #set - const_new[BCS.OWNERSPACE]= BCS.SPACE_LOCAL - const_new.influence = const[2] - # fyi, const[Constraint.Settings.LIMIT] &= ~Constraint.Settings.LIMIT_XROT #reset - return - -def makeConstIK(prefix,pbone,const): - #Blender 246 only supports one IK Solver per bone, but we might want many, - # so we need to create a reference empty named after the bone - # that floats between the markers, so the bone can point to it as a singularity - myob= getOrCreateEmpty(IK_PREFIX+prefix+pbone.name) - myob.layers= LAYERS_IK - # note that this empty gets all the IK constraints added on as location constraints - myconst= myob.constraints.append(Constraint.Type.COPYLOC) - myconst.name=const[0]+"-"+const[1] - myconst[Constraint.Settings.TARGET]= Blender.Object.Get(const[1]) - myconst.influence = const[2] - - #point the bone once to the empty via IK - success=False - for myconst in pbone.constraints: - if myconst.type == Constraint.Type.IKSOLVER: success=True - if not(success): #add an IK constraint to the bone to point to the empty - #print pbone - myconst= pbone.constraints.append(Constraint.Type.IKSOLVER) - myconst.name = const[1] - myconst[BCS.TARGET]= myob - myconst.influence = const[2] - #const_new[Constraint.Settings.BONE]= ? - myconst[BCS.CHAINLEN]= 1 - myconst[BCS.USETIP]= True - myconst[BCS.STRETCH]= False - return - -def makeConstTT(pbone,const): - myconst= pbone.constraints.append(Constraint.Type.TRACKTO) - myconst.name=const[0]+"-"+const[1] - debug(70,"%s %s" % (myconst,const[3])) - myob= getEmpty(const[1]) - if myob!= None: - myconst[BCS.TARGET]= myob - myconst.influence = const[2] - #const[3] is the Track and the thrird char is the Up indicator - myconst[BCS.TRACK]= trackto[const[3][0:2].lower()] - myconst[BCS.UP]=trackup[const[3][2].lower()]#up direction - myconst[BCS.OWNERSPACE]= BCS.SPACE_LOCAL - myconst[BCS.TARGETSPACE]= [BCS.SPACE_LOCAL] - if const[3][1]==const[3][2]: debug(0,"WARNING: Track To axis and up axis should not be the same. Constraint is INACTIVE") - else: #marker not found. could be missing from this file, or an error in node spec - error("TrackTo Constraint for %s |specifies unknown marker %s" % (pbone.name,const[1])) - return - -def makePoses(prefix,arm_ob,nodes): # pose this armature object based on node requirements - #this is constraint-based posing, not hard-keyed posing. - #we do constraint-based first so that user can adjust the constraints, possibly smooth/tweak motion - # add additional bones or referneces/constraints, before baking to hard keyframes - - pose= arm_ob.getPose() - debug(0,"Posing %s %s" % (arm_ob, pose)) - for node in nodes: - debug(30, "examining %s" %node) - if len(node.const)>0: #constraints for this bone are desired - pbone = pose.bones[node.name] - debug(40,"Posing bone %s" %pbone) - for const in node.const: - debug(50,"Constraining %s by %s" %(pbone,const)) - if const[0]=="LOC":makeConstLoc(pbone,const) - elif const[0]=="IK": makeConstIK(prefix,pbone,const) - elif const[0]=="LR": makeConstLimRot(pbone,const) - elif const[0]=="TT": makeConstTT(pbone,const) - else: - error("FATAL: constraint %s not supported" %const[0]) - break - debug(10, "Posing complete. Cycling pose and edit mode") - pose.update() - return - -def make_arm(subject,prefix,markerList, emptyList,marker_set): - debug(10,"**************************") - debug(00, "**** Making Armature for %s..." % subject) - debug(10, "**************************") - # copied from bvh import bvh_node_dict2armature; trying to use similar process for further integtration down the road - # Add the new armature, - - nodes= makeNodes(prefix, markerList, emptyList, marker_set) #assume everyone in file uses the same mocap suit - # each person in the file may be different height, so each needs their own new armature to match marker location - -## obs= Blender.Object.Get() -## success=False -## for ob in obs: -## if ob.name==subject: -## success=True -## if success: -## menu="Human Armature already exists for this subject." -## menu+="%t|Create another in this scene" -## menu+="%l|Start a new scene" -## menu+="%l|Use this armature" -## menusel= Draw.PupMenu(menu) - - arm= Blender.Armature.New(subject) #make an armature. - debug(10,"Created Armature %s" % arm) - # Put us into editmode - arm.makeEditable() - arm.drawType = Armature.OCTAHEDRON - makeBones(arm,nodes) - scn = Blender.Scene.GetCurrent() #add it to the current scene. could create new scenes here as yaf - arm_ob= scn.objects.new(arm) #instance it in the scene. this is the new way for 2.46 to instance objects - arm_ob.name= subject #name it something like the person it represents - arm_ob.layers= LAYERS_ARMOB - debug(20,"Instanced Armature %s" % arm_ob) - arm.update() #exit editmode. Arm must be instanced as an object before you can save changes or pose it - Blender.Redraw() # show the world - if DEBUG==100: status("T-Bones made.") - - makePoses(prefix,arm_ob,nodes) #constrain arm_ob with these markers - - scn.update(1) #make everyone behave themselves in the scene, and respect the new constraints - return arm_ob - -def setupAnim(StartFrame, EndFrame, VideoFrameRate): - debug(100, 'VideoFrameRate is %i' %VideoFrameRate) - if VideoFrameRate<1: VideoFrameRate=1 - if VideoFrameRate>120: VideoFrameRate=120 - # set up anim panel for them - context=scn.getRenderingContext() - context.sFrame=StartFrame - context.eFrame=EndFrame - context.fps=int(VideoFrameRate) - - Blender.Set("curframe",StartFrame) - Blender.Redraw() - return - -def makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers): - debug(10, "**************************") - debug(00, "*** Making Cloud Formation") - debug(10, "**************************") - empties=[] - ipos=[] - curvesX=[] - curvesY=[] - curvesZ=[] - debug(0, "%i Markers (empty cloud) will be put on layers %s" % (Nmarkers,LAYERS_MARKER)) - # Empty Cloud formation - for i in range(Nmarkers): - debug(100,"%i marker %s"%(i, markerList[i])) - emptyname = markerList[i] # rdw: to use meaningful names from Points parameter - em= getOrCreateEmpty(emptyname) #in this scene - em.layers= LAYERS_MARKER - #make a list of the actual empty - empties.append(em) - #assign it an ipo with the loc xyz curves - lipo = Ipo.New("Object",em.name) - ipos.append(lipo) - curvesX.append(getOrCreateCurve(ipos[i],'LocX')) - curvesY.append(getOrCreateCurve(ipos[i],'LocY')) - curvesZ.append(getOrCreateCurve(ipos[i],'LocZ')) - empties[i].setIpo(ipos[i]) - debug(30,"Cloud of %i empties created." % len(empties)) - NvideoFrames= EndFrame-StartFrame+1 - debug(10, "**************************") - debug(00, "**** Calculating Marker Ipo Curves over %i Frames ..." % NvideoFrames) - debug(10, "**************************") - err= index=0 #number of errors, logical frame - for frame in range(StartFrame,EndFrame+1): - if index==0: start=sys.time() - elif index==100: - tmp=(NvideoFrames-100)*(sys.time()-start)/6000 - debug(0,"%i minutes process time estimated" % tmp) - elif index >100: print index*100/(NvideoFrames-1),"% complete\r", - for i in range(Nmarkers): - if Markers[index][i].z < 0: Markers[index][i].z= -Markers[index][i].z - success=True - if CLEAN: #check for good data - # C3D marker decoding may have coordinates negative (improper sign bit decoding?) - myX= abs(Markers[index][i].x) - myY= abs(Markers[index][i].y) - myZ= Markers[index][i].z - if myX > 10000 or myY > 10000 or myZ > 10000: success=False - if myX <.01 and myY <.01 and myZ <.01: success=False # discontinuity in marker tracking (lost marker) - - if success: - curvesX[i].append((frame, Markers[index][i].x)) #2.46 knot method - curvesY[i].append((frame, Markers[index][i].y)) - curvesZ[i].append((frame, Markers[index][i].z)) - if frame==StartFrame: debug(40, "%s loc frame %i: (%0.2f, %0.2f, %0.2f)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z)) - else: - err+=1 # some files have thousands... - #debug(30,"Point ignored for marker:%s frame %i: (%i, %i, %i)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z)) - index += 1 - debug(70, "%i points ignored across all markers and frames. Recalculating..." % err) - - for i in range(Nmarkers): - curvesX[i].Recalc() - curvesY[i].Recalc() - curvesZ[i].Recalc() - Blender.Set('curframe', StartFrame) - Blender.Redraw() - if DEBUG==100: status("Clound formed") - return empties - -def getNumber(str, length): - if length==2: # unsigned short - return struct.unpack('H',str[0:2])[0], str[2:] - sum = 0 - for i in range(length): - #sum = (sum << 8) + ord(str[i]) for big endian - sum = sum + ord(str[i])*(2**(8*i)) - return sum, str[length:] -def unpackFloat(chunk,proctype): - #print proctype - myvar=chunk[0:4] - if proctype==2: #DEC-VAX - myvar=chunk[2:4]+chunk[0:2] #swap lo=hi word order pair - return struct.unpack('f',myvar[0:4])[0] - -def getFloat(chunk,proctype): - return unpackFloat(chunk, proctype), chunk[4:] -def parseFloat(chunk,ptr,proctype): - return unpackFloat(chunk[ptr:ptr+4], proctype), ptr+4 - - -def load_c3d(FullFileName): -# Input: FullFileName - file (including path) to be read -# -# Variable: -# Markers 3D-marker data [Nmarkers x NvideoFrames x Ndim(=3)] -# VideoFrameRate Frames/sec -# AnalogSignals Analog signals [Nsignals x NanalogSamples ] -# AnalogFrameRate Samples/sec -# Event Event(Nevents).time ..value ..name -# ParameterGroup ParameterGroup(Ngroups).Parameters(Nparameters).data ..etc. -# CameraInfo MarkerRelated CameraInfo [Nmarkers x NvideoFrames] -# ResidualError MarkerRelated ErrorInfo [Nmarkers x NvideoFrames] - - Markers=[]; - VideoFrameRate=120; - AnalogSignals=[]; - AnalogFrameRate=0; - Event=[]; - ParameterGroups=[]; - CameraInfo=[]; - ResidualError=[]; - - debug(10, "*********************") - debug(10, "**** Opening File ***") - debug(10, "*********************") - - #ind=findstr(FullFileName,'\'); - #if ind>0, FileName=FullFileName(ind(length(ind))+1:length(FullFileName)); else FileName=FullFileName; end - debug(0, "FileName = " + FullFileName) - fid=open(FullFileName,'rb'); # native format (PC-intel). ideasman says maybe rU - content = fid.read(); - content_memory = content - #Header section - NrecordFirstParameterblock, content = getNumber(content,1) # Reading record number of parameter section - - key, content = getNumber(content,1) - if key!=80: - error('File: does not comply to the C3D format') - fid.close() - return - #Paramter section - content = content[512*(NrecordFirstParameterblock-1)+1:] # first word ignored - #file format spec says that 3rd byte=NumberofParmaterRecords... but is ignored here. - proctype,content =getNumber(content,1) - proctype = proctype-83 - proctypes= ["unknown","(INTEL-PC)","(DEC-VAX)","(MIPS-SUN/SGI)"] - - if proctype in (1,2): debug(0, "Processor coding %s"%proctypes[proctype]) - elif proctype==3: debug(0,"Program untested with %s"%proctypes[proctype]) - else: - debug(0, "INVALID processor type %i"%proctype) - proctype=1 - debug(0,"OVERRIDE processor type %i"%proctype) - - #if proctype==2, - # fclose(fid); - # fid=fopen(FullFileName,'r','d'); % DEC VAX D floating point and VAX ordering - #end - debug(10, "***********************") - debug(00, "**** Reading Header ***") - debug(10, "***********************") - - # ############################################### - # ## ## - # ## read header ## - # ## ## - # ############################################### - - #%NrecordFirstParameterblock=fread(fid,1,'int8'); % Reading record number of parameter section - #%key1=fread(fid,1,'int8'); % key = 80; - - content = content_memory - #fseek(fid,2,'bof'); - content = content[2:] - - # - Nmarkers, content=getNumber(content, 2) - NanalogSamplesPerVideoFrame, content = getNumber(content, 2) - StartFrame, content = getNumber(content, 2) - EndFrame, content = getNumber(content, 2) - MaxInterpolationGap, content = getNumber(content, 2) - - Scale, content = getFloat(content,proctype) - - NrecordDataBlock, content = getNumber(content, 2) - NanalogFramesPerVideoFrame, content = getNumber(content, 2) - - if NanalogFramesPerVideoFrame > 0: - NanalogChannels=NanalogSamplesPerVideoFrame/NanalogFramesPerVideoFrame - else: - NanalogChannels=0 - - VideoFrameRate, content = getFloat(content,proctype) - - AnalogFrameRate=VideoFrameRate*NanalogFramesPerVideoFrame - NvideoFrames = EndFrame - StartFrame + 1 - - debug(0, "Scale= %0.2f" %Scale) - debug(0, "NanalogFramesPerVideoFrame= %i" %NanalogFramesPerVideoFrame) - debug(0, "Video Frame Rate= %i" %VideoFrameRate) - debug(0, "AnalogFrame Rate= %i"%AnalogFrameRate) - debug(0, "# markers= %i" %Nmarkers) - debug(0, "StartFrame= %i" %StartFrame) - debug(0, "EndFrame= %i" %EndFrame) - debug(0, "# Video Frames= %i" %NvideoFrames) - - if Scale>0: - debug(0, "Marker data is in integer format") - if Scale>(XYZ_LIMIT/32767): - Scale=XYZ_LIMIT/32767.0 - debug(0, "OVERRIDE: Max coordinate is %i, Scale changed to %0.2f" % (XYZ_LIMIT,Scale)) - else: debug(0, "Marker data is in floating point format") - if VideoFrameRate<1 or VideoFrameRate>120: - VideoFrameRate= 120 - debug(0, "OVERRIDE Video Frame Rate= %i" %VideoFrameRate) - if proctype not in (1,2): # Intel, DEC are known good - debug(0, "OVERRIDE|Program not tested with this encoding. Set to Intel") - proctype= 1 - - debug(10, "***********************") - debug(10, "**** Reading Events ...") - debug(10, "***********************") - - content = content_memory - content = content[298:] #bizarre .. ce devrait être 150 selon la doc rdw skips first 299 bytes? - - EventIndicator, content = getNumber(content, 2) - EventTime=[] - EventValue=[] - EventName=[] - - debug(0, "Event Indicator = %i" %EventIndicator) - if EventIndicator==12345: #rdw: somehow, this original code seems fishy, but I cannot deny it. - Nevents, content = getNumber(content, 2) - debug(0, "Nevents= %i" %Nevents) - content = content[2:] - if Nevents>0: - for i in range(Nevents): - letime, content = getFloat(content,proctype) - EventTime.append(letime) - content = content_memory - content = content[188*2:] - for i in range(Nevents): - lavalue, content = getNumber(content, 1) - EventValue.append(lavalue) - content = content_memory - content = content[198*2:] - for i in range(Nevents): - lenom = content[0:4] - content = content[4:] - EventName.append(lenom) - - debug(00, "***************************") - debug(00, "**** Reading Parameters ...") - debug(10, "***************************") - subjects=[] # a name would be nice, but human will do - prefixes=[] # added on to mocap marker names, one for each subject - marker_subjects = [] # hopefully will be specified in the file and known to this program - markerList=[] - ParameterGroups = [] - ParameterNumberIndex = [] - - content = content_memory - content = content[512*(NrecordFirstParameterblock-1):] - - dat1, content = getNumber(content, 1) - key2, content = getNumber(content, 1) - - NparameterRecords, content = getNumber(content, 1) - debug(100, "NparameterRecords=%i"%NparameterRecords) - proctype,content =getNumber(content,1) - proctype = proctype-83 # proctype: 1(INTEL-PC); 2(DEC-VAX); 3(MIPS-SUN/SGI) - - for i in range(NparameterRecords): - leparam = ParameterGroup(None, None, []) - ParameterGroups.append(leparam) - ParameterNumberIndex.append(0) - # - Ncharacters, content = getNumber(content, 1) - if Ncharacters>=128: - Ncharacters = -(2**8)+(Ncharacters) - GroupNumber, content = getNumber(content, 1) - if GroupNumber>=128: - GroupNumber = -(2**8)+(GroupNumber) - debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters)) - - while Ncharacters > 0: - if GroupNumber<0: - GroupNumber=abs(GroupNumber) - GroupName = content[0:Ncharacters] - content = content[Ncharacters:] - #print "Group Number = ", GroupNumber - ParameterGroups[GroupNumber].name = GroupName - #print "ParameterGroupName =", GroupName - offset, content = getNumber(content, 2) - deschars, content = getNumber(content, 1) - GroupDescription = content[0:deschars] - content = content[deschars:] - ParameterGroups[GroupNumber].description = GroupDescription - # - ParameterNumberIndex[GroupNumber]=0 - content = content[offset-3-deschars:] - else: - - ParameterNumberIndex[GroupNumber]=ParameterNumberIndex[GroupNumber]+1 - ParameterNumber=ParameterNumberIndex[GroupNumber] - #print "ParameterNumber=", ParameterNumber - ParameterGroups[GroupNumber].parameter.append(Parameter(None, None, [], [], None)) - ParameterName = content[0:Ncharacters] - content = content[Ncharacters:] - #print "ParameterName = ",ParameterName - if len(ParameterName)>0: - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].name=ParameterName - offset, content = getNumber(content, 2) - filepos = len(content_memory)-len(content) - nextrec = filepos+offset-2 - - type, content=getNumber(content, 1) - if type>=128: - type = -(2**8)+type - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].type=type - - dimnum, content=getNumber(content, 1) - if dimnum == 0: - datalength = abs(type) - else: - mult=1 - dimension=[] - for j in range (dimnum): - ladim, content = getNumber(content, 1) - dimension.append(ladim) - mult=mult*dimension[j] - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].dim.append(dimension[j]) - datalength = abs(type)*mult - - #print "ParameterNumber = ", ParameterNumber, " Group Number = ", GroupNumber - - if type==-1: - data = "" - wordlength=dimension[0] - if dimnum==2 and datalength>0: - for j in range(dimension[1]): - data=string.rstrip(content[0:wordlength]) - content = content[wordlength:] - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data) - elif dimnum==1 and datalength>0: - data=content[0:wordlength] - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data) # ??? - - myParam=string.rstrip(ParameterName) - myGroup=string.rstrip(GroupName) - msg= "-%s-%s-" % (myGroup,myParam) - if myGroup == "POINT": - if myParam== "LABELS": - # named in form of subject:marker. - # the list "empties" is a corresponding list of actual empty object names that make up the cloud - markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sLABELS = %i %s" %(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points - elif myParam== "LABELS2": #more labels - # named in form of subject:marker. - # the list "empties" is a corresponding list of actual empty object names that make up the cloud - momarkList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - markerList+=momarkList - debug(0, "%sLABELS2 = %i %s" %(msg, len(momarkList),momarkList)) #list of logical markers from 0 to n corresponding to points - else: debug(70, "%s UNUSED = %s" %(msg,ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) - elif myGroup in ["SUBJECT", "SUBJECTS"]: #info about the actor - if myParam in ["NAME", "NAMES"]: - subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sNames of Subjects = %s" %(msg, subjects)) # might be useful in naming armatures - for i in range(len(subjects)): - subjects[i]=subjects[i].rstrip() - if subjects[i]=="": subjects[i]="Human" - elif myParam == "LABEL_PREFIXES": - prefixes = ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sMarker Prefixes = %s" %(msg, prefixes)) # to xlate marker name to that in file - for i in range(len(prefixes)): - prefixes[i]=prefixes[i].rstrip() - elif myParam== "MARKER_SETS": - marker_subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sMarker Set = %s"%(msg, marker_subjects)) # marker set that each subject was wearing - elif myParam== "MODEL_PARAM": - action= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sModel Paramter = %s"%(msg,action)) # might be a good name for the blender scene - elif myParam== "LABELS": - # named in form of subject:marker. - # the list "empties" is a corresponding list of actual empty object names that make up the cloud - markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - debug(0, "%sLABELS = %i %s"%(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points - else: debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) - else: - debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) - elif type == 1: - debug(100,"Block type %i is largely unsupported and untested."%type) - data = [] - Nparameters=datalength/abs(type) - debug(100, "Nparameters=%i"%Nparameters) - for i in range(Nparameters): - ladata,content = getNumber(content, 1) - data.append(ladata) - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - - #print "type boolean" - elif type == 2 and datalength>0: - debug(100,"Block type %i is largely unsupported and untested."%type) - data = [] - Nparameters=datalength/abs(type) - debug(100, "Nparameters=%i"%Nparameters) - for i in range(Nparameters): - ladata,content = getNumber(content, 2) - data.append(ladata) - #ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - if dimnum>1: - #???? print "arg je comprends pas" - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension) - else: - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - #pass - #print "type integer" - elif type == 4 and datalength>0: - debug(100,"Block type %i is largely unsupported and untested."%type) - data = [] - Nparameters=datalength/abs(type) - debug(100, "Nparameters=%i"%Nparameters) - for i in range(Nparameters): - ladata,content = getFloat(content,proctype) - data.append(ladata) - if dimnum>1: - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - #print "arg je comprends pas" - #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension) - else: - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data - #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data - else: - debug(100,"Block type %i is largely unsupported and untested."%type) - #print "error" - pass - deschars, content= getNumber(content, 1) - if deschars>0: - description = content[0:deschars] - content = content[deschars:] - ParameterGroups[GroupNumber].parameter[ParameterNumber-1].description=description - - content = content_memory - content = content[nextrec:] - - Ncharacters,content = getNumber(content, 1) - if Ncharacters>=128: - Ncharacters = -(2**8)+(Ncharacters) - GroupNumber,content = getNumber(content, 1) - if GroupNumber>=128: - GroupNumber = -(2**8)+(GroupNumber) - debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters)) - - debug(00, "***************************") - debug(00, "**** Examining Parameters ...") - debug(10, "***************************") - - if len(subjects)==0: subjects=["Test"] #well, somebody got mocapped! - for i in range(0, len(subjects)-len(prefixes)): prefixes.append("") - for i in range(0, len(subjects)-len(marker_subjects)): marker_subjects.append(subjects[i]) - - #make a markerlist if they didn't - debug(0, "%i Markers specified, %i marker names supplied" %(Nmarkers,len(markerList))) - if len(markerList)==0: - debug(0, "File missing any POINT LABELS marker list. Making defaults") - #I guess just make cloud of empty.xxx - if len(markerList)XYZ_LIMIT or abs(myy)>XYZ_LIMIT or abs(myz)>XYZ_LIMIT: - err+=1 - if err>100: - debug(0, "Warning: 100 data points for markers seem way out there") - debug(0, "data read: (%i, %i, %i)" %(x,y,z)) - debug(0, "Consider revising Scale %0.2f" % Scale) - debug(0, "which now givs coordinates: (%i, %i, %i)" %(x*Scale,y*Scale,z*Scale)) - err=-0 - if abs(myx)>XYZ_LIMIT: myx= XYZ_LIMIT*myx/abs(myx) #preserve sign - if abs(myy)>XYZ_LIMIT: myy= XYZ_LIMIT*myy/abs(myy) #preserve sign - if abs(myz)>XYZ_LIMIT: myz= XYZ_LIMIT*myz/abs(myz) #preserve sign - Markers[i][j].x = myx - Markers[i][j].y = myy - Markers[i][j].z = myz - - a,ptr_read = parseFloat(content, ptr_read, proctype) - a = int(a) - highbyte = int(a/256) - lowbyte=a-highbyte*256 - CameraInfo[i][j] = highbyte - ResidualError[i][j] = lowbyte*abs(Scale) - #Monitor marker location to ensure data block is being parsed properly - if j==0: debug(90,"Frame %i loc of %s: (%i, %i, %i)" % (i,markerList[j],myx,myy,myz)) - if i==0: debug(50, "Initial loc of %s: (%i, %i, %i)" % (markerList[j],myx,myy,myz)) - - ptr_read+=residuals #skip over the following - #for j in range (NanalogFramesPerVideoFrame): - # for k in range(NanalogChannels): - # val, content = getNumber(content, 2) - # AnalogSignals[j+NanalogFramesPerVideoFrame*(i)][k]=val #??? i-1 - #else - # for i=1:NvideoFrames - # for j=1:Nmarkers - # Markers(i,j,1:3)=fread(fid,3,'int16')'.*Scale; - # ResidualError(i,j)=fread(fid,1,'int8'); - # CameraInfo(i,j)=fread(fid,1,'int8'); - # end - # waitbar(i/NvideoFrames) - # for j=1:NanalogFramesPerVideoFrame, - # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=... - # fread(fid,NanalogChannels,'int16')'; - # end - # end - #end - - else: #Scale is positive, but should be <1 to scale down, like 0.05 - two16= -2**16 - if len(content) < NvideoFrames*(Nmarkers*(6+2)+residuals): - error("%i bytes is not enough data for |%i frames|%i markers|%i residual" %(len(content),NvideoFrames,Nmarkers,residuals)) - #Note: I really tried to optimize this loop, since it was taking hours to process - for i in range(NvideoFrames): - if i==0: start=sys.time() - elif i==10: - tmp=(sys.time()-start)*NvideoFrames/600 - debug(0,"%i minutes remaining..." % tmp) - else: print "%i percent complete. On Frame %i Points procesed: %i\r" % (i*100/NvideoFrames,i,i*Nmarkers), - - for j in range(Nmarkers): - #x, content = getNumber(content,2) - # this is old skool signed int, not but not a short. - x = ord(content[ptr_read+0]) + (ord(content[ptr_read+1])<<8) - if x>32768: x+=two16 - y = ord(content[ptr_read+2]) + (ord(content[ptr_read+3])<<8) - if y>32768: y+=two16 - z = ord(content[ptr_read+4]) + (ord(content[ptr_read+5])<<8) - if z>32768: z+=two16 - -## -## x = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) -## ptr_read+=2 -## if x > 32768: -## x=-(2**16)+(x) -## #y, content = getNumber(content,2) -## y = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) -## ptr_read+=2 -## if y > 32768: -## y=-(2**16)+(y) -## #z, content = getNumber(content,2) -## z = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) -## ptr_read+=2 -## if z > 32768: -## z=-(2**16)+(z) -## -## print "(%i=%i, %i=%i, %i=%i)" %(x,myx,y,myy,z,myz) - - # for integers, I changed Scale above to avoid getting impossible numbers - Markers[i][j].x = x*Scale - Markers[i][j].y = y*Scale - Markers[i][j].z = z*Scale - -## ResidualError[i][j], content = getNumber(content, 1) -## CameraInfo[i][j], content = getNumber(content, 1) - #try to improve performance by: - ResidualError[i][j]= ord(content[ptr_read+6]) - CameraInfo[i][j]= ord(content[ptr_read+7]) - - content= content[ptr_read+8:] - ptr_read=0 - - if j==0: debug(100,"Frame %i loc of %s: %s" % (i,markerList[j],Markers[i][j])) - if i==0: debug(50, "Initial loc of %s: (%s)" % (markerList[j],Markers[i][j])) - - #for j in range (NanalogFramesPerVideoFrame): - # for k in range(NanalogChannels): - # val, content = getNumber(content, 2) - #AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=val - ptr_read= residuals # skip over the above - print "\ndone with file." - fid.close() - - cloud= makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers) - - setupAnim(StartFrame, EndFrame,VideoFrameRate) - - debug(10, "**************************") - debug(00, "**** Making %i Armatures" % len(subjects)) - debug(10, "**************************") - for i in range(len(subjects)): - marker_set= marker_subjects[i] - success=False - if len(marker_set)>0: - for trymark in MARKER_SETS: - if trymark[0:len(marker_set)]==marker_set: - marker_set=trymark - success=True - if success: - debug(0, "Armature for %s will be put on layers %s" % (subjects[i],LAYERS_ARMOB)) - debug(0, " based on an markers beginning with %s" % prefixes[i]) - ob= make_arm(subjects[i],prefixes[i],markerList,cloud,marker_set) - else: - debug(00, "Presently, this program can automatically create a constrained armature for marker sets %s" % MARKER_SETS) - debug(00, "%s uses an unknown marker set %s" % (subjects[i],marker_set)) - debug(10, "Have a nice day! If you figure out an armature node system for this cloud, please add it to the program.") - - debug(10, "**************************") - debug(00, "**** Conclusion") - minmax=[0,0,0,0,0,0] - for i in range(NvideoFrames): - for j in range(Nmarkers): - if minmax[0]>Markers[i][j].x: minmax[0]=Markers[i][j].x - if minmax[1]>Markers[i][j].y: minmax[1]=Markers[i][j].y - if minmax[2]>Markers[i][j].z: minmax[2]=Markers[i][j].z - if minmax[3] - - a camera called "10" will become active at frame 10.
- - a camera called "10,25,185" will become active at frames 10, 25 and 185. - -Notes:
- - This script creates another script named camera.py, which is linked to the current scene.
- - If there is already a text called "camera.py", but it's from an old version or is not recognized, -you can choose if you want to rename or overwrite it. - - Script inspired by Jean-Michel (jms) Soler's:
- http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm -""" - - -# $Id$ -# -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004-2005: Regis Montoya -# -# 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 ***** -# -------------------------------------------------------------------------- - -#Script inspired of the idea of this one : -#http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm -# -#---------------------------------------------- -# R3gis Montoya (3R) -# -# Pout tout probleme a: -# cybercreator@free.fr -# --------------------------------------------- - -import Blender -from Blender import * -import string - -header = '# camera.py 1.3 scriptlink' - -camera_change_scriptlink = header + \ -''' -import Blender -def main(): - scn = Blender.Scene.GetCurrent() - frame = str(Blender.Get('curframe')) - - # change the camera if it has the current frame - for ob_cam in [ob for ob in scn.objects if ob.type == 'Camera']: - for number in ob_cam.name.split(','): - if number == frame: - scn.setCurrentCamera(ob_cam) - return -main() -''' - -def main(): - - # Get the text - try: cam_text = Blender.Text.Get('camera.py') - except: cam_text = None - - if cam_text: - if cam_text.asLines()[0] != header: - ret = Blender.Draw.PupMenu("WARNING: An old camera.py exists%t|Overwrite|Rename old version text") - if ret == -1: return # EXIT DO NOTHING - elif ret == 1: Text.unlink(cam_text) - elif ret == 2: cam_text.name = 'old_camera.txt' - cam_text = None - - if not cam_text: - scripting=Blender.Text.New('camera.py') - scripting.write(camera_change_scriptlink) - - scn=Scene.GetCurrent() - scriptlinks = scn.getScriptLinks('FrameChanged') - if not scriptlinks or ('camera.py' not in scriptlinks): - scn.addScriptLink('camera.py','FrameChanged') - Blender.Draw.PupMenu('FrameChange Scriptlink Added%t|Name camera objects to their activation frame numbers(s) seperated by commas|valid names are "1,10,46" or "1,10,200" or "200" (without quotation marks)') - Blender.Window.RedrawAll() - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/config.py b/release/scripts/config.py deleted file mode 100644 index cbf8e272b91..00000000000 --- a/release/scripts/config.py +++ /dev/null @@ -1,801 +0,0 @@ -#!BPY - -""" -Name: 'Scripts Config Editor' -Blender: 236 -Group: 'System' -Tooltip: 'View and edit available scripts configuration data' -""" - -__author__ = "Willian P. Germano" -__version__ = "0.1 2005/04/14" -__email__ = ('scripts', 'Author, wgermano:ig*com*br') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script can be used to view and edit configuration data stored -by other scripts. - -Technical: this data is saved as dictionary keys with the -Blender.Registry module functions. It is persistent while Blender is -running and, if the script's author chose to, is also saved to a file -in the scripts config data dir. - -Usage: - -- Start Screen: - -To access any available key, select it from (one of) the menu(s). - -Hotkeys:
- ESC or Q: [Q]uit
- H: [H]elp - -- Keys Config Screen: - -This screen exposes the configuration data for the chosen script key. If the -buttons don't fit completely on the screen, you can scroll up or down with -arrow keys or a mouse wheel. Leave the mouse pointer over any button to get -a tooltip about that option. - -Any change can be reverted -- unless you have already applied it. - -If the key is already stored in a config file, there will be a toggle button -(called 'file') that controls whether the changes will be written back to -the file or not. If you just want to change the configuration for the current -session, simply unset that button. Note, though, that data from files has -precedence over those keys already loaded in Blender, so if you re-run this -config editor, unsaved changes will not be seen. - -Hotkeys:
- ESC: back to Start Screen
- Q: [Q]uit
- U: [U]ndo changes
- ENTER: apply changes (can't be reverted, then)
- UP, DOWN Arrows and mouse wheel: scroll text up / down - -Notes: - -a) Available keys are determined by which scripts you use. If the key you -expect isn't available (or maybe there are none or too few keys), either the -related script doesn't need or still doesn't support this feature or the key -has not been stored yet, in which case you just need to run that script once -to make its config data available. - -b) There are two places where config data files can be saved: the -bpydata/config/ dir (1) inside the default scripts dir or (2) inside the user -defined Python scripts dir -(User Preferences window -> File Paths tab -> Python path). If available, -(2) is the default and also the recommended option, because then fresh Blender -installations won't delete your config data. To use this option, simply set a -dir for Python scripts at the User Preferences window and make sure this dir -has the subdirs bpydata/ and bpydata/config/ inside it. - -c) The key called "General" in the "Other" menu has general config options. -All scripts where that data is relevant are recommended to access it and set -behaviors accordingly. -""" - -# $Id$ -# -# -------------------------------------------------------------------------- -# config.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br -# -# 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 Blender -from Blender import Draw, BGL, Registry, Window, sys as bsys -from Blender.Window import Theme -from BPyRegistry import LoadConfigData, SaveConfigData, HasConfigData,\ - BPY_KEY_IN_FILE - -MAX_STR_LEN = 300 # max length for a string -MAX_ITEMS_NUM = 100 # max number for each type of button - -# --- -# The "General" configure options key is managed from this script. -verbose = True -confirm_overwrite = True - -tooltips = { - 'verbose': 'print script messages (info, warnings, errors) to the console', - 'confirm_overwrite': 'scripts should always confirm before overwriting files' -} - -CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips'] -KEY_NAME = 'General' - -def update_registry(): - rd = {} - for var in CFG_LIST: - exec("rd['%s']=%s" % (var, var)) - Registry.SetKey(KEY_NAME, rd, True) - -rd = Registry.GetKey('General', True) -if rd: - try: - for var in CFG_LIST[:-1]: # no need to update tooltips - exec("%s=rd['%s']" % (var, var)) - except: update_registry() - -else: - update_registry() -# --- - -# script globals: -CFGKEY = '' -LABELS = [] -GD = {} # groups dict (includes "Other" for unmapped keys) -INDEX = 0 # to pass button indices to fs callbacks -FREEKEY_IDX = 0 # index of set of keys not mapped to a script name -KEYMENUS = [] -ALL_SCRIPTS = {} -ALL_GROUPS = [] -START_SCREEN = 0 -CONFIG_SCREEN = 1 -DISK_UPDATE = True # write changed data to its config file - -ACCEPTED_TYPES = [bool, int, float, str, unicode] - -SCREEN = START_SCREEN - -SCROLL_DOWN = 0 - -# events: -BEVT_START = 50 -BEVT_EXIT = 0 + BEVT_START -BEVT_BACK = 1 + BEVT_START -BEVT_DISK = 2 + BEVT_START -BEVT_CANCEL = 3 + BEVT_START -BEVT_APPLY = 4 + BEVT_START -BEVT_HELP = 5 + BEVT_START -BEVT_DEL = 6 + BEVT_START -BEVT_KEYMENU = [] -BUT_KEYMENU = [] -BEVT_BOOL = 100 -BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM -BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM -BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM -BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM -BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM -BUT_TYPES = { - bool: 0, - int: 0, - float: 0, - str: 0 -} - -# Function definitions: - -def get_keys(): - LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/ - return [k for k in Registry.Keys() if k[0] != "_"] - - -def show_help(script = 'config.py'): - Blender.ShowHelp(script) - - -def fs_dir_callback(pathname): - global CFGKEY, INDEX - - pathname = bsys.dirname(pathname) - datatypes = CFGKEY.sorteddata - datatypes[str][INDEX][1] = pathname - - -def fs_file_callback(pathname): - global CFGKEY, INDEX - - datatypes = CFGKEY.sorteddata - datatypes[str][INDEX][1] = pathname - - -# parse Bpymenus file to get all script filenames -# (used to show help for a given key) -def fill_scripts_dict(): - global ALL_SCRIPTS, ALL_GROUPS - - group = '' - group_len = 0 - sep = bsys.sep - home = Blender.Get('homedir') - if not home: - errmsg = """ -Can't find Blender's home dir and so can't find the -Bpymenus file automatically stored inside it, which -is needed by this script. Please run the -Help -> System -> System Information script to get -information about how to fix this. -""" - raise SystemError, errmsg - fname = bsys.join(home, 'Bpymenus') - if not bsys.exists(fname): return False - f = file(fname, 'r') - lines = f.readlines() - f.close() - for l in lines: - if l.rfind('{') > 0: - group = l.split()[0] - ALL_GROUPS.append(group) - group_len += 1 - continue - elif l[0] != "'": continue - fields = l.split("'") - if len(fields) > 2: - menuname = fields[1].replace('...','') - fields = fields[2].split() - if len(fields) > 1: - fname = fields[1].split(sep)[-1] - i = 1 - while not fname.endswith('.py'): - i += 1 - fname = "%s %s" % (fname, fields[i]) - ALL_SCRIPTS[fname] = (menuname, group_len - 1) - return True - - -def map_to_registered_script(name): - global ALL_SCRIPTS - - if not name.endswith('.py'): - name = "%s.py" % name - if ALL_SCRIPTS.has_key(name): - return ALL_SCRIPTS[name] # == (menuname, group index) - return None - - -def reset(): - global LABELS, GD, KEYMENUS, KEYS - - # init_data is recalled when a key is deleted, so: - LABELS = [] - GD = {} - KEYMENUS = [] - KEYS = get_keys() - - -# gather all script info, fill gui menus -def init_data(): - global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS - global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX - - for k in ALL_GROUPS: - GD[k] = [] - GD[None] = [] - - for k in KEYS: - res = map_to_registered_script(k) - if res: - GD[ALL_GROUPS[res[1]]].append((k, res[0])) - else: GD[None].append((k, k)) - - for k in GD.keys(): - if not GD[k]: GD.pop(k) - - if GD.has_key(None): - GD['Other'] = GD[None] - GD.pop(None) - FREEKEY_IDX = -1 - - BUT_KEYMENU = range(len(GD)) - - for k in GD.keys(): - kmenu = ['Configuration Keys: %s%%t' % k] - for j in GD[k]: - kmenu.append(j[1]) - kmenu = "|".join(kmenu) - KEYMENUS.append(kmenu) - LABELS.append(k) - - if FREEKEY_IDX < 0: - FREEKEY_IDX = LABELS.index('Other') - - length = len(KEYMENUS) - BEVT_KEYMENU = range(1, length + 1) - BUT_KEYMENU = range(length) - - -# for theme colors: -def float_colors(cols): - return map(lambda x: x / 255.0, cols) - - - -class Config: - - def __init__(self, key, has_group = True): - global DISK_UPDATE - - self.key = key - self.has_group = has_group - self.name = key - self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE - if not self.fromdisk: DISK_UPDATE = False - else: DISK_UPDATE = True - - self.origdata = Registry.GetKey(key, True) - data = self.data = self.origdata.copy() - - if not data: - Draw.PupMenu('ERROR: couldn\'t find requested data') - self.data = None - return - - keys = data.keys() - nd = {} - for k in keys: - nd[k.lower()] = k - - if nd.has_key('tooltips'): - ndval = nd['tooltips'] - self.tips = data[ndval] - data.pop(ndval) - else: self.tips = 0 - - if nd.has_key('limits'): - ndval = nd['limits'] - self.limits = data[ndval] - data.pop(ndval) - else: self.limits = 0 - - if self.has_group: - scriptname = key - if not scriptname.endswith('.py'): - scriptname = "%s.py" % scriptname - elif nd.has_key('script'): - ndval = nd['script'] - scriptname = data[ndval] - data.pop(ndval) - if not scriptname.endswith('.py'): - scriptname = "%s.py" % scriptname - else: scriptname = None - - self.scriptname = scriptname - - self.sort() - - - def needs_update(self): # check if user changed data - data = self.data - new = self.sorteddata - - for vartype in new.keys(): - for i in new[vartype]: - if data[i[0]] != i[1]: return 1 - - return 0 # no changes - - - def update(self): # update original key - global DISK_UPDATE - - data = self.data - odata = self.origdata - new = self.sorteddata - for vartype in new.keys(): - for i in new[vartype]: - if data[i[0]] != i[1]: data[i[0]] = i[1] - if odata[i[0]] != i[1]: odata[i[0]] = i[1] - - if DISK_UPDATE: Registry.SetKey(self.key, odata, True) - - def delete(self): - global DISK_UPDATE - - delmsg = 'OK?%t|Delete key from memory' - if DISK_UPDATE: - delmsg = "%s and from disk" % delmsg - if Draw.PupMenu(delmsg) == 1: - Registry.RemoveKey(self.key, DISK_UPDATE) - return True - - return False - - - def revert(self): # revert to original key - data = self.data - new = self.sorteddata - for vartype in new.keys(): - for i in new[vartype]: - if data[i[0]] != i[1]: i[1] = data[i[0]] - - - def sort(self): # create a new dict with types as keys - global ACCEPTED_TYPES, BUT_TYPES - - data = self.data - datatypes = {} - keys = [k for k in data.keys() if k[0] != '_'] - for k in keys: - val = data[k] - tval = type(val) - if tval not in ACCEPTED_TYPES: continue - if not datatypes.has_key(tval): - datatypes[tval] = [] - datatypes[type(val)].append([k, val]) - if datatypes.has_key(unicode): - if not datatypes.has_key(str): datatypes[str] = datatypes[unicode] - else: - for i in datatypes[unicode]: datatypes[str].append(i) - datatypes.pop(unicode) - for k in datatypes.keys(): - dk = datatypes[k] - dk.sort() - dk.reverse() - BUT_TYPES[k] = range(len(dk)) - self.sorteddata = datatypes - - -# GUI: - -# gui callbacks: - -def gui(): # drawing the screen - - global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS - global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY - global BUT_TYPES, SCROLL_DOWN, VARS_NUM - - WIDTH, HEIGHT = Window.GetAreaSize() - - theme = Theme.Get()[0] - tui = theme.get('ui') - ttxt = theme.get('text') - - COL_BG = float_colors(ttxt.back) - COL_TXT = ttxt.text - COL_TXTHI = ttxt.text_hi - - BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) - BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) - BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) - - if SCREEN == START_SCREEN: - x = 10 - y = 10 - h = 20 - w = 90 - BGL.glRasterPos2i(x, y) - Draw.Text('Select a configuration key to access it. Press Q or ESC to leave.') - km_len = len(KEYMENUS) - km_columns = (WIDTH - x) / w - if km_columns == 0: km_rows = km_len - else: - km_rows = km_len / km_columns - if (km_len % km_columns): km_rows += 1 - if km_rows == 0: km_rows = 1 - ystart = y + 2*h*km_rows - if ystart > (HEIGHT - 70): ystart = HEIGHT - 70 - y = ystart - column = 1 - for i, km in enumerate(KEYMENUS): - column += 1 - BGL.glRasterPos2i(x + 2, y + h + 5) - Draw.Text(LABELS[i]) - BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i], - x, y, w - 10, h, 0, 'Choose a key to access its configuration data') - if column > km_columns: - column = 1 - y -= 2*h - if y < 35: break - x = 10 - else: x += w - x = 10 - y = 50 + ystart - BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2]) - BGL.glRasterPos2i(x, y) - Draw.Text('Scripts Configuration Editor') - Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16, - 'View help information about this script (hotkey: H)') - - elif SCREEN == CONFIG_SCREEN: - x = y = 10 - h = 18 - data = CFGKEY.sorteddata - tips = CFGKEY.tips - fromdisk = CFGKEY.fromdisk - limits = CFGKEY.limits - VARS_NUM = 0 - for k in data.keys(): - VARS_NUM += len(data[k]) - lines = VARS_NUM + 5 # to account for header and footer - y = lines*h - if y > HEIGHT - 20: y = HEIGHT - 20 - BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) - BGL.glRasterPos2i(x, y) - Draw.Text('Scripts Configuration Editor') - y -= 20 - BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) - txtsize = 10 - if HEIGHT < lines*h: - BGL.glRasterPos2i(10, 5) - txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ') - BGL.glRasterPos2i(txtsize, 5) - Draw.Text('Q or ESC to return.') - BGL.glRasterPos2i(x, y) - Draw.Text('Key: "%s"' % CFGKEY.name) - bh = 16 - bw = 45 - by = 16 - i = -1 - if CFGKEY.scriptname: - i = 0 - Draw.PushButton('help', BEVT_HELP, x, by, bw, bh, - 'Show documentation for the script that owns this key (hotkey: H)') - Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh, - 'Back to config keys selection screen (hotkey: ESC)') - Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh, - 'Exit from Scripts Config Editor (hotkey: Q)') - Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh, - 'Revert data to original values (hotkey: U)') - Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh, - 'Apply changes, if any (hotkey: ENTER)') - delmsg = 'Delete this data key from memory' - if fromdisk: delmsg = "%s and from disk" % delmsg - Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh, - '%s (hotkey: DELETE)' % delmsg) - if fromdisk: - Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE, - 'Update also the file where this config key is stored') - i = -1 - top = -1 - y -= 20 - yend = 30 - if data.has_key(bool) and y > 0: - lst = data[bool] - for l in lst: - top += 1 - i += 1 - if top < SCROLL_DOWN: continue - y -= h - if y < yend: break - w = 20 - tog = data[bool][i][1] - if tips and tips.has_key(l[0]): tooltip = tips[l[0]] - else: tooltip = "click to toggle" - BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i, - x, y, w, h, tog, tooltip) - BGL.glRasterPos2i(x + w + 3, y + 5) - Draw.Text(l[0].lower().replace('_', ' ')) - i = -1 - y -= 5 - if data.has_key(int) and y > 0: - lst = data[int] - for l in lst: - w = 70 - top += 1 - i += 1 - if top < SCROLL_DOWN: continue - y -= h - if y < yend: break - val = data[int][i][1] - if limits: min, max = limits[l[0]] - else: min, max = 0, 10 - if tips and tips.has_key(l[0]): tooltip = tips[l[0]] - else: tooltip = "click / drag to change" - BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i, - x, y, w, h, val, min, max, tooltip) - BGL.glRasterPos2i(x + w + 3, y + 3) - Draw.Text(l[0].lower().replace('_', ' ')) - i = -1 - y -= 5 - if data.has_key(float) and y > 0: - lst = data[float] - for l in lst: - w = 70 - top += 1 - i += 1 - if top < SCROLL_DOWN: continue - y -= h - if y < yend: break - val = data[float][i][1] - if limits: min, max = limits[l[0]] - else: min, max = 0.0, 1.0 - if tips and tips.has_key(l[0]): tooltip = tips[l[0]] - else: tooltip = "click and drag to change" - BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i, - x, y, w, h, val, min, max, tooltip) - BGL.glRasterPos2i(x + w + 3, y + 3) - Draw.Text(l[0].lower().replace('_', ' ')) - i = -1 - y -= 5 - if data.has_key(str) and y > 0: - lst = data[str] - for l in lst: - top += 1 - i += 1 - if top < SCROLL_DOWN: continue - y -= h - if y < yend: break - name = l[0].lower() - is_dir = is_file = False - if name.find('_dir', -4) > 0: is_dir = True - elif name.find('_file', -5) > 0: is_file = True - w = WIDTH - 20 - wbrowse = 50 - if is_dir and w > wbrowse: w -= wbrowse - if tips and tips.has_key(l[0]): tooltip = tips[l[0]] - else: tooltip = "click to write a new string" - name = name.replace('_',' ') + ': ' - if len(l[1]) > MAX_STR_LEN: - l[1] = l[1][:MAX_STR_LEN] - BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i, - x, y, w, h, l[1], MAX_STR_LEN, tooltip) - if is_dir: - Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h, - 'click to open a file selector (pick any file in the desired dir)') - elif is_file: - Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h, - 'click to open a file selector') - - -def fit_scroll(): - global SCROLL_DOWN, VARS_NUM - max = VARS_NUM - 1 # so last item is always visible - if SCROLL_DOWN > max: - SCROLL_DOWN = max - elif SCROLL_DOWN < 0: - SCROLL_DOWN = 0 - - -def event(evt, val): # input events - - global SCREEN, START_SCREEN, CONFIG_SCREEN - global SCROLL_DOWN, CFGKEY - - if not val: return - - if evt == Draw.ESCKEY: - if SCREEN == START_SCREEN: Draw.Exit() - else: - if CFGKEY.needs_update(): - if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: - CFGKEY.update() - SCREEN = START_SCREEN - SCROLL_DOWN = 0 - Draw.Redraw() - return - elif evt == Draw.QKEY: - if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update(): - if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: - CFGKEY.update() - Draw.Exit() - return - elif evt == Draw.HKEY: - if SCREEN == START_SCREEN: show_help() - elif CFGKEY.scriptname: show_help(CFGKEY.scriptname) - return - - elif SCREEN == CONFIG_SCREEN: - if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]: - SCROLL_DOWN += 1 - fit_scroll() - elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]: - SCROLL_DOWN -= 1 - fit_scroll() - elif evt == Draw.UKEY: - if CFGKEY.needs_update(): - CFGKEY.revert() - elif evt == Draw.RETKEY or evt == Draw.PADENTER: - if CFGKEY.needs_update(): - CFGKEY.update() - elif evt == Draw.DELKEY: - if CFGKEY.delete(): - reset() - init_data() - SCREEN = START_SCREEN - SCROLL_DOWN = 0 - else: return - Draw.Redraw() - - -def button_event(evt): # gui button events - - global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE - global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX - global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX - - if SCREEN == START_SCREEN: - for e in BEVT_KEYMENU: - if evt == e: - index = e - 1 - k = BUT_KEYMENU[index].val - 1 - CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX) - if CFGKEY.data: - SCREEN = CONFIG_SCREEN - Draw.Redraw() - return - if evt == BEVT_EXIT: - Draw.Exit() - elif evt == BEVT_HELP: - show_help() - return - - elif SCREEN == CONFIG_SCREEN: - datatypes = CFGKEY.sorteddata - if evt >= BEVT_BROWSEFILE: - INDEX = evt - BEVT_BROWSEFILE - Window.FileSelector(fs_file_callback, 'Choose file') - elif evt >= BEVT_BROWSEDIR: - INDEX = evt - BEVT_BROWSEDIR - Window.FileSelector(fs_dir_callback, 'Choose any file') - elif evt >= BEVT_STR: - var = BUT_TYPES[str][evt - BEVT_STR].val - datatypes[str][evt - BEVT_STR][1] = var - elif evt >= BEVT_FLOAT: - var = BUT_TYPES[float][evt - BEVT_FLOAT].val - datatypes[float][evt - BEVT_FLOAT][1] = var - elif evt >= BEVT_INT: - var = BUT_TYPES[int][evt - BEVT_INT].val - datatypes[int][evt - BEVT_INT][1] = var - elif evt >= BEVT_BOOL: - var = datatypes[bool][evt - BEVT_BOOL][1] - if var == True: var = False - else: var = True - datatypes[bool][evt - BEVT_BOOL][1] = var - - elif evt == BEVT_BACK: - if SCREEN == CONFIG_SCREEN: - SCREEN = START_SCREEN - SCROLL_DOWN = 0 - Draw.Redraw() - elif evt == BEVT_EXIT: - if CFGKEY.needs_update(): - if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: - CFGKEY.update() - Draw.Exit() - return - elif evt == BEVT_APPLY: - if CFGKEY.needs_update(): - CFGKEY.update() - elif evt == BEVT_CANCEL: - if CFGKEY.needs_update(): - CFGKEY.revert() - elif evt == BEVT_DEL: - if CFGKEY.delete(): - reset() - init_data() - SCREEN = START_SCREEN - SCROLL_DOWN = 0 - elif evt == BEVT_DISK: - if DISK_UPDATE: DISK_UPDATE = False - else: DISK_UPDATE = True - elif evt == BEVT_HELP: - show_help(CFGKEY.scriptname) - return - else: - return - Draw.Redraw() - -# End of definitions - - -KEYS = get_keys() - -if not KEYS: - Draw.PupMenu("NO DATA: please read this help screen") - Blender.ShowHelp('config.py') -else: - fill_scripts_dict() - init_data() - Draw.Register(gui, event, button_event) diff --git a/release/scripts/console.py b/release/scripts/console.py deleted file mode 100644 index c6ae22a86f5..00000000000 --- a/release/scripts/console.py +++ /dev/null @@ -1,861 +0,0 @@ -#!BPY - -""" -Name: 'Interactive Python Console' -Blender: 245 -Group: 'System' -Tooltip: 'Interactive Python Console' -""" - -__author__ = "Campbell Barton aka ideasman42" -__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] -__bpydoc__ = """\ -This is an interactive console, similar to Python's own command line interpreter. Since it is embedded in Blender, it has access to all Blender Python modules. - -Those completely new to Python are recommended to check the link button above -that points to its official homepage, with news, downloads and documentation. - -Usage:
- Type your code and hit "Enter" to get it executed.
- - Right mouse click: Console Menu (Save output, etc);
- - Mousewheel: Scroll text - - Arrow keys: command history and cursor;
- - Shift + Backspace: Backspace whole word;
- - Shift + Arrow keys: jump words;
- - Ctrl + (+/- or mousewheel): Zoom text size;
- - Ctrl + Enter: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;
- - Shift + Enter: multiline functions -- delays executing code until only Enter is pressed. -""" - -# -------------------------------------------------------------------------- -# ***** 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 Blender -import bpy -from Blender import * -import sys as python_sys -import StringIO - -# Constants -__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t' -__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t' - -__LINE_HISTORY__ = 500 - -global __FONT_SIZE__ - -__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normalfix', 14), ('large', 16) ) -__FONT_SIZE__ = 2 # index for the list above, normal default. - -global __CONSOLE_LINE_OFFSET__ -__CONSOLE_LINE_OFFSET__ = 0 - -cmdBuffer = [] # dosnt need to be global - -''' -# Generic Blender functions -def getActScriptWinRect(): - area = Window.GetAreaSize() - area = (area[0]-1, area[1]-1) - for scrInfo in Window.GetScreenInfo(Window.Types['SCRIPT'], 'win', ''): - if scrInfo['vertices'][2]-scrInfo['vertices'][0] == area[0]: - if scrInfo['vertices'][3]-scrInfo['vertices'][1] == area[1]: - return scrInfo['vertices'] - return None -''' - - -# menuText, # per group -def PupMenuLess(menu, groupSize=35): - more = [' more...'] - less = [' less...'] - - menuList= menu.split('|') - - # No Less Needed, just call. - if len(menuList) < groupSize: - return Draw.PupMenu(menu) - - title = menuList[0].split('%t')[0] - - # Split the list into groups - menuGroups = [[]] - for li in menuList[1:]: - if len(menuGroups[-1]) < groupSize: - menuGroups[-1].append(li) - else: - menuGroups.append([li]) - - # Stores teh current menu group we are looking at - groupIdx = 0 - while 1: - # Give us a title with the menu number - numTitle = [ ' '.join([title, str(groupIdx + 1), 'of', str(len(menuGroups)), '%t'])] - if groupIdx == 0: - menuString = '|'.join(numTitle + menuGroups[groupIdx] + more) - elif groupIdx == len(menuGroups)-1: - menuString = '|'.join(numTitle + less + menuGroups[groupIdx]) - else: # In the middle somewhere so Show a more and less - menuString = '|'.join(numTitle + less + menuGroups[groupIdx] + more) - result = Draw.PupMenu(menuString) - # User Exit - if result == -1: - return -1 - - if groupIdx == 0: # First menu - if result-1 < groupSize: - return result - else: # must be more - groupIdx +=1 - elif groupIdx == len(menuGroups): # Last Menu - if result == 1: # Must be less - groupIdx -= 1 - else: # Must be a choice - return result + (groupIdx*groupSize) - - else: - if result == 1: # Must be less - groupIdx -= 1 - elif result-2 == groupSize: - groupIdx +=1 - else: - return result - 1 + (groupIdx*groupSize) - - - -# Use newstyle classes, Im not bothering with inheretence -# but slots are faster. -class cmdLine(object): - __slots__ = [\ - 'cmd', # is the command string, or any other message - 'type',# type: 0:user input 1:program feedback 2:error message. 3:option feedback - 'exe' # 0- not yet executed 1:executed - ] - def __init__(self, cmd, type, exe): - self.cmd = cmd - self.type = type - self.exe = exe - -# Include external file with internal namespace -def include(filename): - file = open(filename, 'r') - filedata = file.read() - file.close() - return compile(filedata, filename, 'exec') - -# Writes command line data to a blender text file. -def writeCmdData(type): - newText = Text.New('command_output.py', 1) - if type == 3: newText.write('\n'.join( [ myCmd.cmd for myCmd in cmdBuffer ] )) - else: newText.write('\n'.join( [ myCmd.cmd for myCmd in cmdBuffer if myCmd.type is type] )) - Draw.PupMenu('%s written' % newText.name) - -def insertCmdData(): - texts = list(bpy.data.texts) - textNames = [tex.name for tex in texts] - if textNames: - choice = Draw.PupMenu('|'.join(textNames)) - if choice != -1: - text = texts[choice-1] - - # Add the text! - for l in text.asLines(): - cmdBuffer.append(cmdLine('%s ' % l, 0, 0)) - Draw.Redraw() - - -COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths - -# Pain and simple recursice dir(), accepts a string -unused_types = str, dict, list, float, int, str, type, tuple, type(dir), type(None) -def rdir(dirString, depth=0): - #print ' ' * depth, dirString - # MAX DEPTH SET HERE - if depth > 5: - # print 'maxdepoth reached.' - return - - global COLLECTED_VAR_NAMES - dirStringSplit = dirString.split('.') - - exec('value=' + dirString) - - if type(value) in unused_types: - # print 'bad type' - return - dirList = dir(value) - - for dirItem in dirList: - if dirItem.startswith('_'): - continue - - dirData = None - try: - # Rare cases this can mess up, material.shader was a problem. - exec('dirData = %s.%s' % (dirString, dirItem)) - #print dirData - except: - # Dont bother with this data. - continue - #print 'HEY', dirData, dirItem - #if type(dirItem) != str: - # print dirItem, type(dirItem) - - if dirItem not in COLLECTED_VAR_NAMES: # .keys() - COLLECTED_VAR_NAMES[dirItem] = [] - - # Add the string - # splitD = dirString.split('"')[-2] - - # Example of dirString - # __CONSOLE_VAR_DICT__["Main"].scenes.active.render - - # Works but can be faster - # splitD = dirString.replace('__CONSOLE_VAR_DICT__["', '').replace('"]', '') - - splitD = dirString[22:].replace('"]', '') - - if splitD not in COLLECTED_VAR_NAMES[dirItem]: - # print dirItem, dirString, splitD, - COLLECTED_VAR_NAMES[dirItem].append(splitD) - - - # Stops recursice stuff, overlooping - #print type(dirItem) - #if type(dirData) == types.ClassType or \ - # type(dirData) == types.ModuleType: - type_dirData = type(dirData) - if type_dirData not in unused_types: - # print type(dirData), dirItem - # Dont loop up dirs for strings ints etc. - if dirItem not in dirStringSplit: - rdir( '%s.%s' % (dirString, dirItem), depth+1) - ''' - elif depth == 0: # Add local variables - # print type(dirData), dirItem - # Dont loop up dirs for strings ints etc. - if dirItem not in dirStringSplit: - rdir( '%s.%s' % (dirString, dirItem), depth+1) - ''' - -def recursive_dir(): - global COLLECTED_VAR_NAMES - - for name in __CONSOLE_VAR_DICT__: # .keys() - if not name.startswith('_'): # Dont pick names like __name__ - rdir('__CONSOLE_VAR_DICT__["%s"]' % name) - #print COLLECTED_VAR_NAMES - COLLECTED_VAR_NAMES[name] = [''] - return COLLECTED_VAR_NAMES - -# Runs the code line(s) the user has entered and handle errors -# As well as feeding back the output into the blender window. -def runUserCode(__USER_CODE_STRING__): - global __CONSOLE_VAR_DICT__ # We manipulate the variables here. loading and saving from localspace to this global var. - - # Open A File like object to write all output to, that would useually be printed. - python_sys.stdout.flush() # Get rid of whatever came before - __FILE_LIKE_STRING__ = StringIO.StringIO() # make a new file like string, this saves up from making a file. - __STD_OUTPUT__ = python_sys.stdout # we need to store the normal output. - python_sys.stdout=__FILE_LIKE_STRING__ # Now anything printed will be written to the file like string. - - # Try and run the user entered line(s) - try: - # Load all variabls from global dict to local space. - __TMP_VAR_NAME__ = __TMP_VAR__ = '' # so as not to raise an error when del'ing - - for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items(): - exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__')) - del __TMP_VAR_NAME__ - del __TMP_VAR__ - - # Now all the vars are loaded, execute the code. # Newline thanks to phillip, - exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec')) - - # Flush global dict, allow the user to remove items. - __CONSOLE_VAR_DICT__ = {} - - __TMP_VAR_NAME__ = '' # so as not to raise an error when del'ing - # Write local veriables to global __CONSOLE_VAR_DICT__ - for __TMP_VAR_NAME__ in dir(): - if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\ - __TMP_VAR_NAME__ != '__STD_OUTPUT__' and\ - __TMP_VAR_NAME__ != '__TMP_VAR_NAME__' and\ - __TMP_VAR_NAME__ != '__USER_CODE_STRING__': - - # Execute the local > global coversion. - exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) - del __TMP_VAR_NAME__ - - except: # Prints the REAL exception. - error = '%s: %s' % (python_sys.exc_type, python_sys.exc_value) - for errorLine in error.split('\n'): - cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into - - python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console - - # Copy all new output to cmdBuffer - - __FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file. - - for line in __FILE_LIKE_STRING__.readlines(): - cmdBuffer.append(cmdLine(line, 1, None)) - - cmdBuffer.append(cmdLine(' ', 0, 0)) # new line to type into - python_sys.stdout=__STD_OUTPUT__ - __FILE_LIKE_STRING__.close() - - - - - -#------------------------------------------------------------------------------# -# event handling code # -#------------------------------------------------------------------------------# -def handle_event(evt, val): - - # Insert Char into the cammand line - def insCh(ch): # Instert a char - global cursor - # Later account for a cursor variable - cmdBuffer[-1].cmd = ('%s%s%s' % ( cmdBuffer[-1].cmd[:cursor], ch, cmdBuffer[-1].cmd[cursor:])) - - #------------------------------------------------------------------------------# - # Define Complex Key Actions # - #------------------------------------------------------------------------------# - def actionEnterKey(): - global histIndex, cursor - - def getIndent(string): - # Gather white space to add in the previous line - # Ignore the last char since its padding. - whiteSpace = '' - #for i in range(len(cmdBuffer[-1].cmd)): - for i in xrange(len(string)-1): - if cmdBuffer[-1].cmd[i] == ' ' or cmdBuffer[-1].cmd[i] == '\t': - whiteSpace += string[i] - else: - break - return whiteSpace - - # Autocomplete - if Window.GetKeyQualifiers() & Window.Qual.CTRL: - actionAutoCompleate() - return - - # Are we in the middle of a multiline part or not? - # try be smart about it - if cmdBuffer[-1].cmd.split('#')[0].rstrip().endswith(':'): - # : indicates an indent is needed - cmdBuffer.append(cmdLine('\t%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) - print ': indicates an indent is needed' - - elif cmdBuffer[-1].cmd[0] in [' ', '\t'] and len(cmdBuffer[-1].cmd) > 1 and cmdBuffer[-1].cmd.split(): - # white space at the start means he havnt finished the multiline. - cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) - print 'white space at the start means he havnt finished the multiline.' - - elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: - # Crtl forces multiline - cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) - print 'Crtl forces multiline' - - else: # Execute multiline code block - - # Multiline code will still run with 1 line, - multiLineCode = ['if 1:'] # End of the multiline first. - - # Seek the start of the file multiline - i = 1 - while cmdBuffer[-i].exe == 0: - i+=1 - - while i > 1: - i-=1 - - if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history - cmdBuffer[-i].type = 1 - else: # Tab added at the start for added if 1: statement - multiLineCode.append('\t%s' % cmdBuffer[-i].cmd ) - - # Mark as executed - cmdBuffer[-i].exe = 1 - - multiLineCode.append('\tpass') # reverse will make this the start. - - # Dubug, print the code that is executed. - #for m in multiLineCode: print m - - runUserCode('\n'.join(multiLineCode)) - - # Clear the output based on __LINE_HISTORY__ - if len(cmdBuffer) > __LINE_HISTORY__: - cmdBuffer[:__LINE_HISTORY__] = [] - - histIndex = cursor = -1 # Reset cursor and history - - def actionUpKey(): - global histIndex - if abs(histIndex)+1 >= len(cmdBuffer): - histIndex = -1 - - # When wrapping allow 1 plank lines - if cmdBuffer[-1].cmd != ' ': - cmdBuffer[-1].cmd = ' ' - return - - histIndex_orig = histIndex - histIndex -= 1 - - while (cmdBuffer[histIndex].type != 0 and abs(histIndex) < len(cmdBuffer)) or \ - ( cmdBuffer[histIndex].cmd == cmdBuffer[histIndex_orig].cmd): - histIndex -= 1 - - if cmdBuffer[histIndex].type == 0: # we found one - cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd - - def actionDownKey(): - global histIndex - if histIndex >= -2: - histIndex = -len(cmdBuffer) - - # When wrapping allow 1 plank lines - if cmdBuffer[-1].cmd != ' ': - cmdBuffer[-1].cmd = ' ' - return - - histIndex_orig = histIndex - histIndex += 1 - while (cmdBuffer[histIndex].type != 0 and histIndex != -2) or \ - ( cmdBuffer[histIndex].cmd == cmdBuffer[histIndex_orig].cmd): - - histIndex += 1 - - if cmdBuffer[histIndex].type == 0: # we found one - cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd - - def actionRightMouse(): - global __FONT_SIZE__ - choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Clear Output|Quit') - - if choice == 1: - writeCmdData(0) # type 0 user - elif choice == 2: - writeCmdData(1) # type 1 user output - elif choice == 3: - writeCmdData(2) # type 2 errors - elif choice == 4: - writeCmdData(3) # All - elif choice == 6: - insertCmdData() # Insert text from Blender and run it. - elif choice == 8: - # Fontsize. - font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny') - if font_choice != -1: - if font_choice == 1: - __FONT_SIZE__ = 3 - elif font_choice == 2: - __FONT_SIZE__ = 2 - elif font_choice == 3: - __FONT_SIZE__ = 1 - elif font_choice == 4: - __FONT_SIZE__ = 0 - Draw.Redraw() - elif choice == 10: # Clear all output - cmdBuffer[:] = [cmd for cmd in cmdBuffer if cmd.type == 0] # keep user input - Draw.Redraw() - elif choice == 11: # Exit - Draw.Exit() - - - # Auto compleating, quite complex- use recutsice dir for the moment. - def actionAutoCompleate(): # Ctrl + Tab - if not cmdBuffer[-1].cmd[:cursor].split(): - return - - - RECURSIVE_DIR = recursive_dir() - - # get last name of user input - editVar = cmdBuffer[-1].cmd[:cursor] - # Split off spaces operators etc from the staryt of the command so we can use the startswith function. - for splitChar in __VARIABLE_DELIMETERS__: - editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1] - - - # Now we should have the var by its self - if editVar: - possibilities = [] - - for __TMP_VAR_NAME__ in RECURSIVE_DIR: #.keys(): - #print '\t', __TMP_VAR_NAME__ - if __TMP_VAR_NAME__ == editVar: - # print 'ADITVAR IS A VAR' - pass - ''' - elif __TMP_VAR_NAME__.startswith( editVar ): - print __TMP_VAR_NAME__, 'aaa' - possibilities.append( __TMP_VAR_NAME__ ) - ''' - possibilities.append( __TMP_VAR_NAME__ ) - - if len(possibilities) == 1: - cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:])) - - elif possibilities: # If its not just [] - # -1 with insert is the second last. - - # Text choice - #cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None)) - - menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE - - for __TMP_VAR_NAME__ in possibilities: - for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]: - # Account for non absolute (variables for eg.) - if usage: # not '' - absName = '%s.%s' % (usage, __TMP_VAR_NAME__) - - if __TMP_VAR_NAME__.startswith(editVar): - menuList.append( # Used for names and can be entered when pressing shift. - (absName, # Absolute name - __TMP_VAR_NAME__) # Relative name, non shift - ) - - #else: - # if absName.find(editVar) != -1: - # menuList.append((__TMP_VAR_NAME__, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift. - - # No items to display? no menu - if not menuList: - return - - menuList.sort() - - choice = PupMenuLess( # Menu for the user to choose the autocompleate - 'Choices (Shift for local name, Ctrl for Docs)%t|' + # Title Text - '|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0] - - if choice != -1: - if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help - cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0])) - elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name - cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:])) - else: # Only paste in the Short name - cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:])) - - - else: - # print 'NO EDITVAR' - return - - # ------------------end------------------ # - - # Quit from menu only - #if (evt == Draw.ESCKEY and not val): - # Draw.Exit() - if evt == Draw.MOUSEX or evt == Draw.MOUSEY: # AVOID TOO MANY REDRAWS. - return - - - global cursor - global histIndex - global __FONT_SIZE__ - global __CONSOLE_LINE_OFFSET__ - - ascii = Blender.event - - resetScroll = True - - #------------------------------------------------------------------------------# - # key codes and key handling # - #------------------------------------------------------------------------------# - - # UP DOWN ARROW KEYS, TO TRAVERSE HISTORY - if (evt == Draw.UPARROWKEY and val): actionUpKey() - elif (evt == Draw.DOWNARROWKEY and val): actionDownKey() - - elif (evt == Draw.RIGHTARROWKEY and val): - if Window.GetKeyQualifiers() & Window.Qual.SHIFT: - wordJump = False - newCursor = cursor+1 - while newCursor<0: - - if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__: - newCursor+=1 - else: - wordJump = True - break - if wordJump: # Did we find a new cursor pos? - cursor = newCursor - else: - cursor = -1 # end of line - else: - cursor +=1 - if cursor > -1: - cursor = -1 - - elif (evt == Draw.LEFTARROWKEY and val): - if Window.GetKeyQualifiers() & Window.Qual.SHIFT: - wordJump = False - newCursor = cursor-1 - while abs(newCursor) < len(cmdBuffer[-1].cmd): - - if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__ or\ - newCursor == cursor: - newCursor-=1 - else: - wordJump = True - break - if wordJump: # Did we find a new cursor pos? - cursor = newCursor - else: - cursor = -len(cmdBuffer[-1].cmd) # Start of line - - else: - if len(cmdBuffer[-1].cmd) > abs(cursor): - cursor -=1 - - elif (evt == Draw.HOMEKEY and val): - cursor = -len(cmdBuffer[-1].cmd) - - elif (evt == Draw.ENDKEY and val): - cursor = -1 - - elif (evt == Draw.TABKEY and val): - insCh('\t') - - elif (evt == Draw.BACKSPACEKEY and val): - if Window.GetKeyQualifiers() & Window.Qual.SHIFT: - i = -1 - for d in __DELIMETERS__: - i = max(i, cmdBuffer[-1].cmd[:cursor-1].rfind(d)) - if i == -1: - i=0 - cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:i] , cmdBuffer[-1].cmd[cursor:])) - - else: - # Normal backspace. - cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:])) - - elif (evt == Draw.DELKEY and val) and cursor < -1: - cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:] - cursor +=1 - - elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): - actionEnterKey() - - elif (evt == Draw.RIGHTMOUSE and not val): actionRightMouse(); return - - elif (evt == Draw.PADPLUSKEY or evt == Draw.EQUALKEY or evt == Draw.WHEELUPMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: - __FONT_SIZE__ += 1 - __FONT_SIZE__ = min(len(__FONT_SIZES__)-1, __FONT_SIZE__) - elif (evt == Draw.PADMINUS or evt == Draw.MINUSKEY or evt == Draw.WHEELDOWNMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: - __FONT_SIZE__ -=1 - __FONT_SIZE__ = max(0, __FONT_SIZE__) - - - elif evt == Draw.WHEELUPMOUSE and val: - __CONSOLE_LINE_OFFSET__ += 1 - __CONSOLE_LINE_OFFSET__ = min(len(cmdBuffer)-2, __CONSOLE_LINE_OFFSET__) - resetScroll = False - - elif evt == Draw.WHEELDOWNMOUSE and val: - __CONSOLE_LINE_OFFSET__ -= 1 - __CONSOLE_LINE_OFFSET__ = max(0, __CONSOLE_LINE_OFFSET__) - resetScroll = False - - - elif ascii: - insCh(chr(ascii)) - else: - return # dont redraw. - - # If the user types in anything then scroll to bottom. - if resetScroll: - __CONSOLE_LINE_OFFSET__ = 0 - Draw.Redraw() - - -def draw_gui(): - # Get the bounds from ObleGL directly - __CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4) - BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__) - __CONSOLE_RECT__= __CONSOLE_RECT__.list - - # Clear the screen - BGL.glClearColor(0.0, 0.0, 0.0, 1.0) - BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer - - - # Fixed margin. use a margin since 0 margin can be hard to seewhen close to a crt's edge. - margin = 4 - - # Convenience - FNT_NAME, FNT_HEIGHT = __FONT_SIZES__[__FONT_SIZE__] - - # Draw cursor location colour - if __CONSOLE_LINE_OFFSET__ == 0: - cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], FNT_NAME) - BGL.glColor3f(0.8, 0.2, 0.2) - if cmd2curWidth == 0: - BGL.glRecti(margin,2,margin+2, FNT_HEIGHT+2) - else: - BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, FNT_HEIGHT+2) - - BGL.glColor3f(1,1,1) - # Draw the set of cammands to the buffer - consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1 - wrapLineIndex = 0 - while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > (consoleLineIdx - __CONSOLE_LINE_OFFSET__) * FNT_HEIGHT: - if cmdBuffer[-consoleLineIdx].type == 0: - BGL.glColor3f(1, 1, 1) - elif cmdBuffer[-consoleLineIdx].type == 1: - BGL.glColor3f(.3, .3, 1) - elif cmdBuffer[-consoleLineIdx].type == 2: - BGL.glColor3f(1.0, 0, 0) - elif cmdBuffer[-consoleLineIdx].type == 3: - BGL.glColor3f(0, 0.8, 0) - else: - BGL.glColor3f(1, 1, 0) - - if consoleLineIdx == 1: # user input - BGL.glRasterPos2i(margin, (FNT_HEIGHT * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8) - Draw.Text(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME) - else: # WRAP - lwid = Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME) - if margin + lwid > __CONSOLE_RECT__[2]: - wrapLineList = [] - wtext = cmdBuffer[-consoleLineIdx].cmd - wlimit = len(wtext) - chunksz = int(( __CONSOLE_RECT__[2] - margin ) / (lwid / len(wtext))) - lstart = 0 - fsize = FNT_NAME - while lstart < wlimit: - lend = min(lstart+chunksz,wlimit) - ttext = wtext[lstart:lend] - while lend < wlimit and Draw.GetStringWidth(ttext, fsize) + margin < __CONSOLE_RECT__[2]: - lend += 1 - ttext = wtext[lstart:lend] - while lend > lstart+1 and Draw.GetStringWidth(ttext, fsize) + margin > __CONSOLE_RECT__[2]: - lend -= 1 - ttext = wtext[lstart:lend] - wrapLineList.append(ttext) - lstart = lend - # Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change) - wrapLineList.reverse() - for wline in wrapLineList: - BGL.glRasterPos2i(margin, (FNT_HEIGHT*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8) - Draw.Text(wline, FNT_NAME) - wrapLineIndex += 1 - wrapLineIndex-=1 # otherwise we get a silly extra line. - - else: # no wrapping. - - BGL.glRasterPos2i(margin, (FNT_HEIGHT * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8) - Draw.Text(cmdBuffer[-consoleLineIdx].cmd, FNT_NAME) - consoleLineIdx += 1 - -# This recieves the event index, call a function from here depending on the event. -def handle_button_event(evt): - pass - - -# Run the console -__CONSOLE_VAR_DICT__ = {} # Initialize var dict - - -# Print Startup lines, add __bpydoc__ to the console startup. -for l in __bpydoc__.split('
'): - cmdBuffer.append( cmdLine(l, 1, None) ) - - -histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines. - -# Autoexec, startup code. -scriptDir = Get('scriptsdir') -console_autoexec = None -if scriptDir: - if not scriptDir.endswith(Blender.sys.sep): - scriptDir += Blender.sys.sep - - console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py') - - if not sys.exists(console_autoexec): - # touch the file - try: - open(console_autoexec, 'w').close() - cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None)) - except: - cmdBuffer.append(cmdLine('...console_autoexec.py could not write, this is ok', 1, None)) - scriptDir = None # make sure we only use this for console_autoexec.py - - if not sys.exists(console_autoexec): - console_autoexec = None - - else: - cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts dir', 1, None)) - - - -#-Autoexec---------------------------------------------------------------------# -# Just use the function to jump into local naming mode. -# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__ -def include_console(includeFile): - global __CONSOLE_VAR_DICT__ # write autoexec vars to this. - - # Execute an external py file as if local - exec(include(includeFile)) - -def standard_imports(): - # Write local to global __CONSOLE_VAR_DICT__ for reuse, - - exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy')) - exec('%s%s' % ('__CONSOLE_VAR_DICT__["Blender"]=', 'Blender')) - - for ls in (dir(), dir(Blender)): - for __TMP_VAR_NAME__ in ls: - # Execute the local > global coversion. - exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) - - # Add dummy imports to input so output scripts to a text file work as expected - cmdBuffer.append(cmdLine('import bpy', 0, 1)) - cmdBuffer.append(cmdLine('import Blender', 0, 1)) # pretend we have been executed, as we kindof have. - cmdBuffer.append(cmdLine('from Blender import *', 0, 1)) - -if scriptDir and console_autoexec: - include_console(console_autoexec) # pass the blender module - -standard_imports() # import Blender and bpy - -#-end autoexec-----------------------------------------------------------------# - - -# Append new line to write to -cmdBuffer.append(cmdLine(' ', 0, 0)) - -#------------------------------------------------------------------------------# -# register the event handling code, GUI # -#------------------------------------------------------------------------------# -def main(): - Draw.Register(draw_gui, handle_event, handle_button_event) - -if __name__ == '__main__': - main() diff --git a/release/scripts/discombobulator.py b/release/scripts/discombobulator.py deleted file mode 100644 index 6dbb4e5382b..00000000000 --- a/release/scripts/discombobulator.py +++ /dev/null @@ -1,1526 +0,0 @@ -#!BPY - -""" -Name: 'Discombobulator' -Blender: 237 -Group: 'Mesh' -Tip: 'Adds random geometry to a mesh' -""" - -__author__ = "Evan J. Rosky (syrux)" -__url__ = ("Script's homepage, http://evan.nerdsofparadise.com/programs/discombobulator/index.html") -__version__ = "237" -__bpydoc__ = """\ -Discombobulator adds random geometry to a mesh. - -As an example, this script can easily give a "high-tech" -look to walls and spaceships. - -Definitions:
- - Protrusions: extrusions of each original face on the mesh. -You may have from 1 to 4 protrusions on each face.
- - Taper: The tips of each protrusion will be a percentage -smaller than the base.
- - Doodads: small extruded blocks/shapes that are randomly placed -about the top of a protrusion or face. - - -Usage:
- Input your settings, make sure the mesh you would like to modify -is selected (active) and then click on "Discombobulate".
- See the scripts tutorial page (on the homepage) for more info. - - -New Features:
- - Will use existing materials if there are any.
- - Clicking "Assign materials by part" will allow assigning -of different material indices to Protrusion or Doodad Sides -and Tops in the gui element below it.
- - Setting a material index to 0 will use whatever material -is assigned to the face that is discombobulated. - - You can now scroll using the arrow keys. - - -Notes:
- - Modifications can be restricted to selected faces -by setting "Only selected faces" for protrusions and/or -doodads.
- - It's possible to restrict mesh generation to add only -protrusions or only doodads instead of both.
- - You may also choose to have Discombobulator select the -tops of created protrusions by clicking the corresponding -number of protrusion buttons under "Select Tops". You may -also do the same for doodads by choosing "Select Doodads" and -"Only Select Tops". You may choose to select the whole doodads -by leaving "Only Select Tops" off.
- - By selecting "Deselect Selected" you can have -discombobulator deselect everything but the selections it -makes.
- - The "Face %" option will set the percentage of faces that -will be modified either for the doodads or the protrusions.
- - "Copy Before Modifying" will create a new object with the -modifications where leaving it off will overwrite the original -mesh.
- -You can find more information at the Link above. -""" - - -# $Id$ -# -# Updated 2006-09-26 -# Changes since last version: -# > Works with Blender CVS and hopefully with Blender 2.40. -# > Swaps min/max values when min>max rather than complaining. -# > Will keep previously assigned materials. -# > Now allows user to assign custom material indices to -# Protrusion and Doodad Sides and Tops. -# > The initial Gui Layout will change depending on the aspect -# ratio of the window it is in. -# > Using the arrow keys will scroll the gui. -# -# -------------------------------------------------------------------------- -# Discombobulator v2.1b -# by Evan J. Rosky, 2005 -# This plugin is protected by the GPL: Gnu Public Licence -# GPL - http://www.gnu.org/copyleft/gpl.html -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2005: Evan J. Rosky -# -# 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 ***** -# -------------------------------------------------------------------------- - -#Hit Alt-P to run - -import Blender -from Blender import NMesh,Object,Material,Window,Types,Scene -from Blender.NMesh import Vert,Face -from Blender.Mathutils import * - -import defaultdoodads -import BPyMathutils -from BPyMathutils import genrand -a = BPyMathutils.sgenrand(int(round(Rand(1000,99999),0))) - -#Create random numbers -def randnum(low,high): - num = genrand() - num = num*(high-low) - num = num+low - return num - -#Object Vars -newmesh = NMesh.GetRaw() -materialArray = [0] - -#Material Vars -reassignMats = 0 -protSideMat = 1 -protTopMat = 2 -doodSideMat = 3 -doodTopMat = 4 -thereAreMats = 0 -currmat = 0 - -#Global Vars -makenewobj = 1 -errortext = "Remember to select an object." -editmode = 0 - -#Protrusion Vars -makeprots = 1 -faceschangedpercent = 1.0 -minimumheight = 0.2 -maximumheight = 0.4 -subface1 = 1 -subface2 = 1 -subface3 = 1 -subface4 = 1 -subfaceArray = [1,2,3,4] -minsubfaces = 1 -minimumtaperpercent = 0.15 -maximumtaperpercent = 0.35 -useselectedfaces = 0 -selectface1 = 1 -selectface2 = 1 -selectface3 = 1 -selectface4 = 1 -deselface = 1 - -#Doodad Vars -makedoodads = 1 -doodadfacepercent = 1.0 -selectdoodad = 0 -onlyonprotrusions = 0 -doodonselectedfaces = 0 -selectdoodadtoponly = 0 -doodad1 = 1 -doodad2 = 1 -doodad3 = 1 -doodad4 = 1 -doodad5 = 1 -doodad6 = 1 -doodadminperface = 2 -doodadmaxperface = 6 -doodadminsize = 0.15 -doodadmaxsize = 0.45 -doodadminheight = 0.0 -doodadmaxheight = 0.1 -doodadArray = [1,2,3,4,5,6] - -def makeSubfaceArray(): - global subfaceArray - global subface1 - global subface2 - global subface3 - global subface4 - - subfaceArray = [] - if subface1 > 0: - subfaceArray.append(1) - if subface2 > 0: - subfaceArray.append(2) - if subface3 > 0: - subfaceArray.append(3) - if subface4 > 0: - subfaceArray.append(4) - -def makeDoodadArray(): - global doodadArray - global doodad1 - global doodad2 - global doodad3 - global doodad4 - global doodad5 - global doodad6 - - doodadArray = [] - if doodad1 > 0: - doodadArray.append(1) - if doodad2 > 0: - doodadArray.append(2) - if doodad3 > 0: - doodadArray.append(3) - if doodad4 > 0: - doodadArray.append(4) - if doodad5 > 0: - doodadArray.append(5) - if doodad6 > 0: - doodadArray.append(6) - -def extrude(mid,nor,protrusion,v1,v2,v3,v4,tosel=1,flipnor=0): - taper = 1 - randnum(minimumtaperpercent,maximumtaperpercent) - newmesh_verts = newmesh.verts - newmesh_faces = newmesh.faces - - vert = newmesh_verts[v1] - point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) - ver = Vert(point[0],point[1],point[2]) - ver.sel = tosel - newmesh_verts.append(ver) - vert = newmesh_verts[v2] - point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) - ver = Vert(point[0],point[1],point[2]) - ver.sel = tosel - newmesh_verts.append(ver) - vert = newmesh_verts[v3] - point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) - ver = Vert(point[0],point[1],point[2]) - ver.sel = tosel - newmesh_verts.append(ver) - vert = newmesh_verts[v4] - point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) - ver = Vert(point[0],point[1],point[2]) - ver.sel = tosel - newmesh_verts.append(ver) - - faceindex = len(newmesh_verts) - 4 - - #side face 1 - face = Face([newmesh_verts[v1], newmesh_verts[v2], newmesh_verts[faceindex+1], newmesh_verts[faceindex]]) - if flipnor != 0: - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh_faces.append(face) - - #side face 2 - face = Face([newmesh_verts[v2], newmesh_verts[v3], newmesh_verts[faceindex+2], newmesh_verts[faceindex+1]]) - if flipnor != 0: - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh_faces.append(face) - - #side face 3 - face = Face([newmesh_verts[v3], newmesh_verts[v4], newmesh_verts[faceindex+3], newmesh_verts[faceindex+2]]) - if flipnor != 0: - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh_faces.append(face) - - #side face 4 - face = Face([newmesh_verts[v4], newmesh_verts[v1], newmesh_verts[faceindex], newmesh_verts[faceindex+3]]) - if flipnor != 0: - face.v.reverse() - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh_faces.append(face) - - #top face - face = Face(newmesh_verts[-4:]) - if flipnor != 0: - face.v.reverse() - if tosel == 1: - face.sel = 1 - if thereAreMats == 1: - if reassignMats == 0 or protTopMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protTopMat-1 - newmesh_faces.append(face) - return face - -#Sets the global protrusion values -def setProtrusionValues(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15): - - #Protrusions - global makeprots - global minimumtaperpercent - global maximumtaperpercent - global faceschangedpercent - global minimumheight - global maximumheight - global subface1 - global subface2 - global subface3 - global subface4 - global useselectedfaces - global selectface1 - global selectface2 - global selectface3 - global selectface4 - global deselface - global subfaceArray - - #Protrusions - makeprots = p0 - faceschangedpercent = p1 - minimumheight = p2 - maximumheight = p3 - subface1 = p4 - subface2 = p5 - subface3 = p6 - subface4 = p7 - minimumtaperpercent = p8 - maximumtaperpercent = p9 - useselectedfaces = p10 - selectface1 = p11 - selectface2 = p12 - selectface3 = p13 - selectface4 = p14 - deselface = p15 - makeSubfaceArray() - if len(subfaceArray) == 0: - makeprots = 0 - - if minimumheight > maximumheight: - a = maximumheight - maximimheight = minimumheight - minimumheight = a - elif minimumtaperpercent > maximumtaperpercent: - a = maximumtaperpercent - maximimtaperpercent = minimumtaperpercent - minimumtaperpercent = a - -#Sets the global Doodad values -def setDoodadValues(d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17): - - #Doodads - global makedoodads - global doodadfacepercent - global selectdoodad - global onlyonprotrusions - global doodad1 - global doodad2 - global doodad3 - global doodad4 - global doodad5 - global doodad6 - global doodadminperface - global doodadmaxperface - global doodadminsize - global doodadmaxsize - global doodadminheight - global doodadmaxheight - global doodadArray - global doodonselectedfaces - global selectdoodadtoponly - - #Doodads - makedoodads = d0 - doodadfacepercent = d1 - selectdoodad = d2 - onlyonprotrusions = d3 - doodad1 = d4 - doodad2 = d5 - doodad3 = d6 - doodad4 = d7 - doodad5 = d8 - doodad6 = d9 - doodadminperface = d10 - doodadmaxperface = d11 - doodadminsize = d12 - doodadmaxsize = d13 - doodadminheight = d14 - doodadmaxheight = d15 - doodonselectedfaces = d16 - selectdoodadtoponly = d17 - makeDoodadArray() - if len(doodadArray) == 0: - makedoodads = 0 - - elif doodadminperface > doodadmaxperface: - a = doodadmaxperface - doodadmaxperface = doodadminperface - doodadminperface = a - elif doodadminsize > doodadmaxsize: - a = doodadmaxsize - doodadmaxsize = doodadminsize - doodadminsize = a - elif doodadminheight > doodadmaxheight: - a = doodadmaxheight - doodadmaxheight = doodadminheight - doodadminheight = a - -#Sets other global values -def setOtherValues(g0,m0,m1,m2,m3,m4): - - #Global - global reassignMats - global makenewobj - global protSideMat - global protTopMat - global doodSideMat - global doodTopMat - - #Get Misc Variables - makenewobj = g0 - reassignMats = m0 - protSideMat = m1 - protTopMat = m2 - doodSideMat = m3 - doodTopMat = m4 - -def discombobulate(): - - #Global - global origmesh - global newmesh - global makenewobj - global origobj - global newobj - global messagetext - global errortext - global editmode - - #Protrusions - global makeprots - global minimumtaperpercent - global maximumtaperpercent - global faceschangedpercent - global minimumheight - global maximumheight - global subface1 - global subface2 - global subface3 - global subface4 - global useselectedfaces - global selectface1 - global selectface2 - global selectface3 - global selectface4 - global deselface - global subfaceArray - - #Doodads - global makedoodads - global doodadfacepercent - global selectdoodad - global onlyonprotrusions - global doodad1 - global doodad2 - global doodad3 - global doodad4 - global doodad5 - global doodad6 - global doodadminperface - global doodadmaxperface - global doodadminsize - global doodadmaxsize - global doodadminheight - global doodadmaxheight - global doodadArray - global doodonselectedfaces - global selectdoodadtoponly - - #Global - global materialArray - global reassignMats - global protSideMat - global protTopMat - global doodSideMat - global doodTopMat - global thereAreMats - global currmat - - origobj = Scene.GetCurrent().objects.active - if not origobj: - glRasterPos2d(10,50) - errortext = "YOU MUST SELECT AN OBJECT!" - messagetext = ErrorText(errortext) - Blender.Redraw() - return - - #Leave Editmode - editmode = Window.EditMode() - if editmode: Window.EditMode(0) - - #Get Major Variables - - origmesh = origobj.getData() - - if origobj.type != 'Mesh': - glRasterPos2d(10,50) - errortext = "OBJECT MUST BE MESH!" - messagetext = ErrorText(errortext) - Blender.Redraw() - return - - newmesh = NMesh.GetRaw() - materialArray = origmesh.getMaterials() - if len(materialArray) < 1: - thereAreMats = 0 - else: - thereAreMats = 1 - - #add material indices if necessary (only up to 4) - if thereAreMats == 1 and reassignMats == 1: - if len(materialArray) < 4: - if protSideMat > 4: protSideMat = 4 - if protTopMat > 4: protTopMat = 4 - if doodSideMat > 4: doodSideMat = 4 - if doodTopMat > 4: doodTopMat = 4 - else: - if protSideMat > len(materialArray): protSideMat = len(materialArray) - if protTopMat > len(materialArray): protTopMat = len(materialArray) - if doodSideMat > len(materialArray): doodSideMat = len(materialArray) - if doodTopMat > len(materialArray): doodTopMat = len(materialArray) - - #This only does something if there are less than 4 verts - for matind in [protSideMat,protTopMat,doodSideMat,doodTopMat]: - if matind > len(materialArray) and matind <= 4: - for i in xrange(len(materialArray),matind+1): - materialArray.append(Material.New("AddedMat " + str(i))) - - #Sets the materials - newmesh.setMaterials(materialArray) - - #Set the doodad settings - defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,doodSideMat,doodTopMat) - #defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,currmat) - - newmesh.verts.extend(origmesh.verts) - - #Start modifying faces - for currface in origmesh.faces: - - currmat = currface.materialIndex - defaultdoodads.setCurrMat(currmat) - - #Check if it is a triangle - if len(currface.v)<4: - face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) - if thereAreMats == 1: - face.materialIndex = currmat - newmesh.faces.append(face) - continue - - #Check whether or not to make protrusions - if makeprots == 0: - face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) - if thereAreMats == 1: - face.materialIndex = currmat - newmesh.faces.append(face) - if makedoodads == 1 and onlyonprotrusions == 0: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - continue - - #Check if only changing selected faces - if useselectedfaces == 1: - #check if currface is selected - if currface.sel: - a = 1 - else: - face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) - if thereAreMats == 1: - face.materialIndex = currmat - newmesh.faces.append(face) - if makedoodads == 1 and onlyonprotrusions == 0: - if doodonselectedfaces != 1: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - continue - #Check if face should be modified by random chance - if randnum(0,1)>faceschangedpercent: - face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) - if thereAreMats == 1: - face.materialIndex = currmat - newmesh.faces.append(face) - if makedoodads == 1 and onlyonprotrusions == 0: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - continue - - center = Vector([0,0,0]) - for pt in currface.v: - center = center + pt.co - center = center / len(currface.v) - - #Determine amount of subfaces - subfaces = round(randnum(1,len(subfaceArray)),0) - subfaces = subfaceArray[(int(subfaces) - 1)] - - ######################## START DEALING WITH PROTRUSIONS ##################### - - if subfaces == 1: - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,currface.v[0].index,currface.v[1].index,currface.v[2].index,currface.v[3].index,selectface1) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - elif subfaces == 2: - orientation = int(round(randnum(0,1))) - p1 = currface.v[orientation] - p2 = currface.v[orientation + 1] - p3 = ((p2.co - p1.co)/2) + p1.co - ve1 = Vert(p3[0],p3[1],p3[2]) - ve1.sel = 0 - p1 = currface.v[2 + orientation] - if orientation < 0.5: - p2 = currface.v[3] - else: - p2 = currface.v[0] - p3 = ((p2.co - p1.co)/2) + p1.co - ve2 = Vert(p3[0],p3[1],p3[2]) - ve2.sel = 0 - if orientation < 0.5: - verti = currface.v[3] - p3 = verti.index - v1 = p3 - verti = currface.v[0] - p0 = verti.index - v2 = p0 - else: - verti = currface.v[0] - p0 = verti.index - v1 = p0 - verti = currface.v[1] - p1 = verti.index - v2 = p1 - newmesh.verts.append(ve1) - newmesh.verts.append(ve2) - index = len(newmesh.verts) - 2 - v4 = index + 1 - v3 = index - center = Vector([0, 0, 0]) - for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface2) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - if orientation < 0.5: - verti = currface.v[1] - p1 = verti.index - v1 = p1 - verti = currface.v[2] - p2 = verti.index - v2 = p2 - else: - verti = currface.v[2] - p2 = verti.index - v1 = p2 - verti = currface.v[3] - p3 = verti.index - v2 = p3 - center = Vector([0]*3) - for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface2) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - if orientation < 0.5: - face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v3]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v4]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - else: - face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v3]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - - elif subfaces == 3: - layer2inds = [] - layer2verts = [] - orientation = int(round(randnum(0,1))) - rotation = int(round(randnum(0,1))) - p1 = currface.v[orientation] - p2 = currface.v[orientation + 1] - p3 = ((p2.co - p1.co)/2) + p1.co - ve1 = Vert(p3[0],p3[1],p3[2]) - ve1.sel = 0 - p1 = currface.v[2 + orientation] - if orientation < 0.5: - p2 = currface.v[3] - else: - p2 = currface.v[0] - p3 = ((p2.co - p1.co)/2) + p1.co - ve2 = Vert(p3[0],p3[1],p3[2]) - ve2.sel = 0 - fp = [] - - #make first protrusion - if rotation < 0.5: - if orientation < 0.5: - verti = currface.v[3] - fp.append(verti.index) - v1 = verti.index - verti = currface.v[0] - fp.append(verti.index) - v2 = verti.index - layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) - else: - verti = currface.v[0] - fp.append(verti.index) - v1 = verti.index - verti = currface.v[1] - fp.append(verti.index) - v2 = verti.index - layer2verts.extend([newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) - newmesh.verts.append(ve1) - newmesh.verts.append(ve2) - index = len(newmesh.verts) - 2 - v4 = index + 1 - v3 = index - center = Vector([0]*3) - for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - layer2inds.extend([v3,v4]) - tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface3) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - #Still first protrusion - else: - if orientation < 0.5: - verti = currface.v[1] - fp.append(verti.index) - v1 = verti.index - verti = currface.v[2] - fp.append(verti.index) - v2 = verti.index - layer2verts.extend([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[3].index]]) - else: - verti = currface.v[2] - fp.append(verti.index) - v1 = verti.index - verti = currface.v[3] - fp.append(verti.index) - v2 = verti.index - layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[0].index]]) - newmesh.verts.append(ve2) - newmesh.verts.append(ve1) - index = len(newmesh.verts) - 2 - v4 = index - v3 = index + 1 - center = Vector([0]*3) - for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - layer2inds.extend([index, index +1]) - tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface3) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - #split next rect(pre-arranged, no orientation crud)--make flag in extruder for only one existing vert in mesh - p1 = newmesh.verts[layer2inds[0]] - p2 = newmesh.verts[layer2inds[1]] - p3 = ((p2.co - p1.co)/2) + p1.co - ve3 = Vert(p3[0],p3[1],p3[2]) - ve3.sel = 0 - p1 = layer2verts[0] - p2 = layer2verts[1] - p3 = ((p2.co - p1.co)/2) + p1.co - ve4 = Vert(p3[0],p3[1],p3[2]) - ve4.sel = 0 - newmesh.verts.append(ve3) - newmesh.verts.append(ve4) - tempindex = len(newmesh.verts) - 2 - v5 = tempindex - v6 = tempindex + 1 - verti = layer2verts[0] - t0 = verti.index - center = Vector([0]*3) - for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[t0],newmesh.verts[v3]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - if rotation < 0.5: flino = 1 - else: flino = 0 - tempface = extrude(center,currface.no,prot,v3,v5,v6,t0,selectface3,flino) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - if rotation < 0.5: - fpt = t0 - face = Face([newmesh.verts[fp[1]],newmesh.verts[fpt],newmesh.verts[v3]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - else: - fpt = t0 - face = Face([newmesh.verts[fp[0]],newmesh.verts[v3],newmesh.verts[fpt]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - verti = layer2verts[1] - tempindex = verti.index - center = Vector([0]*3) - for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[tempindex],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,v6,v5,v4,tempindex,selectface3,flino) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - if rotation < 0.5: - face = Face([newmesh.verts[tempindex],newmesh.verts[fp[0]],newmesh.verts[v4]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[fpt],newmesh.verts[tempindex],newmesh.verts[v6]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - else: - face = Face([newmesh.verts[tempindex],newmesh.verts[v4],newmesh.verts[fp[1]]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[tempindex],newmesh.verts[fpt],newmesh.verts[v6]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - - else: - #get all points - verti = currface.v[0] - p0 = verti.index - - verti = currface.v[1] - p1 = verti.index - - pt = ((newmesh.verts[p1].co - newmesh.verts[p0].co)/2) + newmesh.verts[p0].co - v1 = Vert(pt[0],pt[1],pt[2]) - v1.sel = 0 - - verti = currface.v[2] - p2 = verti.index - - pt = ((newmesh.verts[p2].co - newmesh.verts[p1].co)/2) + newmesh.verts[p1].co - v2 = Vert(pt[0],pt[1],pt[2]) - v2.sel = 0 - - verti = currface.v[3] - p3 = verti.index - - pt = ((newmesh.verts[p3].co - newmesh.verts[p2].co)/2) + newmesh.verts[p2].co - v3 = Vert(pt[0],pt[1],pt[2]) - v3.sel = 0 - - pt = ((newmesh.verts[p0].co - newmesh.verts[p3].co)/2) + newmesh.verts[p3].co - v4 = Vert(pt[0],pt[1],pt[2]) - v4.sel = 0 - - pt = ((v3.co - v1.co)/2) + v1.co - m = Vert(pt[0],pt[1],pt[2]) - m.sel = 0 - - #extrusion 1 - newmesh.verts.extend([v1,m,v4]) - index = len(newmesh.verts) - 3 - v1 = index - m = index + 1 - v4 = index + 2 - center = Vector([0]*3) - for pt in [newmesh.verts[p0],newmesh.verts[v1],newmesh.verts[m],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,p0,v1,m,v4,selectface4) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - #extrusion 2 - newmesh.verts.extend([v2]) - index = len(newmesh.verts) - 1 - v2 = index - center = Vector([0]*3) - for pt in [newmesh.verts[m],newmesh.verts[v1],newmesh.verts[p1],newmesh.verts[v2]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,m,v1,p1,v2,selectface4) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - #extrusion 3 - newmesh.verts.extend([v3]) - index = len(newmesh.verts) - 1 - v3 = index - center = Vector([0]*3) - for pt in [newmesh.verts[m],newmesh.verts[v2],newmesh.verts[p2],newmesh.verts[v3]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,m,v2,p2,v3,selectface4) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - #extrusion 4 - center = Vector([0]*3) - for pt in [newmesh.verts[m],newmesh.verts[v3],newmesh.verts[p3],newmesh.verts[v4]]: - center += pt.co - center = center/4 - prot = randnum(minimumheight,maximumheight) - tempface = extrude(center,currface.no,prot,v4,m,v3,p3,selectface4) - if makedoodads == 1: - if doodonselectedfaces == 1: - if currface.sel: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - else: - tempmesh = NMesh.GetRaw() - tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) - newmesh.verts.extend(tempmesh.verts) - newmesh.faces.extend(tempmesh.faces) - - face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v1]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v2]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v3]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) - if thereAreMats == 1: - if reassignMats == 0 or protSideMat == 0: - face.materialIndex = currmat - else: - face.materialIndex = protSideMat-1 - newmesh.faces.append(face) - - #NMesh.PutRaw(newmesh) - if deselface == 1: - for unvert in origmesh.verts: - newmesh.verts[unvert.index].sel = 0 - if makenewobj == 1: - newobj = origobj.__copy__() - newobj.link(newmesh) - scene = Blender.Scene.GetCurrent() - scene.objects.link(newobj) - origobj.sel = 0 - else: - origobj.link(newmesh) - - #Return to Editmode if previously in it - if editmode: Window.EditMode(1) - -####################### gui ###################### -from Blender.BGL import * -from Blender.Draw import * - -def ErrorText(errortext): - Window.WaitCursor(0) - Text(errortext) - PupMenu("ERROR: %s" % errortext.lower()) - -#Global Buttons -makenewobject = Create(makenewobj) -messagetext = Create(errortext) - -#Protrusion Buttons -doprots = Create(makeprots) -facechange = Create(faceschangedpercent*100) -minheight = Create(minimumheight) -maxheight = Create(maximumheight) -sub1 = Create(subface1) -sub2 = Create(subface2) -sub3 = Create(subface3) -sub4 = Create(subface4) -mintaper = Create(minimumtaperpercent*100) -maxtaper = Create(maximumtaperpercent*100) -useselected = Create(useselectedfaces) -selface1 = Create(selectface1) -selface2 = Create(selectface2) -selface3 = Create(selectface3) -selface4 = Create(selectface4) -deselectvertices = Create(deselface) -#selectbyverts = Create(vertselected) - -#Doodad Buttons -dodoodads = Create(makedoodads) -doodadfacechange = Create(doodadfacepercent*100) -seldoodad = Create(selectdoodad) -onprot = Create(onlyonprotrusions) -dood1 = Create(doodad1) -dood2 = Create(doodad2) -dood3 = Create(doodad3) -dood4 = Create(doodad4) -dood5 = Create(doodad5) -dood6 = Create(doodad6) -doodadminamount = Create(doodadminperface) -doodadmaxamount = Create(doodadmaxperface) -doodsizemin = Create(doodadminsize*100) -doodsizemax = Create(doodadmaxsize*100) -doodheightmin = Create(doodadminheight) -doodheightmax = Create(doodadmaxheight) -doodonselface = Create(doodonselectedfaces) -seldoodtop = Create(selectdoodadtoponly) - -#Material Buttons -assignNewMats = Create(reassignMats) -replProtSideIndex = Create(protSideMat) -replProtTopIndex = Create(protTopMat) -replDoodSideIndex = Create(doodSideMat) -replDoodTopIndex = Create(doodTopMat) - -# Events -EVENT_NONE = 1 -EVENT_DISCOMBOBULATE = 2 -EVENT_EXIT = 3 - -# Additions for moving gui -hadd = 0 -wadd = 0 -thadd = 410 -phadd = 245 -pwadd = 0 -dhadd = 55 -dwadd = 0 -ghadd = 10 -gwadd = 0 -mhadd = 55 -mwadd = 312 - -def colorbox(x,y,xright,bottom): - glColor3f(0.75, 0.75, 0.75) - glRecti(x + 1, y + 1, xright - 1, bottom - 1) - -firstDraw = 1 - -def draw(): - - #Protrusions - global doprots - global facechange - global minheight - global maxheight - global sub1 - global sub2 - global sub3 - global sub4 - global mintaper - global maxtaper - global useselected - global selface1 - global selface2 - global selface3 - global selface4 - global deselectvertices - #global selectbyverts - - #Doodads - global dodoodads - global doodadfacechange - global seldoodad - global onprot - global dood1 - global dood2 - global dood3 - global dood4 - global dood5 - global dood6 - global doodadminamount - global doodadmaxamount - global doodsizemin - global doodsizemax - global doodheightmin - global doodheightmax - global doodonselface - global seldoodtop - - #Materials - global assignNewMats - global replProtSideIndex - global replProtTopIndex - global replDoodSideIndex - global replDoodTopIndex - - #Global Settings - global makenewobject - global messagetext - global errortext - global EVENT_NONE,EVENT_DRAW,EVENT_EXIT,EVENT_UP,EVENT_DOWN,EVENT_LEFT,EVENT_RIGHT - - # Additions for moving gui - global hadd - global wadd - global thadd - global phadd - global pwadd - global dhadd - global dwadd - global ghadd - global gwadd - global mhadd - global mwadd - - #This is for creating the initial layout - global firstDraw - if(firstDraw == 1): - if(((Window.GetAreaSize()[1])*1.7) < Window.GetAreaSize()[0]): - thadd = 180 - phadd = 10 - dhadd = 10 - mhadd = 55 - ghadd = 10 - pwadd = 0 - dwadd = 305 - mwadd = 610 - gwadd = 610 - else: - thadd = 505 - phadd = 346 - dhadd = 160 - mhadd = 56 - ghadd = 10 - pwadd = 0 - dwadd = 0 - mwadd = 0 - gwadd = 0 - firstDraw = 0 - - - #Title :420high - glClearColor(0.6, 0.6, 0.6, 1.0) - glClear(GL_COLOR_BUFFER_BIT) - glColor3f(0.0,0.0,0.0) - glRasterPos2d(8+wadd, thadd+hadd) - Text("Discombobulator v2.1b") - - #Protrusion - colorbox(8+pwadd+wadd,150+phadd+hadd,312+pwadd+wadd,phadd-5+hadd) - glColor3f(0.0,0.0,0.0) - glRasterPos2d(12+pwadd+wadd, 140+phadd+hadd) - Text("Protrusions:") - doprots = Toggle("Make Protrusions",EVENT_NONE,12+pwadd+wadd,117+phadd+hadd,145,18,doprots.val,"Make Protrusions?") - facechange = Number("Face %: ",EVENT_NONE,162+pwadd+wadd,117+phadd+hadd,145,18,facechange.val,0,100,"Percentage of faces that will grow protrusions") - useselected = Toggle("Only selected faces",EVENT_NONE,12+pwadd+wadd,97+phadd+hadd,145,18,useselected.val,"If on, only selected faces will be modified") - deselectvertices = Toggle("Deselect Selected",EVENT_NONE,162+pwadd+wadd,97+phadd+hadd,145,18,deselectvertices.val,"Deselects any selected vertex except for ones selected by \"Select Tops\"") - - #Protrusion properties - glColor3f(0.0,0.0,0.0) - glRasterPos2d(12+pwadd+wadd, 80+phadd+hadd) - Text("Protrusion Properties:") - BeginAlign() - minheight = Number("Min Height: ",EVENT_NONE,12+pwadd+wadd,57+phadd+hadd,145,18,minheight.val,-100.0,100.0,"Minimum height of any protrusion") - maxheight = Number("Max Height: ",EVENT_NONE,162+pwadd+wadd,57+phadd+hadd,145,18,maxheight.val,-100.0,100.0,"Maximum height of any protrusion") - EndAlign() - BeginAlign() - mintaper = Number("Min Taper %: ",EVENT_NONE,12+pwadd+wadd,37+phadd+hadd,145,18,mintaper.val,0,100,"Minimum taper percentage of protrusion") - maxtaper = Number("Max Taper %: ",EVENT_NONE,162+pwadd+wadd,37+phadd+hadd,145,18,maxtaper.val,0,100,"Maximum taper percentage of protrusion") - EndAlign() - glRasterPos2d(19+pwadd+wadd, 22+phadd+hadd) - Text("Number of protrusions:") - BeginAlign() - sub1 = Toggle("1",EVENT_NONE,12+pwadd+wadd,phadd+hadd,34,18,sub1.val,"One Protrusion") - sub2 = Toggle("2",EVENT_NONE,48+pwadd+wadd,phadd+hadd,34,18,sub2.val,"Two Protrusions") - sub3 = Toggle("3",EVENT_NONE,84+pwadd+wadd,phadd+hadd,34,18,sub3.val,"Three Protrusions") - sub4 = Toggle("4",EVENT_NONE,120+pwadd+wadd,phadd+hadd,34,18,sub4.val,"Four Protrusions") - EndAlign() - glRasterPos2d(195+pwadd+wadd, 22+phadd+hadd) - Text("Select tops of:") - BeginAlign() - selface1 = Toggle("1",EVENT_NONE,165+pwadd+wadd,phadd+hadd,34,18,selface1.val,"Select the tip of the protrusion when it is created") - selface2 = Toggle("2",EVENT_NONE,201+pwadd+wadd,phadd+hadd,34,18,selface2.val,"Select the tips of each protrusion when they are created") - selface3 = Toggle("3",EVENT_NONE,237+pwadd+wadd,phadd+hadd,34,18,selface3.val,"Select the tips of each protrusion when they are created") - selface4 = Toggle("4",EVENT_NONE,273+pwadd+wadd,phadd+hadd,34,18,selface4.val,"Select the tips of each protrusion when they are created") - EndAlign() - #Doodads - colorbox(8+dwadd+wadd,175+dhadd+hadd,312+dwadd+wadd,dhadd-5+hadd) - glColor3f(0.0,0.0,0.0) - glRasterPos2d(12+dwadd+wadd, 165+dhadd+hadd) - Text("Doodads:") - BeginAlign() - dood1 = Toggle("1 Box",EVENT_NONE,12+dwadd+wadd,142+dhadd+hadd,45,18,dood1.val,"Creates a rectangular box") - dood2 = Toggle("2 Box",EVENT_NONE,61+dwadd+wadd,142+dhadd+hadd,45,18,dood2.val,"Creates 2 side-by-side rectangular boxes") - dood3 = Toggle("3 Box",EVENT_NONE,110+dwadd+wadd,142+dhadd+hadd,45,18,dood3.val,"Creates 3 side-by-side rectangular boxes") - EndAlign() - BeginAlign() - dood4 = Toggle("\"L\"",EVENT_NONE,164+dwadd+wadd,142+dhadd+hadd,45,18,dood4.val,"Creates a Tetris-style \"L\" shape") - dood5 = Toggle("\"T\"",EVENT_NONE,213+dwadd+wadd,142+dhadd+hadd,45,18,dood5.val,"Creates a Tetris-style \"T\" shape") - dood6 = Toggle("\"S\"",EVENT_NONE,262+dwadd+wadd,142+dhadd+hadd,45,18,dood6.val,"Creates a sort-of \"S\" or \"Z\" shape") - EndAlign() - dodoodads = Toggle("Make Doodads",EVENT_NONE,12+dwadd+wadd,120+dhadd+hadd,145,18,dodoodads.val,"Make Doodads?") - doodadfacechange = Number("Face %: ",EVENT_NONE,162+dwadd+wadd,120+dhadd+hadd,145,18,doodadfacechange.val,0,100,"Percentage of faces that will gain doodads") - seldoodad = Toggle("Select Doodads",EVENT_NONE,12+dwadd+wadd,100+dhadd+hadd,145,18,seldoodad.val,"Selects doodads when they are created") - seldoodtop = Toggle("Only Select Tops",EVENT_NONE,162+dwadd+wadd,100+dhadd+hadd,145,18,seldoodtop.val,"Only Selects tops of doodads when\"Select Doodads\" is on") - doodonselface = Toggle("Only selected faces",EVENT_NONE,12+dwadd+wadd,80+dhadd+hadd,145,18,doodonselface.val,"Only create doodads on selected faces") - onprot = Toggle("Only on Protrusions",EVENT_NONE,162+dwadd+wadd,80+dhadd+hadd,145,18,onprot.val,"Only place doodads on protrusions") - - #Doodad Properties - glColor3f(0.0,0.0,0.0) - glRasterPos2d(12+dwadd+wadd, 63+dhadd+hadd) - Text("Doodad Properties:") - BeginAlign() - doodadminamount = Number("Min Amount: ",EVENT_NONE,12+dwadd+wadd,40+dhadd+hadd,145,18,doodadminamount.val,0,100,"Minimum number of doodads per face") - doodadmaxamount = Number("Max Amount: ",EVENT_NONE,162+dwadd+wadd,40+dhadd+hadd,145,18,doodadmaxamount.val,0,100,"Maximum number of doodads per face") - EndAlign() - BeginAlign() - doodheightmin = Number("Min Height: ",EVENT_NONE,12+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmin.val,0.0,100.0,"Minimum height of any doodad") - doodheightmax = Number("Max Height: ",EVENT_NONE,162+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmax.val,0.0,100.0,"Maximum height of any doodad") - EndAlign() - BeginAlign() - doodsizemin = Number("Min Size %: ",EVENT_NONE,12+dwadd+wadd,dhadd+hadd,145,18,doodsizemin.val,0.0,100.0,"Minimum size of any doodad in percentage of face") - doodsizemax = Number("Max Size %: ",EVENT_NONE,162+dwadd+wadd,dhadd+hadd,145,18,doodsizemax.val,0.0,100.0,"Maximum size of any doodad in percentage of face") - EndAlign() - - #Materials - colorbox(8+mwadd+wadd,93+mhadd+hadd,312+mwadd+wadd,mhadd-5+hadd) - glColor3f(0.0,0.0,0.0) - glRasterPos2d(12+mwadd+wadd, 83+mhadd+hadd) - Text("Materials:") - glRasterPos2d(12+mwadd+wadd, 43+mhadd+hadd) - Text("Assigned Material Indices:") - assignNewMats = Toggle("Assign materials by part",EVENT_NONE,32+mwadd+wadd,60+mhadd+hadd,256,18,assignNewMats.val,"Otherwise, previous materials will be preserved") - replProtSideIndex = Number("Protrusion Sides:",EVENT_NONE,12+mwadd+wadd,20+mhadd+hadd,145,18,replProtSideIndex.val,0,16,"Material index assigned to sides of protrusions") - replProtTopIndex = Number("Protrusion Tops:",EVENT_NONE,162+mwadd+wadd,20+mhadd+hadd,145,18,replProtTopIndex.val,0,16,"Material index assigned to tops of protrusions") - replDoodSideIndex = Number("Doodad Sides:",EVENT_NONE,12+mwadd+wadd,mhadd+hadd,145,18,replDoodSideIndex.val,0,16,"Material index assigned to sides of doodads") - replDoodTopIndex = Number("Doodad Tops:",EVENT_NONE,162+mwadd+wadd,mhadd+hadd,145,18,replDoodTopIndex.val,0,16,"Material index assigned to tops and bottoms of doodads") - - #Global Parts - colorbox(8+gwadd+wadd,35+ghadd+hadd,312+gwadd+wadd,ghadd-5+hadd) - glColor3f(1.0,0.0,0.0) - glRasterPos2d(12+gwadd+wadd,25+ghadd+hadd) - messagetext = Text(errortext) - glColor3f(0.0,0.0,0.0) - makenewobject = Toggle("Copy Before Modifying",EVENT_NONE,162+gwadd+wadd,ghadd+hadd,145,18,makenewobject.val,"If selected, the original object will be copied before it is changed") - Button("Discombobulate",EVENT_DISCOMBOBULATE,12+gwadd+wadd,ghadd+hadd,100,18) - Button("Exit",EVENT_EXIT,120+gwadd+wadd,ghadd+hadd,30,18) - -def event(evt, val): - global wadd - global hadd - - if (evt == RIGHTARROWKEY and val): - wadd = wadd + 20 - Redraw(1) - if (evt == LEFTARROWKEY and val): - wadd = wadd - 20 - Redraw(1) - if (evt == UPARROWKEY and val): - hadd = hadd + 20 - Redraw(1) - if (evt == DOWNARROWKEY and val): - hadd = hadd - 20 - Redraw(1) - if (evt == QKEY and not val): - Exit() - -def bevent(evt): - - #Protrusions - global doprots - global facechange - global minheight - global maxheight - global sub1 - global sub2 - global sub3 - global sub4 - global mintaper - global maxtaper - global useselected - global selface1 - global selface2 - global selface3 - global selface4 - global deselectvertices - #global selectbyverts - - #Doodads - global dodoodads - global doodadfacechange - global seldoodad - global onprot - global dood1 - global dood2 - global dood3 - global dood4 - global dood5 - global dood6 - global doodadminamount - global doodadmaxamount - global doodsizemin - global doodsizemax - global doodheightmin - global doodheightmax - global doodonselface - global seldoodtop - - #Materials - global assignNewMats - global replProtSideIndex - global replProtTopIndex - global replDoodSideIndex - global replDoodTopIndex - - #Global Settings - global makenewobject - global messagetext - global errortext - global EVENT_NONE,EVENT_DRAW,EVENT_EXIT - - ######### Manages GUI events - if evt==EVENT_EXIT: - Exit() - elif evt==EVENT_DISCOMBOBULATE: - Window.WaitCursor(1) - setProtrusionValues(doprots.val,facechange.val/100,minheight.val,maxheight.val,sub1.val,sub2.val,sub3.val,sub4.val,mintaper.val/100,maxtaper.val/100,useselected.val,selface1.val,selface2.val,selface3.val,selface4.val,deselectvertices.val) - setDoodadValues(dodoodads.val,doodadfacechange.val/100,seldoodad.val,onprot.val,dood1.val,dood2.val,dood3.val,dood4.val,dood5.val,dood6.val,doodadminamount.val,doodadmaxamount.val,doodsizemin.val/100,doodsizemax.val/100,doodheightmin.val,doodheightmax.val,doodonselface.val,seldoodtop.val) - setOtherValues(makenewobject.val,assignNewMats.val,replProtSideIndex.val,replProtTopIndex.val,replDoodSideIndex.val,replDoodTopIndex.val) - discombobulate() - Window.WaitCursor(0) - Blender.Redraw() - -Register(draw, event, bevent) diff --git a/release/scripts/envelope_symmetry.py b/release/scripts/envelope_symmetry.py deleted file mode 100644 index a72e8c060b4..00000000000 --- a/release/scripts/envelope_symmetry.py +++ /dev/null @@ -1,174 +0,0 @@ -#!BPY - -""" -Name: 'Envelope Symmetry' -Blender: 234 -Group: 'Animation' -Tooltip: 'Make envelope symmetrical' -""" - -__author__ = "Jonas Petersen" -__url__ = ("blender", "blenderartists.org", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858 ") -__version__ = "0.9 2004-11-10" -__doc__ = """\ -This script creates perfectly symmetrical envelope sets. It is part of the -envelop assignment tools. - -"Envelopes" are Mesh objects with names following this naming convention: - -: - -Please check the script's homepage and the thread at blender.org (last link button above) for more info. - -For this version users need to edit the script code to change default options. -""" - -# -------------------------------------------------------------------------- -# "Envelope Symmetry" by Jonas Petersen -# Version 0.9 - 10th November 2004 - first public release -# -------------------------------------------------------------------------- -# -# A script for creating perfectly symmetrical envelope sets. It is -# part of the envelope assignment tool. -# -# It is available in Object Mode via the menu item: -# -# Object -> Scripts -> Envelope Symmetry -# -# With default settings it will: -# -# - Look for bones -# -# Find the latest version at: http://www.mindfloaters.de/blender/ -# -# -------------------------------------------------------------------------- -# $Id$ -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de -# -# 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 ***** - -# -------------------------------------------------------------------------- -# CONFIGURATION -# -------------------------------------------------------------------------- - -# Note: Theses values will later be editable via a gui interface -# within Blender. - -# The suffix for the reference and opposite envelope. -# The configuration of of the opposite envelope will be overwritten by -# the configuration of the reference envelope (shape, position, bone, weight). -# The default is REF_SUFFIX = '.L' and OPP_SUFFIX = '.R'. -REF_SUFFIX = '.R' -OPP_SUFFIX = '.L' - -# MIRROR_AXIS defines the axis in which bones are mirrored/aligned. -# Values: -# 0 for X (default) -# 1 for Y -# 2 for Z -MIRROR_AXIS = 0 - -# SEPARATOR is the character used to delimit the bone name and the weight -# in the envelope name. -SEPARATOR = ":" - -# -------------------------------------------------------------------------- -# END OF CONFIGURATION -# -------------------------------------------------------------------------- - -import Blender, math, sys -from Blender import Mathutils -from BPyNMesh import * - -def flipFace(v): - if len(v) == 3: v[0], v[1], v[2] = v[2], v[1], v[0] - elif len(v) == 4: v[0], v[1], v[2], v[3] = v[3], v[2], v[1], v[0] - -# return object with given object name (with variable parts) and mesh name -def getObjectByName(obj_name, mesh_name): - for obj in Blender.Scene.GetCurrent().objects: - if obj.type == "Mesh": -# if obj.getName()[0:len(obj_name)] == obj_name and obj.getData().name == mesh_name: - # use only mesh_name so bone name and weight (in the envelope name) - # can be changed by the user and mirrored by the script. - if obj.getData(name_only=1) == mesh_name: - return obj - return False - -SUFFIX_LEN = len(REF_SUFFIX); - -Blender.Window.EditMode(0) - -count = 0 -for obj in Blender.Scene.GetCurrent().objects: - if obj.type != 'Mesh': - continue - - count += 1 - name = obj.name - pos = name.find(SEPARATOR) - if (pos > -1): - ApplySizeAndRotation(obj) - - base_name = name[0:pos-SUFFIX_LEN] - suffix = name[pos-SUFFIX_LEN:pos] - weight = name[pos:len(name)] # the SEPARATOR following a float value - - if suffix == REF_SUFFIX: - mesh = obj.getData() - mirror_name = base_name + OPP_SUFFIX + weight - mirror_mesh_name = mesh.name + ".mirror" - - mirror_obj = getObjectByName(base_name + OPP_SUFFIX, mirror_mesh_name) - - if mirror_obj: - - # update vertices - - mirror_mesh = mirror_obj.getData() - for i in xrange(len(mesh.verts)): - org = mesh.verts[i] - mir = mirror_mesh.verts[i] - mir.co[0], mir.co[1], mir.co[2] = org.co[0], org.co[1], org.co[2] - mir.co[MIRROR_AXIS] *= -1 - - mirror_mesh.update() - else: - - # create mirror object - - mirror_mesh = obj.data - for face in mirror_mesh.faces: - flipFace(face.v) - for vert in mirror_mesh.verts: - vert.co[MIRROR_AXIS] *= -1 - - mirror_obj = Blender.NMesh.PutRaw(mirror_mesh, mirror_mesh_name) - - # update name, drawType and location - - mirror_obj.setName(mirror_name) - mirror_obj.drawType = obj.drawType - - loc = [obj.LocX, obj.LocY, obj.LocZ] - loc[MIRROR_AXIS] *= -1 - mirror_obj.setLocation(loc) - -Blender.Window.EditMode(0) diff --git a/release/scripts/export-iv-0.1.py b/release/scripts/export-iv-0.1.py deleted file mode 100644 index 647dd9c5518..00000000000 --- a/release/scripts/export-iv-0.1.py +++ /dev/null @@ -1,304 +0,0 @@ -#!BPY - -""" -Name: 'OpenInventor (.iv)...' -Blender: 236 -Group: 'Export' -Tip: 'Export to OpenInventor file format. (.iv)' -""" -__author__ = ("Radek Barton") -__url__ = ["http://blackhex.no-ip.org/"] -__email__ = ["scripts"] -__version__ = "0.1" - - -__bpydoc__ = """\ -This script exports to the Open Inventor format. - -Usage: - -Run this script from "File->Export" menu. - -Note: -""" -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Radek Barton -# -# 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 Blender -math_pi= 3.1415926535897931 - -def WriteHeader(file): - file.write("#Inventor V2.1 ascii\n\n") - file.write("Separator\n") - file.write("{\n") - file.write(" ShapeHints\n") - file.write(" {\n") - file.write(" vertexOrdering COUNTERCLOCKWISE\n") - file.write(" }\n") - -def WriteFooter(file): - file.write("}\n") - -def WriteMesh(file, ob): - file.write(" Separator\n") - file.write(" {\n") - file.write(" # %s\n" % ob.name) - WriteMatrix(file, ob) - mesh = ob.getData() - WriteMaterials(file, mesh) - WriteTexture(file, mesh) - WriteNormals(file, mesh) - WriteVertices(file, mesh) - WriteFaces(file, mesh) - file.write(" }\n") - -def WriteMatrix(file, ob): - matrix = ob.getMatrix() - file.write(" MatrixTransform\n") - file.write(" {\n") - file.write(" matrix\n") - for line in matrix: - file.write(" %.6f %.6f %.6f %.6f\n" % (line[0], line[1], line[2], line[3])) - file.write(" }\n") - -def WriteColors(file, mesh): - file.write(" vertexProperty VertexProperty\n") - file.write(" {\n") - file.write(" orderedRGBA\n") - file.write(" [\n") - for face in mesh.faces: - for I in xrange(len(face)): - file.write(" 0x%02x%02x%02x%02x,\n" % (face.col[I].r, - face.col[I].g, face.col[I].b, face.col[I].a)) - file.write(" ]\n") - file.write(" materialBinding PER_VERTEX\n") - file.write(" }\n") - -def WriteMaterials(file, mesh): - if mesh.materials: - file.write(" Material\n") - file.write(" {\n") - file.write(" ambientColor\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f %.6f %.6f,\n" % (mat.mirCol[0], mat.mirCol[1], - mat.mirCol[2])) - file.write(" ]\n") - file.write(" diffuseColor\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0], mat.rgbCol[1], - mat.rgbCol[2])) - file.write(" ]\n") - file.write(" specularColor\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f %.6f %.6f,\n" % (mat.specCol[0] * mat.spec / 2.0, - mat.specCol[1] * mat.spec / 2.0, mat.specCol[2] * mat.spec / 2.0)) - file.write(" ]\n") - file.write(" emissiveColor\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0] * mat.emit, - mat.rgbCol[1] * mat.emit, mat.rgbCol[0] * mat.emit)) - file.write(" ]\n") - file.write(" shininess\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f,\n" % (mat.hard / 255.0)) - file.write(" ]\n") - file.write(" transparency\n") - file.write(" [\n") - for mat in mesh.materials: - file.write(" %.6f,\n" % (1.0 - mat.alpha)) - file.write(" ]\n") - file.write(" }\n") - file.write(" MaterialBinding\n") - file.write(" {\n") - file.write(" value PER_FACE_INDEXED\n") - file.write(" }\n") - -def WriteTexture(file, mesh): - texture = mesh.faces[0].image # BAD Ju Ju - if texture: - file.write(" Texture2\n") - file.write(" {\n") - file.write(' filename "%s"\n' % texture.getName()) - file.write(" }\n") - file.write(" TextureCoordinate2\n") - file.write(" {\n") - file.write(" point\n") - file.write(" [\n") - if mesh.hasVertexUV(): - for vert in mesh.verts: - file.write(" %s %s,\n" % (vert.uvco[0], vert.uvco[1])) - file.write(" ]\n") - file.write(" }\n") - file.write(" TextureCoordinateBinding\n") - file.write(" {\n") - file.write(" value PER_VERTEX_INDEXED\n") - file.write(" }\n") - elif mesh.hasFaceUV(): - for face in mesh.faces: - for uv in face.uv: - file.write(" %.6f %.6f,\n" % (uv[0], uv[1])) - file.write(" ]\n") - file.write(" }\n") - file.write(" TextureCoordinateBinding\n") - file.write(" {\n") - file.write(" value PER_VERTEX\n") - file.write(" }\n") - -def WriteVertices(file, mesh): - file.write(" Coordinate3\n") - file.write(" {\n") - file.write(" point\n") - file.write(" [\n") - for vert in mesh.verts: - file.write(" %.6f %.6f %.6f,\n" % (vert[0], vert[1], vert[2])) - file.write(" ]\n") - file.write(" }\n") - -def WriteNormals(file, mesh): - file.write(" Normal\n") - file.write(" {\n") - file.write(" vector\n") - file.write(" [\n") - - # make copy of vertex normals - normals = [] - for face in mesh.faces: - if len(face.v) in [3, 4]: - if face.smooth: - for v in face.v: - normals.append(v.no) - else: - for v in face.v: - normals.append(face.no) - - # write normals - for no in normals: - file.write(" %.6f %.6f %.6f,\n" % (no[0], no[1], no[2])) - file.write(" ]\n") - file.write(" }\n") - - # write way how normals are binded - file.write(" NormalBinding\n") - file.write(" {\n") - file.write(" value PER_VERTEX\n") - file.write(" }\n") - -def WriteFaces(file, mesh): - file.write(" IndexedFaceSet\n") - file.write(" {\n") - - # write vertex paint - if mesh.hasVertexColours(): - WriteColors(file, mesh) - - # write material indexes - file.write(" materialIndex\n") - file.write(" [\n") - for face in mesh.faces: - file.write(" %i,\n" % face.mat); - file.write(" ]\n") - - # write faces with coordinate indexes - file.write(" coordIndex\n") - file.write(" [\n") - for face in mesh.faces: - face_v= face.v - if len(face_v) == 3: - file.write(" %i, %i, %i, -1,\n" % (face_v[0].index, - face_v[1].index, face_v[2].index)) - elif len(face_v) == 4: - file.write(" %i, %i, %i, %i, -1,\n" % (face_v[0].index, - face_v[1].index, face_v[2].index, face_v[3].index)) - file.write(" ]\n") - file.write(" }\n") - - -def WriteCamera(file, ob): - camera = ob.getData(); - # perspective camera - if camera.type == 0: - file.write(" PerspectiveCamera\n") - file.write(" {\n") - file.write(" nearDistance %s\n" % (camera.clipStart)) - file.write(" farDistance %s\n" % (camera.clipEnd)) - file.write(" }\n") - # ortho camera - else: - print camera.type - -def WriteLamp(file, ob): - lamp = ob.getData(); - # spot lamp - if lamp.type == 2: - file.write(" SpotLight\n") - file.write(" {\n") - file.write(" intensity %s\n" % (lamp.energy / 10.0)) - file.write(" color %s %s %s\n" % (lamp.col[0], lamp.col[1], lamp.col[2])) - #file.write(" location %s\n" % ()) - #file.write(" direction %s\n" % ()) - file.write(" dropOffRate %s\n" % (lamp.spotBlend)) - file.write(" cutOffAngle %s\n" % (lamp.spotSize * math_pi / 180.0)) - file.write(" }\n") - -# script main function -def ExportToIv(file_name): - scene = Blender.Scene.GetCurrent() - file = open(file_name, "w") - - # make lists of individual ob types - meshes = [] - lamps = [] - cameras = [] - for ob in scene.objects: - obtype= ob.type - if obtype == "Mesh": - meshes.append(ob); - #elif obtype == "Lamp": - # lamps.append(ob); - #elif obtype == "Camera": - # cameras.append(ob); - #else: - # print "Exporting %s objects isn't supported!" % ob.type - - # write header, footer and groups of ob types - WriteHeader(file); - #for camera in cameras: - # WriteCamera(file, camera); - #for lamp in lamps: - # WriteLamp(file, lamp) - for mesh in meshes: - WriteMesh(file, mesh) - WriteFooter(file) - - file.close() - -def FileSelectorCB(file_name): - if not file_name.lower().endswith('.iv'): - file_name += '.iv' - ExportToIv(file_name) - -if __name__ == '__main__': - Blender.Window.FileSelector(FileSelectorCB, "Export IV", Blender.sys.makename(ext='.iv')) diff --git a/release/scripts/export_dxf.py b/release/scripts/export_dxf.py deleted file mode 100644 index 17f2132fbe8..00000000000 --- a/release/scripts/export_dxf.py +++ /dev/null @@ -1,3041 +0,0 @@ -#!BPY - -""" - Name: 'Autodesk DXF (.dxf/dwg)' - Blender: 249 - Group: 'Export' - Tooltip: 'Export geometry to DXF/DWG-r12 (Drawing eXchange Format).' -""" - -__version__ = "1.35 - 2009.06.18" -__author__ = "Remigiusz Fiedler (AKA migius)" -__license__ = "GPL" -__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" -__bpydoc__ ="""The script exports Blender geometry to DXF format r12 version. - -Version %s -Copyright %s -License %s - -extern dependances: dxfLibrary.py, dxfColorMap.py (optionaly: DConvertCon.exe) - -CONTRIBUTORS: -Remigiusz Fiedler (AKA migius) -Alexandros Sigalas (AKA alxarch) -Stani Michiels (AKA stani) - -See the homepage for documentation. -url: %s - -IDEAs: -- HPGL output, usefull for correct scaled printing of 2d drawings - -TODO: -- export dupligroups and dupliverts as blocks (as option) -- optimize POLYFACE routine: remove double-vertices -- fix support for X,Y-rotated curves(to POLYLINEs): fix blender negative-matrix.invert() -- support hierarchies: groups, instances, parented structures -- support n/f-gons as POLYFACEs with invisible edges -- mapping materials to DXF-styles -- ProgressBar -- export rotation of Camera to VIEW/VPORT -- export parented Cameras to VIEW/VPORT -- wip: write drawing extends for automatic view positioning in CAD -- wip: fix text-objects in persp-projection -- wip: translate current 3D-View to *ACTIVE-VPORT -- wip: fix support Include-Duplis, cause not conform with INSERT-method - -History -v1.35 - 2009.06.18 by migius -- export multiple-instances of Curve-Objects as BLOCK/INSERTs -- added export Cameras (ortho and persp) to VPORTs, incl. clipping -- added export Cameras (ortho and persp) to VIEWs, incl. clipping -- export multiple-instances of Mesh-Objects as BLOCK/INSERTs -- on start prints dxfLibrary version -v1.34 - 2009.06.08 by migius -- export Lamps and Cameras as POINTs -- export passepartout for perspective projection -- added option for export objects only from visible layers -- optimized POLYFACE output: remove loose vertices in back-faces-mode -- cleaning code -- fix nasty bug in getExtrusion() -- support text-objects, also in ortho/persp-projection -- support XYmirrored 2d-curves to 2dPOLYLINEs -- support thickness and elevation for curve-objects -- fix extrusion 210-code (3d orientation vector) -- fix POLYFACE export, synchronized also dxfLibrary.py -- changed to the new 2.49 method Vector.cross() -- output style manager (first try) -v1.33 - 2009.05.25 by migius -- bugfix flipping normals in mirrored mesh-objects -- added UI-Button for future Shadow Generator -- support curve objects in projection-2d mode -- UI stuff: camera selector/manager -v1.32 - 2009.05.22 by migius -- debug mode for curve-objects: output redirect to Blender -- wip support 210-code(extrusion) calculation -- default settings for 2D and 3D export -v1.31 - 2009.05.18 by migius -- globals translated to GUI_A/B dictionary -- optimizing back-faces removal for "hidden-lines" mode -- presets for global location and scale (architecture) -- UI layout: scrollbars, pan with MMB/WHEEL, dynamic width -- new GUI with Draw.Register() from DXF-importer.py -v1.30 - 2008.12.14 by migius -- started work on GUI with Draw.Register() -v1.29 - 2009.04.11 by stani -- added DWG support, Stani Michiels idea for binding an extern DXF-DWG-converter -v1.28 - 2009.02.05 by Alexandros Sigalas (alxarch) -- added option to apply modifiers on exported meshes -- added option to also export duplicates (from dupliverts etc) -v1.28 - 2008.10.22 by migius -- workaround for PVert-bug on ubuntu (reported by Yorik) -- add support for FGons - ignore invisible_tagged edges -- add support for camera: ortho and perspective -v1.27 - 2008.10.07 by migius -- exclude Stani's DXF-Library to extern module -v1.26 - 2008.10.05 by migius -- add "hidden mode" substitut: back-faces removal -- add support for mesh ->POLYFACE -- optimized code for "Flat" procedure -v1.25 - 2008.09.28 by migius -- modif FACE class for r12 -- add mesh-polygon -> Bezier-curve converter (Yorik's code) -- add support for curves ->POLYLINEs -- add "3d-View to Flat" - geometry projection to XY-plane -v1.24 - 2008.09.27 by migius -- add start UI with preferences -- modif POLYLINE class for r12 -- changing output format from r9 to r12(AC1009) -v1.23 - 2008.09.26 by migius -- add finish message-box -v1.22 - 2008.09.26 by migius -- add support for curves ->LINEs -- add support for mesh-edges ->LINEs -v1.21 - 2008.06.04 by migius -- initial adaptation for Blender -v1.1 (20/6/2005) by Stani Michiels www.stani.be/python/sdxf -- Python library to generate dxf drawings -______________________________________________________________ -""" % (__author__,__version__,__license__,__url__) - -# -------------------------------------------------------------------------- -# Script copyright (C) 2008 Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** 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 Blender -from Blender import Mathutils, Window, Scene, Draw, Camera, BezTriple -from Blender import Registry, Object, Mesh, Curve -import os -import subprocess - -try: - import dxfLibrary as DXF - #reload(DXF) - #reload(dxfLibrary) - #from dxfLibrary import * -except: - DXF=None - print "DXF-Exporter: error! found no dxfLibrary.py module in Blender script folder" - Draw.PupMenu("Error%t|found no dxfLibrary.py module in script folder") - - -import math -from math import atan, atan2, log10, sin, cos - -#pi = math.pi -#pi = 3.14159265359 -r2d = 180.0 / math.pi -d2r = math.pi / 180.0 -#note: d2r * angle == math.radians(angle) -#note: r2d * angle == math.degrees(angle) - - -#DEBUG = True #activates debug mode - - -#----globals------------------------------------------ -ONLYSELECTED = 1 # 0/1 = False/True -ONLYVISIBLE = 1 # ignore objects on invisible layers -POLYLINES = 1 # prefer POLYLINEs not LINEs -POLYFACES = 1 # prefer POLYFACEs not 3DFACEs -PROJECTION = 0 # output geometry will be projected to XYplane with Z=0.0 -HIDDEN_LINES = 0 #filter out hidden geometry -SHADOWS = 0 # sun/shadows simulation -CAMERA = 1 # selected camera index -PERSPECTIVE = 0 # projection (camera) type: perspective, opposite to orthographic -CAMERAVIEW = 0 # use camera for projection, opposite is 3d-view -INSTANCES = 1 # Export instances of Mesh/Curve as BLOCK/INSERTs on/off -APPLY_MODIFIERS = 1 -INCLUDE_DUPLIS = 0 -OUTPUT_DWG = 0 #optional save to DWG with extern converter - -G_SCALE = 1.0 #(0.0001-1000) global scaling factor for output dxf data -G_ORIGIN = [0.0,0.0,0.0] #global translation-vector (x,y,z) in Blender units -ELEVATION = 0.0 #standard elevation = coordinate Z value in Blender units - -BYBLOCK = 0 #DXF-attribute: assign property to BLOCK defaults -BYLAYER = None #256 #DXF-attribute: assign property to LAYER defaults -PREFIX = 'BF_' #used as prefix for DXF names -LAYERNAME_DEF = '' #default layer name -LAYERCOLOR_DEF = 7 #default layer color index -LAYERLTYPE_DEF = 0 #'CONTINUOUS' - default layer lineType -ENTITYLAYER_DEF = LAYERNAME_DEF #default entity color index -ENTITYCOLOR_DEF = BYLAYER #default entity color index -ENTITYLTYPE_DEF = BYLAYER #default entity lineType - -E_M = 0 -LAB = "scroll MMB/WHEEL . wip .. todo" #"*) parts under construction" -M_OBJ = 0 - -FILENAME_MAX = 180 #max length of path+file_name string (FILE_MAXDIR + FILE_MAXFILE) -NAMELENGTH_MAX = 80 #max_obnamelength in DXF, (limited to 256? ) -INIFILE_DEFAULT_NAME = 'exportDXF' -INIFILE_EXTENSION = '.ini' -INIFILE_HEADER = '#ExportDXF.py ver.1.0 config data' -INFFILE_HEADER = '#ExportDXF.py ver.1.0 analyze of DXF-data' - -BLOCKREGISTRY = {} # registry and map for BLOCKs -SCENE = None -WORLDX = Mathutils.Vector((1,0,0)) -WORLDY = Mathutils.Vector((0,1,0)) -WORLDZ = Mathutils.Vector((0,0,1)) - -AUTO = BezTriple.HandleTypes.AUTO -FREE = BezTriple.HandleTypes.FREE -VECT = BezTriple.HandleTypes.VECT -ALIGN = BezTriple.HandleTypes.ALIGN - - -#-------- DWG support ------------------------------------------ -extCONV_OK = True -extCONV = 'DConvertCon.exe' -extCONV_PATH = os.path.join(Blender.Get('scriptsdir'),extCONV) -if not os.path.isfile(extCONV_PATH): - extCONV_OK = False - extCONV_TEXT = 'DWG-Exporter: Abort, nothing done!|\ -Copy first %s into Blender script directory.|\ -More details in online Help.' %extCONV -else: - if not os.sys.platform.startswith('win'): - # check if Wine installed: - if subprocess.Popen(('which', 'winepath'), stdout=subprocess.PIPE).stdout.read().strip(): - extCONV_PATH = 'wine %s'%extCONV_PATH - else: - extCONV_OK = False - extCONV_TEXT = 'DWG-Exporter: Abort, nothing done!|\ -The external DWG-converter (%s) needs Wine installed on your system.|\ -More details in online Help.' %extCONV -#print 'extCONV_PATH = ', extCONV_PATH - - -#---------------------------------------------- -def updateMenuCAMERA(): - global CAMERAS - global MenuCAMERA - global MenuLIGHT - - scn = Scene.GetCurrent() - objs = scn.getChildren() - currcam = scn.getCurrentCamera() - if currcam: currcam = currcam.getName() - maincams = [] - MenuCAMERA = "Select Camera%t" - for cam in objs: - if cam.getType() == 'Camera': - if cam.getName()[0:4] != "Temp": - maincams.append(cam.getName()) - maincams.sort() - maincams.reverse() - CAMERAS = maincams - for i, cam in enumerate(CAMERAS): - if cam==currcam: - MenuCAMERA += "|* " + cam - else: MenuCAMERA += "| " + cam - MenuCAMERA += "|current 3d-View" - MenuLIGHT = "Select Sun%t| *todo" - - -#---------------------------------------------- -def updateCAMERA(): - global CAMERA, GUI_A - #CAMERA = 1 - scn = Scene.GetCurrent() - currcam = scn.getCurrentCamera() - if currcam: currcam = currcam.getName() - if currcam in CAMERAS: - CAMERA = CAMERAS.index(currcam)+1 - GUI_A['camera_selected'].val = CAMERA - -#---------------------------------------------- -def gotoCAMERA(): - cam = Object.Get(CAMERAS[CAMERA-1]) - #print 'deb: CAMERA, cam',CAMERA, cam - if cam.getType() != 'Camera': - sure = Draw.PupMenu("Info: %t| It is not a Camera Object.") - else: - scn = Scene.getCurrent() - scn.setCurrentCamera(cam) - Window.CameraView(0) - Window.Redraw() - updateMenuCAMERA() - - -#------- Duplicates support ---------------------------------------------- -def dupTest(object): - """ - Checks objects for duplicates enabled (any type) - object: Blender Object. - Returns: Boolean - True if object has any kind of duplicates enabled. - """ - if (object.enableDupFrames or \ - object.enableDupGroup or \ - object.enableDupVerts): - return True - else: - return False - -def getObjectsAndDuplis(oblist,MATRICES=False,HACK=False): - """ - Return a list of real objects and duplicates and optionally their matrices - oblist: List of Blender Objects - MATRICES: Boolean - Check to also get the objects matrices, default=False - HACK: Boolean - See note, default=False - Returns: List of objects or - List of tuples of the form:(ob,matrix) if MATRICES is set to True - NOTE: There is an ugly hack here that excludes all objects whose name - starts with "dpl_" to exclude objects that are parented to a duplicating - object, User must name objects properly if hack is used. - """ - - result = [] - for ob in oblist: - if INCLUDE_DUPLIS and dupTest(ob): - dup_obs=ob.DupObjects - if len(dup_obs): - for dup_ob, dup_mx in dup_obs: - if MATRICES: - result.append((dup_ob,dup_mx)) - else: - result.append(dup_ob) - else: - if HACK: - if ob.getName()[0:4] != "dpl_": - if MATRICES: - mx = ob.mat - result.append((ob,mx)) - else: - result.append(ob) - else: - if MATRICES: - mx = ob.mat - result.append((ob,mx)) - else: - result.append(ob) - return result - -#----------------------------------------------------- -def hidden_status(faces, mx, mx_n): - # sort out back-faces = with normals pointed away from camera - #print 'HIDDEN_LINES: caution! not full implemented yet' - front_faces = [] - front_edges = [] - for f in faces: - #print 'deb: face=', f #--------- - #print 'deb: dir(face)=', dir(f) #--------- - # get its normal-vector in localCS - vec_normal = f.no.copy() - #print 'deb: vec_normal=', vec_normal #------------------ - # must be transfered to camera/view-CS - vec_normal *= mx_n - #vec_normal *= mb.rotationPart() - #print 'deb:2vec_normal=', vec_normal #------------------ - #vec_normal *= mw0.rotationPart() - #print 'deb:3vec_normal=', vec_normal, '\n' #------------------ - - - frontFace = False - if not PERSPECTIVE: #for ortho mode ---------- - # normal must point the Z direction-hemisphere - if vec_normal[2] > 0.00001: - frontFace = True - else: - v = f.verts[0] - vert = Mathutils.Vector(v.co) * mx - if Mathutils.DotVecs(vert, vec_normal) < 0.00001: - frontFace = True - - if frontFace: - front_faces.append(f.index) - for key in f.edge_keys: - #this test can be done faster with set() - if key not in front_edges: - front_edges.append(key) - - #print 'deb: amount of visible faces=', len(front_faces) #--------- - #print 'deb: visible faces=', front_faces #--------- - #print 'deb: amount of visible edges=', len(front_edges) #--------- - #print 'deb: visible edges=', front_edges #--------- - return front_faces, front_edges - - -#---- migration to 2.49------------------------------------------------- -if 'cross' in dir(Mathutils.Vector()): - #Draw.PupMenu('DXF exporter: Abort%t|This script version works for Blender up 2.49 only!') - def M_CrossVecs(v1,v2): - return v1.cross(v2) #for up2.49 - def M_DotVecs(v1,v2): - return v1.dot(v2) #for up2.49 -else: - def M_CrossVecs(v1,v2): - return Mathutils.CrossVecs(v1,v2) #for pre2.49 - def M_DotVecs(v1,v2): - return Mathutils.DotVecs(v1,v2) #for pre2.49 - - -#----------------------------------------------------- -def getExtrusion(matrix): - """calculates DXF-Extrusion = Arbitrary Xaxis and Zaxis vectors - - """ - AZaxis = matrix[2].copy().resize3D().normalize() # = ArbitraryZvector - Extrusion = [AZaxis[0],AZaxis[1],AZaxis[2]] - if AZaxis[2]==1.0: - Extrusion = None - AXaxis = matrix[0].copy().resize3D() # = ArbitraryXvector - else: - threshold = 1.0 / 64.0 - if abs(AZaxis[0]) < threshold and abs(AZaxis[1]) < threshold: - # AXaxis is the intersection WorldPlane and ExtrusionPlane - AXaxis = M_CrossVecs(WORLDY,AZaxis) - else: - AXaxis = M_CrossVecs(WORLDZ,AZaxis) - #print 'deb:\n' #------------- - #print 'deb:getExtrusion() Extrusion=', Extrusion #--------- - return Extrusion, AXaxis.normalize() - - -#----------------------------------------------------- -def getZRotation(AXaxis, rot_matrix_invert): - """calculates ZRotation = angle between ArbitraryXvector and obj.matrix.Xaxis - - """ - # this works: Xaxis is the obj.matrix-Xaxis vector - # but not correct for all orientations - #Xaxis = matrix[0].copy().resize3D() # = ArbitraryXvector - ##Xaxis.normalize() # = ArbitraryXvector - #ZRotation = - Mathutils.AngleBetweenVecs(Xaxis,AXaxis) #output in radians - - # this works for all orientations, maybe a bit faster - # transform AXaxis into OCS:Object-Coord-System - #rot_matrix = normalizeMat(matrix.rotationPart()) - #rot_matrix_invert = rot_matrix.invert() - vec = AXaxis * rot_matrix_invert - ##vec = AXaxis * matrix.copy().invert() - ##vec.normalize() # not needed for atan2() - #print '\ndeb:getExtrusion() vec=', vec #--------- - ZRotation = - atan2(vec[1],vec[0]) #output in radians - - #print 'deb:ZRotation() ZRotation=', ZRotation*r2d #--------- - return ZRotation - - -#------------------------------------------ -def normalizeMat(matrix): - mat12 = matrix.copy() - mat12 = [Mathutils.Vector(v).normalize() for v in mat12] - if len(mat12)>3: - matr12 = Mathutils.Matrix(mat12[0],mat12[1],mat12[2],mat12[3]) - else: - matr12 = Mathutils.Matrix(mat12[0],mat12[1],mat12[2]) - return matr12 - - -#----------------------------------------------------- -def projected_co(verts, matrix): - """ converts coordinates of points from OCS to WCS->ScreenCS - needs matrix: a projection matrix - needs verts: a list of vectors[x,y,z] - returns a list of [x,y,z] - """ - #print 'deb:projected_co() verts=', verts #--------- - temp_verts = [Mathutils.Vector(v)*matrix for v in verts] - #print 'deb:projected_co() temp_verts=', temp_verts #--------- - - if GUI_A['Z_force_on'].val: locZ = GUI_A['Z_elev'].val - else: locZ = 0.0 - - if PROJECTION: - if PERSPECTIVE: - clipStart = 10.0 - for v in temp_verts: - coef = - clipStart / v[2] - v[0] *= coef - v[1] *= coef - v[2] = locZ - for v in temp_verts: - v[2] = locZ - temp_verts = [v[:3] for v in temp_verts] - #print 'deb:projected_co() out_verts=', temp_verts #--------- - return temp_verts - - -#----------------------------------------------------- -def isLeftHand(matrix): - #Is the matrix a left-hand-system, or not? - ma = matrix.rotationPart() - crossXY = M_CrossVecs(ma[0], ma[1]) - check = M_DotVecs(ma[2], crossXY) - if check < 0.00001: return 1 - return 0 - - -#----------------------------------------------------- -def exportMesh(ob, mx, mx_n, me=None, **common): - """converts Mesh-Object to desired projection and representation(DXF-Entity type) - """ - global BLOCKREGISTRY - entities = [] - block = None - #print 'deb:exportMesh() given common=', common #--------- - if me==None: - me = ob.getData(mesh=1) - else: - me.getFromObject(ob) - # idea: me.transform(mx); get verts data; me.transform(mx_inv)= back to the origin state - # the .transform-method is fast, but bad, cause invasive: - # it manipulates original geometry and by retransformation lefts back rounding-errors - # we dont want to manipulate original data! - #temp_verts = me.verts[:] #doesn't work on ubuntu(Yorik), bug? - if me.verts: - #print 'deb:exportMesh() started' #--------- - - #print 'deb:exportMesh() ob.name=', ob.name #--------- - #print 'deb:exportMesh() me.name=', me.name #--------- - #print 'deb:exportMesh() me.users=', me.users #--------- - # check if there are more instances of this mesh (if used by other objects), then write to BLOCK/INSERT - if GUI_A['instances_on'].val and me.users>1 and not PROJECTION: - if me.name in BLOCKREGISTRY.keys(): - insert_name = BLOCKREGISTRY[me.name] - # write INSERT to entities - entities = exportInsert(ob, mx,insert_name, **common) - else: - # generate geom_output in ObjectCS - allpoints = [v.co for v in me.verts] - identity_matrix = Mathutils.Matrix().identity() - allpoints = projected_co(allpoints, identity_matrix) - #allpoints = toGlobalOrigin(allpoints) - faces=[] - edges=[] - for e in me.edges: edges.append(e.key) - faces = [[v.index for v in f.verts] for f in me.faces] - entities = writeMeshEntities(allpoints, edges, faces, **common) - if entities: # if not empty block - # write BLOCK definition and INSERT entity - # BLOCKREGISTRY = dictionary 'blender_name':'dxf_name'.append(me.name) - BLOCKREGISTRY[me.name]=validDXFr12name(('ME_'+ me.name)) - insert_name = BLOCKREGISTRY[me.name] - block = DXF.Block(insert_name,flag=0,base=(0,0,0),entities=entities) - # write INSERT as entity - entities = exportInsert(ob, mx, insert_name, **common) - - else: # no other instances, so go the standard way - allpoints = [v.co for v in me.verts] - allpoints = projected_co(allpoints, mx) - allpoints = toGlobalOrigin(allpoints) - faces=[] - edges=[] - if me.faces and PROJECTION and HIDDEN_LINES: - #if DEBUG: print 'deb:exportMesh HIDDEN_LINES mode' #--------- - faces, edges = hidden_status(me.faces, mx, mx_n) - faces = [[v.index for v in me.faces[f_nr].verts] for f_nr in faces] - else: - #if DEBUG: print 'deb:exportMesh STANDARD mode' #--------- - for e in me.edges: edges.append(e.key) - #faces = [f.index for f in me.faces] - faces = [[v.index for v in f.verts] for f in me.faces] - #faces = [[allpoints[v.index] for v in f.verts] for f in me.faces] - #print 'deb: allpoints=\n', allpoints #--------- - #print 'deb: edges=\n', edges #--------- - #print 'deb: faces=\n', faces #--------- - if isLeftHand(mx): # then change vertex-order in every face - for f in faces: - f.reverse() - #f = [f[-1]] + f[:-1] #TODO: might be needed - #print 'deb: faces=\n', faces #--------- - entities = writeMeshEntities(allpoints, edges, faces, **common) - - return entities, block - - -#------------------------------------------------- -def writeMeshEntities(allpoints, edges, faces, **common): - """help routine for exportMesh() - """ - entities = [] - - c = mesh_as_list[GUI_A['mesh_as'].val] - if 'POINTs'==c: # export Mesh as multiple POINTs - for p in allpoints: - dxfPOINT = DXF.Point(points=[p],**common) - entities.append(dxfPOINT) - elif 'LINEs'==c or (not faces): - if edges and allpoints: - if DEBUG: mesh_drawBlender(allpoints, edges, None) #deb: draw to blender scene - for e in edges: - points = [allpoints[e[0]], allpoints[e[1]]] - dxfLINE = DXF.Line(points, **common) - entities.append(dxfLINE) - elif faces: - if c in ('POLYFACE','POLYLINE'): - if allpoints: - #TODO: purge allpoints: left only vertices used by faces - if DEBUG: mesh_drawBlender(allpoints, None, faces) #deb: draw to scene - if not (PROJECTION and HIDDEN_LINES): - faces = [[v+1 for v in f] for f in faces] - else: - # for back-Faces-mode remove face-free verts - map=verts_state= [0]*len(allpoints) - for f in faces: - for v in f: - verts_state[v]=1 - if 0 in verts_state: # if dirty state - i,newverts=0,[] - for used_i,used in enumerate(verts_state): - if used: - newverts.append(allpoints[used_i]) - map[used_i]=i - i+=1 - allpoints = newverts - faces = [[map[v]+1 for v in f] for f in faces] - dxfPOLYFACE = DXF.PolyLine([allpoints, faces], flag=64, **common) - #print '\n deb: dxfPOLYFACE=',dxfPOLYFACE #------------- - entities.append(dxfPOLYFACE) - elif '3DFACEs'==c: - if DEBUG: mesh_drawBlender(allpoints, None, faces) #deb: draw to scene - for f in faces: - #print 'deb: face=', f #--------- - points = [allpoints[key] for key in f] - #points = [p.co[:3] for p in points] - #print 'deb: pointsXX=\n', points #--------- - dxfFACE = DXF.Face(points, **common) - entities.append(dxfFACE) - - return entities - - -#----------------------------------------------------- -def mesh_drawBlender(vertList, edgeList, faceList, name="dxfMesh", flatten=False, AT_CUR=True, link=True): - #print 'deb:mesh_drawBlender started XXXXXXXXXXXXXXXXXX' #--------- - ob = Object.New("Mesh",name) - me = Mesh.New(name) - #print 'deb: vertList=\n', vertList #--------- - #print 'deb: edgeList=\n', edgeList #--------- - #print 'deb: faceList=\n', faceList #--------- - me.verts.extend(vertList) - if edgeList: me.edges.extend(edgeList) - if faceList: me.faces.extend(faceList) - if flatten: - for v in me.verts: v.co.z = 0.0 - ob.link(me) - if link: - sce = Scene.getCurrent() - sce.objects.link(ob) - #me.triangleToQuad() - if AT_CUR: - cur_loc = Window.GetCursorPos() - ob.setLocation(cur_loc) - Blender.Redraw() - #return ob - -#----------------------------------------------------- -def curve_drawBlender(vertList, org_point=[0.0,0.0,0.0], closed=0, name="dxfCurve", flatten=False, AT_CUR=True, link=True): - #print 'deb:curve_drawBlender started XXXXXXXXXXXXXXXXXX' #--------- - ob = Object.New("Curve",name) - cu = Curve.New(name) - #print 'deb: vertList=\n', vertList #--------- - curve = cu.appendNurb(BezTriple.New(vertList[0])) - for p in vertList[1:]: - curve.append(BezTriple.New(p)) - for point in curve: - #point.handleTypes = [VECT, VECT] - point.handleTypes = [FREE, FREE] - point.radius = 1.0 - curve.flagU = closed # 0 sets the curve not cyclic=open - cu.setResolu(6) - cu.update() #important for handles calculation - if flatten: - for v in cu.verts: v.co.z = 0.0 - ob.link(cu) - if link: - sce = Scene.getCurrent() - sce.objects.link(ob) - #me.triangleToQuad() - if AT_CUR: - cur_loc = Window.GetCursorPos() - ob.setLocation(cur_loc) - elif org_point: - cur_loc=org_point - ob.setLocation(cur_loc) - Blender.Redraw() - #return ob - - -#----------------------------------------------------- -def toGlobalOrigin(points): - """relocates points to the new location - needs a list of points [x,y,z] - """ - if GUI_A['g_origin_on'].val: - for p in points: - p[0] += G_ORIGIN[0] - p[1] += G_ORIGIN[1] - p[2] += G_ORIGIN[2] - return points - - -#----------------------------------------------------- -def exportEmpty(ob, mx, mw, **common): - """converts Empty-Object to desired projection and representation(DXF-Entity type) - """ - p = Mathutils.Vector(ob.loc) - [p] = projected_co([p], mx) - [p] = toGlobalOrigin([p]) - - entities = [] - c = empty_as_list[GUI_A['empty_as'].val] - if c=="POINT": # export Empty as POINT - dxfPOINT = DXF.Point(points=[p],**common) - entities.append(dxfPOINT) - return entities - -#----------------------------------------------------- -def exportCamera(ob, mx, mw, **common): - """converts Camera-Object to desired projection and representation(DXF-Entity type) - """ - location = Mathutils.Vector(ob.loc) - [location] = projected_co([location], mx) - [location] = toGlobalOrigin([location]) - view_name=validDXFr12name(('CAM_'+ ob.name)) - - camera = Camera.Get(ob.getData(name_only=True)) - #print 'deb: camera=', dir(camera) #------------------ - if camera.type=='persp': - mode = 1+2+4+16 - # mode flags: 1=persp, 2=frontclip, 4=backclip,16=FrontZ - elif camera.type=='ortho': - mode = 0+2+4+16 - - leftBottom=(0.0,0.0) # default - rightTop=(1.0,1.0) # default - center=(0.0,0.0) # default - - direction = Mathutils.Vector(0.0,0.0,1.0) * mx.rotationPart() # in W-C-S - direction.normalize() - target=Mathutils.Vector(ob.loc) - direction # in W-C-S - #ratio=1.0 - width=height= camera.scale # for ortho-camera - lens = camera.lens # for persp-camera - frontClipping = -(camera.clipStart - 1.0) - backClipping = -(camera.clipEnd - 1.0) - - entities, vport, view = [], None, None - c = camera_as_list[GUI_A['camera_as'].val] - if c=="POINT": # export as POINT - dxfPOINT = DXF.Point(points=[location],**common) - entities.append(dxfPOINT) - elif c=="VIEW": # export as VIEW - view = DXF.View(name=view_name, - center=center, width=width, height=height, - frontClipping=frontClipping,backClipping=backClipping, - direction=direction,target=target,lens=lens,mode=mode - ) - elif c=="VPORT": # export as VPORT - vport = DXF.VPort(name=view_name, - center=center, ratio=1.0, height=height, - frontClipping=frontClipping,backClipping=backClipping, - direction=direction,target=target,lens=lens,mode=mode - ) - return entities, vport, view - -#----------------------------------------------------- -def exportLamp(ob, mx, mw, **common): - """converts Lamp-Object to desired projection and representation(DXF-Entity type) - """ - p = Mathutils.Vector(ob.loc) - [p] = projected_co([p], mx) - [p] = toGlobalOrigin([p]) - - entities = [] - c = lamp_as_list[GUI_A['lamp_as'].val] - if c=="POINT": # export as POINT - dxfPOINT = DXF.Point(points=[p],**common) - entities.append(dxfPOINT) - return entities - -#----------------------------------------------------- -def exportInsert(ob, mx, insert_name, **common): - """converts Object to DXF-INSERT in given orientation - """ - WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem - sizeX = ob.SizeX - sizeY = ob.SizeY - sizeZ = ob.SizeZ - rotX = ob.RotX - rotY = ob.RotY - rotZ = ob.RotZ - #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- - - Thickness,Extrusion,ZRotation,Elevation = None,None,None,None - - AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector - if not PROJECTION: - #Extrusion, ZRotation, Elevation = getExtrusion(mx) - Extrusion, AXaxis = getExtrusion(mx) - - entities = [] - - if 1: - if not PROJECTION: - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ - AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) - ZRotation *= r2d - point = ECS_origin - else: #TODO: fails correct location - point1 = Mathutils.Vector(ob.loc) - [point] = projected_co([point1], mx) - if PERSPECTIVE: - clipStart = 10.0 - coef = -clipStart / (point1*mx)[2] - #print 'deb: coef=', coef #-------------- - #TODO: ? sizeX *= coef - #sizeY *= coef - #sizeZ *= coef - - #print 'deb: point=', point #-------------- - [point] = toGlobalOrigin([point]) - - #if DEBUG: text_drawBlender(textstr,points,OCS_origin) #deb: draw to scene - common['extrusion']= Extrusion - #common['elevation']= Elevation - #print 'deb: common=', common #------------------ - if 0: #DEBUG - #linepoints = [[0,0,0], [AXaxis[0],AXaxis[1],AXaxis[2]]] - linepoints = [[0,0,0], point] - dxfLINE = DXF.Line(linepoints,**common) - entities.append(dxfLINE) - - xscale=sizeX - yscale=sizeY - zscale=sizeZ - cols=None - colspacing=None - rows=None - rowspacing=None - - dxfINSERT = DXF.Insert(insert_name,point=point,rotation=ZRotation,\ - xscale=xscale,yscale=yscale,zscale=zscale,\ - cols=cols,colspacing=colspacing,rows=rows,rowspacing=rowspacing,\ - **common) - entities.append(dxfINSERT) - - return entities - - -#----------------------------------------------------- -def exportText(ob, mx, mw, **common): - """converts Text-Object to desired projection and representation(DXF-Entity type) - """ - text3d = ob.getData() - textstr = text3d.getText() - WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem - sizeX = ob.SizeX - sizeY = ob.SizeY - sizeZ = ob.SizeZ - rotX = ob.RotX - rotY = ob.RotY - rotZ = ob.RotZ - #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- - - Thickness,Extrusion,ZRotation,Elevation = None,None,None,None - - AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector - if not PROJECTION: - #Extrusion, ZRotation, Elevation = getExtrusion(mx) - Extrusion, AXaxis = getExtrusion(mx) - - # no thickness/width for TEXTs converted into ScreenCS - if text3d.getExtrudeDepth(): - Thickness = text3d.getExtrudeDepth() * sizeZ - - #Horizontal text justification type, code 72, (optional, default = 0) - # integer codes (not bit-coded) - #0=left, 1=center, 2=right - #3=aligned, 4=middle, 5=fit - Alignment = None - alignment = text3d.getAlignment().value - if alignment in (1,2): Alignment = alignment - - textHeight = text3d.getSize() / 1.7 - textFlag = 0 - if sizeX < 0.0: textFlag |= 2 # set flag for horizontal mirrored - if sizeZ < 0.0: textFlag |= 4 # vertical mirrored - - entities = [] - c = text_as_list[GUI_A['text_as'].val] - - if c=="TEXT": # export text as TEXT - if not PROJECTION: - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ - AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) - ZRotation *= r2d - point = ECS_origin - else: #TODO: fails correct location - point1 = Mathutils.Vector(ob.loc) - [point] = projected_co([point1], mx) - if PERSPECTIVE: - clipStart = 10.0 - coef = -clipStart / (point1*mx)[2] - textHeight *= coef - #print 'deb: coef=', coef #-------------- - - #print 'deb: point=', point #-------------- - [point] = toGlobalOrigin([point]) - point2 = point - - #if DEBUG: text_drawBlender(textstr,points,OCS_origin) #deb: draw to scene - common['extrusion']= Extrusion - #common['elevation']= Elevation - common['thickness']= Thickness - #print 'deb: common=', common #------------------ - if 0: #DEBUG - #linepoints = [[0,0,0], [AXaxis[0],AXaxis[1],AXaxis[2]]] - linepoints = [[0,0,0], point] - dxfLINE = DXF.Line(linepoints,**common) - entities.append(dxfLINE) - - dxfTEXT = DXF.Text(text=textstr,point=point,alignment=point2,rotation=ZRotation,\ - flag=textFlag,height=textHeight,justifyhor=Alignment,**common) - entities.append(dxfTEXT) - if Thickness: - common['thickness']= -Thickness - dxfTEXT = DXF.Text(text=textstr,point=point,alignment=point2,rotation=ZRotation,\ - flag=textFlag,height=textHeight,justifyhor=Alignment,**common) - entities.append(dxfTEXT) - return entities - - -#------------------------------------------- -def euler2matrix(rx, ry, rz): - """creates full 3D rotation matrix (optimized) - needs rx, ry, rz angles in radians - """ - #print 'rx, ry, rz: ', rx, ry, rz - A, B = sin(rx), cos(rx) - C, D = sin(ry), cos(ry) - E, F = sin(rz), cos(rz) - AC, BC = A*C, B*C - return Mathutils.Matrix([D*F, D*E, -C], - [AC*F-B*E, AC*E+B*F, A*D], - [BC*F+A*E, BC*E-A*F, B*D]) - - -#----------------------------------------------------- -def getTargetOrientation(mx,Extrusion,AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ): - """given - """ - if 1: - rot_matrix = normalizeMat(mx.rotationPart()) - #TODO: workaround for blender negative-matrix.invert() - # partially done: works only for rotX,rotY==0.0 - if sizeX<0.0: rot_matrix[0] *= -1 - if sizeY<0.0: rot_matrix[1] *= -1 - #if sizeZ<0.0: rot_matrix[2] *= -1 - rot_matrix_invert = rot_matrix.invert() - else: #TODO: to check, why below rot_matrix_invert is not equal above one - rot_euler_matrix = euler2matrix(rotX,rotY,rotZ) - rot_matrix_invert = euler2matrix(-rotX,-rotY,-rotZ) - - # OCS_origin is Global_Origin in ObjectCoordSystem - OCS_origin = Mathutils.Vector(WCS_loc) * rot_matrix_invert - #print 'deb: OCS_origin=', OCS_origin #--------- - - ZRotation = rotZ - if Extrusion!=None: - ZRotation = getZRotation(AXaxis,rot_matrix_invert) - #Zrotmatrix = Mathutils.RotationMatrix(-ZRotation, 3, "Z") - rs, rc = sin(ZRotation), cos(ZRotation) - Zrotmatrix = Mathutils.Matrix([rc, rs,0.0],[-rs,rc,0.0],[0.0,0.0,1.0]) - #print 'deb: Zrotmatrix=\n', Zrotmatrix #-------------- - - # ECS_origin is Global_Origin in EntityCoordSystem - ECS_origin = OCS_origin * Zrotmatrix - #print 'deb: ECS_origin=', ECS_origin #--------- - #TODO: it doesnt work yet for negative scaled curve-objects! - return ZRotation,Zrotmatrix,OCS_origin,ECS_origin - - -#----------------------------------------------------- -def exportCurve(ob, mx, mw, **common): - """converts Curve-Object to desired projection and representation(DXF-Entity type) - """ - entities = [] - block = None - curve = ob.getData() - #print 'deb: curve=', dir(curve) #--------- - # TODO: should be: if curve.users>1 and not (PERSPECTIVE or (PROJECTION and HIDDEN_MODE): - if GUI_A['instances_on'].val and curve.users>1 and not PROJECTION: - if curve.name in BLOCKREGISTRY.keys(): - insert_name = BLOCKREGISTRY[curve.name] - # write INSERT to entities - entities = exportInsert(ob, mx,insert_name, **common) - else: - # generate geom_output in ObjectCS - imx = Mathutils.Matrix().identity() - WCS_loc = [0,0,0] # WCS_loc is object location in WorldCoordSystem - #print 'deb: WCS_loc=', WCS_loc #--------- - sizeX = sizeY = sizeZ = 1.0 - rotX = rotY = rotZ = 0.0 - Thickness,Extrusion,ZRotation,Elevation = None,None,None,None - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = None,None,None,None - AXaxis = imx[0].copy().resize3D() # = ArbitraryXvector - OCS_origin = [0,0,0] - if not PROJECTION: - #Extrusion, ZRotation, Elevation = getExtrusion(mx) - Extrusion, AXaxis = getExtrusion(imx) - - # no thickness/width for POLYLINEs converted into Screen-C-S - #print 'deb: curve.ext1=', curve.ext1 #--------- - if curve.ext1: Thickness = curve.ext1 * sizeZ - if curve.ext2 and sizeX==sizeY: - Width = curve.ext2 * sizeX - if "POLYLINE"==curve_as_list[GUI_A['curve_as'].val]: # export as POLYLINE - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(imx,Extrusion,\ - AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) - - entities = writeCurveEntities(curve, imx, - Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, - WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, - **common) - - if entities: # if not empty block - # write BLOCK definition and INSERT entity - # BLOCKREGISTRY = dictionary 'blender_name':'dxf_name'.append(me.name) - BLOCKREGISTRY[curve.name]=validDXFr12name(('CU_'+ curve.name)) - insert_name = BLOCKREGISTRY[curve.name] - block = DXF.Block(insert_name,flag=0,base=(0,0,0),entities=entities) - # write INSERT as entity - entities = exportInsert(ob, mx, insert_name, **common) - - else: # no other instances, so go the standard way - WCS_loc = ob.loc # WCS_loc is object location in WorldCoordSystem - #print 'deb: WCS_loc=', WCS_loc #--------- - sizeX = ob.SizeX - sizeY = ob.SizeY - sizeZ = ob.SizeZ - rotX = ob.RotX - rotY = ob.RotY - rotZ = ob.RotZ - #print 'deb: sizeX=%s, sizeY=%s' %(sizeX, sizeY) #--------- - - Thickness,Extrusion,ZRotation,Elevation = None,None,None,None - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = None,None,None,None - AXaxis = mx[0].copy().resize3D() # = ArbitraryXvector - OCS_origin = [0,0,0] - if not PROJECTION: - #Extrusion, ZRotation, Elevation = getExtrusion(mx) - Extrusion, AXaxis = getExtrusion(mx) - - # no thickness/width for POLYLINEs converted into Screen-C-S - #print 'deb: curve.ext1=', curve.ext1 #--------- - if curve.ext1: Thickness = curve.ext1 * sizeZ - if curve.ext2 and sizeX==sizeY: - Width = curve.ext2 * sizeX - if "POLYLINE"==curve_as_list[GUI_A['curve_as'].val]: # export as POLYLINE - ZRotation,Zrotmatrix,OCS_origin,ECS_origin = getTargetOrientation(mx,Extrusion,\ - AXaxis,WCS_loc,sizeX,sizeY,sizeZ,rotX,rotY,rotZ) - entities = writeCurveEntities(curve, mx, - Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, - WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, - **common) - - return entities, block - - -#------------------------------------------------- -def writeCurveEntities(curve, mx, - Thickness,Extrusion,ZRotation,Elevation,AXaxis,Zrotmatrix, - WCS_loc,OCS_origin,ECS_origin,sizeX,sizeY,sizeZ, - **common): - """help routine for exportCurve() - """ - entities = [] - - if 1: - for cur in curve: - #print 'deb: START cur=', cur #-------------- - points = [] - if cur.isNurb(): - for point in cur: - #print 'deb:isNurb point=', point #--------- - vec = point[0:3] - #print 'deb: vec=', vec #--------- - pkt = Mathutils.Vector(vec) - #print 'deb: pkt=', pkt #--------- - points.append(pkt) - else: - for point in cur: - #print 'deb:isBezier point=', point.getTriple() #--------- - vec = point.getTriple()[1] - #print 'deb: vec=', vec #--------- - pkt = Mathutils.Vector(vec) - #print 'deb: pkt=', pkt #--------- - points.append(pkt) - - #print 'deb: points', points #-------------- - if len(points)>1: - c = curve_as_list[GUI_A['curve_as'].val] - - if c=="POLYLINE": # export Curve as POLYLINE - if not PROJECTION: - # recalculate points(2d=X,Y) into Entity-Coords-System - for p in points: # list of vectors - p[0] *= sizeX - p[1] *= sizeY - p2 = p * Zrotmatrix - p2[0] += ECS_origin[0] - p2[1] += ECS_origin[1] - p[0],p[1] = p2[0],p2[1] - else: - points = projected_co(points, mx) - #print 'deb: points', points #-------------- - - if cur.isCyclic(): closed = 1 - else: closed = 0 - points = toGlobalOrigin(points) - - if DEBUG: curve_drawBlender(points,OCS_origin,closed) #deb: draw to scene - - common['extrusion']= Extrusion - ##common['rotation']= ZRotation - ##common['elevation']= Elevation - common['thickness']= Thickness - #print 'deb: common=', common #------------------ - - if 0: #DEBUG - p=AXaxis[:3] - entities.append(DXF.Line([[0,0,0], p],**common)) - p=ECS_origin[:3] - entities.append(DXF.Line([[0,0,0], p],**common)) - common['color']= 5 - p=OCS_origin[:3] - entities.append(DXF.Line([[0,0,0], p],**common)) - #OCS_origin=[0,0,0] #only debug---------------- - dxfPLINE = DXF.PolyLine(points,OCS_origin,closed,**common) - entities.append(dxfPLINE) - - dxfPLINE = DXF.PolyLine(points,OCS_origin,closed,**common) - entities.append(dxfPLINE) - if Thickness: - common['thickness']= -Thickness - dxfPLINE = DXF.PolyLine(points,OCS_origin,closed,**common) - entities.append(dxfPLINE) - - elif c=="LINEs": # export Curve as multiple LINEs - points = projected_co(points, mx) - if cur.isCyclic(): points.append(points[0]) - #print 'deb: points', points #-------------- - points = toGlobalOrigin(points) - - if DEBUG: curve_drawBlender(points,WCS_loc,closed) #deb: draw to scene - common['extrusion']= Extrusion - common['elevation']= Elevation - common['thickness']= Thickness - #print 'deb: common=', common #------------------ - for i in range(len(points)-1): - linepoints = [points[i], points[i+1]] - dxfLINE = DXF.Line(linepoints,**common) - entities.append(dxfLINE) - if Thickness: - common['thickness']= -Thickness - for i in range(len(points)-1): - linepoints = [points[i], points[i+1]] - dxfLINE = DXF.Line(linepoints,**common) - entities.append(dxfLINE) - - elif c=="POINTs": # export Curve as multiple POINTs - points = projected_co(points, mx) - for p in points: - dxfPOINT = DXF.Point(points=[p],**common) - entities.append(dxfPOINT) - return entities - - -#----------------------------------------------------- -def getClipBox(camera): - """calculates Field-of-View-Clipping-Box of given Camera - returns clip_box: a list of vertices - returns matr: translation matrix - """ - sce = Scene.GetCurrent() - context = sce.getRenderingContext() - #print 'deb: context=\n', context #------------------ - sizeX = context.sizeX - sizeY = context.sizeY - ratioXY = sizeX/float(sizeY) - #print 'deb: size X,Y, ratio=', sizeX, sizeY, ratioXY #------------------ - - clip1_Z = - camera.clipStart - clip2_Z = - camera.clipEnd - #print 'deb: clip Start=', camera.clipStart #------------------ - #print 'deb: clip End=', camera.clipEnd #------------------ - - if camera.type=='ortho': - scale = camera.scale - #print 'deb: camscale=', scale #------------------ - clip1shiftX = clip2shiftX = camera.shiftX * scale - clip1shiftY = clip2shiftY = camera.shiftY * scale - clip1_X = scale * 0.5 - clip1_Y = scale * 0.5 - if ratioXY > 1.0: clip1_Y /= ratioXY - else: clip1_X *= ratioXY - clip2_X = clip1_X - clip2_Y = clip1_Y - - near = clip1_Z - far = clip2_Z - right, left = clip1_X, -clip1_X - top, bottom = clip1_Y, -clip1_Y - - scaleX = 2.0/float(right - left) - x3 = -float(right + left)/float(right - left) - scaleY = 2.0/float(top - bottom) - y3 = -float(top + bottom)/float(top - bottom) - scaleZ = 1.0/float(far - near) - z3 = -float(near)/float(far - near) - - matrix = Mathutils.Matrix( [scaleX, 0.0, 0.0, x3], - [0.0, scaleY, 0.0, y3], - [0.0, 0.0, scaleZ, z3], - [0.0, 0.0, 0.0, 1.0]) - - elif camera.type=='persp': - #viewpoint = [0.0, 0.0, 0.0] #camera's coordinate system, hehe - #lens = camera.lens - angle = camera.angle - #print 'deb: cam angle=', angle #------------------ - shiftX = camera.shiftX - shiftY = camera.shiftY - fov_coef = atan(angle * d2r) - fov_coef *= 1.3 #incl. passpartou - clip1_k = clip1_Z * fov_coef - clip2_k = clip2_Z * fov_coef - clip1shiftX = - camera.shiftX * clip1_k - clip2shiftX = - camera.shiftX * clip2_k - clip1shiftY = - camera.shiftY * clip1_k - clip2shiftY = - camera.shiftY * clip2_k - clip1_X = clip1_Y = clip1_k * 0.5 - clip2_X = clip2_Y = clip2_k * 0.5 - if ratioXY > 1.0: - clip1_Y /= ratioXY - clip2_Y /= ratioXY - else: - clip1_X *= ratioXY - clip2_X *= ratioXY - - near = clip1_Z - far = clip2_Z - right, left = clip1_X, -clip1_X - top, bottom = clip1_Y, -clip1_Y - #return Matrix( [scaleX, 0.0, x2, 0.0], - #[0.0, scaleY, y2, 0.0], - #[0.0, 0.0, scaleZ, wZ], - #[0.0, 0.0, -1.0, 0.0]) - matrix = Mathutils.Matrix( [(2.0 * near)/float(right - left), 0.0, float(right + left)/float(right - left), 0.0], - [0.0, (2.0 * near)/float(top - bottom), float(top + bottom)/float(top - bottom), 0.0], - [0.0, 0.0, -float(far + near)/float(far - near), -(2.0 * far * near)/float(far - near)], - [0.0, 0.0, -1.0, 0.0]) - - - clip_box = [ - -clip1_X + clip1shiftX, clip1_X + clip1shiftX, - -clip1_Y + clip1shiftY, clip1_Y + clip1shiftY, - -clip2_X + clip2shiftX, clip2_X + clip2shiftX, - -clip2_Y + clip2shiftY, clip2_Y + clip2shiftY, - clip1_Z, clip2_Z] - #print 'deb: clip_box=\n', clip_box #------------------ - #drawClipBox(clip_box) - return clip_box, matrix - - -#----------------------------------------------------- -def drawClipBox(clip_box): - """debug tool: draws Clipping-Box of a Camera View - """ - min_X1, max_X1, min_Y1, max_Y1,\ - min_X2, max_X2, min_Y2, max_Y2,\ - min_Z, max_Z = clip_box - verts = [] - verts.append([min_X1, min_Y1, min_Z]) - verts.append([max_X1, min_Y1, min_Z]) - verts.append([max_X1, max_Y1, min_Z]) - verts.append([min_X1, max_Y1, min_Z]) - verts.append([min_X2, min_Y2, max_Z]) - verts.append([max_X2, min_Y2, max_Z]) - verts.append([max_X2, max_Y2, max_Z]) - verts.append([min_X2, max_Y2, max_Z]) - faces = [[0,1,2,3],[4,5,6,7]] - newmesh = Mesh.New() - newmesh.verts.extend(verts) - newmesh.faces.extend(faces) - - plan = Object.New('Mesh','clip_box') - plan.link(newmesh) - sce = Scene.GetCurrent() - sce.objects.link(plan) - plan.setMatrix(sce.objects.camera.matrix) - - -#------------------------------------------------- -def getCommons(ob): - """set up common attributes for output style: - color=None - extrusion=None - layer='0', - lineType=None - lineTypeScale=None - lineWeight=None - thickness=None - parent=None - """ - - layers = ob.layers #gives a list e.g.[1,5,19] - if layers: ob_layer_nr = layers[0] - #print 'ob_layer_nr=', ob_layer_nr #-------------- - - materials = ob.getMaterials() - if materials: - ob_material = materials[0] - ob_mat_color = ob_material.rgbCol - else: ob_mat_color, ob_material = None, None - #print 'ob_mat_color, ob_material=', ob_mat_color, ob_material #-------------- - - data = ob.getData() - data_materials = ob.getMaterials() - if data_materials: - data_material = data_materials[0] - data_mat_color = data_material.rgbCol - else: data_mat_color, data_material = None, None - #print 'data_mat_color, data_material=', data_mat_color, data_material #-------------- - - entitylayer = ENTITYLAYER_DEF - c = entitylayer_from_list[GUI_A['entitylayer_from'].val] - #["default_LAYER","obj.name","obj.layer","obj.material","obj.data.name","obj.data.material","..vertexgroup","..group","..map_table"] - if c=="default_LAYER": - entitylayer = LAYERNAME_DEF - elif c=="obj.layer" and ob_layer_nr: - entitylayer = 'LAYER'+ str(ob_layer_nr) - elif c=="obj.material" and ob_material: - entitylayer = ob_material.name - elif c=="obj.name": - entitylayer = ob.name - elif c=="obj.data.material" and ob_material: - entitylayer = data_material.name - elif c=="obj.data.name": - entitylayer = data.name - entitylayer = validDXFr12name(PREFIX+entitylayer) - if entitylayer=="": entitylayer = "BF_0" - - entitycolor = ENTITYCOLOR_DEF - c = entitycolor_from_list[GUI_A['entitycolor_from'].val] - if c=="default_COLOR": - entitycolor = LAYERCOLOR_DEF - elif c=="BYLAYER": - entitycolor = BYLAYER - elif c=="BYBLOCK": - entitycolor = BYBLOCK - elif c=="obj.layer" and ob_layer_nr: - entitycolor = ob_layer_nr - elif c=="obj.color" and ob.color: - entitycolor = col2DXF(ob.color) - elif c=="obj.material" and ob_mat_color: - entitycolor = col2DXF(ob_mat_color) - elif c=="obj.data.material" and data_mat_color: - entitycolor = col2DXF(data_mat_color) - #if entitycolor!=None: layercolor = entitycolor - - entityltype = ENTITYLTYPE_DEF - c = entityltype_from_list[GUI_A['entityltype_from'].val] - if c=="default_LTYPE": - entityltype = LAYERLTYPE_DEF - elif c=="BYLAYER": - entityltype = BYLAYER - elif c=="BYBLOCK": - entityltype = BYBLOCK - elif c: - entityltype = c - - return entitylayer,entitycolor,entityltype - - -#----------------------------------------------------- -def do_export(export_list, filepath): - global PERSPECTIVE, CAMERAVIEW, BLOCKREGISTRY - Window.WaitCursor(1) - t = Blender.sys.time() - - # init Drawing --------------------- - d=DXF.Drawing() - # add Tables ----------------- - # initialized automatic: d.blocks.append(b) #section BLOCKS - # initialized automatic: d.styles.append(DXF.Style()) #table STYLE - - #table LTYPE --------------- - #d.linetypes.append(DXF.LineType(name='CONTINUOUS',description='--------',elements=[0.0])) - d.linetypes.append(DXF.LineType(name='DOT',description='. . . . . . .',elements=[0.25, 0.0, -0.25])) - d.linetypes.append(DXF.LineType(name='DASHED',description='__ __ __ __ __',elements=[0.8, 0.5, -0.3])) - d.linetypes.append(DXF.LineType(name='DASHDOT',description='__ . __ . __ .',elements=[1.0, 0.5, -0.25, 0.0, -0.25])) - d.linetypes.append(DXF.LineType(name='DIVIDE',description='____ . . ____ . . ',elements=[1.25, 0.5, -0.25, 0.0, -0.25, 0.0, -0.25])) - d.linetypes.append(DXF.LineType(name='BORDER',description='__ __ . __ __ . ',elements=[1.75, 0.5, -0.25, 0.5, -0.25, 0.0, -0.25])) - d.linetypes.append(DXF.LineType(name='HIDDEN',description='__ __ __ __ __',elements=[0.4, 0.25, -0.25])) - d.linetypes.append(DXF.LineType(name='CENTER',description='____ _ ____ _ __',elements=[2.0, 1.25, -0.25, 0.25, -0.25])) - - #d.vports.append(DXF.VPort('*ACTIVE')) - d.vports.append(DXF.VPort('*ACTIVE',center=(-5.0,1.0),height=10.0)) - #d.vports.append(DXF.VPort('*ACTIVE',leftBottom=(-100.0,-60.0),rightTop=(100.0,60.0))) - #d.views.append(DXF.View('Normal')) #table view - d.views.append(DXF.ViewByWindow('BF_TOPVIEW',leftBottom=(-100,-60),rightTop=(100,60))) #idem - - # add Entities -------------------- - BLOCKREGISTRY = {} # registry and map for BLOCKs - PERSPECTIVE = 0 - something_ready = 0 - selected_len = len(export_list) - sce = Scene.GetCurrent() - - mw = Mathutils.Matrix( [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 1.0]) - if PROJECTION: - if CAMERA ',\n' - # replace: '{' -> '\n{\n' - # replace: '}' -> '\n}\n' - output_str = ',\n'.join(output_str.split(',')) - output_str = '\n}'.join(output_str.split('}')) - output_str = '{\n'.join(output_str.split('{')) - try: - f = file(iniFile, 'w') - f.write(INIFILE_HEADER + '\n# this is a comment line\n') - f.write(output_str) - f.close() - #Draw.PupMenu('DXF-Exporter: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) - except: - Draw.PupMenu('DXF-Exporter: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile) - - else: - Draw.PupMenu('DXF-Exporter: INI-file: Alert!%t|no valid name/extension for INI-file selected!') - print "DXF-Exporter: Alert!: no valid INI-file selected." - if not iniFile: - if dxfFileName.val.lower().endswith('.dxf'): - iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION - - -def loadConfig(): #remi--todo----------------------------------------------- - """Load settings/config/materials from INI-file. - - TODO: Read material-assignements from config-file. - """ - #20070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename) - global iniFileName, GUI_A, GUI_B - - iniFile = iniFileName.val - update_RegistryKey('iniFileName', iniFile) - #print 'deb:loadConfig iniFile: ', iniFile #---------------------- - if iniFile.lower().endswith(INIFILE_EXTENSION) and Blender.sys.exists(iniFile): - f = file(iniFile, 'r') - header_str = f.readline() - if header_str.startswith(INIFILE_HEADER): - data_str = f.read() - f.close() - #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #----------------- - data = eval(data_str) - for k, v in data[0].iteritems(): - try: GUI_A[k].val = v - except: GUI_A[k] = Draw.Create(v) - for k, v in data[1].iteritems(): - try: GUI_B[k].val = v - except: GUI_B[k] = Draw.Create(v) - else: - f.close() - Draw.PupMenu('DXF-Exporter: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) - else: - Draw.PupMenu('DXF-Exporter: INI-file: Alert!%t|no valid INI-file selected!') - print "DXF-Exporter: Alert!: no valid INI-file selected." - if not iniFileName: - if dxfFileName.val.lower().endswith('.dxf'): - iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION - - - -def updateConfig(keywords, drawTypes): #----------------------------------------------- - """updates GUI_settings with given dictionaries - - """ - global GUI_A, GUI_B - #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- - for k, v in keywords.iteritems(): - GUI_A[k].val = v - for k, v in drawTypes.iteritems(): - GUI_B[k].val = v - -def resetDefaultConfig(): #----------------------------------------------- - """Resets settings/config/materials to defaults. - - """ - #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- - updateConfig(keywords_org, drawTypes_org) - - -def presetConfig_polyline(activate): #----------------------------------------------- - """Sets settings/config for polygon representation: POLYLINE(FACE) or LINEs/3DFACEs. - - """ - global GUI_A - if activate: - GUI_A['to_polyline_on'].val = 1 - GUI_A['mesh_as'].val = 1 - GUI_A['curve_as'].val = 1 - else: - GUI_A['to_polyline_on'].val = 0 - GUI_A['mesh_as'].val = 0 - GUI_A['curve_as'].val = 0 - -def resetDefaultConfig_2D(): #----------------------------------------------- - """Sets settings/config/materials to defaults 2D. - - """ - keywords2d = { - 'projection_on' : 1, - 'fill_on' : 1, - 'text_as' : 0, - 'group_as' : 0, - } - - drawTypes2d = { - 'bmesh' : 1, - 'bcurve': 1, - 'surface':0, - 'bmeta' : 0, - 'text' : 1, - 'empty' : 1, - 'group' : 1, - 'parent' : 1, - #'proxy' : 0, - #'camera': 0, - #'lamp' : 0, - - } - presetConfig_polyline(1) - updateConfig(keywords2d, drawTypes2d) - -def resetDefaultConfig_3D(): #----------------------------------------------- - """Sets settings/config/materials to defaults 3D. - - """ - keywords3d = { - 'projection_on' : 0, - 'fill_on' : 0, - 'text_as' : 0, - 'group_as' : 0, - } - - drawTypes3d = { - 'bmesh' : 1, - 'bcurve': 1, - 'surface':0, - 'bmeta' : 0, - 'text' : 0, - 'empty' : 1, - 'group' : 1, - 'parent' : 1, - #'proxy' : 0, - #'camera': 1, - #'lamp' : 1, - } - presetConfig_polyline(1) - updateConfig(keywords3d, drawTypes3d) - - -def inputGlobalScale(): - """Pop-up UI-Block for global scale factor - """ - global GUI_A - #print 'deb:inputGlobalScale ##########' #------------ - x_scale = Draw.Create(GUI_A['g_scale'].val) - block = [] - #block.append("global translation vector:") - block.append(("", x_scale, 0.0, 10000000.0)) - - retval = Draw.PupBlock("set global scale factor:", block) - - GUI_A['g_scale'].val = float(x_scale.val) - - -def inputOriginVector(): - """Pop-up UI-Block for global translation vector - """ - global GUI_A - #print 'deb:inputOriginVector ##########' #------------ - x_origin = Draw.Create(GUI_A['g_originX'].val) - y_origin = Draw.Create(GUI_A['g_originY'].val) - z_origin = Draw.Create(GUI_A['g_originZ'].val) - block = [] - #block.append("global translation vector:") - block.append(("X: ", x_origin, -100000000.0, 100000000.0)) - block.append(("Y: ", y_origin, -100000000.0, 100000000.0)) - block.append(("Z: ", z_origin, -100000000.0, 100000000.0)) - - retval = Draw.PupBlock("set global translation vector:", block) - - GUI_A['g_originX'].val = x_origin.val - GUI_A['g_originY'].val = y_origin.val - GUI_A['g_originZ'].val = z_origin.val - - -def update_globals(): #----------------------------------------------------------------- - """ update globals if GUI_A changed - """ - global ONLYSELECTED,ONLYVISIBLE, DEBUG,\ - PROJECTION, HIDDEN_LINES, CAMERA, \ - G_SCALE, G_ORIGIN,\ - PREFIX, LAYERNAME_DEF, LAYERCOLOR_DEF, LAYERLTYPE_DEF,\ - APPLY_MODIFIERS, INCLUDE_DUPLIS,\ - OUTPUT_DWG - #global POLYLINES - - ONLYSELECTED = GUI_A['only_selected_on'].val - ONLYVISIBLE = GUI_A['only_visible_on'].val - """ - POLYLINES = GUI_A['to_polyline_on'].val - if GUI_A['curve_as'].val==1: POLYLINES=1 - else: POLYLINES=0 - """ - - if GUI_A['optimization'].val==0: DEBUG = 1 - else: DEBUG = 0 - PROJECTION = GUI_A['projection_on'].val - HIDDEN_LINES = GUI_A['hidden_lines_on'].val - CAMERA = GUI_A['camera_selected'].val - G_SCALE = GUI_A['g_scale'].val - if GUI_A['g_origin_on'].val: - G_ORIGIN[0] = GUI_A['g_originX'].val - G_ORIGIN[1] = GUI_A['g_originY'].val - G_ORIGIN[2] = GUI_A['g_originZ'].val - if GUI_A['g_scale_on'].val: - G_ORIGIN[0] *= G_SCALE - G_ORIGIN[1] *= G_SCALE - G_ORIGIN[2] *= G_SCALE - - PREFIX = GUI_A['prefix_def'].val - LAYERNAME_DEF = GUI_A['layername_def'].val - LAYERCOLOR_DEF = GUI_A['layercolor_def'].val - LAYERLTYPE_DEF = layerltype_def_list[GUI_A['layerltype_def'].val] - - APPLY_MODIFIERS = GUI_A['apply_modifiers_on'].val - INCLUDE_DUPLIS = GUI_A['include_duplis_on'].val - OUTPUT_DWG = GUI_A['outputDWG_on'].val - #print 'deb: GUI HIDDEN_LINES=', HIDDEN_LINES #--------- - #print 'deb: GUI GUI_A: ', GUI_A['hidden_lines_on'].val #--------------- - #print 'deb: GUI GUI_B: ', GUI_B #--------------- - - -def draw_UI(): #----------------------------------------------------------------- - """ Draw startUI and setup Settings. - """ - global GUI_A, GUI_B #__version__ - global user_preset, iniFileName, dxfFileName, config_UI, g_scale_as - global model_space_on - global SCROLL - - global mPAN_X, menu_orgX, mPAN_Xmax - global mPAN_Y, menu_orgY, mPAN_Ymax - global menu__Area, headerArea, screenArea, scrollArea - - size=Buffer(GL_FLOAT, 4) - glGetFloatv(GL_SCISSOR_BOX, size) #window X,Y,sizeX,sizeY - size= size.list - #print '-------------size:', size #-------------------------- - for s in [0,1,2,3]: size[s]=int(size[s]) - window_Area = [0,0,size[2],size[3]-2] - scrollXArea = [0,0,window_Area[2],15] - scrollYArea = [0,0,15,window_Area[3]] - - menu_orgX = -mPAN_X - #menu_orgX = 0 #scrollW - #if menu_pan: menu_orgX -= mPAN_X - if menu_orgX < -mPAN_Xmax: menu_orgX, mPAN_X = -mPAN_Xmax,mPAN_Xmax - if menu_orgX > 0: menu_orgX, mPAN_X = 0,0 - - menu_orgY = -mPAN_Y - #if menu_pan: menu_orgY -= mPAN_Y - if menu_orgY < -mPAN_Ymax: menu_orgY, mPAN_Y = -mPAN_Ymax,mPAN_Ymax - if menu_orgY > 0: menu_orgY, mPAN_Y = 0,0 - - - menu_margin = 10 - butt_margin = 10 - common_column = int((window_Area[2] - (3 * butt_margin) - (2 * menu_margin)-30) / 4.0) - common_column = 70 - # This is for easy layout changes - but_0c = common_column #button 1.column width - but_1c = common_column #button 1.column width - but_2c = common_column #button 2.column - but_3c = common_column #button 3.column - menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width - - simple_menu_h = 260 - extend_menu_h = 345 - menu_h = simple_menu_h # y is menu upper.y - if config_UI.val: - menu_h += extend_menu_h - - mPAN_Xmax = menu_w-window_Area[2]+50 - mPAN_Ymax = menu_h-window_Area[3]+30 - - y = menu_h - x = 0 #menu left.x - x +=menu_orgX+20 - y +=menu_orgY+20 - - - but0c = x + menu_margin #buttons 0.column position.x - but1c = but0c + but_0c + butt_margin - but2c = but1c + but_1c + butt_margin - but3c = but2c + but_2c + butt_margin - but4c = but3c + but_3c - - # Here starts menu ----------------------------------------------------- - #glClear(GL_COLOR_BUFFER_BIT) - #glRasterPos2d(8, 125) - - - ui_box(x, y, x+menu_w+menu_margin*2, y-menu_h) - y -= 20 - Draw.Label("DXF(r12)-Exporter v" + __version__, but0c, y, menu_w, 20) - - if config_UI.val: - b0, b0_ = but0c, but_0c-20 + butt_margin - b1, b1_ = but1c-20, but_1c+20 - y_top = y - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_B['bmesh'] = Draw.Toggle('Mesh', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['bmesh'].val, "Export Mesh-Objects on/off") - if GUI_B['bmesh'].val: - GUI_A['mesh_as'] = Draw.Menu(mesh_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['mesh_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['bcurve'] = Draw.Toggle('Curve', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['bcurve'].val, "Export Curve-Objects on/off") - if GUI_B['bcurve'].val: - GUI_A['curve_as'] = Draw.Menu(curve_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['curve_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['surface'] = Draw.Toggle('..Surface', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['surface'].val, "(*todo) Export Surface-Objects on/off") - if GUI_B['surface'].val: - GUI_A['surface_as'] = Draw.Menu(surface_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['surface_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['bmeta'] = Draw.Toggle('..Meta', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['bmeta'].val, "(*todo) Export Meta-Objects on/off") - if GUI_B['bmeta'].val: - GUI_A['meta_as'] = Draw.Menu(meta_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['meta_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['text'] = Draw.Toggle('Text', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['text'].val, "Export Text-Objects on/off") - if GUI_B['text'].val: - GUI_A['text_as'] = Draw.Menu(text_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['text_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['empty'] = Draw.Toggle('Empty', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['empty'].val, "Export Empty-Objects on/off") - if GUI_B['empty'].val: - GUI_A['empty_as'] = Draw.Menu(empty_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['empty_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y_down = y - # ----------------------------------------------- - - y = y_top - b0, b0_ = but2c, but_2c-20 + butt_margin - b1, b1_ = but3c-20, but_3c+20 - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_B['group'] = Draw.Toggle('..Group', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['group'].val, "(*todo) Export Group-Relationships on/off") - if GUI_B['group'].val: - GUI_A['group_as'] = Draw.Menu(group_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['group_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['parent'] = Draw.Toggle('..Parent', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['parent'].val, "(*todo) Export Parent-Relationships on/off") - if GUI_B['parent'].val: - GUI_A['parent_as'] = Draw.Menu(parent_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['parent_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['proxy'] = Draw.Toggle('..Proxy', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['proxy'].val, "(*todo) Export Proxy-Objects on/off") - if GUI_B['proxy'].val: - GUI_A['proxy_as'] = Draw.Menu(proxy_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['proxy_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['camera'] = Draw.Toggle('Camera', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['camera'].val, "(*wip) Export Camera-Objects on/off") - if GUI_B['camera'].val: - GUI_A['camera_as'] = Draw.Menu(camera_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['camera_as'].val, "Select target DXF-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['lamp'] = Draw.Toggle('Lamp', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['lamp'].val, "(*wip) Export Lamp-Objects on/off") - if GUI_B['lamp'].val: - GUI_A['lamp_as'] = Draw.Menu(lamp_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['lamp_as'].val, "Select target DXF-object") - Draw.EndAlign() - - - if y < y_down: y_down = y - # -----end supported objects-------------------------------------- - - y_top = y_down - y = y_top - y -= 10 - y -= 20 - but_ = menu_w / 6 - b0 = but0c + (menu_w - but_*6)/2 - Draw.BeginAlign() - #GUI_A['dummy_on'] = Draw.Toggle('-', EVENT_NONE, b0+but_*0, y, but_, 20, GUI_A['dummy_on'].val, "placeholder only on/off") - GUI_A['paper_space_on'] = Draw.Toggle('Paper', EVENT_NONE, b0+but_*0, y, but_, 20, GUI_A['paper_space_on'].val, "Export to Paper-Space, otherwise to Model-Space on/off") - GUI_A['layFrozen_on'] = Draw.Toggle ('..frozen', EVENT_NONE, b0+but_*1, y, but_, 20, GUI_A['layFrozen_on'].val, "(*todo) Support LAYER.frozen status on/off") - GUI_A['materialFilter_on'] = Draw.Toggle('..material', EVENT_NONE, b0+but_*2, y, but_, 20, GUI_A['materialFilter_on'].val, "(*todo) Material filtering on/off") - GUI_A['colorFilter_on'] = Draw.Toggle('..color', EVENT_NONE, b0+but_*3, y, but_, 20, GUI_A['colorFilter_on'].val, "(*todo) Color filtering on/off") - GUI_A['groupFilter_on'] = Draw.Toggle('..group', EVENT_NONE, b0+but_*4, y, but_, 20, GUI_A['groupFilter_on'].val, "(*todo) Group filtering on/off") - GUI_A['objectFilter_on'] = Draw.Toggle('..object', EVENT_NONE, b0+but_*5, y, but_, 20, GUI_A['objectFilter_on'].val, "(*todo) Object filtering on/off") - Draw.EndAlign() - - # -----end filters-------------------------------------- - - b0, b0_ = but0c, but_0c + butt_margin - b1, b1_ = but1c, but_1c - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_A['g_origin_on'] = Draw.Toggle('Location', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_origin_on'].val, "Global relocate all objects on/off") - if GUI_A['g_origin_on'].val: - tmp = Draw.PushButton('=', EVENT_ORIGIN, b1, y, 20, 20, "Edit relocation-vector (x,y,z in DXF units)") - origin_str = '(%.4f, %.4f, %.4f)' % ( - GUI_A['g_originX'].val, - GUI_A['g_originY'].val, - GUI_A['g_originZ'].val - ) - tmp = Draw.Label(origin_str, b1+20, y, 300, 20) - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['g_scale_on'] = Draw.Toggle('Scale', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_scale_on'].val, "Global scale all objects on/off") - if GUI_A['g_scale_on'].val: - g_scale_as = Draw.Menu(g_scale_list, EVENT_SCALE, b1, y, 45, 20, g_scale_as.val, "Factor for scaling the DXFdata") - if g_scale_as.val == 12: - pass - else: - if g_scale_as.val == 6: #scale inches to meters - GUI_A['g_scale'].val = 0.0254000 - elif g_scale_as.val == 7: #scale feets to meters - GUI_A['g_scale'].val = 0.3048000 - elif g_scale_as.val == 8: #scale yards to meters - GUI_A['g_scale'].val = 0.9144000 - else: - GUI_A['g_scale'].val = 10.0 ** int(g_scale_as.val) - scale_float = GUI_A['g_scale'].val - if scale_float < 0.000001 or scale_float > 1000000: - scale_str = ' = %s' % GUI_A['g_scale'].val - else: - scale_str = ' = %.6f' % GUI_A['g_scale'].val - Draw.Label(scale_str, b1+45, y, 200, 20) - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['Z_force_on'] = Draw.Toggle('Elevation', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['Z_force_on'].val, "Overwrite Z-coordinates (flatten geometry) on/off") - if GUI_A['Z_force_on'].val: - GUI_A['Z_elev'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['Z_elev'].val, -1000, 1000, "Set value for default Z-coordinate (in DXF units)") - Draw.EndAlign() - - """ - y -= 30 - Draw.BeginAlign() - GUI_A['material_on'] = Draw.Toggle('.material', EVENT_REDRAW, b0, y, b0_-20, 20, GUI_A['material_on'].val, "Support for material assignment on/off") - if GUI_A['material_on'].val: - GUI_A['material_to'] = Draw.Menu(material_to_menu, EVENT_NONE, b1-20, y, b1_+20, 20, GUI_A['material_to'].val, "Material assigned to?") - Draw.EndAlign() - """ - - #b0, b0_ = but0c, but_0c + butt_margin - b0, b0_ = but0c, 50 - b1, b1_ = b0+b0_, but_0c-b0_+ but_1c + butt_margin - b2, b2_ = but2c, but_2c - b3, b3_ = but3c, but_3c - - y -= 30 - Draw.Label('Output:', b0, y, b0_, 20) - Draw.Label('LAYER:', b1, y, b1_, 20) - Draw.Label('COLOR:', b2, y, b2_, 20) - Draw.Label('LINETYPE:', b3, y, b3_, 20) - #Draw.Label('LINESIZE:', b4, y, b4_, 20) - - y -= 20 - Draw.BeginAlign() - GUI_A['prefix_def'] = Draw.String('', EVENT_NONE, b0, y, b0_, 20, GUI_A['prefix_def'].val, 10, "Type Prefix for LAYERs") - GUI_A['layername_def'] = Draw.String('', EVENT_NONE, b1, y, b1_, 20, GUI_A['layername_def'].val, 10, "Type default LAYER name") - GUI_A['layercolor_def'] = Draw.Number('', EVENT_NONE, b2, y, b2_, 20, GUI_A['layercolor_def'].val, 1, 255, "Set default COLOR. (0=BYBLOCK,256=BYLAYER)") - GUI_A['layerltype_def'] = Draw.Menu(layerltype_def_menu, EVENT_NONE, b3, y, b3_, 20, GUI_A['layerltype_def'].val, "Set default LINETYPE") - Draw.EndAlign() - - y -= 25 - Draw.Label('Style:', b0, y, b0_, 20) - Draw.BeginAlign() - GUI_A['entitylayer_from'] = Draw.Menu(entitylayer_from_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['entitylayer_from'].val, "entity LAYER assigned to?") - GUI_A['entitycolor_from'] = Draw.Menu(entitycolor_from_menu, EVENT_NONE, b2, y, b2_, 20, GUI_A['entitycolor_from'].val, "entity COLOR assigned to?") - GUI_A['entityltype_from'] = Draw.Menu(entityltype_from_menu, EVENT_NONE, b3, y, b3_, 20, GUI_A['entityltype_from'].val, "Set entity LINETYPE") - Draw.EndAlign() - - y -= 10 - - y_down = y - # -----end material,translate,scale------------------------------------------ - - - #-------------------------------------- - y_top = y_down - y = y_top - - y -= 30 - Draw.BeginAlign() - Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file with file selector') - iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_1c-60, 20, iniFileName.val, FILENAME_MAX, "Write here the name of the INI-file") - but = but4c-60 - Draw.PushButton('#', EVENT_PRESETS, but, y, 20, 20, "Toggle Preset-INI-files") - Draw.PushButton('L', EVENT_LOAD_INI, but+20, y, 20, 20, 'Loads configuration from selected ini-file: %s' % iniFileName.val) - Draw.PushButton('S', EVENT_SAVE_INI, but+40, y, 20, 20, 'Saves configuration to selected ini-file: %s' % iniFileName.val) - Draw.EndAlign() - - bm = butt_margin/2 - - y -= 10 - y -= 20 - Draw.BeginAlign() - Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF-file with file selector') - dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_0c-menu_margin, 20, dxfFileName.val, FILENAME_MAX, "Type path/name of output DXF-file") - Draw.EndAlign() - - y -= 30 - config_UI = Draw.Toggle('CONFIG', EVENT_REDRAW, but0c, y, but_0c+bm, 20, config_UI.val, 'Advanced configuration on/off' ) - Draw.BeginAlign() - but, but_ = but1c, but_1c+bm - but_ /= 3 - Draw.PushButton('X', EVENT_RESET, but, y, 15, 20, "Reset configuration to defaults") - Draw.PushButton('2D', EVENT_PRESET2D, but+but_, y, but_, 20, 'Set to standard configuration for 2D export') - Draw.PushButton('3D', EVENT_PRESET3D, but+(but_*2), y, but_, 20, 'Set to standard configuration for 3D import') - Draw.EndAlign() - - - y -= 30 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['only_selected_on'] = Draw.Toggle('Export Selection', EVENT_NONE, b0, y, b0_, 20, GUI_A['only_selected_on'].val, "Export only selected geometry on/off") - b0, b0_ = but2c, but_2c + butt_margin + but_3c - Draw.BeginAlign() - GUI_A['projection_on'] = Draw.Toggle('2d Projection', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['projection_on'].val, "Export a 2d Projection according 3d-View or Camera-View on/off") - if GUI_A['projection_on'].val: - GUI_A['camera_selected'] = Draw.Menu(MenuCAMERA, EVENT_CAMERA, b0, y-20, b0_-20, 20, GUI_A['camera_selected'].val, 'Choose the camera to be rendered') - Draw.PushButton('>', EVENT_setCAMERA, b0+b0_-20, y-20, 20, 20, 'switch to selected Camera - make it active') - GUI_A['hidden_lines_on'] = Draw.Toggle('Remove backFaces', EVENT_NONE, b0, y-40, b0_, 20, GUI_A['hidden_lines_on'].val, "Filter out backFaces on/off") - #GUI_A['shadows_on'] = Draw.Toggle('..Shadows', EVENT_REDRAW, b0, y-60, but_2c, 20, GUI_A['shadows_on'].val, "(*todo) Shadow tracing on/off") - #GUI_A['light_on'] = Draw.Menu(MenuLIGHT, EVENT_LIGHT, but3c, y-60, but_3c, 20, GUI_A['light_on'].val, '(*todo) Choose the light source(sun) to be rendered') - Draw.EndAlign() - - y -= 20 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['only_visible_on'] = Draw.Toggle('Visible only', EVENT_PRESETPLINE, b0, y, b0_, 20, GUI_A['only_visible_on'].val, "Export only from visible layers on/off") - #b0, b0_ = but2c, but_2c + butt_margin + but_3c - - y -= 20 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['to_polyline_on'] = Draw.Toggle('POLYLINE-Mode', EVENT_PRESETPLINE, b0, y, b0_, 20, GUI_A['to_polyline_on'].val, "Export to POLYLINE/POLYFACEs, otherwise to LINEs/3DFACEs on/off") - #b0, b0_ = but2c, but_2c + butt_margin + but_3c - - y -= 20 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['instances_on'] = Draw.Toggle('Instances as BLOCKs', EVENT_NONE, b0, y, b0_, 20, GUI_A['instances_on'].val, "Export instances (multi-users) of Mesh/Curve as BLOCK/INSERTs on/off") - #b0, b0_ = but2c, but_2c + butt_margin + but_3c - - y -= 20 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['apply_modifiers_on'] = Draw.Toggle('Apply Modifiers', EVENT_NONE, b0, y, b0_, 20, GUI_A['apply_modifiers_on'].val, "Apply modifier stack to mesh objects before export on/off") - #b0, b0_ = but2c, but_2c + butt_margin + but_3c - - y -= 20 - b0, b0_ = but0c, but_0c + butt_margin +but_1c - GUI_A['include_duplis_on'] = Draw.Toggle('Include Duplis', EVENT_NONE, b0, y, b0_, 20, GUI_A['include_duplis_on'].val, "Export Duplicates (dupliverts, dupliframes, dupligroups) on/off") - #b0, b0_ = but2c, but_2c + butt_margin + but_3c - - - - y -= 30 - Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c+bm, 20, '' ) - Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c+bm, 20, 'goes to online-Manual on wiki.blender.org') - GUI_A['optimization'] = Draw.Number('', EVENT_NONE, but2c, y, 40, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/Draw-in, 1=Verbose, 2=ProgressBar, 3=SilentMode") - GUI_A['outputDWG_on'] = Draw.Toggle('DWG*', EVENT_NONE, but2c, y+20, 40, 20, GUI_A['outputDWG_on'].val, "converts DXF to DWG (needs external converter) on/off") - - Draw.BeginAlign() - Draw.PushButton('START EXPORT', EVENT_START, but2c+40, y, but_2c-40+but_3c+butt_margin, 40, 'Start the export process. For Cancel go to console and hit Ctrl-C') - Draw.EndAlign() - - y -= 20 - #Draw.BeginAlign() - #Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20) - #Draw.Label(LAB, but0c, y, menu_w, 20) - Draw.Label(LAB, 30, y, menu_w, 20) - #Draw.Label(' ', but0c+menu_w, y, menu_margin, 20) - #Draw.EndAlign() - - ui_scrollbarX(menu_orgX, menu_w+50, scrollXArea, c_fg, c_bg) - ui_scrollbarY(menu_orgY, menu_h+30, scrollYArea, c_fg, c_bg) - - - - -#-- END GUI Stuf----------------------------------------------------- - -c0=[0.2,0.2,0.2,0.0] -c1=[0.7,0.7,0.9,0.0] -c2=[0.71,0.71,0.71,0.0] -c3=[0.4,0.4,0.4,0.0] -c4=[0.95,0.95,0.9,0.0] -c5=[0.64,0.64,0.64,0] -c6=[0.75,0.75,0.75,0] -c7=[0.6,0.6,0.6,0] -c8=[1.0,0.0,0.0,0] -c9=[0.7,0.0,0.0,0] -c10=[0.64,0.81,0.81,0] -c11=[0.57,0.71,0.71,0] -c_nor= c5[:3] -c_act= c10[:3] -c_sel= c11[:3] -c_tx = c0[:3] -c_fg = c2[:3] -c_bg = c5[:3] - -def ui_rect(coords,color): - [X1,Y1,X2,Y2],[r,g,b] = coords,color - glColor3f(r,g,b) - glRecti(X1,Y1,X2,Y2) -def ui_rectA(coords,color): - [X1,Y1,X2,Y2],[r,g,b,a] = coords,color - glColor4f(r,g,b,a) - glRecti(X1,Y1,X2,Y2) #integer coords - #glRectf(X1,Y1,X2,Y2) #floating coords -def ui_line(coords,color): - [X1,Y1,X2,Y2],[r,g,b] = coords,color - glColor3f(r,g,b) - glBegin(GL_LINES) - glVertex2i(X1,Y1) - glVertex2i(X2,Y2) - glEnd() -def ui_panel(posX,posY,L,H,color): - [r,g,b] = color - ui_rect([posX+4,posY-4,posX+L+4,posY-H-4],[.55,.55,.55]) #1st shadow - ui_rect([posX+3,posY-3,posX+L+3,posY-H-3],[.45,.45,.45]) - ui_rect([posX+3,posY-3,posX+L+2,posY-H-2],[.30,.30,.30]) #2nd shadow - ui_rect([posX,posY-H,posX+L,posY],[r,g,b]) #Main - ui_rect([posX+3,posY-19,posX+L-3,posY-2],[.75*r,.75*g,.75*b]) #Titlebar - ui_line([posX+3,posY-19,posX+3,posY-2],[.25,.25,.25]) - ui_line([posX+4,posY-19,posX+4,posY-2],[(r+.75)/4,(g+.75)/4,(b+.75)/4]) - ui_line([posX+4,posY-2,posX+L-3,posY-2],[(r+.75)/4,(g+.75)/4,(b+.75)/4]) -def ui_box(x,y,xright,bottom): - color = [0.75, 0.75, 0.75] - coords = x+1,y+1,xright-1,bottom-1 - ui_rect(coords,color) - -def ui_scrollbarX(Focus,PanelH,Area, color_fg, color_bg): - # Area = ScrollBarArea - # point1=down/left, point2=top/right - P1X,P1Y,P2X,P2Y = Area - AreaH = P2X-P1X - if PanelH > AreaH: - Slider = int(AreaH * (AreaH / float(PanelH))) - if Slider<3: Slider = 3 #minimal slider heigh - posX = -int(AreaH * (Focus / float(PanelH))) - ui_rect([P1X,P1Y,P2X,P2Y], color_bg) - ui_rect([P1X+posX,P1Y+3,P1X+posX+Slider,P2Y-3], color_fg) - -def ui_scrollbarY(Focus,PanelH,Area, color_fg, color_bg): - # Area = ScrollBarArea - # point1=down/left, point2=top/right - P1X,P1Y,P2X,P2Y = Area - AreaH = P2Y-P1Y - if PanelH > AreaH: - Slider = int(AreaH * (AreaH / float(PanelH))) - if Slider<3: Slider = 3 #minimal slider heigh - posY = -int(AreaH * (Focus / float(PanelH))) - ui_rect([P1X,P1Y,P2X-1,P2Y], color_bg) - #ui_rect([P1X+3,P2Y-posY,P2X-4,P2Y-posY-Slider], color_fg) - ui_rect([P1X+3,P1Y+posY,P2X-4,P1Y+posY+Slider], color_fg) - - -#------------------------------------------------------------ -def dxf_callback(input_filename): - global dxfFileName - dxfFileName.val=input_filename -# dirname == Blender.sys.dirname(Blender.Get('filename')) -# update_RegistryKey('DirName', dirname) -# update_RegistryKey('dxfFileName', input_filename) - -def ini_callback(input_filename): - global iniFileName - iniFileName.val=input_filename - -#------------------------------------------------------------ -def getSpaceRect(): - __UI_RECT__ = Buffer(GL_FLOAT, 4) - glGetFloatv(GL_SCISSOR_BOX, __UI_RECT__) - __UI_RECT__ = __UI_RECT__.list - return (int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2]), int(__UI_RECT__[3])) - -def getRelMousePos(mco, winRect): - # mco = Blender.Window.GetMouseCoords() - if pointInRect(mco, winRect): - return (mco[0] - winRect[0], mco[1] - winRect[1]) - return None - - -def pointInRect(pt, rect): - if rect[0] < pt[0] < rect[0]+rect[2] and\ - rect[1] < pt[1] < rect[1]+rect[3]: - return True - else: - return False - - - -#--- variables UI menu --------------------------- -mco = [0,0] # mouse coordinaten -mbX, mbY = 0,0 # mouse buffer coordinaten -scrollW = 20 # width of scrollbar -rowH = 20 # height of menu raw -menu__H = 2 * rowH +5 # height of menu bar -headerH = 1 * rowH # height of column header bar -scroll_left = True # position of scrollbar -menu_bottom = False # position of menu -edit_mode = False # indicator/activator -iconlib_mode = False # indicator/activator -icon_maps = [] #[['blenderbuttons.png',12,25,20,21], -#['referenceicons.png',12,25,20,21]] -help_text = False # indicator/activator -menu_pan = False # indicator/activator -compact_DESIGN = True # toggle UI -showLINK = True # toggle Links -filterList=[-1,-1,-1,-1,-1] -dubbleclik_delay = 0.25 - -PAN_X,PAN_Y = 0,0 # pan coordinates in characters -mPAN_X,mPAN_Y = 0,0 # manu pan coordinates in characters -menu_orgX = 0 -menu_orgY = 0 -mPAN_Xmax = 800 -mPAN_Ymax = 800 - - -#------------------------------------------------------------ -def event(evt, val): - global mbX, mbY, UP, UP0, scroll_pan, FOCUS_fix - global menu_bottom, scroll_left, mco - global PAN_X, PAN_Y, PAN_X0, PAN_Y0 - global mPAN_X, mPAN_Y, mPAN_X0, mPAN_Y0, menu_pan - - #if Blender.event: - # print 'Blender.event:%s, evt:%s' %(Blender.event, evt) #------------ - - if evt in (Draw.QKEY, Draw.ESCKEY) and not val: - print 'DXF-Exporter *** end ***' #--------------------- - Draw.Exit() - - elif val: - if evt==Draw.MIDDLEMOUSE: - mco2 = Window.GetMouseCoords() - relativeMouseCo = getRelMousePos(mco2, getSpaceRect()) - if relativeMouseCo != None: - #rect = [menu__X1,menu__Y1,menu__X2,menu__Y2] - if 1: #pointInRect(relativeMouseCo, menu__Area): - menu_pan = True - mPAN_X0 = mPAN_X - mPAN_Y0 = mPAN_Y - mco = mco2 - elif evt == Draw.MOUSEY or evt == Draw.MOUSEX: - if menu_pan: - mco2 = Window.GetMouseCoords() - mbX = mco2[0]-mco[0] - mbY = mco2[1]-mco[1] - mPAN_X = mPAN_X0 - mbX - mPAN_Y = mPAN_Y0 - mbY - #print mbX, mbY #-------------------- - Draw.Redraw() - elif evt == Draw.WHEELDOWNMOUSE: - mPAN_Y -= 80 - Draw.Redraw() - elif evt == Draw.WHEELUPMOUSE: - mPAN_Y += 80 - Draw.Redraw() - else: # = if val==False: - if evt==Draw.LEFTMOUSE: - scroll_pan = False - elif evt==Draw.MIDDLEMOUSE: - menu_pan = False - -def bevent(evt): - global config_UI, user_preset - global CAMERA, GUI_A - - ######### Manages GUI events - if (evt==EVENT_EXIT): - Draw.Exit() - print 'DXF-Exporter *** end ***' #--------------------- - elif (evt==EVENT_CHOOSE_INI): - Window.FileSelector(ini_callback, "INI-file Selection", '*.ini') - elif (evt==EVENT_REDRAW): - Draw.Redraw() - elif (evt==EVENT_RESET): - resetDefaultConfig() - Draw.Redraw() - elif (evt==EVENT_PRESET2D): - resetDefaultConfig_2D() - Draw.Redraw() - elif (evt==EVENT_PRESET3D): - resetDefaultConfig_3D() - Draw.Redraw() - elif evt in (EVENT_CAMERA,EVENT_LIGHT): - CAMERA = GUI_A['camera_selected'].val - if CAMERA==len(CAMERAS)+1: - doAllCameras = True - else: - pass #print 'deb: CAMERAS=',CAMERAS #---------------- - Draw.Redraw() - elif (evt==EVENT_setCAMERA): - if CAMERA 5: user_preset = 0; index = '' - iniFileName.val = INIFILE_DEFAULT_NAME + index + INIFILE_EXTENSION - Draw.Redraw() - elif (evt==EVENT_HELP): - try: - import webbrowser - webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf') - except: - Draw.PupMenu('DXF-Exporter: HELP Alert!%t|no connection to manual-page on Blender-Wiki! try:|\ -http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf') - Draw.Redraw() - elif (evt==EVENT_LOAD_INI): - loadConfig() - Draw.Redraw() - elif (evt==EVENT_SAVE_INI): - saveConfig() - Draw.Redraw() - elif (evt==EVENT_DXF_DIR): - dxfFile = dxfFileName.val - dxfPathName = '' - if '/' in dxfFile: - dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/' - elif '\\' in dxfFile: - dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\' - dxfFileName.val = dxfPathName + '*.dxf' -# dirname == Blender.sys.dirname(Blender.Get('filename')) -# update_RegistryKey('DirName', dirname) -# update_RegistryKey('dxfFileName', dxfFileName.val) - GUI_A['only_selected_on'].val = 1 - Draw.Redraw() - elif (evt==EVENT_CHOOSE_DXF): - filename = '' # '*.dxf' - if dxfFileName.val: filename = dxfFileName.val - Window.FileSelector(dxf_callback, "DXF-file Selection", filename) - elif (evt==EVENT_START): - dxfFile = dxfFileName.val - #print 'deb: dxfFile file: ', dxfFile #---------------------- - if E_M: dxfFileName.val, dxfFile = e_mode(dxfFile) #evaluation mode - update_RegistryKey('dxfFileName', dxfFileName.val) - update_globals() - if dxfFile.lower().endswith('*.dxf'): - if Draw.PupMenu('DXF-Exporter: OK?|will write multiple DXF-files, one for each Scene, in:|%s' % dxfFile) == 1: - global UI_MODE - UI_MODE = False - #TODO: multi_export(dxfFile[:-5]) # cut last 5 characters '*.dxf' - Draw.Redraw() - UI_MODE = True - else: - Draw.Redraw() - elif dxfFile.lower()[-4:] in ('.dxf','.dwg'): # and Blender.sys.exists(dxfFile): - print 'preparing for export ---' #Standard Mode: activated - filepath = dxfFile - sce = Scene.GetCurrent() - if ONLYSELECTED: sel_group = sce.objects.selected - else: sel_group = sce.objects - - if ONLYVISIBLE: - sel_group_temp = [] - layerlist = sce.getLayers() - for ob in sel_group: - for lay in ob.layers: - if lay in layerlist: - sel_group_temp.append(ob) - break - sel_group = sel_group_temp - - export_list = getObjectsAndDuplis(sel_group,MATRICES=True) - - if export_list: do_export(export_list, filepath) - else: - print "Abort: selection was empty, no object to export!" - Draw.PupMenu('DXF Exporter: nothing exported!|empty selection!') - else: - Draw.PupMenu('DXF-Exporter: Alert!%t|no valid DXF-file selected!') - print "DXF-Exporter: error, no valid DXF-file selected! try again" - Draw.Redraw() - - - - -def multi_export(DIR): #TODO: - """Imports all DXF-files from directory DIR. - - """ - global SCENE - batchTIME = Blender.sys.time() - #if #DIR == "": DIR = os.path.curdir - if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename')) - print 'Multifiles Import from %s' %DIR - files = \ - [Blender.sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] - if not files: - print '...None DXF-files found. Abort!' - return - - i = 0 - for dxfFile in files: - i += 1 - print '\nDXF-file', i, 'of', len(files) #,'\nImporting', dxfFile - if ONLYSELECTED: - _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] - _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' - _dxf_file = _dxf_file[:NAMELENGTH_MAX] #? [-NAMELENGTH_MAX:]) - SCENE = Blender.Scene.New(_dxf_file) - SCENE.makeCurrent() - #or so? Blender.Scene.makeCurrent(_dxf_file) - #sce = bpy.data.scenes.new(_dxf_file) - #bpy.data.scenes.active = sce - else: - SCENE = Blender.Scene.GetCurrent() - SCENE.objects.selected = [] # deselect all - main(dxfFile) - #Blender.Redraw() - - print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME) - print '\a\r', # beep when done - - -#----------------------------------------------------- -if __name__=='__main__': - - if DXF: - print '\n\n\n' - print 'DXF-Exporter v%s *** start ***' %(__version__) #--------------------- - print 'with Library %s' %(DXF.__version__) #--------------------- - if not DXF.copy: - print "DXF-Exporter: dxfLibrary.py script requires a full Python install" - Draw.PupMenu('Error%t|The dxfLibrary.py script requires a full Python install') - else: - #Window.FileSelector(dxf_export_ui, 'EXPORT DXF', Blender.sys.makename(ext='.dxf')) - # recall last used DXF-file and INI-file names - dxffilename = check_RegistryKey('dxfFileName') - #print 'deb:start dxffilename:', dxffilename #---------------- - if dxffilename: dxfFileName.val = dxffilename - else: - dirname = Blender.sys.dirname(Blender.Get('filename')) - #print 'deb:start dirname:', dirname #---------------- - dxfFileName.val = Blender.sys.join(dirname, '') - inifilename = check_RegistryKey('iniFileName') - if inifilename: iniFileName.val = inifilename - - updateMenuCAMERA() - updateCAMERA() - - Draw.Register(draw_UI, event, bevent) - - \ No newline at end of file diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py deleted file mode 100644 index 50357cbfa75..00000000000 --- a/release/scripts/export_fbx.py +++ /dev/null @@ -1,3084 +0,0 @@ -#!BPY -""" -Name: 'Autodesk FBX (.fbx)...' -Blender: 249 -Group: 'Export' -Tooltip: 'Selection to an ASCII Autodesk FBX ' -""" -__author__ = "Campbell Barton" -__url__ = ['www.blender.org', 'blenderartists.org'] -__version__ = "1.2" - -__bpydoc__ = """\ -This script is an exporter to the FBX file format. - -http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx -""" -# -------------------------------------------------------------------------- -# FBX Export v0.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 ***** -# -------------------------------------------------------------------------- - -try: - import time - # import os # only needed for batch export, nbot used yet -except: - time = None # use this to check if they have python modules installed - -# for python 2.3 support -try: - set() -except: - try: - from sets import Set as set - except: - set = None # so it complains you dont have a ! - -# os is only needed for batch 'own dir' option -try: - import os -except: - os = None - -import Blender -import bpy -from Blender.Mathutils import Matrix, Vector, RotationMatrix - -import BPyObject -import BPyMesh -import BPySys -import BPyMessages - -## This was used to make V, but faster not to do all that -##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' -##v = range(255) -##for c in valid: v.remove(ord(c)) -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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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]) -def cleanName(name): - for ch in invalid: name = name.replace(ch, '_') - return name -del v, i - - -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, textures): - if not dest_dir.endswith(Blender.sys.sep): - dest_dir += Blender.sys.sep - - image_paths = set() - for tex in textures: - image_paths.add(Blender.sys.expandpath(tex.filename)) - - # Now copy images - copyCount = 0 - for image_path in image_paths: - if Blender.sys.exists(image_path): - # Make a name for the target path. - dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] - if not Blender.sys.exists(dest_image_path): # Image isnt alredy there - print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) - try: - copy_file(image_path, dest_image_path) - copyCount+=1 - except: - print '\t\tWarning, file failed to copy, skipping.' - - print '\tCopied %d images' % copyCount - -mtx4_identity = Matrix() - -# testing -mtx_x90 = RotationMatrix( 90, 3, 'x') # used -#mtx_x90n = RotationMatrix(-90, 3, 'x') -#mtx_y90 = RotationMatrix( 90, 3, 'y') -#mtx_y90n = RotationMatrix(-90, 3, 'y') -#mtx_z90 = RotationMatrix( 90, 3, 'z') -#mtx_z90n = RotationMatrix(-90, 3, 'z') - -#mtx4_x90 = RotationMatrix( 90, 4, 'x') -mtx4_x90n = RotationMatrix(-90, 4, 'x') # used -#mtx4_y90 = RotationMatrix( 90, 4, 'y') -mtx4_y90n = RotationMatrix(-90, 4, 'y') # used -mtx4_z90 = RotationMatrix( 90, 4, 'z') # used -mtx4_z90n = RotationMatrix(-90, 4, 'z') # used - -def strip_path(p): - return p.split('\\')[-1].split('/')[-1] - -# Used to add the scene name into the filename without using odd chars -sane_name_mapping_ob = {} -sane_name_mapping_mat = {} -sane_name_mapping_tex = {} -sane_name_mapping_take = {} -sane_name_mapping_group = {} - -# Make sure reserved names are not used -sane_name_mapping_ob['Scene'] = 'Scene_' -sane_name_mapping_ob['blend_root'] = 'blend_root_' - -def increment_string(t): - name = t - num = '' - while name and name[-1].isdigit(): - num = name[-1] + num - name = name[:-1] - if num: return '%s%d' % (name, int(num)+1) - else: return name + '_0' - - - -# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. -def sane_name(data, dct): - #if not data: return None - - if type(data)==tuple: # materials are paired up with images - data, other = data - use_other = True - else: - other = None - use_other = False - - if data: name = data.name - else: name = None - orig_name = name - - if other: - orig_name_other = other.name - name = '%s #%s' % (name, orig_name_other) - else: - orig_name_other = None - - # dont cache, only ever call once for each data type now, - # so as to avoid namespace collision between types - like with objects <-> bones - #try: return dct[name] - #except: pass - - if not name: - name = 'unnamed' # blank string, ASKING FOR TROUBLE! - else: - #name = BPySys.cleanName(name) - name = cleanName(name) # use our own - - while name in dct.itervalues(): name = increment_string(name) - - if use_other: # even if other is None - orig_name_other will be a string or None - dct[orig_name, orig_name_other] = name - else: - dct[orig_name] = name - - return name - -def sane_obname(data): return sane_name(data, sane_name_mapping_ob) -def sane_matname(data): return sane_name(data, sane_name_mapping_mat) -def sane_texname(data): return sane_name(data, sane_name_mapping_tex) -def sane_takename(data): return sane_name(data, sane_name_mapping_take) -def sane_groupname(data): return sane_name(data, sane_name_mapping_group) - -def derived_paths(fname_orig, basepath, FORCE_CWD=False): - ''' - fname_orig - blender path, can be relative - basepath - fname_rel will be relative to this - FORCE_CWD - dont use the basepath, just add a ./ to the filename. - use when we know the file will be in the basepath. - ''' - fname = Blender.sys.expandpath(fname_orig) - fname_strip = strip_path(fname) - if FORCE_CWD: fname_rel = '.' + Blender.sys.sep + fname_strip - else: fname_rel = Blender.sys.relpath(fname, basepath) - if fname_rel.startswith('//'): fname_rel = '.' + Blender.sys.sep + fname_rel[2:] - return fname, fname_strip, fname_rel - - -def mat4x4str(mat): - return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) - -def meshNormalizedWeights(me): - try: # account for old bad BPyMesh - groupNames, vWeightList = BPyMesh.meshWeight2List(me) - except: - return [],[] - - if not groupNames: - return [],[] - - for i, vWeights in enumerate(vWeightList): - tot = 0.0 - for w in vWeights: - tot+=w - - if tot: - for j, w in enumerate(vWeights): - vWeights[j] = w/tot - - return groupNames, vWeightList - -header_comment = \ -'''; FBX 6.1.0 project file -; Created by Blender FBX Exporter -; for support mail: ideasman42@gmail.com -; ---------------------------------------------------- - -''' - -# This func can be called with just the filename -def write(filename, batch_objects = None, \ - EXP_OBS_SELECTED = True, - EXP_MESH = True, - EXP_MESH_APPLY_MOD = True, - EXP_MESH_HQ_NORMALS = False, - EXP_ARMATURE = True, - EXP_LAMP = True, - EXP_CAMERA = True, - EXP_EMPTY = True, - EXP_IMAGE_COPY = False, - GLOBAL_MATRIX = Matrix(), - ANIM_ENABLE = True, - ANIM_OPTIMIZE = True, - ANIM_OPTIMIZE_PRECISSION = 6, - ANIM_ACTION_ALL = False, - BATCH_ENABLE = False, - BATCH_GROUP = True, - BATCH_SCENE = False, - BATCH_FILE_PREFIX = '', - BATCH_OWN_DIR = False - ): - - # ----------------- Batch support! - if BATCH_ENABLE: - if os == None: BATCH_OWN_DIR = False - - fbxpath = filename - - # get the path component of filename - tmp_exists = Blender.sys.exists(fbxpath) - - if tmp_exists != 2: # a file, we want a path - while fbxpath and fbxpath[-1] not in ('/', '\\'): - fbxpath = fbxpath[:-1] - if not filename: - Draw.PupMenu('Error%t|Directory does not exist!') - return - - tmp_exists = Blender.sys.exists(fbxpath) - - if tmp_exists != 2: - Draw.PupMenu('Error%t|Directory does not exist!') - return - - if not fbxpath.endswith(Blender.sys.sep): - fbxpath += Blender.sys.sep - del tmp_exists - - - if BATCH_GROUP: - data_seq = bpy.data.groups - else: - data_seq = bpy.data.scenes - - # call this function within a loop with BATCH_ENABLE == False - orig_sce = bpy.data.scenes.active - - - new_fbxpath = fbxpath # own dir option modifies, we need to keep an original - for data in data_seq: # scene or group - newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) - - - if BATCH_OWN_DIR: - new_fbxpath = fbxpath + newname + Blender.sys.sep - # path may alredy exist - # TODO - might exist but be a file. unlikely but should probably account for it. - - if Blender.sys.exists(new_fbxpath) == 0: - os.mkdir(new_fbxpath) - - - filename = new_fbxpath + newname + '.fbx' - - print '\nBatch exporting %s as...\n\t"%s"' % (data, filename) - - if BATCH_GROUP: #group - # group, so objects update properly, add a dummy scene. - sce = bpy.data.scenes.new() - sce.Layers = (1<<20) -1 - bpy.data.scenes.active = sce - for ob_base in data.objects: - sce.objects.link(ob_base) - - sce.update(1) - - # TODO - BUMMER! Armatures not in the group wont animate the mesh - - else:# scene - - - data_seq.active = data - - - # Call self with modified args - # Dont pass batch options since we alredy usedt them - write(filename, data.objects, - False, - EXP_MESH, - EXP_MESH_APPLY_MOD, - EXP_MESH_HQ_NORMALS, - EXP_ARMATURE, - EXP_LAMP, - EXP_CAMERA, - EXP_EMPTY, - EXP_IMAGE_COPY, - GLOBAL_MATRIX, - ANIM_ENABLE, - ANIM_OPTIMIZE, - ANIM_OPTIMIZE_PRECISSION, - ANIM_ACTION_ALL - ) - - if BATCH_GROUP: - # remove temp group scene - bpy.data.scenes.unlink(sce) - - bpy.data.scenes.active = orig_sce - - return # so the script wont run after we have batch exported. - - # end batch support - - # Use this for working out paths relative to the export location - basepath = Blender.sys.dirname(filename) - - # ---------------------------------------------- - # storage classes - class my_bone_class: - __slots__ =(\ - 'blenName',\ - 'blenBone',\ - 'blenMeshes',\ - 'restMatrix',\ - 'parent',\ - 'blenName',\ - 'fbxName',\ - 'fbxArm',\ - '__pose_bone',\ - '__anim_poselist') - - def __init__(self, blenBone, fbxArm): - - # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace - self.fbxName = sane_obname(blenBone) - - self.blenName = blenBone.name - self.blenBone = blenBone - self.blenMeshes = {} # fbxMeshObName : mesh - self.fbxArm = fbxArm - self.restMatrix = blenBone.matrix['ARMATURESPACE'] - - # not used yet - # self.restMatrixInv = self.restMatrix.copy().invert() - # self.restMatrixLocal = None # set later, need parent matrix - - self.parent = None - - # not public - pose = fbxArm.blenObject.getPose() - self.__pose_bone = pose.bones[self.blenName] - - # store a list if matricies here, (poseMatrix, head, tail) - # {frame:posematrix, frame:posematrix, ...} - self.__anim_poselist = {} - - ''' - def calcRestMatrixLocal(self): - if self.parent: - self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() - else: - self.restMatrixLocal = self.restMatrix.copy() - ''' - def setPoseFrame(self, f): - # cache pose info here, frame must be set beforehand - - # Didnt end up needing head or tail, if we do - here it is. - ''' - self.__anim_poselist[f] = (\ - self.__pose_bone.poseMatrix.copy(),\ - self.__pose_bone.head.copy(),\ - self.__pose_bone.tail.copy() ) - ''' - - self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() - - # get pose from frame. - def getPoseMatrix(self, f):# ---------------------------------------------- - return self.__anim_poselist[f] - ''' - def getPoseHead(self, f): - #return self.__pose_bone.head.copy() - return self.__anim_poselist[f][1].copy() - def getPoseTail(self, f): - #return self.__pose_bone.tail.copy() - return self.__anim_poselist[f][2].copy() - ''' - # end - - def getAnimParRelMatrix(self, frame): - #arm_mat = self.fbxArm.matrixWorld - #arm_mat = self.fbxArm.parRelMatrix() - if not self.parent: - #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore - return mtx4_z90 * self.getPoseMatrix(frame) - else: - #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() - return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() - - # we need thes because cameras and lights modified rotations - def getAnimParRelMatrixRot(self, frame): - return self.getAnimParRelMatrix(frame) - - def flushAnimData(self): - self.__anim_poselist.clear() - - - class my_object_generic: - # Other settings can be applied for each type - mesh, armature etc. - def __init__(self, ob, matrixWorld = None): - self.fbxName = sane_obname(ob) - self.blenObject = ob - self.fbxGroupNames = [] - self.fbxParent = None # set later on IF the parent is in the selection. - if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX - else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX - self.__anim_poselist = {} # we should only access this - - def parRelMatrix(self): - if self.fbxParent: - return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() - else: - return self.matrixWorld - - def setPoseFrame(self, f): - self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() - - def getAnimParRelMatrix(self, frame): - if self.fbxParent: - #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX - return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() - else: - return self.__anim_poselist[frame] * GLOBAL_MATRIX - - def getAnimParRelMatrixRot(self, frame): - type = self.blenObject.type - if self.fbxParent: - matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() - else: - matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() - - # Lamps need to be rotated - if type =='Lamp': - matrix_rot = mtx_x90 * matrix_rot - elif ob and type =='Camera': - y = Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) - - return matrix_rot - - # ---------------------------------------------- - - - - - - print '\nFBX export starting...', filename - start_time = Blender.sys.time() - try: - file = open(filename, 'w') - except: - return False - - sce = bpy.data.scenes.active - world = sce.world - - - # ---------------------------- Write the header first - file.write(header_comment) - if time: - curtime = time.localtime()[0:6] - else: - curtime = (0,0,0,0,0,0) - # - file.write(\ -'''FBXHeaderExtension: { - FBXHeaderVersion: 1003 - FBXVersion: 6100 - CreationTimeStamp: { - Version: 1000 - Year: %.4i - Month: %.2i - Day: %.2i - Hour: %.2i - Minute: %.2i - Second: %.2i - Millisecond: 0 - } - Creator: "FBX SDK/FBX Plugins build 20070228" - OtherFlags: { - FlagPLE: 0 - } -}''' % (curtime)) - - file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) - file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) - - pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way - - # --------------- funcs for exporting - def object_tx(ob, loc, matrix, matrix_mod = None): - ''' - Matrix mod is so armature objects can modify their bone matricies - ''' - if isinstance(ob, Blender.Types.BoneType): - - # we know we have a matrix - # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) - matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore - - parent = ob.parent - if parent: - #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) - par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore - matrix = matrix * par_matrix.copy().invert() - - matrix_rot = matrix.rotationPart() - - loc = tuple(matrix.translationPart()) - scale = tuple(matrix.scalePart()) - rot = tuple(matrix_rot.toEuler()) - - else: - # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore - #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX - if ob and not matrix: raise "error: this should never happen!" - - matrix_rot = matrix - #if matrix: - # matrix = matrix_scale * matrix - - if matrix: - loc = tuple(matrix.translationPart()) - scale = tuple(matrix.scalePart()) - - matrix_rot = matrix.rotationPart() - # Lamps need to be rotated - if ob and ob.type =='Lamp': - matrix_rot = mtx_x90 * matrix_rot - rot = tuple(matrix_rot.toEuler()) - elif ob and ob.type =='Camera': - y = Vector(0,1,0) * matrix_rot - matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) - rot = tuple(matrix_rot.toEuler()) - else: - rot = tuple(matrix_rot.toEuler()) - else: - if not loc: - loc = 0,0,0 - scale = 1,1,1 - rot = 0,0,0 - - return loc, rot, scale, matrix, matrix_rot - - def write_object_tx(ob, loc, matrix, matrix_mod= None): - ''' - We have loc to set the location if non blender objects that have a location - - matrix_mod is only used for bones at the moment - ''' - loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) - - file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) - file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) - file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) - return loc, rot, scale, matrix, matrix_rot - - def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): - # if the type is 0 its an empty otherwise its a mesh - # only difference at the moment is one has a color - file.write(''' - Properties60: { - Property: "QuaternionInterpolate", "bool", "",0 - Property: "Visibility", "Visibility", "A+",1''') - - loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) - - # Rotation order, note, for FBX files Iv loaded normal order is 1 - # setting to zero. - # eEULER_XYZ = 0 - # eEULER_XZY - # eEULER_YZX - # eEULER_YXZ - # eEULER_ZXY - # eEULER_ZYX - - file.write(''' - Property: "RotationOffset", "Vector3D", "",0,0,0 - Property: "RotationPivot", "Vector3D", "",0,0,0 - Property: "ScalingOffset", "Vector3D", "",0,0,0 - Property: "ScalingPivot", "Vector3D", "",0,0,0 - Property: "TranslationActive", "bool", "",0 - Property: "TranslationMin", "Vector3D", "",0,0,0 - Property: "TranslationMax", "Vector3D", "",0,0,0 - Property: "TranslationMinX", "bool", "",0 - Property: "TranslationMinY", "bool", "",0 - Property: "TranslationMinZ", "bool", "",0 - Property: "TranslationMaxX", "bool", "",0 - Property: "TranslationMaxY", "bool", "",0 - Property: "TranslationMaxZ", "bool", "",0 - Property: "RotationOrder", "enum", "",0 - Property: "RotationSpaceForLimitOnly", "bool", "",0 - Property: "AxisLen", "double", "",10 - Property: "PreRotation", "Vector3D", "",0,0,0 - Property: "PostRotation", "Vector3D", "",0,0,0 - Property: "RotationActive", "bool", "",0 - Property: "RotationMin", "Vector3D", "",0,0,0 - Property: "RotationMax", "Vector3D", "",0,0,0 - Property: "RotationMinX", "bool", "",0 - Property: "RotationMinY", "bool", "",0 - Property: "RotationMinZ", "bool", "",0 - Property: "RotationMaxX", "bool", "",0 - Property: "RotationMaxY", "bool", "",0 - Property: "RotationMaxZ", "bool", "",0 - Property: "RotationStiffnessX", "double", "",0 - Property: "RotationStiffnessY", "double", "",0 - Property: "RotationStiffnessZ", "double", "",0 - Property: "MinDampRangeX", "double", "",0 - Property: "MinDampRangeY", "double", "",0 - Property: "MinDampRangeZ", "double", "",0 - Property: "MaxDampRangeX", "double", "",0 - Property: "MaxDampRangeY", "double", "",0 - Property: "MaxDampRangeZ", "double", "",0 - Property: "MinDampStrengthX", "double", "",0 - Property: "MinDampStrengthY", "double", "",0 - Property: "MinDampStrengthZ", "double", "",0 - Property: "MaxDampStrengthX", "double", "",0 - Property: "MaxDampStrengthY", "double", "",0 - Property: "MaxDampStrengthZ", "double", "",0 - Property: "PreferedAngleX", "double", "",0 - Property: "PreferedAngleY", "double", "",0 - Property: "PreferedAngleZ", "double", "",0 - Property: "InheritType", "enum", "",0 - Property: "ScalingActive", "bool", "",0 - Property: "ScalingMin", "Vector3D", "",1,1,1 - Property: "ScalingMax", "Vector3D", "",1,1,1 - Property: "ScalingMinX", "bool", "",0 - Property: "ScalingMinY", "bool", "",0 - Property: "ScalingMinZ", "bool", "",0 - Property: "ScalingMaxX", "bool", "",0 - Property: "ScalingMaxY", "bool", "",0 - Property: "ScalingMaxZ", "bool", "",0 - Property: "GeometricTranslation", "Vector3D", "",0,0,0 - Property: "GeometricRotation", "Vector3D", "",0,0,0 - Property: "GeometricScaling", "Vector3D", "",1,1,1 - Property: "LookAtProperty", "object", "" - Property: "UpVectorProperty", "object", "" - Property: "Show", "bool", "",1 - Property: "NegativePercentShapeSupport", "bool", "",1 - Property: "DefaultAttributeIndex", "int", "",0''') - if ob and type(ob) != Blender.Types.BoneType: - # Only mesh objects have color - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Size", "double", "",100') - file.write('\n\t\t\tProperty: "Look", "enum", "",1') - - return loc, rot, scale, matrix, matrix_rot - - - # -------------------------------------------- Armatures - #def write_bone(bone, name, matrix_mod): - def write_bone(my_bone): - file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) - file.write('\n\t\tVersion: 232') - - #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] - poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore - pose_items.append( (my_bone.fbxName, poseMatrix) ) - - - # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) - file.write('\n\t\t\tProperty: "Size", "double", "",1') - - #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) - - """ - file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ - ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) - """ - - file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ - (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) - - #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') - file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 1') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Skeleton"') - file.write('\n\t}') - - def write_camera_switch(): - file.write(''' - Model: "Model::Camera Switcher", "CameraSwitcher" { - Version: 232''') - - write_object_props() - file.write(''' - Property: "Color", "Color", "A",0.8,0.8,0.8 - Property: "Camera Index", "Integer", "A+",100 - } - MultiLayer: 0 - MultiTake: 1 - Hidden: "True" - Shading: W - Culling: "CullingOff" - Version: 101 - Name: "Model::Camera Switcher" - CameraId: 0 - CameraName: 100 - CameraIndexName: - }''') - - def write_camera_dummy(name, loc, near, far, proj_type, up): - file.write('\n\tModel: "Model::%s", "Camera" {' % name ) - file.write('\n\t\tVersion: 232') - write_object_props(None, loc) - - file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') - file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') - file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') - file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') - file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') - file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') - file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') - file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') - file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') - file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') - file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') - file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') - file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') - file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') - file.write('\n\t\t\tProperty: "AspectW", "double", "",320') - file.write('\n\t\t\tProperty: "AspectH", "double", "",200') - file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') - file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') - file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') - file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') - file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) - file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) - file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') - file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') - file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') - file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') - file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') - file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') - file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') - file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') - file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') - file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') - file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') - file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') - file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') - file.write('\n\t\t\tProperty: "Crop", "bool", "",0') - file.write('\n\t\t\tProperty: "Center", "bool", "",1') - file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') - file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') - file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') - file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') - file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') - file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') - file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') - file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') - file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') - file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') - file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') - file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) - file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') - file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') - file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') - file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') - file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') - file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') - file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') - file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tHidden: "True"') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Camera"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) - file.write('\n\t\tUp: %i,%i,%i' % up) - file.write('\n\t\tLookAt: 0,0,0') - file.write('\n\t\tShowInfoOnMoving: 1') - file.write('\n\t\tShowAudio: 0') - file.write('\n\t\tAudioColor: 0,1,0') - file.write('\n\t\tCameraOrthoZoom: 1') - file.write('\n\t}') - - def write_camera_default(): - # This sucks but to match FBX converter its easier to - # write the cameras though they are not needed. - write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) - write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) - write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) - write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) - write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) - - def write_camera(my_cam): - ''' - Write a blender camera - ''' - render = sce.render - width = render.sizeX - height = render.sizeY - aspect = float(width)/height - - data = my_cam.blenObject.data - - file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) - file.write('\n\t\tVersion: 232') - loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) - - file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') - file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) - file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') - file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') - file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? - file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto - file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') - file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') - file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') - file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') - file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') - file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') - file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') - file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') - file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) - file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) - - '''Camera aspect ratio modes. - 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. - 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. - 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. - 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. - 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. - - Definition at line 234 of file kfbxcamera.h. ''' - - file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') - - file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') - file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') - file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') - file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') - file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) - file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) - file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') - file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') - file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) - file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') - file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') - file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') - file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') - file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') - file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') - file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') - file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') - file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') - file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') - file.write('\n\t\t\tProperty: "Crop", "bool", "",0') - file.write('\n\t\t\tProperty: "Center", "bool", "",1') - file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') - file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') - file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') - file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') - file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') - file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') - file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) - file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') - file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') - file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') - file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') - file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') - file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') - file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') - file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') - file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') - file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') - file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') - file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') - file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') - file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') - - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Camera"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) - file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) ) - file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) ) - - #file.write('\n\t\tUp: 0,0,0' ) - #file.write('\n\t\tLookAt: 0,0,0' ) - - file.write('\n\t\tShowInfoOnMoving: 1') - file.write('\n\t\tShowAudio: 0') - file.write('\n\t\tAudioColor: 0,1,0') - file.write('\n\t\tCameraOrthoZoom: 1') - file.write('\n\t}') - - def write_light(my_light): - light = my_light.blenObject.data - file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) - file.write('\n\t\tVersion: 232') - - write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) - - # Why are these values here twice?????? - oh well, follow the holy sdk's output - - # Blender light types match FBX's, funny coincidence, we just need to - # be sure that all unsupported types are made into a point light - #ePOINT, - #eDIRECTIONAL - #eSPOT - light_type = light.type - if light_type > 2: light_type = 1 # hemi and area lights become directional - - mode = light.mode - if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: - do_shadow = 1 - else: - do_shadow = 0 - - if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): - do_light = 0 - else: - do_light = 1 - - scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case - - file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) - file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') - file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') - file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 - file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) - file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') - file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 - file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) - file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') - file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) - file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) - file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') - file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') - file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') - file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') - file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') - file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) - file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') - file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') - file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') - file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') - file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') - file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') - file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) - file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 0') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - file.write('\n\t\tTypeFlags: "Light"') - file.write('\n\t\tGeometryVersion: 124') - file.write('\n\t}') - - # matrixOnly is not used at the moment - def write_null(my_null = None, fbxName = None, matrixOnly = None): - # ob can be null - if not fbxName: fbxName = my_null.fbxName - - file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) - file.write('\n\t\tVersion: 232') - - # only use this for the root matrix at the moment - if matrixOnly: - poseMatrix = write_object_props(None, None, matrixOnly)[3] - - else: # all other Null's - if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] - else: poseMatrix = write_object_props()[3] - - pose_items.append((fbxName, poseMatrix)) - - file.write(''' - } - MultiLayer: 0 - MultiTake: 1 - Shading: Y - Culling: "CullingOff" - TypeFlags: "Null" - }''') - - # Material Settings - if world: world_amb = world.getAmb() - else: world_amb = (0,0,0) # Default value - - def write_material(matname, mat): - file.write('\n\tMaterial: "Material::%s", "" {' % matname) - - # Todo, add more material Properties. - if mat: - mat_cold = tuple(mat.rgbCol) - mat_cols = tuple(mat.specCol) - #mat_colm = tuple(mat.mirCol) # we wont use the mirror color - mat_colamb = tuple([c for c in world_amb]) - - mat_dif = mat.ref - mat_amb = mat.amb - mat_hard = (float(mat.hard)-1)/5.10 - mat_spec = mat.spec/2.0 - mat_alpha = mat.alpha - mat_emit = mat.emit - mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS - if mat_shadeless: - mat_shader = 'Lambert' - else: - if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: - mat_shader = 'Lambert' - else: - mat_shader = 'Phong' - else: - mat_cols = mat_cold = 0.8, 0.8, 0.8 - mat_colamb = 0.0,0.0,0.0 - # mat_colm - mat_dif = 1.0 - mat_amb = 0.5 - mat_hard = 20.0 - mat_spec = 0.2 - mat_alpha = 1.0 - mat_emit = 0.0 - mat_shadeless = False - mat_shader = 'Phong' - - file.write('\n\t\tVersion: 102') - file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) - file.write('\n\t\tMultiLayer: 0') - - file.write('\n\t\tProperties60: {') - file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) - file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') - file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender - file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_emit) - - file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) - file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) - file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) - file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_dif) - file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') - file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') - file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) - file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) - file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') - file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') - file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') - file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') - file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) - file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) - file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) - file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) - if not mat_shadeless: - file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') - - file.write('\n\t\t}') - file.write('\n\t}') - - def write_video(texname, tex): - # Same as texture really! - file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) - - file.write(''' - Type: "Clip" - Properties60: { - Property: "FrameRate", "double", "",0 - Property: "LastFrame", "int", "",0 - Property: "Width", "int", "",0 - Property: "Height", "int", "",0''') - if tex: - fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) - else: - fname = fname_strip = fname_rel = '' - - file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) - - - file.write(''' - Property: "StartFrame", "int", "",0 - Property: "StopFrame", "int", "",0 - Property: "PlaySpeed", "double", "",1 - Property: "Offset", "KTime", "",0 - Property: "InterlaceMode", "enum", "",0 - Property: "FreeRunning", "bool", "",0 - Property: "Loop", "bool", "",0 - Property: "AccessMode", "enum", "",0 - } - UseMipMap: 0''') - - file.write('\n\t\tFilename: "%s"' % fname_strip) - if fname_strip: fname_strip = '/' + fname_strip - file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative - file.write('\n\t}') - - - def write_texture(texname, tex, num): - # if tex == None then this is a dummy tex - file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) - file.write('\n\t\tType: "TextureVideoClip"') - file.write('\n\t\tVersion: 202') - # TODO, rare case _empty_ exists as a name. - file.write('\n\t\tTextureName: "Texture::%s"' % texname) - - file.write(''' - Properties60: { - Property: "Translation", "Vector", "A+",0,0,0 - Property: "Rotation", "Vector", "A+",0,0,0 - Property: "Scaling", "Vector", "A+",1,1,1''') - file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) - - - # WrapModeU/V 0==rep, 1==clamp, TODO add support - file.write(''' - Property: "TextureTypeUse", "enum", "",0 - Property: "CurrentTextureBlendMode", "enum", "",1 - Property: "UseMaterial", "bool", "",0 - Property: "UseMipMap", "bool", "",0 - Property: "CurrentMappingType", "enum", "",0 - Property: "UVSwap", "bool", "",0''') - - file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) - file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) - - file.write(''' - Property: "TextureRotationPivot", "Vector3D", "",0,0,0 - Property: "TextureScalingPivot", "Vector3D", "",0,0,0 - Property: "VideoProperty", "object", "" - }''') - - file.write('\n\t\tMedia: "Video::%s"' % texname) - - if tex: - fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) - else: - fname = fname_strip = fname_rel = '' - - file.write('\n\t\tFileName: "%s"' % fname_strip) - file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command - - file.write(''' - ModelUVTranslation: 0,0 - ModelUVScaling: 1,1 - Texture_Alpha_Source: "None" - Cropping: 0,0,0,0 - }''') - - def write_deformer_skin(obname): - ''' - Each mesh has its own deformer - ''' - file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) - file.write(''' - Version: 100 - MultiLayer: 0 - Type: "Skin" - Properties60: { - } - Link_DeformAcuracy: 50 - }''') - - # in the example was 'Bip01 L Thigh_2' - def write_sub_deformer_skin(my_mesh, my_bone, weights): - - ''' - Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers - So the SubDeformer needs the mesh-object name as a prefix to make it unique - - Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, - a but silly but dosnt really matter - ''' - file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) - - file.write(''' - Version: 100 - MultiLayer: 0 - Type: "Cluster" - Properties60: { - Property: "SrcModel", "object", "" - Property: "SrcModelReference", "object", "" - } - UserData: "", ""''') - - # Support for bone parents - if my_mesh.fbxBoneParent: - if my_mesh.fbxBoneParent == my_bone: - # TODO - this is a bit lazy, we could have a simple write loop - # for this case because all weights are 1.0 but for now this is ok - # Parent Bones arent used all that much anyway. - vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))] - else: - # This bone is not a parent of this mesh object, no weights - vgroup_data = [] - - else: - # Normal weight painted mesh - if my_bone.blenName in weights[0]: - # Before we used normalized wright list - #vgroup_data = me.getVertsFromGroup(bone.name, 1) - group_index = weights[0].index(my_bone.blenName) - vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] - else: - vgroup_data = [] - - file.write('\n\t\tIndexes: ') - - i = -1 - for vg in vgroup_data: - if i == -1: - file.write('%i' % vg[0]) - i=0 - else: - if i==23: - file.write('\n\t\t') - i=0 - file.write(',%i' % vg[0]) - i+=1 - - file.write('\n\t\tWeights: ') - i = -1 - for vg in vgroup_data: - if i == -1: - file.write('%.8f' % vg[1]) - i=0 - else: - if i==38: - file.write('\n\t\t') - i=0 - file.write(',%.8f' % vg[1]) - i+=1 - - if my_mesh.fbxParent: - # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! - m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) - else: - # Yes! this is it... - but dosnt work when the mesh is a. - m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) - - #m = mtx4_z90 * my_bone.restMatrix - matstr = mat4x4str(m) - matstr_i = mat4x4str(m.invert()) - - file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ - file.write('\n\t\tTransformLink: %s' % matstr) - file.write('\n\t}') - - def write_mesh(my_mesh): - - me = my_mesh.blenData - - # if there are non NULL materials on this mesh - if my_mesh.blenMaterials: do_materials = True - else: do_materials = False - - if my_mesh.blenTextures: do_textures = True - else: do_textures = False - - do_uvs = me.faceUV - - - file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) - file.write('\n\t\tVersion: 232') # newline is added in write_object_props - - poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3] - pose_items.append((my_mesh.fbxName, poseMatrix)) - - file.write('\n\t\t}') - file.write('\n\t\tMultiLayer: 0') - file.write('\n\t\tMultiTake: 1') - file.write('\n\t\tShading: Y') - file.write('\n\t\tCulling: "CullingOff"') - - - # Write the Real Mesh data here - file.write('\n\t\tVertices: ') - i=-1 - - for v in me.verts: - if i==-1: - file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 - else: - if i==7: - file.write('\n\t\t'); i=0 - file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) - i+=1 - - file.write('\n\t\tPolygonVertexIndex: ') - i=-1 - for f in me.faces: - fi = [v.index for v in f] - # flip the last index, odd but it looks like - # this is how fbx tells one face from another - fi[-1] = -(fi[-1]+1) - fi = tuple(fi) - if i==-1: - if len(f) == 3: file.write('%i,%i,%i' % fi ) - else: file.write('%i,%i,%i,%i' % fi ) - i=0 - else: - if i==13: - file.write('\n\t\t') - i=0 - if len(f) == 3: file.write(',%i,%i,%i' % fi ) - else: file.write(',%i,%i,%i,%i' % fi ) - i+=1 - - file.write('\n\t\tEdges: ') - i=-1 - for ed in me.edges: - if i==-1: - file.write('%i,%i' % (ed.v1.index, ed.v2.index)) - i=0 - else: - if i==13: - file.write('\n\t\t') - i=0 - file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) - i+=1 - - file.write('\n\t\tGeometryVersion: 124') - - file.write(''' - LayerElementNormal: 0 { - Version: 101 - Name: "" - MappingInformationType: "ByVertice" - ReferenceInformationType: "Direct" - Normals: ''') - - i=-1 - for v in me.verts: - if i==-1: - file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 - else: - if i==2: - file.write('\n '); i=0 - file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) - i+=1 - file.write('\n\t\t}') - - # Write Face Smoothing - file.write(''' - LayerElementSmoothing: 0 { - Version: 102 - Name: "" - MappingInformationType: "ByPolygon" - ReferenceInformationType: "Direct" - Smoothing: ''') - - i=-1 - for f in me.faces: - if i==-1: - file.write('%i' % f.smooth); i=0 - else: - if i==54: - file.write('\n '); i=0 - file.write(',%i' % f.smooth) - i+=1 - - file.write('\n\t\t}') - - # Write Edge Smoothing - file.write(''' - LayerElementSmoothing: 1 { - Version: 101 - Name: "" - MappingInformationType: "ByEdge" - ReferenceInformationType: "Direct" - Smoothing: ''') - - SHARP = Blender.Mesh.EdgeFlags.SHARP - i=-1 - for ed in me.edges: - if i==-1: - file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 - else: - if i==54: - file.write('\n '); i=0 - file.write(',%i' % ((ed.flag&SHARP)!=0)) - i+=1 - - file.write('\n\t\t}') - del SHARP - - - # Write VertexColor Layers - # note, no programs seem to use this info :/ - collayers = [] - if me.vertexColors: - collayers = me.getColorLayerNames() - collayer_orig = me.activeColorLayer - for colindex, collayer in enumerate(collayers): - me.activeColorLayer = collayer - file.write('\n\t\tLayerElementColor: %i {' % colindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % collayer) - - file.write(''' - MappingInformationType: "ByPolygonVertex" - ReferenceInformationType: "IndexToDirect" - Colors: ''') - - i = -1 - ii = 0 # Count how many Colors we write - - for f in me.faces: - for col in f.col: - if i==-1: - file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) - i=0 - else: - if i==7: - file.write('\n\t\t\t\t') - i=0 - file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) - i+=1 - ii+=1 # One more Color - - file.write('\n\t\t\tColorIndex: ') - i = -1 - for j in xrange(ii): - if i == -1: - file.write('%i' % j) - i=0 - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - file.write(',%i' % j) - i+=1 - - file.write('\n\t\t}') - - - - # Write UV and texture layers. - uvlayers = [] - if do_uvs: - uvlayers = me.getUVLayerNames() - uvlayer_orig = me.activeUVLayer - for uvindex, uvlayer in enumerate(uvlayers): - me.activeUVLayer = uvlayer - file.write('\n\t\tLayerElementUV: %i {' % uvindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer) - - file.write(''' - MappingInformationType: "ByPolygonVertex" - ReferenceInformationType: "IndexToDirect" - UV: ''') - - i = -1 - ii = 0 # Count how many UVs we write - - for f in me.faces: - for uv in f.uv: - if i==-1: - file.write('%.6f,%.6f' % tuple(uv)) - i=0 - else: - if i==7: - file.write('\n ') - i=0 - file.write(',%.6f,%.6f' % tuple(uv)) - i+=1 - ii+=1 # One more UV - - file.write('\n\t\t\tUVIndex: ') - i = -1 - for j in xrange(ii): - if i == -1: - file.write('%i' % j) - i=0 - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - file.write(',%i' % j) - i+=1 - - file.write('\n\t\t}') - - if do_textures: - file.write('\n\t\tLayerElementTexture: %i {' % uvindex) - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: "%s"' % uvlayer) - - if len(my_mesh.blenTextures) == 1: - file.write('\n\t\t\tMappingInformationType: "AllSame"') - else: - file.write('\n\t\t\tMappingInformationType: "ByPolygon"') - - file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') - file.write('\n\t\t\tBlendMode: "Translucent"') - file.write('\n\t\t\tTextureAlpha: 1') - file.write('\n\t\t\tTextureId: ') - - if len(my_mesh.blenTextures) == 1: - file.write('0') - else: - texture_mapping_local = {None:-1} - - i = 0 # 1 for dummy - for tex in my_mesh.blenTextures: - if tex: # None is set above - texture_mapping_local[tex] = i - i+=1 - - i=-1 - for f in me.faces: - img_key = f.image - - if i==-1: - i=0 - file.write( '%s' % texture_mapping_local[img_key]) - else: - if i==55: - file.write('\n ') - i=0 - - file.write(',%s' % texture_mapping_local[img_key]) - i+=1 - - else: - file.write(''' - LayerElementTexture: 0 { - Version: 101 - Name: "" - MappingInformationType: "NoMappingInformation" - ReferenceInformationType: "IndexToDirect" - BlendMode: "Translucent" - TextureAlpha: 1 - TextureId: ''') - file.write('\n\t\t}') - - me.activeUVLayer = uvlayer_orig - - # Done with UV/textures. - - if do_materials: - file.write('\n\t\tLayerElementMaterial: 0 {') - file.write('\n\t\t\tVersion: 101') - file.write('\n\t\t\tName: ""') - - if len(my_mesh.blenMaterials) == 1: - file.write('\n\t\t\tMappingInformationType: "AllSame"') - else: - file.write('\n\t\t\tMappingInformationType: "ByPolygon"') - - file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') - file.write('\n\t\t\tMaterials: ') - - if len(my_mesh.blenMaterials) == 1: - file.write('0') - else: - # Build a material mapping for this - material_mapping_local = {} # local-mat & tex : global index. - - for j, mat_tex_pair in enumerate(my_mesh.blenMaterials): - material_mapping_local[mat_tex_pair] = j - - len_material_mapping_local = len(material_mapping_local) - - mats = my_mesh.blenMaterialList - - i=-1 - for f in me.faces: - try: mat = mats[f.mat] - except:mat = None - - if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ - else: tex = None - - if i==-1: - i=0 - file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 - - file.write(',%s' % (material_mapping_local[mat, tex])) - i+=1 - - file.write('\n\t\t}') - - file.write(''' - Layer: 0 { - Version: 100 - LayerElement: { - Type: "LayerElementNormal" - TypedIndex: 0 - }''') - - if do_materials: - file.write(''' - LayerElement: { - Type: "LayerElementMaterial" - TypedIndex: 0 - }''') - - # Always write this - if do_textures: - file.write(''' - LayerElement: { - Type: "LayerElementTexture" - TypedIndex: 0 - }''') - - if me.vertexColors: - file.write(''' - LayerElement: { - Type: "LayerElementColor" - TypedIndex: 0 - }''') - - if do_uvs: # same as me.faceUV - file.write(''' - LayerElement: { - Type: "LayerElementUV" - TypedIndex: 0 - }''') - - - file.write('\n\t\t}') - - if len(uvlayers) > 1: - for i in xrange(1, len(uvlayers)): - - file.write('\n\t\tLayer: %i {' % i) - file.write('\n\t\t\tVersion: 100') - - file.write(''' - LayerElement: { - Type: "LayerElementUV"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - - if do_textures: - - file.write(''' - LayerElement: { - Type: "LayerElementTexture"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - - file.write('\n\t\t}') - - if len(collayers) > 1: - # Take into account any UV layers - layer_offset = 0 - if uvlayers: layer_offset = len(uvlayers)-1 - - for i in xrange(layer_offset, len(collayers)+layer_offset): - file.write('\n\t\tLayer: %i {' % i) - file.write('\n\t\t\tVersion: 100') - - file.write(''' - LayerElement: { - Type: "LayerElementColor"''') - - file.write('\n\t\t\t\tTypedIndex: %i' % i) - file.write('\n\t\t\t}') - file.write('\n\t\t}') - file.write('\n\t}') - - def write_group(name): - file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) - - file.write(''' - Properties60: { - Property: "MultiLayer", "bool", "",0 - Property: "Pickable", "bool", "",1 - Property: "Transformable", "bool", "",1 - Property: "Show", "bool", "",1 - } - MultiLayer: 0 - }''') - - - # add meshes here to clear because they are not used anywhere. - meshes_to_clear = [] - - ob_meshes = [] - ob_lights = [] - ob_cameras = [] - # in fbx we export bones as children of the mesh - # armatures not a part of a mesh, will be added to ob_arms - ob_bones = [] - ob_arms = [] - ob_null = [] # emptys - - # List of types that have blender objects (not bones) - ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] - - groups = [] # blender groups, only add ones that have objects in the selections - materials = {} # (mat, image) keys, should be a set() - textures = {} # should be a set() - - tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error - - # if EXP_OBS_SELECTED is false, use sceens objects - if not batch_objects: - if EXP_OBS_SELECTED: tmp_objects = sce.objects.context - else: tmp_objects = sce.objects - else: - tmp_objects = batch_objects - - if EXP_ARMATURE: - # This is needed so applying modifiers dosnt apply the armature deformation, its also needed - # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. - # set every armature to its rest, backup the original values so we done mess up the scene - ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] - - for arm in bpy.data.armatures: - arm.restPosition = True - - if ob_arms_orig_rest: - for ob_base in bpy.data.objects: - #if ob_base.type == 'Armature': - ob_base.makeDisplayList() - - # This causes the makeDisplayList command to effect the mesh - Blender.Set('curframe', Blender.Get('curframe')) - - - for ob_base in tmp_objects: - for ob, mtx in BPyObject.getDerivedObjects(ob_base): - #for ob in [ob_base,]: - tmp_ob_type = ob.type - if tmp_ob_type == 'Camera': - if EXP_CAMERA: - ob_cameras.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'Lamp': - if EXP_LAMP: - ob_lights.append(my_object_generic(ob, mtx)) - elif tmp_ob_type == 'Armature': - if EXP_ARMATURE: - # TODO - armatures dont work in dupligroups! - if ob not in ob_arms: ob_arms.append(ob) - # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" - elif tmp_ob_type == 'Empty': - if EXP_EMPTY: - ob_null.append(my_object_generic(ob, mtx)) - elif EXP_MESH: - origData = True - if tmp_ob_type != 'Mesh': - me = bpy.data.meshes.new() - try: me.getFromObject(ob) - except: me = None - if me: - meshes_to_clear.append( me ) - mats = me.materials - origData = False - else: - # Mesh Type! - if EXP_MESH_APPLY_MOD: - me = bpy.data.meshes.new() - me.getFromObject(ob) - - # so we keep the vert groups - if EXP_ARMATURE: - orig_mesh = ob.getData(mesh=1) - if orig_mesh.getVertGroupNames(): - ob.copy().link(me) - # If new mesh has no vgroups we can try add if verts are teh same - if not me.getVertGroupNames(): # vgroups were not kept by the modifier - if len(me.verts) == len(orig_mesh.verts): - groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) - BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) - - # print ob, me, me.getVertGroupNames() - meshes_to_clear.append( me ) - origData = False - mats = me.materials - else: - me = ob.getData(mesh=1) - mats = me.materials - - # Support object colors - tmp_colbits = ob.colbits - if tmp_colbits: - tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. - for i in xrange(16): - if tmp_colbits & (1< fbxObject mapping - # this is needed for groups as well as fbxParenting - bpy.data.objects.tag = False - tmp_obmapping = {} - for ob_generic in ob_all_typegroups: - for ob_base in ob_generic: - ob_base.blenObject.tag = True - tmp_obmapping[ob_base.blenObject] = ob_base - - # Build Groups from objects we export - for blenGroup in bpy.data.groups: - fbxGroupName = None - for ob in blenGroup.objects: - if ob.tag: - if fbxGroupName == None: - fbxGroupName = sane_groupname(blenGroup) - groups.append((fbxGroupName, blenGroup)) - - tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames - - groups.sort() # not really needed - - # Assign parents using this mapping - for ob_generic in ob_all_typegroups: - for my_ob in ob_generic: - parent = my_ob.blenObject.parent - if parent and parent.tag: # does it exist and is it in the mapping - my_ob.fbxParent = tmp_obmapping[parent] - - - del tmp_obmapping - # Finished finding groups we use - - - materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.iterkeys()] - textures = [(sane_texname(tex), tex) for tex in textures.iterkeys() if tex] - materials.sort() # sort by name - textures.sort() - - camera_count = 8 - file.write(''' - -; Object definitions -;------------------------------------------------------------------ - -Definitions: { - Version: 100 - Count: %i''' % (\ - 1+1+camera_count+\ - len(ob_meshes)+\ - len(ob_lights)+\ - len(ob_cameras)+\ - len(ob_arms)+\ - len(ob_null)+\ - len(ob_bones)+\ - bone_deformer_count+\ - len(materials)+\ - (len(textures)*2))) # add 1 for the root model 1 for global settings - - del bone_deformer_count - - file.write(''' - ObjectType: "Model" { - Count: %i - }''' % (\ - 1+camera_count+\ - len(ob_meshes)+\ - len(ob_lights)+\ - len(ob_cameras)+\ - len(ob_arms)+\ - len(ob_null)+\ - len(ob_bones))) # add 1 for the root model - - file.write(''' - ObjectType: "Geometry" { - Count: %i - }''' % len(ob_meshes)) - - if materials: - file.write(''' - ObjectType: "Material" { - Count: %i - }''' % len(materials)) - - if textures: - file.write(''' - ObjectType: "Texture" { - Count: %i - }''' % len(textures)) # add 1 for an empty tex - file.write(''' - ObjectType: "Video" { - Count: %i - }''' % len(textures)) # add 1 for an empty tex - - tmp = 0 - # Add deformer nodes - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - tmp+=1 - - # Add subdeformers - for my_bone in ob_bones: - tmp += len(my_bone.blenMeshes) - - if tmp: - file.write(''' - ObjectType: "Deformer" { - Count: %i - }''' % tmp) - del tmp - - # we could avoid writing this possibly but for now just write it - - file.write(''' - ObjectType: "Pose" { - Count: 1 - }''') - - if groups: - file.write(''' - ObjectType: "GroupSelection" { - Count: %i - }''' % len(groups)) - - file.write(''' - ObjectType: "GlobalSettings" { - Count: 1 - } -}''') - - file.write(''' - -; Object properties -;------------------------------------------------------------------ - -Objects: {''') - - # To comply with other FBX FILES - write_camera_switch() - - # Write the null object - write_null(None, 'blend_root')# , GLOBAL_MATRIX) - - for my_null in ob_null: - write_null(my_null) - - for my_arm in ob_arms: - write_null(my_arm) - - for my_cam in ob_cameras: - write_camera(my_cam) - - for my_light in ob_lights: - write_light(my_light) - - for my_mesh in ob_meshes: - write_mesh(my_mesh) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - write_bone(my_bone) - - write_camera_default() - - for matname, (mat, tex) in materials: - write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard) - - # each texture uses a video, odd - for texname, tex in textures: - write_video(texname, tex) - i = 0 - for texname, tex in textures: - write_texture(texname, tex, i) - i+=1 - - for groupname, group in groups: - write_group(groupname) - - # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. - - # Write armature modifiers - # TODO - add another MODEL? - because of this skin definition. - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - write_deformer_skin(my_mesh.fbxName) - - # Get normalized weights for temorary use - if my_mesh.fbxBoneParent: - weights = None - else: - weights = meshNormalizedWeights(my_mesh.blenData) - - #for bonename, bone, obname, bone_mesh, armob in ob_bones: - for my_bone in ob_bones: - if me in my_bone.blenMeshes.itervalues(): - write_sub_deformer_skin(my_mesh, my_bone, weights) - - # Write pose's really weired, only needed when an armature and mesh are used together - # each by themselves dont need pose data. for now only pose meshes and bones - - file.write(''' - Pose: "Pose::BIND_POSES", "BindPose" { - Type: "BindPose" - Version: 100 - Properties60: { - } - NbPoseNodes: ''') - file.write(str(len(pose_items))) - - - for fbxName, matrix in pose_items: - file.write('\n\t\tPoseNode: {') - file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) - if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) - else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) - file.write('\n\t\t}') - - file.write('\n\t}') - - - # Finish Writing Objects - # Write global settings - file.write(''' - GlobalSettings: { - Version: 1000 - Properties60: { - Property: "UpAxis", "int", "",1 - Property: "UpAxisSign", "int", "",1 - Property: "FrontAxis", "int", "",2 - Property: "FrontAxisSign", "int", "",1 - Property: "CoordAxis", "int", "",0 - Property: "CoordAxisSign", "int", "",1 - Property: "UnitScaleFactor", "double", "",100 - } - } -''') - file.write('}') - - file.write(''' - -; Object relations -;------------------------------------------------------------------ - -Relations: {''') - - file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') - - for my_null in ob_null: - file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) - - for my_arm in ob_arms: - file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) - - for my_mesh in ob_meshes: - file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) - - # TODO - limbs can have the same name for multiple armatures, should prefix. - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) - - for my_cam in ob_cameras: - file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) - - for my_light in ob_lights: - file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) - - file.write(''' - Model: "Model::Producer Perspective", "Camera" { - } - Model: "Model::Producer Top", "Camera" { - } - Model: "Model::Producer Bottom", "Camera" { - } - Model: "Model::Producer Front", "Camera" { - } - Model: "Model::Producer Back", "Camera" { - } - Model: "Model::Producer Right", "Camera" { - } - Model: "Model::Producer Left", "Camera" { - } - Model: "Model::Camera Switcher", "CameraSwitcher" { - }''') - - for matname, (mat, tex) in materials: - file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) - - if textures: - for texname, tex in textures: - file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) - for texname, tex in textures: - file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) - - # deformers - modifiers - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName - # is this bone effecting a mesh? - file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) - - # This should be at the end - # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') - - for groupname, group in groups: - file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) - - file.write('\n}') - file.write(''' - -; Object connections -;------------------------------------------------------------------ - -Connections: {''') - - # NOTE - The FBX SDK dosnt care about the order but some importers DO! - # for instance, defining the material->mesh connection - # before the mesh->blend_root crashes cinema4d - - - # write the fake root node - file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') - - for ob_generic in ob_all_typegroups: # all blender 'Object's we support - for my_ob in ob_generic: - if my_ob.fbxParent: - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) - else: - file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) - - if materials: - for my_mesh in ob_meshes: - # Connect all materials to all objects, not good form but ok for now. - for mat, tex in my_mesh.blenMaterials: - if mat: mat_name = mat.name - else: mat_name = None - - if tex: tex_name = tex.name - else: tex_name = None - - file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName)) - - if textures: - for my_mesh in ob_meshes: - if my_mesh.blenTextures: - # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) - for tex in my_mesh.blenTextures: - if tex: - file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) - - for texname, tex in textures: - file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) - - for my_mesh in ob_meshes: - if my_mesh.fbxArm: - file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) - - # limbs -> deformers - # for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - for fbxMeshObName in my_bone.blenMeshes: # .keys() - file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) - - - #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - # Always parent to armature now - if my_bone.parent: - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) - else: - # the armature object is written as an empty and all root level bones connect to it - file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) - - # groups - if groups: - for ob_generic in ob_all_typegroups: - for ob_base in ob_generic: - for fbxGroupName in ob_base.fbxGroupNames: - file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) - - for my_arm in ob_arms: - file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) - - file.write('\n}') - - - # Needed for scene footer as well as animation - render = sce.render - - # from the FBX sdk - #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) - def fbx_time(t): - # 0.5 + val is the same as rounding. - return int(0.5 + ((t/fps) * 46186158000)) - - fps = float(render.fps) - start = render.sFrame - end = render.eFrame - if end < start: start, end = end, start - if start==end: ANIM_ENABLE = False - - # animations for these object types - ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms - - if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: - - frame_orig = Blender.Get('curframe') - - if ANIM_OPTIMIZE: - ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION - - # default action, when no actions are avaioable - tmp_actions = [None] # None is the default action - blenActionDefault = None - action_lastcompat = None - - if ANIM_ACTION_ALL: - bpy.data.actions.tag = False - tmp_actions = list(bpy.data.actions) - - - # find which actions are compatible with the armatures - # blenActions is not yet initialized so do it now. - tmp_act_count = 0 - for my_arm in ob_arms: - - # get the default name - if not blenActionDefault: - blenActionDefault = my_arm.blenAction - - arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) - - for action in tmp_actions: - - action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) - - if action_chan_names: # at least one channel matches. - my_arm.blenActionList.append(action) - action.tag = True - tmp_act_count += 1 - - # incase there is no actions applied to armatures - action_lastcompat = action - - if tmp_act_count: - # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. - if not blenActionDefault: - blenActionDefault = action_lastcompat - - del action_lastcompat - - file.write(''' -;Takes and animation section -;---------------------------------------------------- - -Takes: {''') - - if blenActionDefault: - file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) - else: - file.write('\n\tCurrent: "Default Take"') - - for blenAction in tmp_actions: - # we have tagged all actious that are used be selected armatures - if blenAction: - if blenAction.tag: - print '\taction: "%s" exporting...' % blenAction.name - else: - print '\taction: "%s" has no armature using it, skipping' % blenAction.name - continue - - if blenAction == None: - # Warning, this only accounts for tmp_actions being [None] - file.write('\n\tTake: "Default Take" {') - act_start = start - act_end = end - else: - # use existing name - if blenAction == blenActionDefault: # have we alredy got the name - file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) - else: - file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) - - tmp = blenAction.getFrameNumbers() - if tmp: - act_start = min(tmp) - act_end = max(tmp) - del tmp - else: - # Fallback on this, theres not much else we can do? :/ - # when an action has no length - act_start = start - act_end = end - - # Set the action active - for my_bone in ob_arms: - if blenAction in my_bone.blenActionList: - ob.action = blenAction - # print '\t\tSetting Action!', blenAction - # sce.update(1) - - file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed - file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed - file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed - - file.write(''' - - ;Models animation - ;----------------------------------------------------''') - - - # set pose data for all bones - # do this here incase the action changes - ''' - for my_bone in ob_bones: - my_bone.flushAnimData() - ''' - i = act_start - while i <= act_end: - Blender.Set('curframe', i) - for ob_generic in ob_anim_lists: - for my_ob in ob_generic: - #Blender.Window.RedrawAll() - if ob_generic == ob_meshes and my_ob.fbxArm: - # We cant animate armature meshes! - pass - else: - my_ob.setPoseFrame(i) - - i+=1 - - - #for bonename, bone, obname, me, armob in ob_bones: - for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): - - for my_ob in ob_generic: - - if ob_generic == ob_meshes and my_ob.fbxArm: - # do nothing, - pass - else: - - file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed - file.write('\n\t\t\tVersion: 1.1') - file.write('\n\t\t\tChannel: "Transform" {') - - context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] - - # ---------------- - # ---------------- - for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale - - if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] - elif TX_CHAN=='S': context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] - elif TX_CHAN=='R': - # Was.... - # elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] - # - # ...but we need to use the previous euler for compatible conversion. - context_bone_anim_vecs = [] - prev_eul = None - for mtx in context_bone_anim_mats: - if prev_eul: prev_eul = mtx[1].toEuler(prev_eul) - else: prev_eul = mtx[1].toEuler() - context_bone_anim_vecs.append(prev_eul) - - file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation - - for i in xrange(3): - # Loop on each axis of the bone - file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation - file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) - file.write('\n\t\t\t\t\t\tKeyVer: 4005') - - if not ANIM_OPTIMIZE: - # Just write all frames, simple but in-eficient - file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) - file.write('\n\t\t\t\t\t\tKey: ') - frame = act_start - while frame <= act_end: - if frame!=act_start: - file.write(',') - - # Curve types are 'C,n' for constant, 'L' for linear - # C,n is for bezier? - linear is best for now so we can do simple keyframe removal - file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) - frame+=1 - else: - # remove unneeded keys, j is the frame, needed when some frames are removed. - context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] - - # last frame to fisrt frame, missing 1 frame on either side. - # removeing in a backwards loop is faster - #for j in xrange( (act_end-act_start)-1, 0, -1 ): - # j = (act_end-act_start)-1 - j = len(context_bone_anim_keys)-2 - while j > 0 and len(context_bone_anim_keys) > 2: - # print j, len(context_bone_anim_keys) - # Is this key the same as the ones next to it? - - # co-linear horizontal... - if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ - abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: - - del context_bone_anim_keys[j] - - else: - frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1]) - frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range - frame_range_fac2 = 1.0 - frame_range_fac1 - - if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: - del context_bone_anim_keys[j] - else: - j-=1 - - # keep the index below the list length - if j > len(context_bone_anim_keys)-2: - j = len(context_bone_anim_keys)-2 - - if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: - # This axis has no moton, its okay to skip KeyCount and Keys in this case - pass - else: - # We only need to write these if there is at least one - file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) - file.write('\n\t\t\t\t\t\tKey: ') - for val, frame in context_bone_anim_keys: - if frame != context_bone_anim_keys[0][1]: # not the first - file.write(',') - # frame is alredy one less then blenders frame - file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) - - if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') - elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') - elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') - - file.write('\n\t\t\t\t\t}') - file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) - file.write('\n\t\t\t\t}') - - # --------------- - - file.write('\n\t\t\t}') - file.write('\n\t\t}') - - # end the take - file.write('\n\t}') - - # end action loop. set original actions - # do this after every loop incase actions effect eachother. - for my_bone in ob_arms: - my_bone.blenObject.action = my_bone.blenAction - - file.write('\n}') - - Blender.Set('curframe', frame_orig) - - else: - # no animation - file.write('\n;Takes and animation section') - file.write('\n;----------------------------------------------------') - file.write('\n') - file.write('\nTakes: {') - file.write('\n\tCurrent: ""') - file.write('\n}') - - - # write meshes animation - #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: - - - # Clear mesh data Only when writing with modifiers applied - for me in meshes_to_clear: - me.verts = None - - - - # --------------------------- Footer - if world: - has_mist = world.mode & 1 - mist_intense, mist_start, mist_end, mist_height = world.mist - world_hor = world.hor - else: - has_mist = mist_intense = mist_start = mist_end = mist_height = 0 - world_hor = 0,0,0 - - file.write('\n;Version 5 settings') - file.write('\n;------------------------------------------------------------------') - file.write('\n') - file.write('\nVersion5: {') - file.write('\n\tAmbientRenderSettings: {') - file.write('\n\t\tVersion: 101') - file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) - file.write('\n\t}') - file.write('\n\tFogOptions: {') - file.write('\n\t\tFlogEnable: %i' % has_mist) - file.write('\n\t\tFogMode: 0') - file.write('\n\t\tFogDensity: %.3f' % mist_intense) - file.write('\n\t\tFogStart: %.3f' % mist_start) - file.write('\n\t\tFogEnd: %.3f' % mist_end) - file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) - file.write('\n\t}') - file.write('\n\tSettings: {') - file.write('\n\t\tFrameRate: "%i"' % int(fps)) - file.write('\n\t\tTimeFormat: 1') - file.write('\n\t\tSnapOnFrames: 0') - file.write('\n\t\tReferenceTimeIndex: -1') - file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) - file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) - file.write('\n\t}') - file.write('\n\tRendererSetting: {') - file.write('\n\t\tDefaultCamera: "Producer Perspective"') - file.write('\n\t\tDefaultViewingMode: 0') - file.write('\n\t}') - file.write('\n}') - file.write('\n') - - # Incase sombody imports this, clean up by clearing global dicts - sane_name_mapping_ob.clear() - sane_name_mapping_mat.clear() - sane_name_mapping_tex.clear() - - ob_arms[:] = [] - ob_bones[:] = [] - ob_cameras[:] = [] - ob_lights[:] = [] - ob_meshes[:] = [] - ob_null[:] = [] - - - # copy images if enabled - if EXP_IMAGE_COPY: - copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) - - print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) - return True - - -# -------------------------------------------- -# UI Function - not a part of the exporter. -# this is to seperate the user interface from the rest of the exporter. -from Blender import Draw, Window -EVENT_NONE = 0 -EVENT_EXIT = 1 -EVENT_REDRAW = 2 -EVENT_FILESEL = 3 - -GLOBALS = {} - -# export opts - -def do_redraw(e,v): GLOBALS['EVENT'] = e - -# toggle between these 2, only allow one on at once -def do_obs_sel(e,v): - GLOBALS['EVENT'] = e - GLOBALS['EXP_OBS_SCENE'].val = 0 - GLOBALS['EXP_OBS_SELECTED'].val = 1 - -def do_obs_sce(e,v): - GLOBALS['EVENT'] = e - GLOBALS['EXP_OBS_SCENE'].val = 1 - GLOBALS['EXP_OBS_SELECTED'].val = 0 - -def do_obs_sce(e,v): - GLOBALS['EVENT'] = e - GLOBALS['EXP_OBS_SCENE'].val = 1 - GLOBALS['EXP_OBS_SELECTED'].val = 0 - -def do_batch_type_grp(e,v): - GLOBALS['EVENT'] = e - GLOBALS['BATCH_GROUP'].val = 1 - GLOBALS['BATCH_SCENE'].val = 0 - -def do_batch_type_sce(e,v): - GLOBALS['EVENT'] = e - GLOBALS['BATCH_GROUP'].val = 0 - GLOBALS['BATCH_SCENE'].val = 1 - -def do_anim_act_all(e,v): - GLOBALS['EVENT'] = e - GLOBALS['ANIM_ACTION_ALL'][0].val = 1 - GLOBALS['ANIM_ACTION_ALL'][1].val = 0 - -def do_anim_act_cur(e,v): - if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: - Draw.PupMenu('Warning%t|Cant use this with batch export group option') - else: - GLOBALS['EVENT'] = e - GLOBALS['ANIM_ACTION_ALL'][0].val = 0 - GLOBALS['ANIM_ACTION_ALL'][1].val = 1 - -def fbx_ui_exit(e,v): - GLOBALS['EVENT'] = e - -def do_help(e,v): - url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' - print 'Trying to open web browser with documentation at this address...' - print '\t' + url - - try: - import webbrowser - webbrowser.open(url) - except: - Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation") - print '...could not open a browser window.' - - - -# run when export is pressed -#def fbx_ui_write(e,v): -def fbx_ui_write(filename): - - # Dont allow overwriting files when saving normally - if not GLOBALS['BATCH_ENABLE'].val: - if not BPyMessages.Warning_SaveOver(filename): - return - - GLOBALS['EVENT'] = EVENT_EXIT - - # Keep the order the same as above for simplicity - # the [] is a dummy arg used for objects - - Blender.Window.WaitCursor(1) - - # Make the matrix - GLOBAL_MATRIX = mtx4_identity - GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val - if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n - if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n - if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n - - ret = write(\ - filename, None,\ - GLOBALS['EXP_OBS_SELECTED'].val,\ - GLOBALS['EXP_MESH'].val,\ - GLOBALS['EXP_MESH_APPLY_MOD'].val,\ - GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ - GLOBALS['EXP_ARMATURE'].val,\ - GLOBALS['EXP_LAMP'].val,\ - GLOBALS['EXP_CAMERA'].val,\ - GLOBALS['EXP_EMPTY'].val,\ - GLOBALS['EXP_IMAGE_COPY'].val,\ - GLOBAL_MATRIX,\ - GLOBALS['ANIM_ENABLE'].val,\ - GLOBALS['ANIM_OPTIMIZE'].val,\ - GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ - GLOBALS['ANIM_ACTION_ALL'][0].val,\ - GLOBALS['BATCH_ENABLE'].val,\ - GLOBALS['BATCH_GROUP'].val,\ - GLOBALS['BATCH_SCENE'].val,\ - GLOBALS['BATCH_FILE_PREFIX'].val,\ - GLOBALS['BATCH_OWN_DIR'].val,\ - ) - - Blender.Window.WaitCursor(0) - GLOBALS.clear() - - if ret == False: - Draw.PupMenu('Error%t|Path cannot be written to!') - - -def fbx_ui(): - # Only to center the UI - x,y = GLOBALS['MOUSE'] - x-=180; y-=0 # offset... just to get it centered - - Draw.Label('Export Objects...', x+20,y+165, 200, 20) - - if not GLOBALS['BATCH_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) - GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) - Draw.EndAlign() - - Draw.BeginAlign() - GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') - GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') - GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') - GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') - Draw.EndAlign() - - y -= 35 - - Draw.BeginAlign() - GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') - GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') - GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') - GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') - GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) - Draw.EndAlign() - - if GLOBALS['EXP_MESH'].val: - # below mesh but - Draw.BeginAlign() - GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) - GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) - Draw.EndAlign() - - GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) - - - Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) - - GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) - if GLOBALS['ANIM_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) - if GLOBALS['ANIM_OPTIMIZE'].val: - GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 1, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') - Draw.EndAlign() - - Draw.BeginAlign() - GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) - GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) - Draw.EndAlign() - - - Draw.Label('Export Batch...', x+20,y-60, 300, 20) - GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) - - if GLOBALS['BATCH_ENABLE'].val: - Draw.BeginAlign() - GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) - GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) - - # Own dir requires OS module - if os: - GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') - GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') - else: - GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') - - - Draw.EndAlign() - - #y+=80 - - ''' - Draw.BeginAlign() - GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') - Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) - ''' - # Until batch is added - # - - - #Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) - Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) - - #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) - #Draw.EndAlign() - - # exit when mouse out of the view? - # GLOBALS['EVENT'] = EVENT_EXIT - -#def write_ui(filename): -def write_ui(): - - # globals - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - GLOBALS['FILENAME'] = '' - ''' - # IF called from the fileselector - if filename == None: - GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) - else: - GLOBALS['FILENAME'].val = filename - ''' - GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity - GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) - - GLOBALS['EXP_MESH'] = Draw.Create(1) - GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) - GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) - GLOBALS['EXP_ARMATURE'] = Draw.Create(1) - GLOBALS['EXP_LAMP'] = Draw.Create(1) - GLOBALS['EXP_CAMERA'] = Draw.Create(1) - GLOBALS['EXP_EMPTY'] = Draw.Create(1) - GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) - # animation opts - GLOBALS['ANIM_ENABLE'] = Draw.Create(1) - GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) - GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(4) # decimal places - GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action - - # batch export options - GLOBALS['BATCH_ENABLE'] = Draw.Create(0) - GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. - GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above - GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) - GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) - # done setting globals - - # Used by the user interface - GLOBALS['_SCALE'] = Draw.Create(1.0) - GLOBALS['_XROT90'] = Draw.Create(True) - GLOBALS['_YROT90'] = Draw.Create(False) - GLOBALS['_ZROT90'] = Draw.Create(False) - - # best not do move the cursor - # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] != EVENT_EXIT: - - if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: - #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") - GLOBALS['ANIM_ACTION_ALL'][0].val = 1 - GLOBALS['ANIM_ACTION_ALL'][1].val = 0 - - if GLOBALS['EVENT'] == EVENT_FILESEL: - if GLOBALS['BATCH_ENABLE'].val: - txt = 'Batch FBX Dir' - name = Blender.sys.expandpath('//') - else: - txt = 'Export FBX' - name = Blender.sys.makename(ext='.fbx') - - Blender.Window.FileSelector(fbx_ui_write, txt, name) - #fbx_ui_write('/test.fbx') - break - - Draw.UIBlock(fbx_ui, 0) - - - # GLOBALS.clear() -#test = [write_ui] -if __name__ == '__main__': - # Cant call the file selector first because of a bug in the interface that crashes it. - # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) - #write('/scratch/test.fbx') - #write_ui('/scratch/test.fbx') - - if not set: - Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.') - else: - write_ui() diff --git a/release/scripts/export_lightwave_motion.py b/release/scripts/export_lightwave_motion.py deleted file mode 100644 index 562e44f3a2b..00000000000 --- a/release/scripts/export_lightwave_motion.py +++ /dev/null @@ -1,157 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: <- these words are ignored -Name: 'Lightwave Motion (.mot)...' -Blender: 241 -Group: 'Export' -Tip: 'Export Loc Rot Size chanels to a Lightwave .mot file' -""" - -__author__ = "Daniel Salazar (ZanQdo)" -__url__ = ("blender", "blenderartists.org", -"e-mail: zanqdo@gmail.com") -__version__ = "16/04/08" - -__bpydoc__ = """\ -This script exports the selected object's motion channels to Lightwave -motion files (.mot). - -Usage: -Run the script with one or more objects selected (any kind), frames exported -are between Start and End frames in Render buttons. - -""" - -# $Id$ -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2003, 2004: A Vanpoucke -# -# 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 Blender as B -import math as M -#------------------------------------ -#Declarados: -TotalCanales = 9 -#------------------------------------ - -def FuncionPrincipal (Dir): - B.Window.WaitCursor(1) - ObjSelect = B.Object.GetSelected() - - if not ObjSelect: - B.Draw.PupMenu('Select 1 or more objects, aborting.') - return - - if not Dir.lower().endswith('.mot'): - Dir += '.mot' - - - SC = B.Scene.GetCurrent() - SCR = SC.getRenderingContext() - - for ob in ObjSelect: - origName= NombreObjeto= ob.name - print '----\nExporting Object "%s" motion file...' % origName - - FrameA = B.Get('curframe') - FrameP = B.Get('staframe') - FrameF = B.Get('endframe') - - FrameRate = float(SCR.framesPerSec()) - - #--------------------------------------------- - - # Replace danger characters by '_' - for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n': - NombreObjeto = NombreObjeto.replace(ch, '_') - - # Check for file path extension - if len(ObjSelect) > 1: - DirN= '%s_%s.mot' % (Dir[:-4], NombreObjeto) - else: - DirN= Dir - - # Open the file - File = open(DirN,'w') - File.write ('LWMO\n3\n\n') # 3 is the version number. - - # number of channels - File.write ('NumChannels %i\n' % TotalCanales) - - # ---------------------------- - # Main Cycle - - def CicloPrimario(NumCanal): - B.Set('curframe', FrameP) - - File.write ('Channel %i\n{ Envelope\n %i\n' % (NumCanal, (FrameF - FrameP + 1))) - - FrameA = FrameP - while FrameA < (FrameF + 1): - - B.Set('curframe', FrameA) - - mat= ob.mat # Worldspace matrix - - if NumCanal == 0: - Val = mat.translationPart().x - elif NumCanal == 1: - Val = mat.translationPart().z - elif NumCanal == 2: - Val = mat.translationPart().y - elif NumCanal == 3: - Val = M.radians (-mat.toEuler().z) - elif NumCanal == 4: - Val = M.radians (-mat.toEuler().x) - elif NumCanal == 5: - Val = M.radians (-mat.toEuler().y) - elif NumCanal == 6: - Val = mat.scalePart().x - elif NumCanal == 7: - Val = mat.scalePart().z - elif NumCanal == 8: - Val = mat.scalePart().y - File.write (' Key %f %f 3 0 0 0 0 0 0\n' % (Val, (FrameA/FrameRate))) - - FrameA += 1 - # Ending Stuff - File.write (' Behaviors 1 1\n}\n') - - NumObjetoActual = len(ObjSelect) - Iteraciones = 0 - ProgBarVal = 0.0 - while Iteraciones < TotalCanales: - CicloPrimario(Iteraciones) - - # Start Progress Bar - B.Window.DrawProgressBar(ProgBarVal, origName) - ProgBarVal = (float(Iteraciones) / TotalCanales) * 0.98 - Iteraciones += 1 - - B.Window.DrawProgressBar(1.0, '') # Done - print '\nDone, %s motion file location is:\n%s\n' % (origName, DirN) - B.Window.WaitCursor(0) - -# Check if there are selected objects -def main(): - B.Window.FileSelector(FuncionPrincipal, "Write .mot File", B.sys.makename(ext='.mot')) - -if __name__=='__main__': - main() diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py deleted file mode 100644 index c74e7acbcd3..00000000000 --- a/release/scripts/export_m3g.py +++ /dev/null @@ -1,3074 +0,0 @@ -#!BPY -# coding: utf-8 -""" Registration info for Blender menus: -Name: 'M3G (.m3g, .java)...' -Blender: 244 -Group: 'Export' -Tooltip: 'Export to M3G' -""" -#------------------------------------------------------------------------ -# M3G exporter for blender 2.37 or above -# -# Source: http://www.nelson-games.de/bl2m3g/source -# -# $Id$ -# -# Author: Gerhard Völkl -# -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2005: gerhard völkl gkvoelkl@yahoo.de -# -# 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 ***** -# -# To use script: -# 1.) load this file in the text window. -# (press SHIFT+F11, Open New via Datablock button) -# 2.) make sure your mouse is over the text edit window and -# run this script. (press ALT+P) -# Or: -# copy to the scripts directory and it will appear in the -# export list. (Needs 2.32 or higher) -# -# Based on informations from: -# wrl2export.py from Rick Kimball and others -# --------------------------------------------------------------------------# -# History 0.2 -# * maximal Precision in VertexArray (with algorithms from Kalle Raita) -# * IPO Animation with mesh: Rotation, Translation and Size -# History 0.3 -# * to find a 3d object in your java programm you can assign a userID -# your blender object has name 'cube#01' your 3d object will have ID 01 -# the number after '#' is taken -# * more than one material per mesh can be used -# * uv texture support (implemented by Aki Koskinen and Juha Laitinen) -# The image which is bound to the faces will be exportet within m3g-file -# Limitations by M3G-API: -# The width and height of the image must be non-negative powers of two, -# but they need not to be equal. Maximum value is 256. -# *.java export: Only PNG images can be used. -# History 0.4 -# * check limitation of texture images (credit to MASTER_ZION for Brasil) -# * Better light: The light modeles of Blender and M3G are naturally -# different. So the export script trys to translate as much as possible -# -# M3G Light type Blender Light type -# -------------------------------------------------------------- -# AMIENT Light Not available as light type in Blender -# DIRECTIONAL Light SUN -# OMNIdirectional light LAMP -# SPOT light SPOT -# not translated HEMI -# not translated AREA -# -# Attributs of M3G Lights: -# -# Attenuation (OMNI,SPOT): -# Intensity of light changes with distance -# The attenuation factor is 1 / (c + l d + q d2) -# where d is the distance between the light and the vertex being lighted -# and c, l, q are the constant, linear, and quadratic coefficients. -# In Blender exists much complex posibilies. To simplify exporter uses -# only button Dist: distance at which the light intensity is half -# the Energy -# Color (ALL) -# Color of light -# Intensity (ALL) -# The RGB color of this Light is multiplied component-wise with the -# intensity. In Blender : energy -# SpotAngle (SPOT) -# the spot cone angle for this Light -# In Blender: spotSize -# SpotExponent (SPOT) -# The spot exponent controls the distribution of the intensity of -# this Light within the spot cone, such that larger values yield -# a more concentrated cone. In Blender: SpotBl -# -# * Some GUI for options -# First prototype of GUI was created using RipSting's Blender-Python -# GUI designer. Download at Http://oregonstate.edu/~dennisa/Blender/BPG/ -# -# * Ambiente light -# Information is taken by world ambiente attribute -# -# * Parenting Part 1 -# In Blender the Empty object is used to group objects. All objects -# which have the same empty as parent are the member of the same group. -# -# empty <-- Parent of -- element 1 -# <-- Parent of -- element 2 -# -# is translated in M3G -# -# group-Node -- Member --> element 1 -# -- Member --> element 2 -# -# In Blender every object can be the parent of every other object -# In M3G that is not possible. Only a group object can be parent. -# (Or the world object which is derived from group). -# That will come later as Parenting Part 2 -# -# * Backface Culling -# you can use backface culling, if option "use backface culloing" is on. -# Culling will be set in PolygonMode object of every mesh. The correct -# winding is controlled. -# History 0.5 -#* Bone Animation - Armature (Part 1) -# -# Armature is the skeleton for skinned meshes. It stores the bones in -# rest position (more information http://www.blender.org/cms/How_Armatures_work.634.0.html) -# You can work in Blender with bones and meshes in different ways. In -# this first attempt only the use of vertex groups is assisted. -# -# Blender-Objekts translated into M3G-Objects -# -# MESH SkinnedMesh -# | | -# v v -# ARMATURE Group -# | | -# v v -# BONE_1 Group -# Group_second -# | | -# V v -# BONE_2 Group -# Group_secound -# -# Every bone is translated into two groups at the moment, because -# the second bone is needed to do the animation in an easy way. -# -# The animations in Blender for meshes are stored in action objects. -# -# Blender Objects translated into M3G-Objects -# -# ARMATURE -# | activ -# v -# ACTION ANIMATIONCONTROLLER -# | 1..n ^ -# v ANIMATIONTRACK --> Group_second -# IPOs | -# v -# KEYSEQUENZE -# -# One action is translated into one animationcontroller. One IPO is -# translated in one KEYSEQUENZE and one ANIMATIONTRACK. -# -# At the moment only the active action of the armature object is translated. -# -#* Print Info, if type of light is used that is not supported -# -# History 0.5 -# -#* New Option exportAllAction (default value: false) -# If that option is true, all actions will be exported - not only the active -# action. -# At the moment you can only assign one action to one armature. -# To know which action is used with which armature the action -# needs a special name : -# #AE# - -# Example: Name of action : walk#A10E250#02 -# Name of armature : man#10 -# End Frame: 250 -# -# History 0.6 -# Include the same image only one time into the m3g-file -# -# All the following changes of this version was made by Claus Hoefele -# -#* Until now all vertices of the faces was been written. -# Now the vertices will be used again if possible: -# normal and texture coordinates of to vertices have to be the same -# -#* Smooth/solid shading can now be defined for every single material: -# in Editing panel (F9)>Link and Materials -# -#* This script uses now correctly the TexFace and Shadless Buttons in -# Shading panel (F5)>Material buttons>Material box. -# TexFace switches on/off the Export of texture coordinates. -# Shadeless does the some with the normal coordinates -# -#* The GUI was redesigned in a PupBlock -# -#* Options: -# -#** Texturing Enabled: Switches on/off export of textures and texture -# coordinates. Attention: the TextFace button switches only -# for one mesh -#** Texturing External: the textures will be included it mg3-file or -# exported in seperate file -#** Lighting Enabled: turns on/off export of lights and normal completly -# Attention: Shadeless only for one mesh -#** Persp. Correction: turns on/off perspective correction in PolygonMode. -#** Smooth Shading: turns on/off smooth shading in PolygonMode. -# -#* Textures in external references are used again (with ImageFactory) -# -#* Blender function: Double Sided button in Editing Context -# (F9)>Mesh panel) -# turn on/off PolygonMode.CULL_BACK anzuschalten. -# -#* Script ingnores meshes that have no faces -# -# History 0.7 -# -# * Exporter can work with texture coordinates greater 1 and smaller 0 -# -# * Adler32 did not work always correct. New implementation made. -# -# * Modul shutil is not needed any longer. Exporter has its own copy_file. -# (realized and inspired by ideasman_42 and Martin Neumann) -# -# History 0.8 -# -# * Blender works with SpotAngles 1..180 but M3G works only with 0..90 -# M3G use the 'half angle' (cut off angle) (Thanks to Martin Storsjö) -# -# * Error fixed: Texture coordinates was not calculated correct. -# (Thanks to Milan Piskla, Vlad, Max Gilead, Regis Cosnier ...) -# -# * New options in GUI: -# M3G Version 2.0 : Will export M3G files Vers. 2.0 in future -# Game Physics: Adds Game Physics infos for NOPE API -# -# --------------------------------------------------------------------------# -# TODO: Export only selected mesh -# TODO: Optimize Bones <--> Vertex Group mapping -# TODO: Compressed File -# TODO: MTex - Support -# TODO: By Rotating use SQUAD instead of Beziere. It's smoother -import Blender -from Blender import Types,Lamp,Material,Texture,Window,Registry,Draw -from Blender.BGL import * -from Blender.Object import * -from Blender.Camera import * -from Blender.Mesh import * -from array import array -import sys, struct, zlib -from inspect import * -from types import * -from Blender.Mathutils import * -from os.path import * -#import rpdb2 - -# ---- Helper Functions -------------------------------------------------------# -def copy_file(source, dest): - file = open(source, 'rb') - data = file.read() - file.close() - - file = open(dest, 'wb') - file.write(data) - file.close() - -def tracer(frame, event, arg): - '''Global trace function''' - if event=='call': - tmp = getargvalues(frame) - print event, frame.f_code.co_name, frame.f_lineno, \ - formatargvalues(tmp[0],tmp[1],tmp[2],tmp[3]) - elif event=='line': - print event, frame.f_code.co_name, frame.f_lineno - #print event, frame.f_code.co_name, frame.f_lineno, \ - # getsourcelines(frame.f_code)[frame.f_lineno] - elif event=='return': - print event, frame.f_code.co_name, frame.f_lineno, "->", arg - return tracer - -def doSearchDeep(inList,outList): - '''Does deepsearch for all elements in inList''' - for element in inList: - if element != None : outList = element.searchDeep(outList) - return outList - - -def getId(aObject): - ''' returns 0 if Object is None: M3G value for null''' - if aObject == None: return 0 - return aObject.id - -def toJavaBoolean(aValue): - ''' returns java equivalent to boolean''' - if aValue: - return 'true' - else : - return 'false' - -def sign(a): - if a<0 : return -1 - elif a>0 : return 1 - else : return 0 - -def isOrderClockWise(v,normal): - ''' returns true, if order of vertices is clockwise. Important for - culling ''' - # (v2-v0)x(v2-v1)=surface_normal - # - if type(v[0]) is Types.MVertType: - mNormal = TriangleNormal(Vector(v[0].co),Vector(v[1].co),Vector(v[2].co)) - else: - mNormal = TriangleNormal(Vector(v[0]),Vectot(v[1]),Vector(v[2])) - #print "normal ",mNormal.normalize() - #print "BNormal ",normal.normalize() - - # Do not use any longer. Blender does it correct - - result = (sign(normal.x)==sign(mNormal.x) and - sign(normal.y)==sign(mNormal.y) and - sign(normal.z)==sign(mNormal.z)) - #print "Result ",result - - return True - - -# ---- M3G Types --------------------------------------------------------------# -class M3GVertexList: - def __init__(self, wrapList): - self.mlist = wrapList - - def __getitem__(self, key): - item = self.mlist[key] - if type(item) is Types.MVertType: - result =(item.co[0],item.co[1],item.co[2]) - else: - result = item - return result - -class M3GBoneReference: - def __init__(self,first,count): - self.firstVertex=first #UInt32 - self.vertexCount=count #UInt32 - - -class M3GBone: - def __init__(self): - self.verts=[] #List of influenced verts - self.transformNode=None #ObjectIndex - self.references = [] #References to Verts that are needed - self.weight=0 #Int32 - - - def setVerts(self,aVerts): - self.verts = aVerts - self.createReferences() - - def createReferences(self): - #print "createReference::len(verts) ",len(self.verts) - if len(self.verts)==0: return #No Verts available - self.verts.sort() - ref = [] - list = [] - last = self.verts[0]-1 - count = 0 - for vert in self.verts: - #print "vert ",vert - if vert==last+1: - list.append(vert) - else: - ref.append(M3GBoneReference(list[0],len(list))) - #print list[0],len(list) - list=[vert] - last=vert - #print "list ",list - if len(list)>0: - ref.append(M3GBoneReference(list[0],len(list))) - self.references = ref - - -class M3GVector3D: - def __init__(self,ax=0.0,ay=0.0,az=0.0): - self.x = ax #Float32 - self.y = ay #Float32 - self.z = az #Float32 - - def writeJava(self): - return str(self.x)+"f, "+str(self.y)+"f, "+str(self.z)+"f" - - def getData(self): - return struct.pack("<3f",self.x,self.y,self.z) - - def getDataLength(self): - return struct.calcsize("<3f") - -class M3GMatrix: - """ A 4x4 generalized matrix. The 16 elements of the - matrix are output in the same order as they are - retrieved using the API Transform.get method. In - other words, in this order: - 0 1 2 3 - 4 5 6 7 - 8 9 10 11 - 12 13 14 15 """ - def __init__(self): - self.elements=16 * [0.0] #Float32 - - def identity(self): - self.elements[ 0] = 1.0 - self.elements[ 5] = 1.0 - self.elements[10] = 1.0 - self.elements[15] = 1.0 - - def getData(self): - return struct.pack('<16f',self.elements[0],self.elements[1], - self.elements[2],self.elements[3], - self.elements[4],self.elements[5], - self.elements[6],self.elements[7], - self.elements[8],self.elements[9], - self.elements[10],self.elements[11], - self.elements[12],self.elements[13], - self.elements[14],self.elements[15]) - - def getDataLength(self): - return struct.calcsize('<16f') - - -class M3GColorRGB: - """ A color, with no alpha information. Each compo- - nent is scaled so that 0x00 is 0.0, and 0xFF is 1.0. - """ - def __init__(self,ared=0,agreen=0,ablue=0): - self.red = ared #Byte - self.green = agreen #Byte - self.blue = ablue #Byte - - def writeJava(self): - return "0x"+("%02X%02X%02X%02X" % (0.0, self.red, self.green, self.blue)) - - def getData(self): - return struct.pack('3B',self.red,self.green,self.blue) - - def getDataLength(self): - return struct.calcsize('3B') - - -class M3GColorRGBA: - """ A color, with alpha information. Each component - is scaled so that 0x00 is 0.0, and 0xFF is 1.0. The - alpha value is scaled so that 0x00 is completely - transparent, and 0xFF is completely opaque. - """ - def __init__(self,ared=0,agreen=0,ablue=0,aalpha=0): - self.red = ared #Byte - self.green = agreen #Byte - self.blue = ablue #Byte - self.alpha = aalpha #Byte - - def writeJava(self): - return "0x"+("%02X%02X%02X%02X" % (self.alpha, self.red, self.green, self.blue)) - - def getData(self): - return struct.pack('4B',self.red,self.green,self.blue,self.alpha) - - def getDataLength(self): - return struct.calcsize('4B') - - -#ObjectIndex -#The index of a previously encountered object in -#the file. Although this is serialized as a single -#unsigned integer, it is included in the compound -#type list because of the additional semantic infor- -#mation embodied in its type. A value of 0 is -#reserved to indicate a null reference; actual object indices start from 1. Object indices must refer -#only to null or to an object which has already been -#created during the input deserialization of a file - -#they must be less than or equal to the index of the -#object in which they appear. Other values are dis- -#allowed and must be treated as errors. -#UInt32 -#index; - -# ---- M3G Proxy --------------------------------------------------------------- # -class M3GProxy: - def __init__(self): - self.name = "" - self.id=0 - self.ObjectType=0 - self.binaryFormat='' - - def __repr__(self): - return "<"+str(self.__class__)[9:] + ":" + str(self.name) + ":" + str(self.id) + ">" - - -class M3GHeaderObject(M3GProxy): - def __init__(self): - M3GProxy.__init__(self) - self.M3GHeaderObject_binaryFormat = ' 0: - value += struct.calcsize('<'+str(len(self.animationTracks))+'I') - return value - - def writeJava(self,aWriter,aCreate): - if aCreate : pass #Abstract! Could not be created - if len(self.animationTracks) > 0 : - aWriter.write(2) - for iTrack in self.animationTracks: - aWriter.write(2,"BL%i.addAnimationTrack(BL%i);" % (self.id,iTrack.id)) - - -class M3GTransformable(M3GObject3D): - def __init__(self): - M3GObject3D.__init__(self) - self.hasComponentTransform=False #Boolean - #IF hasComponentTransform==TRUE, THEN - self.translation=M3GVector3D(0,0,0) #Vector3D - self.scale=M3GVector3D(1,1,1) #Vector3D - self.orientationAngle=0 #Float32 - self.orientationAxis=M3GVector3D(0,0,0) #Vector3D undefined - #END - self.hasGeneralTransform=False #Boolean - #IF hasGeneralTransform==TRUE, THEN - self.transform = M3GMatrix() #Matrix identity - self.transform.identity() - #END - #If either hasComponentTransform or hasGeneralTransform is false, the omitted fields will be - #initialized to their default values (equivalent to an identity transform in both cases). - - def writeJava(self,aWriter,aCreate): - if aCreate: pass #Abstract Base Class! Cant't be created - M3GObject3D.writeJava(self,aWriter,False) - if self.hasGeneralTransform : - aWriter.write(2,"float[] BL%i_matrix = {" % (self.id)) - aWriter.writeList(self.transform.elements,4,"f") - aWriter.write(2,"};") - aWriter.write(2) - aWriter.write(2,"Transform BL%i_transform = new Transform();" % (self.id)) - aWriter.write(2,"BL%i_transform.set(BL%i_matrix);" % (self.id,self.id)) - aWriter.write(2,"BL%i.setTransform(BL%i_transform);" % (self.id,self.id)) - aWriter.write(2) - if self.hasComponentTransform: - aWriter.write(2,("BL%i.setTranslation("+self.translation.writeJava()+");") - %(self.id)) - - def getData(self): - data = M3GObject3D.getData(self) - data += struct.pack(" 1: - aWriter.write(2,"IndexBuffer[] BL%i_indexArray = {" % (self.id)) - aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.indexBuffer ])) - aWriter.write(2," };") - aWriter.write(2) - aWriter.write(2,"Appearance[] BL%i_appearanceArray = {" % (self.id)) - aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.appearance ])) - aWriter.write(2," };") - aWriter.write(2) - aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i_indexArray,BL%i_appearanceArray%s);" % \ - (aClassName,self.id,aClassName,self.vertexBuffer.id, self.id,self.id,aExtension)) - else: - #print "indexBuffer", len(self.indexBuffer) - #print "appearance", len(self.appearance) - aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i,BL%i%s);" % \ - (aClassName, - self.id, - aClassName, - self.vertexBuffer.id, - self.indexBuffer[0].id, - self.appearance[0].id, - aExtension)) - M3GNode.writeJava(self,aWriter,False) - aWriter.write(2) - - -class M3GSkinnedMesh(M3GMesh): - def __init__(self,aVertexBuffer=None, aIndexBuffer=[], aAppearance=[]): - M3GMesh.__init__(self,aVertexBuffer, aIndexBuffer, aAppearance) - self.ObjectType=16 - self.skeleton=None #ObjectIndex - self.bones={} - #print"M3GSkinnedMesh.__init__::self.vertexBuffer:",self.vertexBuffer - ##ObjectIndex skeleton; - ##UInt32 transformReferenceCount; - ##FOR each bone reference... - ## ObjectIndex transformNode; - ## UInt32 firstVertex; - ## UInt32 vertexCount; - ## Int32 weight; - ##END - - def searchDeep(self,alist): - alist = doSearchDeep([self.skeleton],alist) - return M3GMesh.searchDeep(self,alist) - - def addSecondBone(self): - secondBones = {} - for bone in self.bones.values(): - bone2 = M3GBone() - bone2.verts=bone.verts - bone.verts=[] - mGroup = M3GGroup() - mGroup.name=bone.transformNode.name+"_second" - bone2.transformNode=mGroup - bone2.references = bone.references - bone.references = [] - bone2.weight = bone.weight - bone.weight=0 - mGroup.children = bone.transformNode.children - bone.transformNode.children = [mGroup] - mGroup.animationTracks=bone.transformNode.animationTracks - bone.transformNode.animationTracks = [] - secondBones[bone.transformNode.name+"_second"]=bone2 - for bone in secondBones.values(): - self.bones[bone.transformNode.name] = bone - - def getBlenderIndexes(self): - #print "M3GSkinnedMesh.vertexBuffer:",self.vertexBuffer - return self.vertexBuffer.positions.blenderIndexes - - def writeJava(self,aWriter,aCreate): - self.writeBaseJava(aWriter,aCreate,"SkinnedMesh", - (",BL%i" % (self.skeleton.id))) - aWriter.write(2,"//Transforms") - for bone in self.bones.values(): - #print "bone: ", bone - #print "bone.references: ", bone.references - for ref in bone.references: - aWriter.write(2,"BL%i.addTransform(BL%i,%i,%i,%i);" % - (self.id, - bone.transformNode.id,bone.weight, - ref.firstVertex, ref.vertexCount)) - aWriter.write(2) - - def getDataLength(self): - value = M3GMesh.getDataLength(self) - value += struct.calcsize(' element[i] : minimum[i] = element[i] - if maximum[i] < element[i] : maximum[i] = element[i] - #print i, maximum[i],element[i] - lrange=[0,0,0] - maxRange=0.0 - maxDimension=-1 - for i in range(3): #set bias - lrange[i] = maximum[i]-minimum[i] - self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 - #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] - if lrange[i] > maxRange: - maxRange = lrange[i] - maxDimension=i - self.scale = maxRange/65533.0 - #print "MaxRange ",maxRange - #print "scale",self.scale - - - def internalAutoScaling(self): - print "internalAutoScaling" - #Already done? - print self.components.typecode - if not self.autoscaling or self.components.typecode!="f":return - #Find bais and scale - minimum=[] - maximum=[] - for i in range(self.componentCount): - minimum.append(self.components[i]) - maximum.append(self.components[i]) - for i in range(0,len(self.components),self.componentCount): - for j in range(self.componentCount): - if minimum[j] > self.components[i+j] : minimum[j] = self.components[i+j] - if maximum[j] < self.components[i+j] : maximum[j] = self.components[i+j] - #print "i+j=",i+j,"min=",minimum[j],"max=",maximum[j],"elem=",self.components[i+j] - #print "min=", minimum - #print "max=", maximum - lrange=[0] * self.componentCount - maxRange=0.0 - maxDimension=-1 - for i in range(self.componentCount): #set bias - lrange[i] = maximum[i]-minimum[i] - self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 - #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] - if lrange[i] > maxRange: - maxRange = lrange[i] - maxDimension=i - maxValue=(2**(8*self.componentSize)*1.0)-2.0 - #print "MaxValue=",maxValue - self.scale = maxRange/maxValue - #print "MaxRange ",maxRange - #print "scale",self.scale - #Copy Components - oldArray=self.components - self.components=self.createComponentArray() - for i in range(0,len(oldArray),self.componentCount): - for j in range(self.componentCount): - element=int((oldArray[i+j]-self.bias[j])/self.scale) - #print "element",element - self.components.append(element) - # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. - if self.uvmapping: - for i in range(0,len(self.components),2): - self.components[i+1]= int(self.components[i+1]*(-1)) #Error in Version 0.7 - for i in range(len(self.components)): - if abs(self.components[i])>maxValue:raise Exception( i+". element too great/small!") - - def writeJava(self,aWriter,aCreate): - self.internalAutoScaling() - if aCreate: - aWriter.write(2,"// VertexArray " + self.name) - if self.componentSize == 1: - aWriter.write(2,"byte[] BL%i_array = {" % (self.id)) - else: - aWriter.write(2,"short[] BL%i_array = {" % (self.id)) - aWriter.writeList(self.components) - aWriter.write(2,"};") - aWriter.write(2) - aWriter.write(2,"VertexArray BL%i = new VertexArray(BL%i_array.length/%i,%i,%i);" % - (self.id,self.id, - self.componentCount,self.componentCount,self.componentSize)) - aWriter.write(2,"BL%i.set(0,BL%i_array.length/%i,BL%i_array);" % - (self.id,self.id,self.componentCount,self.id)) - M3GObject3D.writeJava(self,aWriter,False) - aWriter.write(2) - - - def getData(self): - self.internalAutoScaling() - self.vertexCount = len(self.components)/self.componentCount - data = M3GObject3D.getData(self) - data += struct.pack('<3BH',self.componentSize, - self.componentCount, - self.encoding, - self.vertexCount) - componentType = "" - if self.componentSize == 1: - componentType = "b" - else: - componentType = "h" - for element in self.components: - data += struct.pack('<'+componentType,element) - return data - - def getDataLength(self): - self.internalAutoScaling() - value = M3GObject3D.getDataLength(self) - value += struct.calcsize('<3BH') - componentType = "" - if self.componentSize == 1: - componentType = "b" - else: - componentType = "h" - value += struct.calcsize('<'+str(len(self.components))+componentType) - return value - - def append(self,element,index=None): - #print "type(element):",type(element) - if type(element) is Types.vectorType : - for i in range(3): - value = int((element[i]-self.bias[i])/self.scale) - #print "append:",i,element[i],(element[i]-self.bias[i]),value - self.components.append(value) - elif type(element) is Types.MVertType: - for i in range(3): - value = int((element.co[i]-self.bias[i])/self.scale) - #print "append:",i,element[i],(element[i]-self.bias[i]),value - self.components.append(value) - if index!=None: - key=str(len(self.blenderIndexes)) - #print"key,index:",key,index - self.blenderIndexes[key]=index - #print"blenderIndexes",self.blenderIndexes - else: - print "VertexArray.append: element=",element - self.components.append(element) - -class M3GVertexBuffer(M3GObject3D): - def __init__(self): - M3GObject3D.__init__(self) - self.ObjectType=21 - self.defaultColor=M3GColorRGBA(255,255,255) #ColorRGBA 0xFFFFFFFF (opaque white). - self.positions = None #ObjectIndex - self.positionBias = [0.0,0.0,0.0] #Float32[3] - self.positionScale = 1.0 #Float32 - self.normals = None #ObjectIndex - self.colors = None #ObjectIndex - self.texCoordArrays = [] - self.texcoordArrayCount = 0 #UInt32 -## #FOR each texture coordinate array... -## self.texCoords = [] #ObjectIndex -## self.texCoordBias=[] #Float32[3] -## self.texCoordScale=[] #;Float32 -## #END -## #If a texture coordinate array has only two components, the corresponding texCoordBias[2] element -## #must be 0.0. -## #Null texture coordinate arrays are never serialized, regardless of their position. A single texture -## #coordinate array will therefore always be serialized as belonging to texturing unit 0, regardless of -## #its original unit it was assigned to. -## #There are as many references in the texture coordinates array as there are active texture units for -## #this geometry. The texture coordinate references are loaded sequentially from texture unit 0. If the -## #implementation supports more texture units than are specified, these are left in their default, inactive -## #state, with a null texture coordinate reference and an undefined bias and scale. -## #If more texture coordinate references are specified than are supported by the implementation, then -## #this must be treated as an error, as it would be in the API. The application can then decide on an -## #appropriate course of action to handle this case. - - def searchDeep(self,alist): - if self.positions!=None: alist = self.positions.searchDeep(alist) - if self.normals != None: alist = self.normals.searchDeep(alist) - if self.colors!= None: alist = self.colors.searchDeep(alist) - alist = doSearchDeep(self.texCoordArrays, alist) - return M3GObject3D.searchDeep(self,alist) - - def setPositions(self,aVertexArray): - self.positions = aVertexArray - self.positionBias = aVertexArray.bias - self.positionScale = aVertexArray.scale - - def writeJava(self,aWriter,aCreate): - if aCreate: - aWriter.write(2,"//VertexBuffer"+self.name ) - aWriter.write(2,"VertexBuffer BL%i = new VertexBuffer();" % (self.id)) - aWriter.write(2,"float BL%i_Bias[] = { %ff, %ff, %ff};" % - (self.id,self.positionBias[0], - self.positionBias[1],self.positionBias[2])) - aWriter.write(2,"BL%i.setPositions(BL%i,%ff,BL%i_Bias);" % - (self.id, self.positions.id, - self.positionScale,self.id)) - aWriter.write(2,"BL%i.setNormals(BL%i);" % (self.id,self.normals.id)) - #if self.colors != None: aWriter.write(2,"BL%i.setTexCoords(0,BL%i,1.0f,null);" % - # (self.id,self.colors.id)) - lIndex = 0 - for iTexCoord in self.texCoordArrays: - aWriter.write(2,"float BL%i_%i_TexBias[] = { %ff, %ff, %ff};" % - (self.id,lIndex, iTexCoord.bias[0], - iTexCoord.bias[1],iTexCoord.bias[2])) - #int index, javax.microedition.m3g.VertexArray194 texCoords, float scale, float[] bias - aWriter.write(2,"BL%i.setTexCoords(%i,BL%i,%ff,BL%i_%i_TexBias);" % - (self.id, lIndex, iTexCoord.id, iTexCoord.scale,self.id,lIndex)) - lIndex += 1 - - M3GObject3D.writeJava(self,aWriter,False) - - - def getData(self): - self.texcoordArrayCount = len(self.texCoordArrays) - data = M3GObject3D.getData(self) - data += self.defaultColor.getData() - data += struct.pack(' 0 : - value += struct.calcsize('<' + str(len(self.indices)) + 'I') - value += struct.calcsize(' 0: - value+= struct.calcsize('<'+str(len(self.stripLengths))+'I') - return value - - -class M3GAppearance(M3GObject3D): - def __init__(self): - M3GObject3D.__init__(self) - self.ObjectType=3 - self.layer=0 #Byte - self.compositingMode=None #ObjectIndex - self.fog=None #ObjectIndex - self.polygonMode=None #ObjectIndex - self.material=None #ObjectIndex - self.textures=[] #;ObjectIndex[] - - def searchDeep(self,alist): - alist = doSearchDeep([self.compositingMode,self.fog, - self.polygonMode,self.material] - + self.textures,alist) - return M3GObject3D.searchDeep(self,alist) - - def getData(self): - data = M3GObject3D.getData(self) - data += struct.pack(" 0 : - value += struct.calcsize("<"+str(len(self.textures))+'I') - return value - - - def writeJava(self,aWriter,aCreate): - if aCreate: - aWriter.write(2,"//Appearance") - aWriter.write(2,"Appearance BL%i = new Appearance();" % (self.id)) - if self.compositingMode!= None: - aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % - (self.id,self.compositingMode.id)) - if self.fog!=None: - aWriter.write(2,"BL%i.setFog(BL%i);" % - (self.id,self.fog.id)) - if self.polygonMode!=None: - aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % - (self.id,self.polygonMode.id)) - if self.material!=None: - aWriter.write(2,"BL%i.setMaterial(BL%i);" % - (self.id,self.material.id)) - i=0 - for itexture in self.textures: - aWriter.write(2,"BL%i.setTexture(%i,BL%i);" % - (self.id,i,itexture.id)) - i =+ 1 - M3GObject3D.writeJava(self,aWriter,False) - aWriter.write(2) - -class M3GTexture2D(M3GTransformable): - #M3G imposes the following restrictions when assigning textures to a model: - #The dimensions must be powers of two (4, 8, 16, 32, 64, 128...). - - WRAP_REPEAT = 241 - WRAP_CLAMP = 240 - FILTER_BASE_LEVEL=208 - FILTER_LINEAR=209 - FILTER_NEAREST=210 - FUNC_ADD=224 - FUNC_BLEND=225 - FUNC_DECAL=226 - FUNC_MODULATE=227 - FUNC_REPLACE=228 - - def __init__(self,aImage): - M3GTransformable.__init__(self) - self.ObjectType=17 - self.Image = aImage #ObjectIndex - self.blendColor=M3GColorRGB(0,0,0) - self.blending=M3GTexture2D.FUNC_MODULATE #Byte - self.wrappingS=M3GTexture2D.WRAP_REPEAT #Byte - self.wrappingT=M3GTexture2D.WRAP_REPEAT #Byte - self.levelFilter=M3GTexture2D.FILTER_BASE_LEVEL #Byte - self.imageFilter=M3GTexture2D.FILTER_NEAREST #Byte - - def searchDeep(self,alist): - alist = doSearchDeep([self.Image],alist) - return M3GTransformable.searchDeep(self,alist) - - def getData(self): - data = M3GTransformable.getData(self) - data += struct.pack('#AE# - lError = "Armature name " + name + " is not ok. Perhaps you should set option 'ExportAllAction' to false." - #print "name ", name - lLetter = name.find("#") - if lLetter == -1 :raise Exception(lError) - if name[lLetter+1]!='A': raise Exception(lError) - lName = name[lLetter+2:] - #print "lName ", lName - lLetter = lName.find("E") - #print "lLetter ", lLetter - if lLetter == -1 :raise Exception(lError) - #print "lName[:]", lName[:0] - lArmatureID = int(lName[:lLetter]) - lName = lName[lLetter+1:] - lLetter = lName.find("#") - if lLetter == -1:raise Exception(lError) - lEndFrame = int(lName[:lLetter]) - lActionID = int(lName[lLetter+1:]) - return (lArmatureID,lEndFrame,lActionID) - - - def translateWorld(self,scene): - "creates world object" - world = M3GWorld() - - #Background - world.background = M3GBackground() - blWorld= scene.world - #AllWorlds = Blender.World.Get() # Set Color - #if len(AllWorlds)>=1: # world object available - if blWorld != None: - world.background.backgroundColor=self.translateRGBA(blWorld.getHor(),0) # horizon color of the first world - if mOptions.createAmbientLight & mOptions.lightingEnabled: - lLight = M3GLight() - lLight.mode = lLight.modes['AMBIENT'] - lLight.color = self.translateRGB(blWorld.getAmb()) - self.nodes.append(lLight) - - #TODO: Set background picture from world - - return world - - def translateEmpty(self,obj): - print "translate empty ..." - mGroup = M3GGroup() - self.translateToNode(obj,mGroup) - - def translateCamera(self,obj): - print "translate camera ..." - camera = obj.getData() - if camera.getType()!=0: - print "Only perscpectiv cameras will work korrekt" - return #Type=0 'perspectiv' Camera will be translated - mCamera = M3GCamera() - mCamera.projectionType=mCamera.PERSPECTIVE - mCamera.fovy=60.0 # TODO: Calculate fovy from Blender.lens - mCamera.AspectRatio=4.0/3.0 # TODO: different in every device - mCamera.near=camera.getClipStart() - mCamera.far=camera.getClipEnd() - self.translateToNode(obj,mCamera) - self.world.activeCamera = mCamera # Last one is always the active one - - - def translateMaterials(self, aMaterial, aMesh, aMatIndex, createNormals, createUvs): - print "translate materials ..." - - mAppearance = M3GAppearance() - - if createNormals: - mMaterial = M3GMaterial() - mMaterial.name = aMaterial.name - mMaterial.diffuseColor = self.translateRGBA(aMaterial.rgbCol,1.0) #ColorRGBA - #material.specularColor= self.translateRGB(mat.specCol) #ColorRGB - mAppearance.material = mMaterial - - if createUvs: - # Search file name in mesh face. - lImage = None - for iface in aMesh.faces: - if iface.mat==aMatIndex: - if iface.image != None: - lImage = iface.image - break - if lImage==None: - raise Exception("Mesh " + aMesh.name + ": No image found for uv-texture! Perhaps no uv-coordinates ?") - - # M3G requires textures to have power-of-two dimensions. - [width, height] = lImage.getSize() - powerWidth = 1 - while (powerWidth < width): - powerWidth *= 2 - powerHeight = 1 - while (powerHeight < height): - powerHeight *= 2 - if powerWidth != width or powerHeight != height: - raise Exception("Image " + lImage.filename + ": width and height must be power-of-two!") - - # ImageFactory reuses existing images. - mImage = ImageFactory.getImage(lImage, mOptions.textureExternal) - mTexture = M3GTexture2D(mImage) - mAppearance.textures.append(mTexture) - - mPolygonMode=M3GPolygonMode() - mPolygonMode.perspectiveCorrectionEnabled = mOptions.perspectiveCorrection - if not aMesh.mode & Modes.TWOSIDED: - mPolygonMode.culling=M3GPolygonMode.CULL_BACK - else: - mPolygonMode.culling=M3GPolygonMode.CULL_NONE - if mOptions.smoothShading: - mPolygonMode.shading=M3GPolygonMode.SHADE_SMOOTH - else: - mPolygonMode.shading=M3GPolygonMode.SHADE_FLAT - - mAppearance.polygonMode = mPolygonMode - - return mAppearance - - - def translateMesh(self,obj): - print "translate mesh ..." + str(obj) - - # Mesh data. - mesh = obj.getData(False, True) # get Mesh not NMesh object - if len(mesh.faces) <= 0: # no need to process empty meshes - print "Empty mesh " + str(obj) + " not processed." - return - - vertexBuffer = M3GVertexBuffer() - positions = M3GVertexArray(3, 2) # 3 coordinates - 2 bytes - if mOptions.autoscaling: positions.useMaxPrecision(mesh.verts) - indexBuffers = [] - appearances = [] - print str(len(mesh.materials)) + " material(s) found." - - # Texture coordinates. - createUvs = False - if mOptions.textureEnabled & mesh.faceUV: - for material in mesh.materials: - if material.getMode() & Material.Modes.TEXFACE: createUvs = True; - - if createUvs: - if mOptions.autoscaling: - uvCoordinates = M3GVertexArray(2,2,True,True) #2 coordinates - 2 bytes - autoscaling - else: - uvCoordinates = M3GVertexArray(2, 2) #2 coordinates - 2 bytes - uvCoordinates.bias[0] = 0.5 - uvCoordinates.bias[1] = 0.5 - uvCoordinates.bias[2] = 0.5 - uvCoordinates.scale = 1.0/65535.0 - else: - uvCoordinates = None - - # Normals. - createNormals = False - if mOptions.lightingEnabled: - for material in mesh.materials: - if not (material.getMode() & Material.Modes.SHADELESS): createNormals = True; - - if createNormals: - normals = M3GVertexArray(3, 1) # 3 coordinates - 1 byte - else: - normals = None - - # Create a submesh for each material. - for materialIndex, material in enumerate(mesh.materials): - faces = [face for face in mesh.faces if face.mat == materialIndex] - if len(faces) >= 0: - indexBuffers.append(self.translateFaces(faces, positions, normals, uvCoordinates, createNormals, createUvs)) - appearances.append(self.translateMaterials(material, mesh, materialIndex, createNormals, createUvs)) - - # If the above didn't result in any IndexBuffer (e.g. there's no material), write a single IndexBuffer - # with all faces and a default Appearance. - if len(indexBuffers) == 0: - indexBuffers.append(self.translateFaces(mesh.faces, positions, normals, uvCoordinates, createNormals, createUvs)) - appearances.append(M3GAppearance()) - - vertexBuffer.setPositions(positions) - if createNormals: vertexBuffer.normals = normals - if createUvs: vertexBuffer.texCoordArrays.append(uvCoordinates) - - parent = obj.getParent() - if parent!=None and parent.getType()=='Armature': #Armatures ? - mMesh = M3GSkinnedMesh(vertexBuffer,indexBuffers,appearances) - #print"vertexBuffer.positions:",vertexBuffer.positions - print"mMesh.vertexBuffer:",mMesh.vertexBuffer - self.translateArmature(parent,obj,mMesh) - else: - mMesh = M3GMesh(vertexBuffer,indexBuffers,appearances) - - self.translateToNode(obj,mMesh) - - #Do Animation - self.translateObjectIpo(obj,mMesh) - - def translateFaces(self, faces, positions, normals, uvCoordinates, createNormals, createUvs): - """Translates a list of faces into vertex data and triangle strips.""" - - # Create vertices and triangle strips. - indices = [0, 0, 0, 0] - triangleStrips = M3GTriangleStripArray() - - for face in faces: - for vertexIndex, vertex in enumerate(face.verts): - # Find candidates for sharing (vertices with same Blender ID). - vertexCandidateIds = [int(k) for k, v in positions.blenderIndexes.items() if v == vertex.index] - - # Check normal. - if createNormals and not face.smooth: - # For solid faces, a vertex can only be shared if the the face normal is - # the same as the normal of the shared vertex. - for candidateId in vertexCandidateIds[:]: - for j in range(3): - if face.no[j]*127 != normals.components[candidateId*3 + j]: - vertexCandidateIds.remove(candidateId) - break - - # Check texture coordinates. - if createUvs: - # If texture coordinates are required, a vertex can only be shared if the - # texture coordinates match. - for candidateId in vertexCandidateIds[:]: - s = int((face.uv[vertexIndex][0]-0.5)*65535) - t = int((0.5-face.uv[vertexIndex][1])*65535) - if (s != uvCoordinates.components[candidateId*2 + 0]) or (t != uvCoordinates.components[candidateId*2 + 1]): - vertexCandidateIds.remove(candidateId) - - if len(vertexCandidateIds) > 0: - # Share the vertex. - indices[vertexIndex] = vertexCandidateIds[0] - else: - # Create new vertex. - positions.append(vertex, vertex.index) - indices[vertexIndex] = len(positions.components)/3 - 1 - - # Normal. - if createNormals: - for j in range(3): - if face.smooth: - normals.append(int(vertex.no[j]*127)) # vertex normal - else: - normals.append(int(face.no[j]*127)) # face normal - - # Texture coordinates. - if createUvs: - lUvCoordinatesFound = True - print "face.uv[vertexIndex][0]:",face.uv[vertexIndex][0] - print "face.uv[vertexIndex][1]:",face.uv[vertexIndex][1] - if mOptions.autoscaling: - uvCoordinates.append(face.uv[vertexIndex][0]) - uvCoordinates.append(face.uv[vertexIndex][1]) - else: - uvCoordinates.append(int((face.uv[vertexIndex][0]-0.5)*65535)) - # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. - uvCoordinates.append(int((0.5-face.uv[vertexIndex][1])*65535)) - - # IndexBuffer. - triangleStrips.stripLengths.append(len(face.verts)) - if len(face.verts) > 3 : - triangleStrips.indices += [indices[1], indices[2], indices[0], indices[3]] # quad - else : - triangleStrips.indices += [indices[0], indices[1], indices[2]] # tri - - return triangleStrips - - - def translateObjectIpo(self,obj,aM3GObject): - if obj.getIpo() == None : return #No Ipo available - print "translate Ipo ..." - - lIpo = obj.getIpo() - self.translateIpo(lIpo,aM3GObject) - - - def translateIpo(self,aIpo,aM3GObject,aM3GAnimContr=None,aEndFrame=0): - #Print info about curves - #for iCurve in lIpo.getCurves(): - # print "Extrapolation",iCurve.getExtrapolation() #Constant, Extrapolation, Cyclic or Cyclic_extrapolation - # print "Interpolation",iCurve.getInterpolation() #Constant, Bezier, or Linear - # print "Name",iCurve.getName() - # for iPoint in iCurve.getPoints(): - # print "Knode points",iPoint.getPoints() - types = ['Loc','Rot','Size','Quat'] - - for type in types: - if aIpo.getCurve(type+'X'): - self.translateIpoCurve(aIpo,aM3GObject,type,aM3GAnimContr,aEndFrame) - - - def translateIpoCurve(self,aIpo,aM3GObject,aCurveType,aM3GAnimContr,aEndFrame=0): - - lContext = self.scene.getRenderingContext() - if aEndFrame==0: - lEndFrame = lContext.endFrame() - else: - lEndFrame = aEndFrame - - lTimePerFrame = 1.0 / lContext.framesPerSec() * 1000 - - lCurveX = aIpo.getCurve(aCurveType+'X') - lCurveY = aIpo.getCurve(aCurveType+'Y') - lCurveZ = aIpo.getCurve(aCurveType+'Z') - if aCurveType=='Quat': lCurveW = aIpo.getCurve(aCurveType+'W') - - lInterpolation = None - if aCurveType == 'Rot' or aCurveType == 'Quat': - lTrackType = M3GAnimationTrack.ORIENTATION - lNumComponents=4 - lCurveFactor= 10 #45 Degrees = 4,5 - if aCurveType == 'Quat': - lTrackType = M3GAnimationTrack.ORIENTATION - lNumComponents=4 - lCurveFactor= 1 - lInterpolation = M3GKeyframeSequence.SLERP - #lInterpolation = M3GKeyframeSequence.SQUAD - elif aCurveType == 'Size': - lTrackType = M3GAnimationTrack.SCALE - lNumComponents=3 - lCurveFactor=1 - else: - lTrackType = M3GAnimationTrack.TRANSLATION - lNumComponents=3 - lCurveFactor=1 - - mSequence = M3GKeyframeSequence(len(lCurveX.getPoints()), - lNumComponents, - lCurveX.getInterpolation(), - lInterpolation) - - #print 'ComponentCount',mSequence.componentCount - - mSequence.duration = lEndFrame * lTimePerFrame - mSequence.setRepeatMode(lCurveX.getExtrapolation()) - - lIndex = 0 - for iPoint in lCurveX.getPoints(): - lPoint = iPoint.getPoints() - - lPointList = [(lPoint[1]*lCurveFactor), - (lCurveY.evaluate(lPoint[0])*lCurveFactor), - (lCurveZ.evaluate(lPoint[0])*lCurveFactor)] - - #print "aCurveType ", aCurveType - - if aCurveType == 'Loc': - #print "PointList ", lPointList - #lorgTransVector = aM3GObject.blenderTransformMatrix.translationPart() - #ltrans = TranslationMatrix(Vector(lPointList)) - #ltrans2 = self.calculateChildMatrix(ltrans,aM3GObject.blenderTransformMatrix) - #lVector = ltrans2.translationPart() + lorgTransVector - #lPointList = [lVector.x, lVector.y,lVector.z] - #print "PointList ", lPointList - pass - - if aCurveType == 'Quat': - lPointList.append(lCurveW.evaluate(lPoint[0])*lCurveFactor) - #lQuat = Quaternion([lPointList[3],lPointList[0],lPointList[1],lPointList[2]]) - #print "Quat ", lQuat - #print "Quat.angel ", lQuat.angle - #print "Quat.axis ", lQuat.axis - #print "PointList ", lPointList - - #print "PointList",lPointList - - if aCurveType =='Rot': - lQuat = Euler(lPointList).toQuat() - #lPointList = [lQuat.w,lQuat.x,lQuat.y,lQuat.z] - lPointList = [lQuat.x,lQuat.y,lQuat.z,lQuat.w] - #print " Quat=", lPointList - - mSequence.setKeyframe(lIndex, - lPoint[0]*lTimePerFrame, - lPointList) - lIndex += 1 - mSequence.validRangeFirst = 0 - mSequence.validRangeLast = lIndex - 1 - - mTrack = M3GAnimationTrack(mSequence,lTrackType) - aM3GObject.animationTracks.append(mTrack) - if aM3GAnimContr==None: aM3GAnimContr = M3GAnimationController() - mTrack.animationController = aM3GAnimContr - - - def translateLamp(self,obj): - print "translate lamp ..." - lamp = obj.getData() - - #Type - lampType=lamp.getType() - if not lampType in [Lamp.Types.Lamp,Lamp.Types.Spot,Lamp.Types.Sun]: - print "INFO: Type of light is not supported. See documentation" - return #create not light; type not supported - mLight = M3GLight() - if lampType == Lamp.Types.Lamp: - mLight.mode = mLight.modes['OMNI'] - elif lampType == Lamp.Types.Spot: - mLight.mode = mLight.modes['SPOT'] - elif lampType == Lamp.Types.Sun: - mLight.mode = mLight.modes['DIRECTIONAL'] - #Attenuation (OMNI,SPOT): - if lampType in [Lamp.Types.Lamp,Lamp.Types.Spot]: - mLight.attenuationConstant = 0.0 - mLight.attenuationLinear = 2.0/lamp.dist - mLight.attenuationQuadratic = 0.0 - #Color - mLight.color = self.translateRGB(lamp.col) - #Energy - mLight.intensity = lamp.energy - #SpotAngle, SpotExponent (SPOT) - if lampType == Lamp.Types.Spot: - mLight.spotAngle = lamp.spotSize/2 - mLight.spotExponent = lamp.spotBlend - self.translateToNode(obj,mLight) - - - def translateCore(self,obj,node): - #Name - node.name = obj.name - node.userID = self.translateUserID(obj.name) - #Location - #node.translation=self.translateLoc(obj.LocX,obj.LocY,obj.LocZ - #node.hasComponentTransform=True - #Transform - #node.transform = self.translateMatrix(obj.getMatrix('localspace')) - if type(obj) is Types.BoneType: - #print "BoneMatrix ",obj.matrix['BONESPACE'] - node.transform = self.translateMatrix(obj.matrix['ARMATURESPACE']) - #'ARMATURESPACE' - this matrix of the bone in relation to the armature - #'BONESPACE' - the matrix of the bone in relation to itself - else: - node.transform = self.translateMatrix(obj.matrixWorld) - node.hasGeneralTransform=True - - - def translateToNode(self,obj,node): - self.translateCore(obj,node) - #Nodes - self.nodes.append(node) - #Link to Blender Object - node.blenderObj = obj - node.blenderMatrixWorld = obj.matrixWorld - lparent = None - if obj.getParent()!=None: - if obj.getParent().getType()!='Armature': - lparent = obj.getParent() - else: - if obj.getParent().getParent()!=None and obj.getParent().getParent().getType()!='Armature': - lparent = obj.getParent().getParent() - node.parentBlenderObj = lparent - - - def translateUserID(self, name): - id = 0 - start = name.find('#') - - # Use digits that follow the # sign for id. - if start != -1: - start += 1 - end = start - for char in name[start:]: - if char.isdigit(): - end += 1 - else: - break - - if end > start: - id = int(name[start:end]) - - return id - - def translateLoc(self,aLocX,aLocY,aLocZ): - return M3GVector3D(aLocX,aLocY,aLocZ) - - def translateRGB(self,color): - return M3GColorRGB(int(color[0]*255), - int(color[1]*255), - int(color[2]*255)) - - def translateRGBA(self,color,alpha): - return M3GColorRGBA(int(color[0]*255), - int(color[1]*255), - int(color[2]*255), - int(alpha*255)) - - def translateMatrix(self,aPyMatrix): - """ -  0   1   2   3  - 4   5   6   7  - 8   9  10  11 - 12  13  14  15 """ - #print "Matrix:", aPyMatrix - lMatrix = M3GMatrix() - lMatrix.elements[0] = aPyMatrix[0][0] - lMatrix.elements[1] = aPyMatrix[1][0] - lMatrix.elements[2] = aPyMatrix[2][0] - lMatrix.elements[3] = aPyMatrix[3][0] - lMatrix.elements[4] = aPyMatrix[0][1] - lMatrix.elements[5] = aPyMatrix[1][1] - lMatrix.elements[6] = aPyMatrix[2][1] - lMatrix.elements[7] = aPyMatrix[3][1] - lMatrix.elements[8] = aPyMatrix[0][2] - lMatrix.elements[9] = aPyMatrix[1][2] - lMatrix.elements[10] = aPyMatrix[2][2] - lMatrix.elements[11] = aPyMatrix[3][2] - lMatrix.elements[12] = aPyMatrix[0][3] - lMatrix.elements[13] = aPyMatrix[1][3] - lMatrix.elements[14] = aPyMatrix[2][3] - lMatrix.elements[15] = aPyMatrix[3][3] - return lMatrix - - -# ---- Exporter ---------------------------------------------------------------- # - -class M3GExporter: - "Exports Blender-Scene to M3D" - def __init__(self, aWriter): - self.writer = aWriter - - - def start(self): - print "Info: starting export ..." - #rpdb2.start_embedded_debugger("t",True) - Translator = M3GTranslator() - world = Translator.start() - - #sys.settrace(tracer) - exportList = self.createDeepSearchList(world) - externalReferences = [element for element in exportList if element.__class__ is M3GExternalReference] - exportList = [element for element in exportList if element.__class__ is not M3GExternalReference] - #sys.settrace(None) - - # 1 is reservated for HeaderObject. - i=1 - - # Next are the external references. - for element in externalReferences: - i += 1 - element.id = i - print "object ",element.id, element - - # And the standard scene objects. - for element in exportList: - i += 1 - element.id = i - print "object ",element.id, element - - self.writer.writeFile(world, exportList, externalReferences) - - print("Ready!") - - - def createDeepSearchList(self,aWorld): - "creates the right order for saving m3g : leafs first" - return aWorld.searchDeep([]) - - - -# ---- Writer ---------------------------------------------------------------- # -class JavaWriter: - "writes a java class which creates m3g-Scene in a j2me programm" - def __init__(self,aFilename): - self.filename = aFilename - self.classname = Blender.sys.basename(aFilename) - self.classname = self.classname[:-5] #without extention ".java" - self.outFile = file(aFilename,"w") - - def write(self, tab, zeile=""): - "writes to file" - #print "\t" * tab + zeile - print >>self.outFile, "\t" * tab + zeile - - def writeFile(self,aWorld,aExportList,externalReferences): - self.world = aWorld - self.writeHeader() - for element in aExportList: - element.writeJava(self,True) - self.writeFooter() - self.outFile.close() - - def writeHeader(self): - "writes class header" - self.write(0,"import javax.microedition.lcdui.Image;") - self.write(0,"import javax.microedition.m3g.*;") - self.write(0,"public final class "+self.classname+" {") - self.write(1,"public static World getRoot(Canvas3D aCanvas) {") - - def writeFooter(self): - self.write(1) - self.write(1,"return BL"+str(self.world.id)+";") - self.write(0,"}}") - - def writeList(self,alist,numberOfElementsPerLine=12,aType=""): - '''Writes numberOfElementsPerLine''' - line="" - lastLine="" - counter=0 - for element in alist: - if counter!=0: - line = line + "," + str(element) + aType - else: - line = str(element) + aType - counter = counter + 1 - if counter == numberOfElementsPerLine: - if len(lastLine)>0: - self.write(3,lastLine+",") - lastLine=line - line="" - counter = 0 - if len(lastLine)>0: - if len(line)>0: - self.write(3,lastLine+",") - else: - self.write(3,lastLine) - if len(line) > 0: self.write(3,line) - - def writeClass(self,aName,aM3GObject): - self.write(2) - self.write(2,"//"+aName+":"+aM3GObject.name) - - -class M3GSectionObject: - def __init__(self,aObject): - """Object Structure - Each object in the file represents one object in the - scene graph tree, and is stored in a chunk. The - structure of an object chunk is as follows: - Byte ObjectType - UInt32 Length - Byte[] Data""" - #ObjectType - #This field describes what type of object has been serialized. - #The values 0 and 0xFF are special: 0 represents the header object, - #and 0xFF represents an external reference. - #Example: Byte ObjectType = 14 - self.ObjectType = aObject.ObjectType - self.data = aObject.getData() - self.length = aObject.getDataLength() - - def getData(self): - data = struct.pack(' 2,1,0 - for v in f.v[2::-1]: - file.write(format_vec % tuple(v.co) ) - - try: mode= f.mode - except: mode= 0 - - if mode & Mesh.FaceModes.INVISIBLE: - file.write(PREF_INVIS_TEX.val) - else: - try: image= f.image - except: image= None - - if image: file.write(sys.splitext(sys.basename(image.filename))[0]) - else: file.write(PREF_NULL_TEX.val) - - # Texture stuff ignored for now - file.write(PREF_DEF_TEX_OPTS.val) - file.write('}\n') - - -def round_vec(v): - if PREF_GRID_SNAP.val: - return round(v.x), round(v.y), round(v.z) - else: - return tuple(v) - -def write_face2brush(file, face): - ''' - takes a face and writes it as a brush - each face is a cube/brush - ''' - - if PREF_GRID_SNAP.val: format_vec= '( %d %d %d ) ' - else: format_vec= '( %.8f %.8f %.8f ) ' - - - image_text= PREF_NULL_TEX.val - - try: mode= face.mode - except: mode= 0 - - if mode & Mesh.FaceModes.INVISIBLE: - image_text= PREF_INVIS_TEX.val - else: - try: image= face.image - except: image= None - if image: image_text = sys.splitext(sys.basename(image.filename))[0] - - # original verts as tuples for writing - orig_vco= [tuple(v.co) for v in face] - - # new verts that give the face a thickness - dist= PREF_SCALE.val * PREF_FACE_THICK.val - new_vco= [round_vec(v.co - (v.no * dist)) for v in face] - #new_vco= [round_vec(v.co - (face.no * dist)) for v in face] - - file.write('// brush from face\n{\n') - # front - for co in orig_vco[2::-1]: - file.write(format_vec % co ) - file.write(image_text) - # Texture stuff ignored for now - file.write(PREF_DEF_TEX_OPTS.val) - - - for co in new_vco[:3]: - file.write(format_vec % co ) - if mode & Mesh.FaceModes.TWOSIDE: - file.write(image_text) - else: - file.write(PREF_INVIS_TEX.val) - - # Texture stuff ignored for now - file.write(PREF_DEF_TEX_OPTS.val) - - # sides. - if len(orig_vco)==3: # Tri, it seemms tri brushes are supported. - index_pairs= ((0,1), (1,2), (2,0)) - else: - index_pairs= ((0,1), (1,2), (2,3), (3,0)) - - for i1, i2 in index_pairs: - for co in orig_vco[i1], orig_vco[i2], new_vco[i2]: - file.write( format_vec % co ) - file.write(PREF_INVIS_TEX.val) - file.write(PREF_DEF_TEX_OPTS.val) - - file.write('}\n') - -def is_cube_facegroup(faces): - ''' - Returens a bool, true if the faces make up a cube - ''' - # cube must have 6 faces - if len(faces) != 6: - print '1' - return False - - # Check for quads and that there are 6 unique verts - verts= {} - for f in faces: - if len(f)!= 4: - return False - - for v in f: - verts[v.index]= 0 - - if len(verts) != 8: - return False - - # Now check that each vert has 3 face users - for f in faces: - for v in f: - verts[v.index] += 1 - - for v in verts.itervalues(): - if v != 3: # vert has 3 users? - return False - - # Could we check for 12 unique edges??, probably not needed. - return True - -def is_tricyl_facegroup(faces): - ''' - is the face group a tri cylinder - Returens a bool, true if the faces make an extruded tri solid - ''' - - # cube must have 5 faces - if len(faces) != 5: - print '1' - return False - - # Check for quads and that there are 6 unique verts - verts= {} - tottri= 0 - for f in faces: - if len(f)== 3: - tottri+=1 - - for v in f: - verts[v.index]= 0 - - if len(verts) != 6 or tottri != 2: - return False - - # Now check that each vert has 3 face users - for f in faces: - for v in f: - verts[v.index] += 1 - - for v in verts.itervalues(): - if v != 3: # vert has 3 users? - return False - - # Could we check for 12 unique edges??, probably not needed. - return True - -def write_node_map(file, ob): - ''' - Writes the properties of an object (empty in this case) - as a MAP node as long as it has the property name - classname - returns True/False based on weather a node was written - ''' - props= [(p.name, p.data) for p in ob.game_properties] - - IS_MAP_NODE= False - for name, value in props: - if name=='classname': - IS_MAP_NODE= True - break - - if not IS_MAP_NODE: - return False - - # Write a node - file.write('{\n') - for name_value in props: - file.write('"%s" "%s"\n' % name_value) - if PREF_GRID_SNAP.val: - file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) ) - else: - file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) ) - file.write('}\n') - return True - - -def export_map(filepath): - - pup_block = [\ - ('Scale:', PREF_SCALE, 1, 1000, 'Scale the blender scene by this value.'),\ - ('Face Width:', PREF_FACE_THICK, 0.01, 10, 'Thickness of faces exported as brushes.'),\ - ('Grid Snap', PREF_GRID_SNAP, 'snaps floating point values to whole numbers.'),\ - 'Null Texture',\ - ('', PREF_NULL_TEX, 1, 128, 'Export textureless faces with this texture'),\ - 'Unseen Texture',\ - ('', PREF_INVIS_TEX, 1, 128, 'Export invisible faces with this texture'),\ - ] - - if not Draw.PupBlock('map export', pup_block): - return - - Window.WaitCursor(1) - time= sys.time() - print 'Map Exporter 0.0' - file= open(filepath, 'w') - - - obs_mesh= [] - obs_lamp= [] - obs_surf= [] - obs_empty= [] - - SCALE_MAT= Mathutils.Matrix() - SCALE_MAT[0][0]= SCALE_MAT[1][1]= SCALE_MAT[2][2]= PREF_SCALE.val - - dummy_mesh= Mesh.New() - - TOTBRUSH= TOTLAMP= TOTNODE= 0 - - for ob in Object.GetSelected(): - type= ob.type - if type == 'Mesh': obs_mesh.append(ob) - elif type == 'Surf': obs_surf.append(ob) - elif type == 'Lamp': obs_lamp.append(ob) - elif type == 'Empty': obs_empty.append(ob) - - if obs_mesh or obs_surf: - # brushes and surf's must be under worldspan - file.write('\n// entity 0\n') - file.write('{\n') - file.write('"classname" "worldspawn"\n') - - - print '\twriting cubes from meshes' - for ob in obs_mesh: - dummy_mesh.getFromObject(ob.name) - - #print len(mesh_split2connected(dummy_mesh)) - - # Is the object 1 cube? - object-is-a-brush - dummy_mesh.transform(ob.matrixWorld*SCALE_MAT) # 1 to tx the normals also - - if PREF_GRID_SNAP.val: - for v in dummy_mesh.verts: - co= v.co - co.x= round(co.x) - co.y= round(co.y) - co.z= round(co.z) - - # High quality normals - BPyMesh.meshCalcNormals(dummy_mesh) - - # Split mesh into connected regions - for face_group in BPyMesh.mesh2linkedFaces(dummy_mesh): - if is_cube_facegroup(face_group): - write_cube2brush(file, face_group) - TOTBRUSH+=1 - elif is_tricyl_facegroup(face_group): - write_cube2brush(file, face_group) - TOTBRUSH+=1 - else: - for f in face_group: - write_face2brush(file, f) - TOTBRUSH+=1 - - #print 'warning, not exporting "%s" it is not a cube' % ob.name - - - dummy_mesh.verts= None - - - valid_dims= 3,5,7,9,11,13,15 - for ob in obs_surf: - ''' - Surf, patches - ''' - surf_name= ob.getData(name_only=1) - data= Curve.Get(surf_name) - mat = ob.matrixWorld*SCALE_MAT - - # This is what a valid patch looks like - - """ -// brush 0 -{ -patchDef2 -{ -NULL -( 3 3 0 0 0 ) -( -( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) ) -( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) ) -( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) ) -) -} -} - """ - for i, nurb in enumerate(data): - u= nurb.pointsU - v= nurb.pointsV - if u in valid_dims and v in valid_dims: - - file.write('// brush %d surf_name\n' % i) - file.write('{\n') - file.write('patchDef2\n') - file.write('{\n') - file.write('NULL\n') - file.write('( %d %d 0 0 0 )\n' % (u, v) ) - file.write('(\n') - - u_iter = 0 - for p in nurb: - - if u_iter == 0: - file.write('(') - - u_iter += 1 - - # add nmapping 0 0 ? - if PREF_GRID_SNAP.val: - file.write(' ( %d %d %d 0 0 )' % round_vec(Mathutils.Vector(p[0:3]) * mat)) - else: - file.write(' ( %.6f %.6f %.6f 0 0 )' % tuple(Mathutils.Vector(p[0:3]) * mat)) - - # Move to next line - if u_iter == u: - file.write(' )\n') - u_iter = 0 - - file.write(')\n') - file.write('}\n') - file.write('}\n') - - - # Debugging - # for p in nurb: print 'patch', p - - else: - print "NOT EXPORTING PATCH", surf_name, u,v, 'Unsupported' - - - if obs_mesh or obs_surf: - file.write('}\n') # end worldspan - - - print '\twriting lamps' - for ob in obs_lamp: - print '\t\t%s' % ob.name - lamp= ob.data - file.write('{\n') - file.write('"classname" "light"\n') - file.write('"light" "%.6f"\n' % (lamp.dist* PREF_SCALE.val)) - if PREF_GRID_SNAP.val: - file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) ) - else: - file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) ) - file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col)) - file.write('"style" "0"\n') - file.write('}\n') - TOTLAMP+=1 - - - print '\twriting empty objects as nodes' - for ob in obs_empty: - if write_node_map(file, ob): - print '\t\t%s' % ob.name - TOTNODE+=1 - else: - print '\t\tignoring %s' % ob.name - - Window.WaitCursor(0) - - print 'Exported Map in %.4fsec' % (sys.time()-time) - print 'Brushes: %d Nodes: %d Lamps %d\n' % (TOTBRUSH, TOTNODE, TOTLAMP) - - -def main(): - Window.FileSelector(export_map, 'EXPORT MAP', '*.map') - -if __name__ == '__main__': main() -# export_map('/foo.map') diff --git a/release/scripts/export_mdd.py b/release/scripts/export_mdd.py deleted file mode 100644 index 4f99c9175fd..00000000000 --- a/release/scripts/export_mdd.py +++ /dev/null @@ -1,168 +0,0 @@ -#!BPY - -""" - Name: 'Vertex Keyframe Animation (.mdd)...' - Blender: 242 - Group: 'Export' - Tooltip: 'Animated mesh to MDD vertex keyframe file.' -""" - -__author__ = "Bill L.Nieuwendorp" -__bpydoc__ = """\ -This script Exports Lightwaves MotionDesigner format. - -The .mdd format has become quite a popular Pipeline format
-for moving animations from package to package. - -Be sure not to use modifiers that change the number or order of verts in the mesh -""" -#Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com -#Bill Niewuendorp -# ***** 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 Blender -from Blender import * -import BPyMessages -try: - from struct import pack -except: - pack = None - - -def zero_file(filepath): - ''' - If a file fails, this replaces it with 1 char, better not remove it? - ''' - file = open(filepath, 'w') - file.write('\n') # aparently macosx needs some data in a blank file? - file.close() - - -def check_vertcount(mesh,vertcount): - ''' - check and make sure the vertcount is consistent throghout the frame range - ''' - if len(mesh.verts) != vertcount: - Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export') - f.close() - zero_file(filepath) - return - - -def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): - - Window.EditMode(0) - Blender.Window.WaitCursor(1) - mesh_orig = Mesh.New() - mesh_orig.getFromObject(ob.name) - - #Flip y and z - ''' - mat = Mathutils.Matrix() - mat[2][2] = -1 - rotmat = Mathutils.RotationMatrix(90, 4, 'x') - mat_flip = mat*rotmat - ''' - # Above results in this matrix - mat_flip= Mathutils.Matrix(\ - [1.0, 0.0, 0.0, 0.0],\ - [0.0, 0.0, 1.0, 0.0],\ - [0.0, 1.0, 0.0, 0.0],\ - [0.0, 0.0, 0.0, 1.0],\ - ) - - me_tmp = Mesh.New() # container mesh - - numverts = len(mesh_orig.verts) - numframes = PREF_ENDFRAME-PREF_STARTFRAME+1 - PREF_FPS= float(PREF_FPS) - f = open(filepath, 'wb') #no Errors yet:Safe to create file - - # Write the header - f.write(pack(">2i", numframes, numverts)) - - # Write the frame times (should we use the time IPO??) - f.write( pack(">%df" % (numframes), *[frame/PREF_FPS for frame in xrange(numframes)]) ) # seconds - - #rest frame needed to keep frames in sync - Blender.Set('curframe', PREF_STARTFRAME) - me_tmp.getFromObject(ob.name) - check_vertcount(me_tmp,numverts) - me_tmp.transform(ob.matrixWorld * mat_flip) - f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co])) - me_tmp.verts= None - - for frame in xrange(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame - Blender.Set('curframe', frame) - - me_tmp.getFromObject(ob.name) - - check_vertcount(me_tmp,numverts) - - me_tmp.transform(ob.matrixWorld * mat_flip) - - # Write the vertex data - f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co])) - - me_tmp.verts= None - f.close() - - print'MDD Exported: %s frames:%d\n'% (filepath, numframes-1) - Blender.Window.WaitCursor(0) - - -def mdd_export_ui(filepath): - # Dont overwrite - if not BPyMessages.Warning_SaveOver(filepath): - return - - scn= bpy.data.scenes.active - ob_act= scn.objects.active - if not ob_act or ob_act.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - - ctx = scn.getRenderingContext() - orig_frame = Blender.Get('curframe') - PREF_STARTFRAME= Blender.Draw.Create(int(ctx.startFrame())) - PREF_ENDFRAME= Blender.Draw.Create(int(ctx.endFrame())) - PREF_FPS= Blender.Draw.Create(ctx.fps) - - block = [\ - ("Start Frame: ", PREF_STARTFRAME, 1, 30000, "Start Bake from what frame?: Default 1"),\ - ("End Frame: ", PREF_ENDFRAME, 1, 30000, "End Bake on what Frame?"),\ - ("FPS: ", PREF_FPS, 1, 100, "Frames per second")\ - ] - - if not Blender.Draw.PupBlock("Export MDD", block): - return - - PREF_STARTFRAME, PREF_ENDFRAME=\ - min(PREF_STARTFRAME.val, PREF_ENDFRAME.val),\ - max(PREF_STARTFRAME.val, PREF_ENDFRAME.val) - - print (filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) - mdd_export(filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) - Blender.Set('curframe', orig_frame) - -if __name__=='__main__': - if not pack: - Draw.PupMenu('Error%t|This script requires a full python install') - - Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd')) \ No newline at end of file diff --git a/release/scripts/export_obj.py b/release/scripts/export_obj.py deleted file mode 100644 index 7dffb5d2048..00000000000 --- a/release/scripts/export_obj.py +++ /dev/null @@ -1,933 +0,0 @@ -#!BPY - -""" -Name: 'Wavefront (.obj)...' -Blender: 249 -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.22" - -__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. -""" - - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton 2007-2009 -# - V1.22- bspline import/export added (funded by PolyDimensions GmbH) -# -# 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 Blender -from Blender import Mesh, Scene, Window, sys, Image, Draw -import BPyMesh -import BPyObject -import BPySys -import BPyMessages - -# Returns a tuple - path,extension. -# 'hello.obj' > ('hello', '.obj') -def splitExt(path): - dotidx = path.rfind('.') - if dotidx == -1: - return path, '' - else: - return path[:dotidx], path[dotidx:] - -def fixName(name): - if name == None: - return 'None' - else: - return name.replace(' ', '_') - -# A Dict of Materials -# (material.name, image.name):matname_imagename # matname_imagename has gaps removed. -MTL_DICT = {} - -def write_mtl(filename): - - world = Blender.World.GetCurrent() - if world: - worldAmb = world.getAmb() - else: - worldAmb = (0,0,0) # Default value - - file = open(filename, "w") - file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) - file.write('# Material Count: %i\n' % len(MTL_DICT)) - # Write material/image combinations we have used. - for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): - - # Get the Blender data for the material and the image. - # Having an image named None will make a bug, dont do it :) - - file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname - - if mat: - file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's - file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, - file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse - file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular - file.write('Ni %.6f\n' % mat.IOR) # Refraction index - file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve) - - # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting. - if mat.getMode() & Blender.Material.Modes['SHADELESS']: - file.write('illum 0\n') # ignore lighting - elif mat.getSpec() == 0: - file.write('illum 1\n') # no specular. - else: - file.write('illum 2\n') # light normaly - - else: - #write a dummy material here? - file.write('Ns 0\n') - file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, - file.write('Kd 0.8 0.8 0.8\n') - file.write('Ks 0.8 0.8 0.8\n') - file.write('d 1\n') # No alpha - file.write('illum 2\n') # light normaly - - # Write images! - if img: # We have an image on the face! - file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image - - elif mat: # No face image. if we havea material search for MTex image. - for mtex in mat.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - try: - filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1] - file.write('map_Kd %s\n' % filename) # Diffuse mapping image - break - except: - # Texture has no image though its an image type, best ignore. - pass - - file.write('\n\n') - - file.close() - -def copy_file(source, dest): - file = open(source, 'rb') - data = file.read() - file.close() - - file = open(dest, 'wb') - file.write(data) - file.close() - - -def copy_images(dest_dir): - if dest_dir[-1] != sys.sep: - dest_dir += sys.sep - - # Get unique image names - uniqueImages = {} - for matname, mat, image in MTL_DICT.itervalues(): # Only use image name - # Get Texface images - if image: - uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. - - # Get MTex images - if mat: - for mtex in mat.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - image_tex = mtex.tex.image - if image_tex: - try: - uniqueImages[image_tex] = image_tex - except: - pass - - # Now copy images - copyCount = 0 - - for bImage in uniqueImages.itervalues(): - image_path = sys.expandpath(bImage.filename) - if sys.exists(image_path): - # Make a name for the target path. - dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] - if not sys.exists(dest_image_path): # Image isnt alredy there - print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) - copy_file(image_path, dest_image_path) - copyCount+=1 - print '\tCopied %d images' % copyCount - - -def test_nurbs_compat(ob): - if ob.type != 'Curve': - return False - - for nu in ob.data: - if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier - return True - - return False - -def write_nurb(file, ob, ob_mat): - tot_verts = 0 - cu = ob.data - - # use negative indices - Vector = Blender.Mathutils.Vector - for nu in cu: - - if nu.type==0: DEG_ORDER_U = 1 - else: DEG_ORDER_U = nu.orderU-1 # Tested to be correct - - if nu.type==1: - print "\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported" - continue - - if nu.knotsV: - print "\tWarning, surface:", ob.name, "only poly and nurbs curves supported" - continue - - if len(nu) <= DEG_ORDER_U: - print "\tWarning, orderU is lower then vert count, skipping:", ob.name - continue - - pt_num = 0 - do_closed = (nu.flagU & 1) - do_endpoints = (do_closed==0) and (nu.flagU & 2) - - for pt in nu: - pt = Vector(pt[0], pt[1], pt[2]) * ob_mat - file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2])) - pt_num += 1 - tot_verts += pt_num - - file.write('g %s\n' % (fixName(ob.name))) # fixName(ob.getData(1)) could use the data name too - file.write('cstype bspline\n') # not ideal, hard coded - file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still - - curve_ls = [-(i+1) for i in xrange(pt_num)] - - # 'curv' keyword - if do_closed: - if DEG_ORDER_U == 1: - pt_num += 1 - curve_ls.append(-1) - else: - pt_num += DEG_ORDER_U - curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U] - - file.write('curv 0.0 1.0 %s\n' % (' '.join( [str(i) for i in curve_ls] ))) # Blender has no U and V values for the curve - - # 'parm' keyword - tot_parm = (DEG_ORDER_U + 1) + pt_num - tot_parm_div = float(tot_parm-1) - parm_ls = [(i/tot_parm_div) for i in xrange(tot_parm)] - - if do_endpoints: # end points, force param - for i in xrange(DEG_ORDER_U+1): - parm_ls[i] = 0.0 - parm_ls[-(1+i)] = 1.0 - - file.write('parm u %s\n' % ' '.join( [str(i) for i in parm_ls] )) - - file.write('end\n') - - return tot_verts - -def write(filename, objects,\ -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 in face: - vWeights = vWeightMap[vert.index] - for vGroupName, weight in vWeights: - weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight - - if weightDict: - alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight - alist.sort() - return(alist[-1][1]) # highest value last - else: - return '(null)' - - - print 'OBJ Export path: "%s"' % filename - temp_mesh_name = '~tmp-mesh' - - time1 = sys.time() - scn = Scene.GetCurrent() - - file = open(filename, "w") - - # Write Header - file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) - file.write('# www.blender3d.org\n') - - # Tell the obj file what material file to use. - if EXPORT_MTL: - mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) - file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) - - # Get the container mesh. - used for applying modifiers and non mesh objects. - containerMesh = meshName = tempMesh = None - for meshName in Blender.NMesh.GetNames(): - if meshName.startswith(temp_mesh_name): - tempMesh = Mesh.Get(meshName) - if not tempMesh.users: - containerMesh = tempMesh - if not containerMesh: - containerMesh = Mesh.New(temp_mesh_name) - - if EXPORT_ROTX90: - mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') - - del meshName - del tempMesh - - # Initialize totals, these are updated each object - totverts = totuvco = totno = 1 - - face_vert_index = 1 - - globalNormals = {} - - # Get all meshes - for ob_main in objects: - for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): - - # 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 - - # Will work for non meshes now! :) - # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) - me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) - if not me: - continue - - if EXPORT_UV: - faceuv= me.faceUV - else: - faceuv = False - - # We have a valid mesh - if EXPORT_TRI and me.faces: - # Add a dummy object to it. - has_quads = False - for f in me.faces: - if len(f) == 4: - has_quads = True - break - - if has_quads: - oldmode = Mesh.Mode() - Mesh.Mode(Mesh.SelectModes['FACE']) - - me.sel = True - tempob = scn.objects.new(me) - me.quadToTriangle(0) # more=0 shortest length - oldmode = Mesh.Mode(oldmode) - scn.objects.unlink(tempob) - - Mesh.Mode(oldmode) - - # Make our own list so it can be sorted to reduce context switching - faces = [ f for f in me.faces ] - - if EXPORT_EDGES: - edges = me.edges - else: - edges = [] - - if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write - continue # dont bother with this mesh. - - if EXPORT_ROTX90: - me.transform(ob_mat*mat_xrot90) - else: - me.transform(ob_mat) - - # High Quality Normals - if EXPORT_NORMALS and faces: - if EXPORT_NORMALS_HQ: - BPyMesh.meshCalcNormals(me) - else: - # transforming normals is incorrect - # when the matrix is scaled, - # better to recalculate them - me.calcNormals() - - # # Crash Blender - #materials = me.getMaterials(1) # 1 == will return None in the list. - materials = me.materials - - materialNames = [] - materialItems = materials[:] - if materials: - for mat in materials: - if mat: # !=None - materialNames.append(mat.name) - else: - materialNames.append(None) - # Cant use LC because some materials are None. - # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. - - # Possible there null materials, will mess up indicies - # but at least it will export, wait until Blender gets fixed. - materialNames.extend((16-len(materialNames)) * [None]) - materialItems.extend((16-len(materialItems)) * [None]) - - # Sort by Material, then images - # so we dont over context switch in the obj file. - if EXPORT_KEEP_VERT_ORDER: - pass - elif faceuv: - 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)) - - # 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.getData(1) - if name1 == name2: - obnamestring = fixName(name1) - else: - obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) - - if EXPORT_BLEN_OBS: - file.write('o %s\n' % obnamestring) # Write Object name - else: # if EXPORT_GROUP_BY_OB: - file.write('g %s\n' % obnamestring) - - - # Vert - for v in me.verts: - file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) - - # UV - if faceuv: - uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ - - uv_dict = {} # could use a set() here - 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.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - else: - # Hard, 1 normal from the face. - noKey = veckey3d(f.no) - if not globalNormals.has_key( noKey ): - globalNormals[noKey] = totno - totno +=1 - file.write('vn %.6f %.6f %.6f\n' % noKey) - - if not faceuv: - f_image = None - - 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 xrange(len(me.verts))] - for vertexGroupName in vertGroupNames: - for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): - vgroupsMap[vIdx].append((vertexGroupName, vWeight)) - - for f_index, f in enumerate(faces): - f_v= f.v - f_smooth= f.smooth - f_mat = min(f.mat, len(materialNames)-1) - if faceuv: - 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 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: - file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) - file.write('usemtl (null)\n') # mat, image - - else: - mat_data= MTL_DICT.get(key) - if not mat_data: - # First add to global dict so we can export to mtl - # Then write mtl - - # Make a new names from the mat and image name, - # converting any spaces to underscores with fixName. - - # If none image dont bother adding it to the name - if key[1] == None: - mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image - else: - mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image - - if EXPORT_GROUP_BY_MAT: - file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) - - file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) - - contextMat = key - if f_smooth != contextSmooth: - if f_smooth: # on now off - file.write('s 1\n') - contextSmooth = f_smooth - else: # was off now on - file.write('s off\n') - contextSmooth = f_smooth - - file.write('f') - if faceuv: - if EXPORT_NORMALS: - if f_smooth: # Smoothed, use vertex normals - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % (\ - v.index+totverts,\ - totuvco + uv_face_mapping[f_index][vi],\ - globalNormals[ veckey3d(v.no) ])) # vert, uv, normal - - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] - for vi, v in enumerate(f_v): - file.write( ' %d/%d/%d' % (\ - v.index+totverts,\ - totuvco + uv_face_mapping[f_index][vi],\ - no)) # vert, uv, normal - - 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.no) ])) - else: # No smoothing, face normals - no = globalNormals[ veckey3d(f.no) ] - 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: - LOOSE= Mesh.EdgeFlags.LOOSE - for ed in edges: - if ed.flag & LOOSE: - file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) - - # Make the indicies global rather then per mesh - totverts += len(me.verts) - if faceuv: - totuvco += uv_unique_count - me.verts= None - file.close() - - - # Now we have all our materials, save them - if EXPORT_MTL: - write_mtl(mtlfilename) - if EXPORT_COPY_IMAGES: - dest_dir = filename - # Remove chars until we are just the path. - while dest_dir and dest_dir[-1] not in '\\/': - dest_dir = dest_dir[:-1] - if dest_dir: - copy_images(dest_dir) - else: - print '\tError: "%s" could not be used as a base for an image path.' % filename - - print "OBJ Export time: %.2f" % (sys.time() - time1) - - - -def write_ui(filename): - - if not filename.lower().endswith('.obj'): - filename += '.obj' - - if not BPyMessages.Warning_SaveOver(filename): - return - - global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ - EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ - EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ - EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS - - EXPORT_APPLY_MODIFIERS = Draw.Create(0) - EXPORT_ROTX90 = Draw.Create(1) - EXPORT_TRI = Draw.Create(0) - EXPORT_EDGES = Draw.Create(1) - EXPORT_NORMALS = Draw.Create(0) - EXPORT_NORMALS_HQ = Draw.Create(0) - EXPORT_UV = Draw.Create(1) - EXPORT_MTL = Draw.Create(1) - EXPORT_SEL_ONLY = Draw.Create(1) - EXPORT_ALL_SCENES = Draw.Create(0) - EXPORT_ANIMATION = Draw.Create(0) - EXPORT_COPY_IMAGES = Draw.Create(0) - EXPORT_BLEN_OBS = Draw.Create(0) - EXPORT_GROUP_BY_OB = Draw.Create(0) - EXPORT_GROUP_BY_MAT = Draw.Create(0) - EXPORT_KEEP_VERT_ORDER = Draw.Create(1) - EXPORT_POLYGROUPS = Draw.Create(0) - EXPORT_CURVE_AS_NURBS = Draw.Create(1) - - - # Old UI - ''' - # removed too many options are bad! - - # Get USER Options - pup_block = [\ - ('Context...'),\ - ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\ - ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\ - ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\ - ('Object Prefs...'),\ - ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\ - ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\ - ('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ - ('Extra Data...'),\ - ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\ - ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\ - ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\ - ('UVs', EXPORT_UV, 'Export texface UV coords.'),\ - ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\ - ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\ - ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ - ('Grouping...'),\ - ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\ - ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\ - ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\ - ] - - if not Draw.PupBlock('Export...', pup_block): - return - ''' - - # BEGIN ALTERNATIVE UI ******************* - if True: - - EVENT_NONE = 0 - EVENT_EXIT = 1 - EVENT_REDRAW = 2 - EVENT_EXPORT = 3 - - GLOBALS = {} - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - - def obj_ui_set_event(e,v): - GLOBALS['EVENT'] = e - - def do_split(e,v): - global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER, EXPORT_POLYGROUPS - if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val: - EXPORT_KEEP_VERT_ORDER.val = 0 - else: - EXPORT_KEEP_VERT_ORDER.val = 1 - - def do_vertorder(e,v): - global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER - if EXPORT_KEEP_VERT_ORDER.val: - EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0 - else: - if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val): - EXPORT_KEEP_VERT_ORDER.val = 1 - - - def do_help(e,v): - url = __url__[0] - print 'Trying to open web browser with documentation at this address...' - print '\t' + url - - try: - import webbrowser - webbrowser.open(url) - except: - print '...could not open a browser window.' - - def obj_ui(): - ui_x, ui_y = GLOBALS['MOUSE'] - - # Center based on overall pup size - ui_x -= 165 - ui_y -= 140 - - global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\ - EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\ - EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\ - EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS - - Draw.Label('Context...', ui_x+9, ui_y+239, 220, 20) - Draw.BeginAlign() - EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+219, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.') - EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+219, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.') - EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+219, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.') - Draw.EndAlign() - - - Draw.Label('Output Options...', ui_x+9, ui_y+189, 220, 20) - Draw.BeginAlign() - EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+170, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split) - EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+170, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP') - EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+170, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.') - Draw.EndAlign() - - - Draw.Label('Export...', ui_x+9, ui_y+139, 220, 20) - Draw.BeginAlign() - EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+120, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.') - EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+120, 70, 20, EXPORT_TRI.val, 'Triangulate quads.') - Draw.EndAlign() - Draw.BeginAlign() - EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+120, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.') - EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+120, 31, 20, EXPORT_UV.val, 'Export texface UV coords.') - Draw.EndAlign() - Draw.BeginAlign() - EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+120, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).') - EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+120, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.') - Draw.EndAlign() - EXPORT_POLYGROUPS = Draw.Toggle('Polygroups', EVENT_REDRAW, ui_x+9, ui_y+95, 120, 20, EXPORT_POLYGROUPS.val, 'Export vertex groups as OBJ groups (one group per face approximation).') - - EXPORT_CURVE_AS_NURBS = Draw.Toggle('Nurbs', EVENT_NONE, ui_x+139, ui_y+95, 100, 20, EXPORT_CURVE_AS_NURBS.val, 'Export 3D nurbs curves and polylines as OBJ curves, (bezier not supported).') - - - Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20) - Draw.BeginAlign() - EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split) - EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split) - EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split) - Draw.EndAlign() - - EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder) - - Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event) - Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event) - Draw.EndAlign() - - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT): - Draw.UIBlock(obj_ui, 0) - - if GLOBALS['EVENT'] != EVENT_EXPORT: - return - - # END ALTERNATIVE UI ********************* - - - if EXPORT_KEEP_VERT_ORDER.val: - EXPORT_BLEN_OBS.val = False - EXPORT_GROUP_BY_OB.val = False - EXPORT_GROUP_BY_MAT.val = False - EXPORT_APPLY_MODIFIERS.val = False - - Window.EditMode(0) - Window.WaitCursor(1) - - EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val - EXPORT_ROTX90 = EXPORT_ROTX90.val - EXPORT_TRI = EXPORT_TRI.val - EXPORT_EDGES = EXPORT_EDGES.val - EXPORT_NORMALS = EXPORT_NORMALS.val - EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val - EXPORT_UV = EXPORT_UV.val - EXPORT_MTL = EXPORT_MTL.val - EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val - EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val - EXPORT_ANIMATION = EXPORT_ANIMATION.val - EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val - EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val - EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val - EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val - EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val - EXPORT_POLYGROUPS = EXPORT_POLYGROUPS.val - EXPORT_CURVE_AS_NURBS = EXPORT_CURVE_AS_NURBS.val - - - base_name, ext = splitExt(filename) - context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension - - # Use the options to export the data using write() - # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True): - orig_scene = Scene.GetCurrent() - if EXPORT_ALL_SCENES: - export_scenes = Scene.Get() - else: - export_scenes = [orig_scene] - - # Export all scenes. - for scn in export_scenes: - scn.makeCurrent() # If alredy current, this is not slow. - context = scn.getRenderingContext() - orig_frame = Blender.Get('curframe') - - if EXPORT_ALL_SCENES: # Add scene name into the context_name - context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. - - # Export an animation? - if EXPORT_ANIMATION: - scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame. - else: - scene_frames = [orig_frame] # Dont export an animation. - - # Loop through all frames in the scene and export. - for frame in scene_frames: - if EXPORT_ANIMATION: # Add frame to the filename. - context_name[2] = '_%.6d' % frame - - Blender.Set('curframe', frame) - if EXPORT_SEL_ONLY: - export_objects = scn.objects.context - else: - export_objects = scn.objects - - full_path= ''.join(context_name) - - # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. - # EXPORT THE FILE. - write(full_path, export_objects,\ - EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ - EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ - EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ - EXPORT_ROTX90, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\ - EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS) - - Blender.Set('curframe', orig_frame) - - # Restore old active scene. - orig_scene.makeCurrent() - Window.WaitCursor(0) - - -if __name__ == '__main__': - Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj')) diff --git a/release/scripts/faceselect_same_weights.py b/release/scripts/faceselect_same_weights.py deleted file mode 100644 index 967aedec363..00000000000 --- a/release/scripts/faceselect_same_weights.py +++ /dev/null @@ -1,111 +0,0 @@ -#!BPY -""" -Name: 'Same Weights...' -Blender: 245 -Group: 'FaceSelect' -Tooltip: 'Select same faces with teh same weight for the active group.' -""" - -__author__ = ["Campbell Barton aka ideasman42"] -__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] -__version__ = "0.1" -__bpydoc__ = """\ - -Select Same Weights - -Select same weights as the active face on the active group. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - -from Blender import Scene, Draw, Mesh -import BPyMesh - -def selSameWeights(me, PREF_TOLERENCE): - - # Check for missing data - if not me.faceUV: return - - act_group= me.activeGroup - if not act_group: return - - act_face = me.faces[me.activeFace] - if act_face == None: return - - - - groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) - - def get_face_weight(f): - ''' - Return the faces median weight and weight range. - ''' - wmin = 1.0 - wmax = 0.0 - w = 0.0 - for v in f: - try: - new_weight = vWeightDict[v.index][act_group] - if wmin > new_weight: wmin = new_weight - if wmax < new_weight: wmax = new_weight - w += new_weight - except: - pass - return w, wmax-wmin # weight, range - - weight_from, weight_range_from = get_face_weight(act_face) - for f in me.faces: - if (not f.sel) and f != act_face: - weight, weight_range = get_face_weight(f) - - # Compare the 2 faces weight difference and difference in their contrast. - if\ - abs(weight - weight_from) <= PREF_TOLERENCE and\ - abs(weight_range - weight_range_from) <= PREF_TOLERENCE: - f.sel = True - - -def main(): - scn= Scene.GetCurrent() - ob= scn.objects.active - - if not ob or ob.type != 'Mesh': - Draw.PupMenu('Error, no active mesh object, aborting.') - return - - me= ob.getData(mesh=1) - - PREF_TOLERENCE= Draw.Create(0.1) - - pup_block= [\ - ('Tolerence:', PREF_TOLERENCE, 0.01, 1.0, 'Tolerence for selecting faces of the same weight.'),\ - ] - - if not Draw.PupBlock('Select Same Weight...', pup_block): - return - - PREF_TOLERENCE= PREF_TOLERENCE.val - - selSameWeights(me, PREF_TOLERENCE) - -if __name__=='__main__': - main() \ No newline at end of file diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py deleted file mode 100644 index 5c44fe29a6f..00000000000 --- a/release/scripts/flt_defaultp.py +++ /dev/null @@ -1 +0,0 @@ -pal = [-1,255,16711935,-16776961,-19529729,-19726337,-19922945,-20119553,-20316161,-20578305,-20840449,-21102593,-21364737,-21692417,-22020097,-22413313,-22806529,-23199745,-23658497,-24117249,-24641537,-25165825,-25755649,-26411009,-27066369,-27787265,-28573697,-29425665,-30343169,-31326209,-32374785,-33488897,-354549761,-371458049,-388366337,-405274625,-422182913,-439156737,-456130561,-473104385,-506855425,-540672001,-574488577,-608305153,-642121729,-676003841,-709885953,-760610817,-811335681,-862060545,-912850945,-980418561,-1048051713,-1115684865,-1183383553,-1267924993,-1352466433,-1453850625,-1555300353,-1656815617,-1775173633,-1893597185,-2028863489,2130771967,-1010376193,-1043996161,-1077681665,-1111367169,-1145052673,-1178738177,-1229200897,-1279663617,-1330126337,-1380654593,-1431182849,-1498488321,-1565793793,-1633164801,-1700535809,-1784684033,-1868832257,-1969823233,-2070814209,2123096575,2005262847,1887429119,1752752639,1601298943,1449779711,1281417727,1096278527,911073791,709026303,490201599,254534143,2023935,-1380857601,-1397700353,-1431320321,-1464940289,-1498560257,-1532180225,-1565865729,-1599551233,-1650013953,-1700476673,-1750939393,-1801402113,-1851864833,-1919170305,-1986475777,-2053781249,-2121086721,2089797887,2005649663,1904724223,1803798783,1686030591,1568262399,1450494207,1315883263,1164495103,1013041407,844810495,659736831,457885951,239192319,3655935,-1767919617,-1784762369,-1801605121,-1818447873,-1852067841,-1885687809,-1919307777,-1952927745,-1986547713,-2020167681,-2070564865,-2120962049,2123542527,2073079807,2022617087,1955377151,1888137215,1820897279,1736880127,1652797439,1568714751,1467854847,1366994943,1249357823,1131655167,997175295,862695423,711372799,560050175,391950335,207007743,5287935,2139657983,2122880767,2106103551,2089326335,2072549119,2055771903,2022217471,1988663039,1955108607,1921554175,1887934207,1854314239,1803917055,1753519871,1703122687,1652725503,1602328319,1535153919,1467979519,1400805119,1316853503,1232901887,1148950271,1048221439,947427071,846632703,729061119,611489535,477140735,326014719,174888703,6919935,1837268479,1820491263,1803714047,1786936831,1770159615,1753382399,1736605183,1719827967,1686273535,1652719103,1619164671,1585610239,1552055807,1518501375,1468169727,1417838079,1367506431,1317174783,1266843135,1199734271,1132625407,1065516543,998407679,914521599,830635519,729972223,629308927,528645631,411205119,293764607,159546879,8551935,-2086957569,-2103734785,-2120512001,-2137289217,2140900863,2107346431,2073791999,2040237311,2006682623,1973127935,1939573247,1906018559,1855686655,1805354751,1755022847,1704690943,1654359039,1587249919,1520140799,1453031679,1369145343,1285258751,1201372159,1100708351,1000044543,882603519,765162495,630943999,496725503,345729791,177956863,10183935,-1699437825,-1716215297,-1732992769,-1766547457,-1800102145,-1833656833,-1867211521,-1900766209,-1934320897,-1967875585,-2018207489,-2068539649,-2118871809,2125763327,2058653951,1991544575,1924435199,1857325823,1773438975,1689552127,1588888063,1488223999,1387559679,1270118143,1152676607,1018457855,884238847,733242623,565468927,397695231,213144319,11815935,-1311918593,-1345473281,-1379027969,-1412582657,-1446137345,-1479692289,-1513247233,-1546802177,-1597134337,-1647466497,-1697798657,-1748130817,-1798463233,-1865572865,-1932682497,-1999792129,-2083678977,2127401215,2043514111,1942849791,1842185215,1724743423,1607301631,1473082367,1338863103,1187866367,1020092415,852318207,667766783,466437887,248331519,13447935,-924398849,-957953793,-991508737,-1025063681,-1058618625,-1092173569,-1142505729,-1192837889,-1243170305,-1293502721,-1343835137,-1410944769,-1478054401,-1545164289,-1629051393,-1712938497,-1796825857,-1897490433,-1998155009,-2098819841,2078705407,1961263103,1827043583,1676046591,1525049599,1357275135,1172723199,971394047,753287423,518403327,283518975,15079935,-570434049,-603988993,-637543937,-671098881,-704653825,-754986241,-805318657,-855651073,-905983489,-973093377,-1040203265,-1107313153,-1174423041,-1258310401,-1342197761,-1442862593,-1543527425,-1644192257,-1761634561,-1879076865,-2013296641,2147450879,1996453631,1828678911,1660904191,1476351999,1275022335,1056915199,822030591,570368511,301928959,16711935,-503325185,-536880129,-570435073,-603990017,-637544961,-671100161,-721432577,-771764993,-822097409,-872430081,-922762753,-989872641,-1056982529,-1124092673,-1191202817,-1275090433,-1358978049,-1459642881,-1560307969,-1660973057,-1778415617,-1895858177,-2030078209,2113891583,1962894079,1795119103,1610566655,1426013951,1224683775,1006576127,771691007,520028415,-452993537,-469771265,-503326209,-536881153,-570436097,-603991297,-637546497,-671101697,-721434113,-771766785,-822099457,-872432129,-922764801,-989874945,-1056985089,-1124095489,-1191205889,-1275093505,-1358981377,-1459646465,-1560311809,-1677754369,-1795197185,-1912640257,-2046860545,2097108991,1946110975,1778335487,1593782527,1392452095,1174344191,939458815,-419439105,-436216833,-452994561,-469772289,-503327233,-536882433,-570437633,-603992833,-637548033,-671103489,-721436161,-771768833,-822101505,-872434433,-922767361,-989877761,-1056988161,-1124098561,-1207986433,-1291874305,-1375762433,-1476427777,-1577093377,-1694536449,-1811979521,-1946200065,-2080420865,2063548159,1912549631,1744773631,1560220159,1358889215,-385884673,-402662401,-419440129,-436217857,-452995585,-469773569,-503328769,-536883969,-570439169,-603994625,-637550081,-671105537,-721438209,-771771137,-822104065,-872437249,-922770433,-989880833,-1056991489,-1124102145,-1191213057,-1275101185,-1358989569,-1459655425,-1560321281,-1677764609,-1795208193,-1912652033,-2046873345,2097095167,1946096127,1778319615,-335553025,-352330753,-369108481,-385886209,-402663937,-419441921,-436219905,-452997889,-486553089,-520108545,-553664001,-587219457,-620774913,-654330625,-687886337,-738219521,-788552705,-838885889,-889219329,-939552769,-1006663681,-1073774593,-1140885761,-1224774401,-1308663041,-1392551937,-1493218305,-1593884929,-1711329025,-1828773377,-1962995201,-2097217281,-285221377,-301999105,-318776833,-335554561,-352332289,-369110273,-385888257,-402666241,-419444225,-436222465,-453000705,-469778945,-503334401,-536890113,-570445825,-604001793,-637557761,-671113729,-721447169,-771780609,-822114305,-872448001,-922781953,-989893377,-1057004801,-1124116481,-1191228417,-1275117825,-1359007489,-1459674625,-1560342017,-1677786881,-234889729,-234890241,-251667969,-268445697,-285223425,-302001409,-318779393,-335557377,-352335361,-369113601,-385891841,-402670081,-419448321,-436226817,-453005313,-469784065,-503340033,-536896001,-570452225,-604008449,-637564929,-671121409,-704678145,-755012353,-805346561,-855681025,-906015745,-973127937,-1040240385,-1107353089,-1174466049,-1258356481,-234889729,-234890241,-234890753,-234891265,-234891777,-234892545,-234893313,-234894081,-234894849,-251673089,-268451329,-285229569,-302007809,-318786305,-335564801,-352343553,-369122305,-385901057,-402680065,-419459073,-436238337,-453017601,-486574337,-520131329,-553688321,-587245569,-620803073,-654360833,-687918849,-738254337,-788590081,-838926081,-234889729,-234890241,-234890753,-234891265,-234891777,-234892545,-234893313,-234894081,-234894849,-234895873,-234896897,-234897921,-234898945,-234900225,-234901505,-234903041,-234904577,-234906113,-234907905,-234909697,-234911745,-251691009,-268470529,-285250305,-302030081,-318810113,-335590401,-352370945,-369151745,-385932801,-402714113,-419495681,-8705,-9217,-9729,-10241,-10753,-11521,-12289,-13057,-13825,-14849,-15873,-16897,-17921,-19201,-20481,-22017,-23553,-25089,-26881,-28673,-30721,-32769,-35073,-37633,-40193,-43009,-46081,-49409,-52993,-56833,-60929,-65281,-926209,-926721,-927233,-927745,-928257,-929025,-929793,-930561,-931329,-932353,-933377,-934401,-935425,-936705,-937985,-939521,-941057,-1008129,-1075457,-1142785,-1210369,-1277953,-1345793,-1413889,-1481985,-1550337,-1618945,-1687809,-1756929,-1826305,-1895937,-2031361,-926209,-926721,-927233,-927745,-928257,-929025,-929793,-996097,-1062401,-1128961,-1195521,-1262081,-1328641,-1395457,-1462273,-1529345,-1596417,-1663489,-1730817,-1798145,-1865729,-1998849,-2132225,-2265857,-2399489,-2533377,-2667521,-2867457,-3067649,-3268097,-3468801,-3669761,-926209,-992257,-1058305,-1124353,-1190401,-1256705,-1323009,-1389313,-1455617,-1522177,-1588737,-1655297,-1721857,-1788673,-1855489,-1988097,-2120705,-2253313,-2386177,-2519041,-2652161,-2785281,-2984193,-3183361,-3382529,-3581953,-3847169,-4112641,-4378369,-4644353,-4976129,-5308161,-1188353,-1254401,-1320449,-1386497,-1452545,-1518849,-1585153,-1651457,-1717761,-1784321,-1850881,-1982977,-2115073,-2247425,-2379777,-2512385,-2644993,-2777601,-2976001,-3174401,-3373057,-3571713,-3836161,-4100865,-4365569,-4630529,-4961281,-5292289,-5689089,-6086145,-6483457,-6946561,-1384961,-1451009,-1517057,-1583105,-1649153,-1715457,-1781761,-1848065,-1979905,-2112001,-2244097,-2376193,-2508289,-2640641,-2838529,-3036673,-3234817,-3432961,-3631361,-3895297,-4159489,-4423681,-4688129,-5018369,-5348609,-5744641,-6140929,-6537473,-6999809,-7462401,-7990785,-8584961,-1581569,-1647617,-1713665,-1779713,-1845761,-1977601,-2109441,-2241281,-2373121,-2505217,-2637313,-2769409,-2967041,-3164929,-3362817,-3560961,-3759105,-4022785,-4286721,-4550657,-4880385,-5210113,-5540097,-5935873,-6331649,-6793217,-7255041,-7782657,-8310529,-8904193,-9563649,-10223361,-1712641,-1778689,-1844737,-1976321,-2107905,-2239745,-2371585,-2503425,-2635265,-2767361,-2964993,-3162625,-3360257,-3558145,-3821569,-4085249,-4348929,-4612609,-4942081,-5271553,-5666817,-6062081,-6457601,-6918913,-7380225,-7907329,-8434689,-9027841,-9686785,-10345985,-11070977,-11861761,-1843713,-1975297,-2106881,-2238465,-2370049,-2501889,-2633729,-2765569,-2962945,-3160577,-3358209,-3555841,-3753473,-4016897,-4280321,-4544001,-4873217,-5202433,-5531905,-5926913,-6322177,-6782977,-7244033,-7770881,-8297729,-8890369,-9548801,-10207489,-10931969,-11722241,-12578305,-13500161,-1974785,-2106369,-2237953,-2369537,-2501121,-2632961,-2830337,-3027713,-3225089,-3422721,-3620353,-3883521,-4146689,-4410113,-4673537,-5002753,-5331969,-5726721,-6121729,-6582273,-7043073,-7503873,-8030465,-8622849,-9215233,-9873409,-10597377,-11387137,-12242689,-13164033,-14085633,-15138561,-2236929,-2368513,-2500097,-2631681,-2763265,-2960641,-3158017,-3355393,-3552769,-3815937,-4079105,-4342273,-4605441,-4934401,-5263361,-5658113,-6052865,-6447617,-6908161,-7368705,-7895041,-8421377,-9013505,-9671425,-10329345,-11053057,-11842561,-12697857,-13618945,-14605825,-15658497,-16776961] \ No newline at end of file diff --git a/release/scripts/flt_dofedit.py b/release/scripts/flt_dofedit.py deleted file mode 100644 index 36e8e4d2501..00000000000 --- a/release/scripts/flt_dofedit.py +++ /dev/null @@ -1,835 +0,0 @@ -#!BPY - -""" -Name: 'FLT DOF Editor' -Blender: 240 -Group: 'Misc' -Tooltip: 'Degree of Freedom editor for FLT nodes' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/07" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# 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 Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -reload(flt_properties) -from flt_properties import * - -#event codes -evcode = { - "DOF_MAKE" : 100, - "DOF_UPDATE" : 138, - "DOF_DELETE" : 101, - "DOF_TRANSX" : 102, - "DOF_TRANSY" : 103, - "DOF_TRANSZ" : 104, - "DOF_ROTX" : 105, - "DOF_ROTY" : 106, - "DOF_ROTZ" : 107, - "DOF_SCALEX" : 108, - "DOF_SCALEY" : 109, - "DOF_SCALEZ" : 110, - "DOF_MIN_TRANSX" : 111, - "DOF_MIN_TRANSY" : 112, - "DOF_MIN_TRANSZ" : 113, - "DOF_MIN_ROTX" : 114, - "DOF_MIN_ROTY" : 115, - "DOF_MIN_ROTZ" : 116, - "DOF_MIN_SCALEX" : 117, - "DOF_MIN_SCALEY" : 118, - "DOF_MIN_SCALEZ" : 119, - "DOF_MAX_TRANSX" : 120, - "DOF_MAX_TRANSY" : 121, - "DOF_MAX_TRANSZ" : 122, - "DOF_MAX_ROTX" : 123, - "DOF_MAX_ROTY" : 124, - "DOF_MAX_ROTZ" : 125, - "DOF_MAX_SCALEX" : 126, - "DOF_MAX_SCALEY" : 127, - "DOF_MAX_SCALEZ" : 128, - "DOF_STEP_TRANSX" : 129, - "DOF_STEP_TRANSY" : 130, - "DOF_STEP_TRANSZ" : 131, - "DOF_STEP_ROTX" : 132, - "DOF_STEP_ROTY" : 133, - "DOF_STEP_ROTZ" : 134, - "DOF_STEP_SCALEX" : 135, - "DOF_STEP_SCALEY" : 136, - "DOF_STEP_SCALEZ" : 137 -} - -#system -DOF_MAKE = None -DOF_UPDATE = None -DOF_DELETE = None - -#toggle buttons -DOF_TRANSX = None -DOF_TRANSY = None -DOF_TRANSZ = None -DOF_ROTX = None -DOF_ROTY = None -DOF_ROTZ = None -DOF_SCALEX = None -DOF_SCALEY = None -DOF_SCALEZ = None - -#Minimums -DOF_MIN_TRANSX = None -DOF_MIN_TRANSY = None -DOF_MIN_TRANSZ = None -DOF_MIN_ROTX = None -DOF_MIN_ROTY = None -DOF_MIN_ROTZ = None -DOF_MIN_SCALEX = None -DOF_MIN_SCALEY = None -DOF_MIN_SCALEZ = None - -#maximums -DOF_MAX_TRANSX = None -DOF_MAX_TRANSY = None -DOF_MAX_TRANSZ = None -DOF_MAX_ROTX = None -DOF_MAX_ROTY = None -DOF_MAX_ROTZ = None -DOF_MAX_SCALEX = None -DOF_MAX_SCALEY = None -DOF_MAX_SCALEZ = None - -#step -DOF_STEP_TRANSX = None -DOF_STEP_TRANSY = None -DOF_STEP_TRANSZ = None -DOF_STEP_ROTX = None -DOF_STEP_ROTY = None -DOF_STEP_ROTZ = None -DOF_STEP_SCALEX = None -DOF_STEP_SCALEY = None -DOF_STEP_SCALEZ = None - -#labels -DOF_ROTSTRING = None -DOF_TRANSTRING = None -DOF_SCALESTRING = None -DOF_EDITLABEL = None - -#make ID props easier/morereadable -zmin = '14d!ZMIN' -zmax = '15d!ZMAX' -zcur = '16d!ZCUR' -zstep = '17d!ZSTEP' -ymin = '18d!YMIN' -ymax = '19d!YMAX' -ycur = '20d!YCUR' -ystep = '21d!YSTEP' -xmin = '22d!XMIN' -xmax = '23d!XMAX' -xcur = '24d!XCUR' -xstep = '25d!XSTEP' -pitchmin = '26d!PITCH-MIN' -pitchmax = '27d!PITCH-MAX' -pitchcur = '28d!PITCH-CUR' -pitchstep = '29d!PITCH-STEP' -rollmin = '30d!ROLL-MIN' -rollmax = '31d!ROLL-MAX' -rollcur = '32d!ROLL-CUR' -rollstep = '33d!ROLL-STEP' -yawmin = '34d!YAW-MIN' -yawmax = '35d!YAW-MAX' -yawcur = '36d!YAW-CUR' -yawstep = '37d!YAW-STEP' -zscalemin = '38d!ZSIZE-MIN' -zscalemax = '39d!ZSIZE-MAX' -zscalecur = '40d!ZSIZE-CUR' -zscalestep = '41d!ZSIZE-STEP' -yscalemin = '42d!YSIZE-MIN' -yscalemax = '43d!YSIZE-MAX' -yscalecur = '44d!YSIZE-CUR' -yscalestep = '45d!YSIZE-STEP' -xscalemin = '46d!XSIZE-MIN' -xscalemax = '47d!XSIZE-MAX' -xscalecur = '48d!XSIZE-CUR' -xscalestep = '49d!XSIZE-STEP' - - - -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.GetCurrent() - state["activeObject"] = state["activeScene"].objects.active - if state["activeObject"] and not state["activeObject"].sel: - state["activeObject"] = None - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - - #update editmode - state["editmode"] = Blender.Window.EditMode() - - return state - -def idprops_append(object, typecode, props): - object.properties["FLT"] = dict() - object.properties["FLT"]['type'] = typecode - for prop in props: - object.properties["FLT"][prop] = props[prop] - object.properties["FLT"]['3t8!id'] = object.name - -def idprops_kill(): - state = update_state() - if state["activeObject"] and state["activeObject"].properties.has_key('FLT'): - state["activeObject"].properties.pop('FLT') - -def idprops_copy(source): - state = update_state() - if source.properties.has_key('FLT'): - for object in state["activeScene"].objects: - if object.sel and object != source and (state["activeScene"].Layers & object.Layers): - idprops_kill(object) - object.properties['FLT'] = dict() - for key in source.properties['FLT']: - object.properties['FLT'][key] = source.properties['FLT'][key] - -def select_by_typecode(typecode): - state = update_state() - - for object in state["activeScene"].objects: - if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: - object.select(1) - -def DOF_get_frame(): - state = update_state() - - if not state["activeObject"] and not id_props_type(state["activeObject"], 14): - return - - #Warning! assumes 1 BU == 10 meters. - #do origin - state["activeObject"].properties['FLT']['5d!ORIGX'] = state["activeObject"].getLocation('worldspace')[0]*10.0 - state["activeObject"].properties['FLT']['6d!ORIGY'] = state["activeObject"].getLocation('worldspace')[1]*10.0 - state["activeObject"].properties['FLT']['7d!ORIGZ'] = state["activeObject"].getLocation('worldspace')[2]*10.0 - #do X axis - x = Blender.Mathutils.Vector(1.0,0.0,0.0) - x = x * state["activeObject"].getMatrix('worldspace') - x = x * 10.0 - state["activeObject"].properties['FLT']['8d!XAXIS-X'] = x[0] - state["activeObject"].properties['FLT']['9d!XAXIS-Y'] = x[1] - state["activeObject"].properties['FLT']['10d!XAXIS-Z'] = x[2] - #do X/Y plane - x = Blender.Mathutils.Vector(0.0,1.0,0.0) - x.normalize() - x = x * state["activeObject"].getMatrix('worldspace') - x = x * 10.0 - state["activeObject"].properties['FLT']['11d!XYPLANE-X'] = x[0] - state["activeObject"].properties['FLT']['12d!XYPLANE-Y'] = x[1] - state["activeObject"].properties['FLT']['13d!XZPLANE-Z'] = x[2] - -def idprops_type(object, typecode): - if object.properties.has_key('FLT') and object.properties['FLT'].has_key('type') and object.properties['FLT']['type'] == typecode: - return True - return False - -#ui type code -def get_prop(typecode, prop): - - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], typecode): - props = state["activeObject"].properties['FLT'] - else: - props = flt_properties.FLTDOF - - return props[prop] - -def set_prop(typecode, prop, value): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"],typecode): - state["activeObject"].properties['FLT'][prop] = value - -lockxtrans = (1 << 31) -lockytrans = (1 << 30) -lockztrans = (1 << 29) -lockxrot = (1 << 28) -lockyrot = (1 << 27) -lockzrot = (1 << 26) -lockxscale = (1 << 25) -lockyscale = (1 << 24) -lockzscale = (1 << 23) - -def get_lockmask(mask): - state = update_state() - if state["activeObject"]: - flag = get_prop(14,'50I!FLAG') - if flag & mask: - return True - return False - -def set_lockmask(mask): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 14): - oldvalue = state["activeObject"].properties['FLT']['50I!FLAG'] - oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0] - oldvalue |= mask - state["activeObject"].properties['FLT']['50I!FLAG'] = struct.unpack('>i', struct.pack(">I", oldvalue))[0] - -def clear_lockmask(mask): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 14): - oldvalue = state["activeObject"].properties['FLT']['50I!FLAG'] - oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0] - oldvalue &= ~mask - state["activeObject"].properties['FLT']['50I!FLAG'] = struct.unpack('>i',struct.pack('>I',oldvalue))[0] - - -def create_dof(): - state = update_state() - actobj = state["activeObject"] - if actobj and not idprops_type(actobj, 14): - idprops_kill() - idprops_append(actobj,14, flt_properties.FLTDOF) - DOF_get_frame() - - -def event(evt,val): - if evt == Draw.ESCKEY: - Draw.Exit() - -def but_event(evt): - global DOF_MAKE - global DOF_UPDATE - global DOF_DELETE - - global DOF_TRANSX - global DOF_TRANSY - global DOF_TRANSZ - global DOF_ROTX - global DOF_ROTY - global DOF_ROTZ - global DOF_SCALEX - global DOF_SCALEY - global DOF_SCALEZ - - global DOF_MIN_TRANSX - global DOF_MIN_TRANSY - global DOF_MIN_TRANSZ - global DOF_MIN_ROTX - global DOF_MIN_ROTY - global DOF_MIN_ROTZ - global DOF_MIN_SCALEX - global DOF_MIN_SCALEY - global DOF_MIN_SCALEZ - - global DOF_MAX_TRANSX - global DOF_MAX_TRANSY - global DOF_MAX_TRANSZ - global DOF_MAX_ROTX - global DOF_MAX_ROTY - global DOF_MAX_ROTZ - global DOF_MAX_SCALEX - global DOF_MAX_SCALEY - global DOF_MAX_SCALEZ - - global DOF_STEP_TRANSX - global DOF_STEP_TRANSY - global DOF_STEP_TRANSZ - global DOF_STEP_ROTX - global DOF_STEP_ROTY - global DOF_STEP_ROTZ - global DOF_STEP_SCALEX - global DOF_STEP_SCALEY - global DOF_STEP_SCALEZ - - #labels - global DOF_ROTSTRING - global DOF_TRANSTRING - global DOF_SCALESTRING - - - #masks - global lockxtrans - global lockytrans - global lockztrans - global lockxrot - global lockyrot - global lockzrot - global lockxscale - global lockyscale - global lockzscale - - global zmin - global zmax - global zcur - global zstep - global ymin - global ymax - global ycur - global ystep - global xmin - global xmax - global xcur - global xstep - global pitchmin - global pitchmax - global pitchcur - global pitchstep - global rollmin - global rollmax - global rollcur - global rollstep - global yawmin - global yawmax - global yawcur - global yawstep - global zscalemin - global zscalemax - global zscalecur - global zscalestep - global yscalemin - global yscalemax - global yscalecur - global yscalestep - global xscalemin - global xscalemax - global xscalecur - global xscalestep - - - - #do "system" events - if evt == evcode["DOF_MAKE"]: - create_dof() - - if evt == evcode["DOF_UPDATE"]: - DOF_get_frame() - - if evt == evcode["DOF_DELETE"]: - idprops_kill() - #do translation lock events - if evt == evcode["DOF_TRANSX"]: - if DOF_TRANSX.val == True: - set_lockmask(lockxtrans) - else: - clear_lockmask(lockxtrans) - - if evt == evcode["DOF_TRANSY"]: - if DOF_TRANSY.val == True: - set_lockmask(lockytrans) - else: - clear_lockmask(lockytrans) - - if evt == evcode["DOF_TRANSZ"]: - if DOF_TRANSZ.val == True: - set_lockmask(lockztrans) - else: - clear_lockmask(lockztrans) - - - #do rotation lock events - if evt == evcode["DOF_ROTX"]: - if DOF_ROTX.val == True: - set_lockmask(lockxrot) - else: - clear_lockmask(lockxrot) - - if evt == evcode["DOF_ROTY"]: - if DOF_ROTY.val == True: - set_lockmask(lockyrot) - else: - clear_lockmask(lockyrot) - - if evt == evcode["DOF_ROTZ"]: - if DOF_ROTZ.val == True: - set_lockmask(lockzrot) - else: - clear_lockmask(lockzrot) - - #do scale lock events - if evt == evcode["DOF_SCALEX"]: - if DOF_SCALEX.val == True: - set_lockmask(lockxscale) - else: - clear_lockmask(lockxscale) - - if evt == evcode["DOF_SCALEY"]: - if DOF_SCALEY.val == True: - set_lockmask(lockyscale) - else: - clear_lockmask(lockyscale) - - if evt == evcode["DOF_SCALEZ"]: - if DOF_SCALEZ.val == True: - set_lockmask(lockzscale) - else: - clear_lockmask(lockzscale) - - - #do translation buttons - if evt == evcode["DOF_MIN_TRANSX"]: - set_prop(14, xmin, DOF_MIN_TRANSX.val) - if evt == evcode["DOF_MAX_TRANSX"]: - set_prop(14,xmax, DOF_MAX_TRANSX.val) - if evt == evcode["DOF_STEP_TRANSX"]: - set_prop(14,xstep, DOF_STEP_TRANSX.val) - - if evt == evcode["DOF_MIN_TRANSY"]: - set_prop(14, ymin, DOF_MIN_TRANSY.val) - if evt == evcode["DOF_MAX_TRANSY"]: - set_prop(14,ymax, DOF_MAX_TRANSY.val) - if evt == evcode["DOF_STEP_TRANSY"]: - set_prop(14,ystep, DOF_STEP_TRANSY.val) - - if evt == evcode["DOF_MIN_TRANSZ"]: - set_prop(14, zmin, DOF_MIN_TRANSZ.val) - if evt == evcode["DOF_MAX_TRANSZ"]: - set_prop(14, zmax, DOF_MAX_TRANSZ.val) - if evt == evcode["DOF_STEP_TRANSZ"]: - set_prop(14, zstep, DOF_STEP_TRANSZ.val) - - #do rotation buttons - if evt == evcode["DOF_MIN_ROTX"]: - set_prop(14, pitchmin, DOF_MIN_ROTX.val) - if evt == evcode["DOF_MAX_ROTX"]: - set_prop(14, pitchmax, DOF_MAX_ROTX.val) - if evt == evcode["DOF_STEP_ROTX"]: - set_prop(14, pitchstep, DOF_STEP_ROTX.val) - - if evt == evcode["DOF_MIN_ROTY"]: - set_prop(14, rollmin, DOF_MIN_ROTY.val) - if evt == evcode["DOF_MAX_ROTY"]: - set_prop(14, rollmax, DOF_MAX_ROTY.val) - if evt == evcode["DOF_STEP_ROTY"]: - set_prop(14, rollstep, DOF_STEP_ROTY.val) - - if evt == evcode["DOF_MIN_ROTZ"]: - set_prop(14, yawmin, DOF_MIN_ROTZ.val) - if evt == evcode["DOF_MAX_ROTZ"]: - set_prop(14, yawmax, DOF_MAX_ROTZ.val) - if evt == evcode["DOF_STEP_ROTZ"]: - set_prop(14, yawstep, DOF_STEP_ROTZ.val) - - #do scale buttons - if evt == evcode["DOF_MIN_SCALEX"]: - set_prop(14, xscalemin, DOF_MIN_SCALEX.val) - if evt == evcode["DOF_MAX_SCALEX"]: - set_prop(14, xscalemax, DOF_MAX_SCALEX.val) - if evt == evcode["DOF_STEP_SCALEX"]: - set_prop(14, xscalestep, DOF_STEP_SCALEX.val) - - if evt == evcode["DOF_MIN_SCALEY"]: - set_prop(14, yscalemin, DOF_MIN_SCALEY.val) - if evt == evcode["DOF_MAX_SCALEY"]: - set_prop(14, yscalemax, DOF_MAX_SCALEY.val) - if evt == evcode["DOF_STEP_SCALEY"]: - set_prop(14, yscalestep, DOF_STEP_SCALEY.val) - - if evt == evcode["DOF_MIN_SCALEZ"]: - set_prop(14, zscalemin, DOF_MIN_SCALEZ.val) - if evt == evcode["DOF_MAX_SCALEZ"]: - set_prop(14, zscalemax, DOF_MAX_SCALEZ.val) - if evt == evcode["DOF_STEP_SCALEZ"]: - set_prop(14, zscalestep, DOF_STEP_SCALEZ.val) - - - Draw.Redraw(1) - Blender.Window.RedrawAll() - -def draw_propsheet(x,y): - #UI buttons - global DOF_MAKE - global DOF_UPDATE - global DOF_DELETE - - global DOF_TRANSX - global DOF_TRANSY - global DOF_TRANSZ - global DOF_ROTX - global DOF_ROTY - global DOF_ROTZ - global DOF_SCALEX - global DOF_SCALEY - global DOF_SCALEZ - - global DOF_MIN_TRANSX - global DOF_MIN_TRANSY - global DOF_MIN_TRANSZ - global DOF_MIN_ROTX - global DOF_MIN_ROTY - global DOF_MIN_ROTZ - global DOF_MIN_SCALEX - global DOF_MIN_SCALEY - global DOF_MIN_SCALEZ - - global DOF_MAX_TRANSX - global DOF_MAX_TRANSY - global DOF_MAX_TRANSZ - global DOF_MAX_ROTX - global DOF_MAX_ROTY - global DOF_MAX_ROTZ - global DOF_MAX_SCALEX - global DOF_MAX_SCALEY - global DOF_MAX_SCALEZ - - global DOF_STEP_TRANSX - global DOF_STEP_TRANSY - global DOF_STEP_TRANSZ - global DOF_STEP_ROTX - global DOF_STEP_ROTY - global DOF_STEP_ROTZ - global DOF_STEP_SCALEX - global DOF_STEP_SCALEY - global DOF_STEP_SCALEZ - - #labels - global DOF_ROTSTRING - global DOF_TRANSTRING - global DOF_SCALESTRING - global DOF_EDITLABEL - - #masks - global lockxtrans - global lockytrans - global lockztrans - global lockxrot - global lockyrot - global lockzrot - global lockxscale - global lockyscale - global lockzscale - - global zmin - global zmax - global zcur - global zstep - global ymin - global ymax - global ycur - global ystep - global xmin - global xmax - global xcur - global xstep - global pitchmin - global pitchmax - global pitchcur - global pitchstep - global rollmin - global rollmax - global rollcur - global rollstep - global yawmin - global yawmax - global yawcur - global yawstep - global zscalemin - global zscalemax - global zscalecur - global zscalestep - global yscalemin - global yscalemax - global yscalecur - global yscalestep - global xscalemin - global xscalemax - global xscalecur - global xscalestep - - - global evcode - - state = update_state() - - row_height = 20 - toggle_width = 50 - input_width = 100 - pad = 10 - origx = x - origy = (row_height * 15) + (pad * 15) - - - #editor label - x = origx - y = origy - #y = y - (row_height + pad) - DOF_EDITLABEL = Blender.Draw.Label("FLT Degree of Freedom Editor", x, y, 200, row_height) - - - #draw Translation limits - x = origx - y = y- (row_height + pad) - DOF_TRANSTRING = Blender.Draw.Label("Translation Limits", x, y, input_width, row_height) - - - #X limits - x = origx - y = y- (row_height + pad) - DOF_TRANSX = Blender.Draw.Toggle("LimX", evcode["DOF_TRANSX"], x, y, toggle_width, row_height, get_lockmask(lockxtrans), "") - x = x + (toggle_width + pad) - DOF_MIN_TRANSX = Blender.Draw.Number("MinX", evcode["DOF_MIN_TRANSX"], x, y, input_width, row_height,get_prop(14,xmin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_TRANSX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_TRANSX"], x, y, input_width, row_height,get_prop(14,xmax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_TRANSX = Blender.Draw.Number("StepX", evcode["DOF_STEP_TRANSX"], x, y, input_width, row_height,get_prop(14,xstep), -1000000.0, 1000000.0, "") - - #Y limits - x = origx - y = y- (row_height + pad) - DOF_TRANSY = Blender.Draw.Toggle("LimY", evcode["DOF_TRANSY"], x, y, toggle_width, row_height, get_lockmask(lockytrans), "") - x = x + (toggle_width + pad) - DOF_MIN_TRANSY = Blender.Draw.Number("MinY", evcode["DOF_MIN_TRANSY"], x, y, input_width, row_height, get_prop(14,ymin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_TRANSY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_TRANSY"], x, y, input_width, row_height, get_prop(14,ymax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_TRANSY = Blender.Draw.Number("StepY", evcode["DOF_STEP_TRANSY"], x, y, input_width, row_height, get_prop(14,ystep), -1000000.0, 1000000.0, "") - - #Z limits - x = origx - y = y- (row_height + pad) - DOF_TRANSZ = Blender.Draw.Toggle("LimZ", evcode["DOF_TRANSZ"], x, y, toggle_width, row_height, get_lockmask(lockztrans), "") - x = x + (toggle_width + pad) - DOF_MIN_TRANSZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_TRANSZ"], x, y, input_width, row_height, get_prop(14,zmin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_TRANSZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_TRANSZ"], x, y, input_width, row_height, get_prop(14,zmax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_TRANSZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_TRANSZ"], x, y, input_width, row_height, get_prop(14,zstep), -1000000.0, 1000000.0, "") - - #draw Rotation limits - x = origx - y = y- (row_height + pad) - DOF_ROTSTRING = Blender.Draw.Label("Rotation Limits", x, y, input_width, row_height) - - #draw Rotation limits - #X limits - x = origx - y = y- (row_height + pad) - DOF_ROTX = Blender.Draw.Toggle("LimX", evcode["DOF_ROTX"], x, y, toggle_width, row_height, get_lockmask(lockxrot), "") - x = x + (toggle_width + pad) - DOF_MIN_ROTX = Blender.Draw.Number("MinX", evcode["DOF_MIN_ROTX"], x, y, input_width, row_height, get_prop(14,pitchmin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_ROTX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_ROTX"], x, y, input_width, row_height, get_prop(14,pitchmax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_ROTX = Blender.Draw.Number("StepX", evcode["DOF_STEP_ROTX"], x, y, input_width, row_height, get_prop(14,pitchstep), -1000000.0, 1000000.0, "") - - #Y limits - x = origx - y = y- (row_height + pad) - DOF_ROTY = Blender.Draw.Toggle("LimY", evcode["DOF_ROTY"], x, y, toggle_width, row_height, get_lockmask(lockyrot), "") - x = x + (toggle_width + pad) - DOF_MIN_ROTY = Blender.Draw.Number("MinY", evcode["DOF_MIN_ROTY"], x, y, input_width, row_height, get_prop(14,rollmin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_ROTY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_ROTY"], x, y, input_width, row_height, get_prop(14,rollmax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_ROTY = Blender.Draw.Number("StepY", evcode["DOF_STEP_ROTY"], x, y, input_width, row_height, get_prop(14,rollstep), -1000000.0, 1000000.0, "") - - #Z limits - x = origx - y = y- (row_height + pad) - DOF_ROTZ = Blender.Draw.Toggle("LimZ", evcode["DOF_ROTZ"], x, y, toggle_width, row_height, get_lockmask(lockzrot), "") - x = x + (toggle_width + pad) - DOF_MIN_ROTZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_ROTZ"], x, y, input_width, row_height, get_prop(14, yawmin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_ROTZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_ROTZ"], x, y, input_width, row_height, get_prop(14, yawmax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_ROTZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_ROTZ"], x, y, input_width, row_height, get_prop(14, yawstep), -1000000.0, 1000000.0, "") - - - #draw Scale limits - x = origx - y = y- (row_height + pad) - DOF_SCALESTRING = Blender.Draw.Label("Scale Limits", x, y, input_width, row_height) - - #draw Scale limits - #X limits - x = origx - y = y- (row_height + pad) - DOF_SCALEX = Blender.Draw.Toggle("LimX", evcode["DOF_SCALEX"], x, y, toggle_width, row_height, get_lockmask(lockxscale), "") - x = x + (toggle_width + pad) - DOF_MIN_SCALEX = Blender.Draw.Number("MinX", evcode["DOF_MIN_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalemin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_SCALEX = Blender.Draw.Number("MaxX", evcode["DOF_MAX_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalemax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_SCALEX = Blender.Draw.Number("StepX", evcode["DOF_STEP_SCALEX"], x, y, input_width, row_height, get_prop(14, xscalestep), -1000000.0, 1000000.0, "") - - #Y limits - x = origx - y = y- (row_height + pad) - DOF_SCALEY = Blender.Draw.Toggle("LimY", evcode["DOF_SCALEY"], x, y, toggle_width, row_height, get_lockmask(lockyscale), "") - x = x + (toggle_width + pad) - DOF_MIN_SCALEY = Blender.Draw.Number("MinY", evcode["DOF_MIN_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalemin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_SCALEY = Blender.Draw.Number("MaxY", evcode["DOF_MAX_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalemax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_SCALEY = Blender.Draw.Number("StepY", evcode["DOF_STEP_SCALEY"], x, y, input_width, row_height, get_prop(14, yscalestep), -1000000.0, 1000000.0, "") - - #Z limits - x = origx - y = y- (row_height + pad) - DOF_SCALEZ = Blender.Draw.Toggle("LimZ", evcode["DOF_SCALEZ"], x, y, toggle_width, row_height, get_lockmask(lockzscale), "") - x = x + (toggle_width + pad) - DOF_MIN_SCALEZ = Blender.Draw.Number("MinZ", evcode["DOF_MIN_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalemin), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_MAX_SCALEZ = Blender.Draw.Number("MaxZ", evcode["DOF_MAX_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalemax), -1000000.0, 1000000.0, "") - x = x + (input_width + pad) - DOF_STEP_SCALEZ = Blender.Draw.Number("StepZ", evcode["DOF_STEP_SCALEZ"], x, y, input_width, row_height, get_prop(14, zscalestep), -1000000.0, 1000000.0, "") - - #System - x = origx - y = y - (row_height + (pad)*3) - DOF_MAKE = Blender.Draw.PushButton("Make DOF", evcode["DOF_MAKE"], x, y, input_width, row_height, "Make a Dof Node out of Active Object") - x = x + (input_width + pad) - DOF_UPDATE = Blender.Draw.PushButton("Grab Loc/Rot", evcode["DOF_UPDATE"], x, y, input_width, row_height, "Update the Dof Node position/orientation") - x = x + (input_width + pad) - DOF_DELETE = Blender.Draw.PushButton("Delete DOF", evcode["DOF_DELETE"], x, y, input_width, row_height, "Delete the Dof Node properties") - - - - -def gui(): - #draw the propsheet/toolbox. - psheety = 800 - #psheetx = psheety + 10 - draw_propsheet(20,psheety) - -Draw.Register(gui,event,but_event) - \ No newline at end of file diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py deleted file mode 100644 index c099c8e62d1..00000000000 --- a/release/scripts/flt_export.py +++ /dev/null @@ -1,1697 +0,0 @@ -#!BPY -""" Registration info for Blender menus: -Name: 'OpenFlight (.flt)...' -Blender: 245 -Group: 'Export' -Tip: 'Export to OpenFlight v16.0 (.flt)' -""" - -__author__ = "Greg MacDonald, Geoffrey Bantle" -__version__ = "2.0 11/21/07" -__url__ = ("blender", "blenderartists.org", "Author's homepage, http://sourceforge.net/projects/blight/") -__bpydoc__ = """\ -This script exports v16.0 OpenFlight files. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt -""" - -# flt_export.py is an OpenFlight exporter for blender. -# -# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation. -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -import Blender -from Blender import Modifier -import os.path -import flt_properties -import flt_defaultp as defaultp -from flt_filewalker import FltOut -from flt_filewalker import FileFinder -from flt_properties import * -import shutil -import trace -import sys - -FF = FileFinder() -records = process_recordDefs() - -class ExporterOptions: - - def read_state(self): - reg = Blender.Registry.GetKey('flt_export',1) - if reg: - for key in self.state: - if reg.has_key(key): - self.state[key] = reg[key] - - def write_state(self): - d = dict() - for key in self.state: - d[key] = self.state[key] - Blender.Registry.SetKey('flt_export', d, 1) - def __init__(self): - self.verbose = 1 - self.tolerance = 0.001 - self.writevcol = True - - self.state = {'export_shading' : 0, - 'shading_default' : 45, - 'basepath' : os.path.dirname(Blender.Get('filename')), - 'scale': 1.0, - 'doxrefs' : 1, - 'attrib' : 0, - 'copytex' : 0, - 'transform' : 0, - 'xapp' : 1} - - #default externals path - if(os.path.exists(os.path.join(self.state['basepath'],'externals'))): - self.state['externalspath'] = os.path.join(self.state['basepath'],'externals') - else: - self.state['externalspath'] = self.state['basepath'] - - if(os.path.exists(os.path.join(self.state['basepath'],'textures'))): - self.state['texturespath'] = os.path.join(self.state['basepath'],'textures') - else: - self.state['texturespath'] = self.state['basepath'] - - self.state['xappath'] = '' - self.read_state() #read from registry - - -options = ExporterOptions() -tex_files = dict() #a list of (possibly) modified texture path names - -tex_layers = ['Layer0', 'Layer1', 'Layer2', 'Layer3', 'Layer4', 'Layer5', 'Layer6', 'Layer7'] -mask = 2147483648 -mtexmasks = [] -for i in xrange(7): - mtexmasks.append(mask) - mask = mask / 2 - -FLOAT_TOLERANCE = options.tolerance - -#need to move all this stuff to flt_properties.py. -identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] -alltypes = [2,4,14,11,73,63,111] -childtypes = { - 2 : [111,2,73,4,14,63], - 4 : [111], - 73 : [111,2,73,4,14,63], - 63 : [], - 14 : [111,2,73,4,14,63], - 111 : [] -} -recordlen = { - 2: 44, - 4: 28, - 73: 80, - 63: 216, - 14: 384, - 111: 156 -} - -def is_identity(m): - for i in xrange(4): - for j in xrange(4): - if abs(m[i][j] - identity_matrix[i][j]) > FLOAT_TOLERANCE: - return False - return True - -class MaterialDesc: - def __init__(self): - self.name = 'Blender' - - # Colors, List of 3 floats. - self.diffuse = [1.0, 1.0, 1.0] - self.specular = [1.0, 1.0, 1.0] - - # Scalars - self.ambient = 0.1 # [0.0, 1.0] - self.emissive = 0.0 # [0.0, 1.0] - self.shininess = 32.0 # Range is [0.0, 128.0] - self.alpha = 1.0 # Range is [0.0, 1.0] - -class VertexDesc: - def __init__(self, co=None, no=None, uv=None, fltindex=None,cindex=None): - if co: self.x, self.y, self.z = tuple(co) - else: self.x = self.y = self.z = 0.0 - if no: self.nx, self.ny, self.nz = tuple(no) - else: self.nx = self.ny = self.nz = 0.0 - if uv: self.u, self.v = tuple(uv) - else: self.u = self.v = 0.0 - if cindex: self.cindex = cindex - else: self.cindex = 127 - self.fltindex = fltindex - self.accum = 0 - -class shadowVert: - def __init__(self,bvert,object,world,normal): - global options - - self.co = Blender.Mathutils.Vector(bvert.co[0],bvert.co[1],bvert.co[2]) - #if world: - # vec = self.co - # vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale - # self.co = Blender.Mathutils.TranslationMatrix(vec) * (self.co * object.getMatrix('worldspace')) - - if normal: - #if world: - # self.no = Blender.Mathutils.Vector(normal * object.getMatrix('worldspace')).normalize() - #else: - self.no = Blender.Mathutils.Vector(normal[0],normal[1],normal[2]) - - else: - #if world: - #self.no = Blender.Mathutils.Vector(bvert.no * object.getMatrix('worldspace')).normalize() - #else: - self.no = Blender.Mathutils.Vector(bvert.no[0],bvert.no[1],bvert.no[2]) - - #do scaling factor - #if options.scale != 1.0: - #self.co[0] = self.co[0] * options.scale - #self.co[1] = self.co[1] * options.scale - #self.co[2] = self.co[2] * options.scale - - self.index = bvert.index - -class GlobalResourceRepository: - def new_face_name(self): - self.face_name += 1 - return 'f%i' % (self.face_name-1) - - def vertex_count(self): - return len(self.vertex_lst) - - def request_vertex_desc(self, i): - return self.vertex_lst[i] - - def request_vertex_index(self, object, mesh, face, vfindex, uvok,cindex): - - flatShadeNorm = None - vno = None - - - if type(face) is list: - vertex = face[vfindex] - elif str(type(face)) == "": - vertex = face - vno = Blender.Mathutils.Vector(0.0,0.0,1.0) - elif str(type(face)) == "": - if vfindex == 1: - vertex = face.v1 - elif vfindex == 2: - vertex = face.v2 - elif str(type(face)) == "": - if not face.smooth: - flatShadeNorm = face.no - vertex = face.v[vfindex] - else: - return None - - if not self.namehash.has_key(object.name): - self.namehash[object.name] = dict() - indexhash = self.namehash[object.name] - - #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME - if not options.state['transform']: - vertex = shadowVert(vertex,object,True,flatShadeNorm) - else: - vertex = shadowVert(vertex,object,False,flatShadeNorm) - - if vno: - vertex.no = vno - - - #Check to see if this vertex has been visited before. If not, add - if not indexhash.has_key(vertex.index): - if uvok: - newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) - else: - newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) - - indexhash[vertex.index] = [newvdesc] - self.vertex_lst.append(newvdesc) - self.nextvindex = self.nextvindex + 1 - return newvdesc.fltindex - - else: - desclist = indexhash[vertex.index] - if uvok: - faceu = face.uv[vfindex][0] - facev = face.uv[vfindex][1] - else: - faceu = 0.0 - facev = 0.0 - for vdesc in desclist: - if\ - abs(vdesc.x - vertex.co[0]) > FLOAT_TOLERANCE or\ - abs(vdesc.y - vertex.co[1]) > FLOAT_TOLERANCE or\ - abs(vdesc.z - vertex.co[2]) > FLOAT_TOLERANCE or\ - abs(vdesc.nx - vertex.no[0]) > FLOAT_TOLERANCE or\ - abs(vdesc.ny - vertex.no[1]) > FLOAT_TOLERANCE or\ - abs(vdesc.nz - vertex.no[2]) > FLOAT_TOLERANCE or\ - vdesc.cindex != cindex or\ - abs(vdesc.u - faceu) > FLOAT_TOLERANCE or\ - abs(vdesc.v - facev) > FLOAT_TOLERANCE: - pass - else: - return vdesc.fltindex - - #if we get this far, we didnt find a match. Add a new one and return - if uvok: - newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) - else: - newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) - indexhash[vertex.index].append(newvdesc) - self.vertex_lst.append(newvdesc) - self.nextvindex = self.nextvindex + 1 - return newvdesc.fltindex - - - def request_texture_index(self, image): - match = None - for i in xrange(len(self.texture_lst)): - if self.texture_lst[i] != image: - continue - match = i - break - if match != None: - return match - else: - self.texture_lst.append(image) - return len(self.texture_lst) - 1 - - def request_texture_filename(self, index): - return Blender.sys.expandpath(self.texture_lst[index].getFilename()) - - def texture_count(self): - return len(self.texture_lst) - - def request_material_index(self, desc): - match = None - for i in xrange(len(self.material_lst)): - if self.material_lst[i].diffuse != desc.diffuse: - continue - if self.material_lst[i].specular != desc.specular: - continue - if self.material_lst[i].ambient != desc.ambient: - continue - if self.material_lst[i].emissive != desc.emissive: - continue - if self.material_lst[i].shininess != desc.shininess: - continue - if self.material_lst[i].alpha != desc.alpha: - continue - match = i - break - - if match != None: - return i - else: - self.material_lst.append(desc) - return len(self.material_lst) - 1 - - def request_material_desc(self, index): - return self.material_lst[index] - - def material_count(self): - return len(self.material_lst) - - # Returns not actual index but one that includes intensity information. - # color_index = 127*intensity + 128*actual_index - def request_color_index(self, col): - r,g,b = tuple(col) - m = max(r, g, b) - if m > 0.0: - intensity = m / 1.0 - r = int(round(r/m * 255.0)) - g = int(round(g/m * 255.0)) - b = int(round(b/m * 255.0)) - brightest = [r, g, b] - else: - brightest = [255, 255, 255] - intensity = 0.0 - - match = None - for i in xrange(len(self.color_lst)): - if self.color_lst[i] != brightest: - continue - - match = i - break - - if match != None: - index = match - else: - length = len(self.color_lst) - if length <= 1024: - self.color_lst.append(brightest) - index = length - else: - if options.verbose >= 1: - print 'Warning: Exceeded max color limit.' - index = 0 - - color_index = int(round(127.0*intensity)) + 128*index - return color_index - - # Returns color from actual index. - def request_max_color(self, index): - return self.color_lst[index] - - def color_count(self): - return len(self.color_lst) - - def __init__(self): - #Vertex handling - self.vertex_lst = [] - self.nextvindex = 0 - self.namehash = dict() - - self.texture_lst = [] - self.material_lst = [] - self.color_lst = [[255, 255, 255]] - self.face_name = 0 - -class Node: - # Gathers info from blender needed for export. - # The =[0] is a trick to emulate c-like static function variables - # that are persistant between calls. - def blender_export(self, level=[0]): - if self.object: - if options.verbose >= 2: - print '\t' * level[0], self.name, self.object.type - level[0] += 1 - - self.children.reverse() - for child in self.children: - child.blender_export() - - level[0] -= 1 - - # Exports this node's info to file. - def write(self): - pass - - def write_matrix(self): - if self.matrix and not is_identity(self.matrix): - self.header.fw.write_short(49) # Matrix opcode - self.header.fw.write_ushort(68) # Length of record - for i in xrange(4): - for j in xrange(4): - self.header.fw.write_float(self.matrix[i][j]) - - def write_push(self): - self.header.fw.write_short(10) - self.header.fw.write_ushort(4) - - def write_pop(self): - self.header.fw.write_short(11) - self.header.fw.write_ushort(4) - - def write_push_extension(self): - self.header.fw.write_short(21) - self.header.fw.write_ushort(24) - self.header.fw.pad(18) - self.header.fw.write_ushort(0) - - def write_pop_extension(self): - self.header.fw.write_short(22) - self.header.fw.write_ushort(24) - self.header.fw.pad(18) - self.header.fw.write_ushort(0) - - def write_longid(self, name): - length = len(name) - if length >= 8: - self.header.fw.write_short(33) # Long ID opcode - self.header.fw.write_ushort(length+5) # Length of record - self.header.fw.write_string(name, length+1) # name + zero terminator - - def write_comment(self,comment): - length = len(comment) - if length >= 65535: - comment = comment[:65530] - length = len(comment) - - pad = (length % 4) - 1 - if pad < 0: - pad = None - reclength = length + 5 - else: - reclength = length + 5 + pad - - self.header.fw.write_short(31) # Comment Opcode - self.header.fw.write_ushort(reclength) # Length of record is 4 + comment length + null terminator + pad - self.header.fw.write_string(comment,length+1) # comment + zero terminator - if pad: - self.header.fw.pad(pad) # pad to multiple of 4 bytes - - # Initialization sets up basic tree structure. - def __init__(self, parent, header, object,props): - global options - - self.header = header - self.object = object - if object: - self.name = self.object.name - if not options.state['transform']: - oloc = Blender.Mathutils.Vector(object.getLocation('worldspace')) - vec = Blender.Mathutils.Vector(oloc[0] * options.state['scale'], oloc[1] * options.state['scale'], oloc[2] * options.state['scale']) #scale - self.matrix = self.object.getMatrix('worldspace') * Blender.Mathutils.TranslationMatrix(vec - oloc) - else: - self.matrix = self.object.getMatrix('localspace') #do matrix mult here. - self.props = props - self.child_objects = self.header.parenthash[object.name] - else: - self.name = 'no name' - self.matrix = None - self.props = None - self.child_objects = self.header.child_objects - - self.children = [] - self.parent = parent - if parent: - parent.children.append(self) - - # Spawn children. - for child in self.child_objects: - if(not child.restrictDisplay): - childprops = None - ftype = None - if not child.properties.has_key('FLT'): - if child.type == 'Empty': - if child.DupGroup: - childprops = FLTXRef.copy() - ftype = 63 - else: - childprops = FLTGroup.copy() - ftype = 2 - elif child.type == 'Mesh': - if self.header.childhash[child.name] or not child.parent: - childprops = FLTGroup.copy() - ftype = 2 - else: - childprops = FLTObject.copy() - ftype = 4 - - else: - childprops = dict() - for prop in child.properties['FLT']: - childprops[prop] = child.properties['FLT'][prop] - ftype = child.properties['FLT']['type'] - - if ftype in self.childtypes and ftype in alltypes: - Newnode = FLTNode(self,header,child,childprops,ftype) - if child.type == 'Mesh': - self.header.mnodes.append(Newnode) -class FaceDesc: - def __init__(self): - self.vertex_index_lst = [] - self.mface = None - self.texture_index = 65535 - self.material_index = 65535 - self.color_index = 127 - self.renderstyle = 0 - self.twoside = 0 - self.name = None #uses next FLT name if not set... fix resolution of conflicts! - self.billboard = 0 - - #Multi-Tex info. Dosn't include first UV Layer! - self.uvlayer = list() #list of list of tuples for UV coordinates. - self.images = list() #list of texture indices for seperate UV layers - self.mtex = list() - self.subface = None #can either be 'Push' or 'Pop' - -def edge_get_othervert(vert, edge): - if edge.v1 == vert: - return edge.v2 - elif edge.v2 == vert: - return edge.v1 - return None - -class FLTNode(Node): - def walkLoop(self, targetvert, startvert, startedge, edgelist, visited, vedges, closeloop): - loop = [targetvert] - - curvert = startvert - curedge = startedge - visited[curedge] = True - found = False - - while not found: - loop.append(curvert) - disk = vedges[curvert.index] - if not closeloop: - if len(disk) == 1: - visited[curedge] = True - break - else: - if len(disk) < 2: #what? - visited[curedge] = True - return None - - if disk[0] == curedge: - curedge = disk[1] - else: - curedge = disk[0] - if curedge.v1.index == curvert.index: - curvert = curedge.v2 - else: - curvert = curedge.v1 - - visited[curedge] = True - - if(curvert == targetvert): - found = True - - return loop - - def buildVertFaces(self,vertuse): - for vert in self.exportmesh.verts: - if vertuse[vert.index][0] == False and vertuse[vert.index][1] == 0: - face_desc = FaceDesc() - face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, vert, 0,0,0)) - face_desc.renderstyle = 3 - face_desc.color_index = 227 - self.face_lst.append(face_desc) - - def buildEdgeFaces(self,vertuse): - for edge in self.exportmesh.edges: - v1 = vertuse[edge.v1.index] - v2 = vertuse[edge.v2.index] - if v1[0] == False and v2[0] == False: - if v1[1] == 1 and v2[1] == 1: - face_desc = FaceDesc() - face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 1, 0,0)) - face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 2, 0,0)) - face_desc.renderstyle = 3 - face_desc.color_index = 227 - self.face_lst.append(face_desc) - - - def vertwalk(self, startvert, loop, disk, visited): - visited[startvert] = True - for edge in disk[startvert]: - othervert = edge_get_othervert(startvert, edge) - if not visited[othervert]: - loop.append(othervert) - self.vertwalk(othervert,loop,disk,visited) - - def buildOpenFacesNew(self, vertuse): - wireverts = list() - wiredges = list() - visited = dict() - disk = dict() - loops = list() - - for edge in self.exportmesh.edges: - v1 = vertuse[edge.v1.index] - v2 = vertuse[edge.v2.index] - if v1[0] == False and v2[0] == False: - if v1[1] < 3 and v2[1] < 3: - wireverts.append(edge.v1) - wireverts.append(edge.v2) - wiredges.append(edge) - - #build disk data - for vert in wireverts: - visited[vert] = False - disk[vert] = list() - for edge in wiredges: - disk[edge.v1].append(edge) - disk[edge.v2].append(edge) - - #first pass: do open faces - for vert in wireverts: - if not visited[vert] and vertuse[vert.index][1] == 1: - loop = list() - done = 0 - startvert = vert - while not done: - done = 1 - visited[startvert] = True - loop.append(startvert) - for edge in disk[startvert]: - othervert = edge_get_othervert(startvert, edge) - if not visited[othervert]: - done = 0 - startvert = othervert - break - if len(loop) > 2: loops.append( ('Open', loop) ) - for vert in wireverts: - if not visited[vert]: - loop = list() - done = 0 - startvert = vert - while not done: - done = 1 - visited[startvert] = True - loop.append(startvert) - for edge in disk[startvert]: - othervert = edge_get_othervert(startvert,edge) - if not visited[othervert]: - done = 0 - startvert = othervert - break - if len(loop) > 2: loops.append( ('closed', loop) ) - - #now go through the loops and append. - for l in loops: - (ftype, loop) = l - face_desc = FaceDesc() - for i,vert in enumerate(loop): - face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,loop,i,0,0)) - if ftype == 'closed': - face_desc.renderstyle = 2 - else: - face_desc.renderstyle = 3 - face_desc.color_index = 227 - self.face_lst.append(face_desc) - - - - def sortFLTFaces(self,a,b): - aindex = a.getProperty("FLT_ORIGINDEX") - bindex = b.getProperty("FLT_ORIGINDEX") - - if aindex > bindex: - return 1 - elif aindex < bindex: - return -1 - return 0 - - def buildNormFaces(self): - - global options - meshlayers = self.exportmesh.getUVLayerNames() - oldlayer = self.exportmesh.activeUVLayer - uvok = 0 - subfaceok = 0 - subfacelevel = 0 - - #special case - if self.exportmesh.faceUV and len(meshlayers) == 1: - uvok = 1 - elif self.exportmesh.faceUV and tex_layers[0] in meshlayers: - self.exportmesh.activeUVLayer = tex_layers[0] - uvok = 1 - - #Sort faces according to the subfaces/FLT indices - if "FLT_ORIGINDEX" in self.exportmesh.faces.properties and "FLT_SFLEVEL" in self.exportmesh.faces.properties: - exportfaces = list() - for face in self.exportmesh.faces: - exportfaces.append(face) - exportfaces.sort(self.sortFLTFaces) - subfaceok = 1 - else: - exportfaces = self.exportmesh.faces - - # Faces described as lists of indices into the GRR's vertex_lst. - for face in exportfaces: - descs = list() - #first we export the face as normal - index_lst = [] - face_v = face.verts - for i, v in enumerate(face_v): - index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,face,i,uvok,0)) - face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - face_desc.mface = face - descs.append(face_desc) - - #deal with subfaces - if subfaceok: - fsflevel = face.getProperty("FLT_SFLEVEL") - for face_desc in descs: - if fsflevel > subfacelevel: - face_desc.subface = 'Push' - subfacelevel = fsflevel - elif fsflevel < subfacelevel: - face_desc.subface = 'Pop' - subfacelevel = fsflevel - - - if uvok and (face.mode & Blender.Mesh.FaceModes.TWOSIDE): - face_desc.renderstyle = 1 - for face_desc in descs: - if "FLT_COL" in self.exportmesh.faces.properties: - color_index = face.getProperty("FLT_COL") -# if(color_index < 127): -# color_index = 127 #sanity check for face color indices - if(color_index == 0): - color_index = 127 - face_desc.color_index = color_index - else: - face_desc.color_index = 127 - if "FLT_ID" in self.exportmesh.faces.properties: - face_desc.name = face.getProperty("FLT_ID") #need better solution than this. - - if uvok and face.mode & Blender.Mesh.FaceModes["BILLBOARD"]: - face_desc.billboard = 1 - - self.face_lst.append(face_desc) - if uvok: - self.exportmesh.activeUVLayer = oldlayer - - def buildTexData(self): - - meshlayers = self.exportmesh.getUVLayerNames() - oldlayer = self.exportmesh.activeUVLayer - uvok = 0 - - if self.exportmesh.faceUV and len(meshlayers) == 1: - uvok = 1 - if self.exportmesh.faceUV and tex_layers[0] in meshlayers: - self.exportmesh.activeUVLayer = tex_layers[0] - uvok = 1 - - if uvok: - #do base layer. UVs have been stored on vertices directly already. - for i, face in enumerate(self.face_lst): - if face.mface: - mface = face.mface - image = mface.image - if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: - index = self.header.GRR.request_texture_index(image) - else: - index = -1 - face.texture_index = index - - for i, face in enumerate(self.face_lst): - if face.mface: - mface_v = face.mface.v - for v in mface_v: - face.uvlayer.append([]) - - for layername in tex_layers[1:]: - if layername in meshlayers: - self.exportmesh.activeUVLayer=layername - for i, face in enumerate(self.face_lst): - if face.mface: - - face.mtex.append(layername) - mface = face.mface - mface_v = mface.v - image = mface.image - - if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: - index = self.header.GRR.request_texture_index(image) - face.images.append(index) - else: - face.images.append(-1) - - for j, v in enumerate(mface_v): - face.uvlayer[j].append(tuple(mface.uv[j])) - if uvok: - self.exportmesh.activeUVLayer = oldlayer - def blender_export(self): - global options - Node.blender_export(self) - if self.opcode == 111: - self.exportmesh = Blender.Mesh.New() - self.exportmesh.getFromObject(self.object.name) - - for vert in self.exportmesh.verts: - if not options.state['transform']: - vec = vert.co - vec = Blender.Mathutils.Vector(vec[0] * options.state['scale'], vec[1] * options.state['scale'], vec[2] * options.state['scale']) #scale - vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) - - if options.state['scale'] != 1.0: - vert.co = vert.co * options.state['scale'] - - if("FLT_VCOL") in self.mesh.verts.properties: - for v in self.exportmesh.verts: - self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,v,0,0,v.getProperty("FLT_VCOL"))) - else: - for v in self.mesh.verts: - self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.mesh,v,0,0,127)) - - - - elif self.mesh: - orig_mesh = self.object.getData(mesh=True) - self.exportmesh = Blender.Mesh.New() - default = None - - - if options.state['export_shading']: - mods = self.object.modifiers - hasedsplit = False - for mod in mods: - if mod.type == Blender.Modifier.Types.EDGESPLIT: - hasedsplit = True - break - if not hasedsplit: - default = mods.append(Modifier.Types.EDGESPLIT) - default[Modifier.Settings.EDGESPLIT_ANGLE] = options.state['shading_default'] - default[Modifier.Settings.EDGESPLIT_FROM_ANGLE] = True - default[Modifier.Settings.EDGESPLIT_FROM_SHARP] = False - self.object.makeDisplayList() - - self.exportmesh.getFromObject(self.object.name) - - #recalculate vertex positions - for vert in self.exportmesh.verts: - if not options.state['transform']: - vec = vert.co - vec = Blender.Mathutils.Vector(vec[0] * options.state['scale'], vec[1] * options.state['scale'], vec[2] * options.state['scale']) #scale - vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) - - if options.state['scale'] != 1.0: - vert.co = vert.co * options.state['scale'] - - flipped = self.object.getMatrix('worldspace').determinant() - - if not options.state['transform']: - self.exportmesh.calcNormals() - - - if default: - #remove modifier from list - mods.remove(default) - self.object.makeDisplayList() - - #build some adjacency data - vertuse = list() - wiredges = list() - openends = list() - for v in self.exportmesh.verts: - vertuse.append([False,0]) - - #build face incidence data - for face in self.exportmesh.faces: - for i, v in enumerate(face.verts): - vertuse[v.index][0] = True - - for edge in self.exportmesh.edges: #count valance - vertuse[edge.v1.index][1] = vertuse[edge.v1.index][1] + 1 - vertuse[edge.v2.index][1] = vertuse[edge.v2.index][1] + 1 - - #create all face types - self.buildVertFaces(vertuse) - self.buildEdgeFaces(vertuse) - self.buildOpenFacesNew(vertuse) - self.buildNormFaces() - self.buildTexData() - - if not options.state['transform']: - if flipped < 0: - for vdesc in self.header.GRR.vertex_lst: - vdesc.accum = 0 - for face in self.face_lst: - face.vertex_index_lst.reverse() - for vert in face.vertex_index_lst: - self.header.GRR.vertex_lst[vert].accum = 1 - - for vdesc in self.header.GRR.vertex_lst: - if vdesc.accum: - vdesc.nx = vdesc.nx * -1 - vdesc.ny = vdesc.ny * -1 - vdesc.nz = vdesc.nz * -1 - - - def write_faces(self): - sublevel = 0 - for face_desc in self.face_lst: - if face_desc.name: - face_name = face_desc.name - else: - face_name = self.header.GRR.new_face_name() - - #grab the alpha value. - alpha = 0 - if face_desc.texture_index > -1: - try: - typestring = os.path.splitext(self.header.GRR.texture_lst[face_desc.texture_index].getFilename())[1] - if typestring == '.inta' or typestring == '.rgba': - alpha = 1 - except: - pass - - if not alpha: - for index in face_desc.images: - try: - typestring = os.path.splitext(self.header.GRR.texture_lst[index].getFilename())[1] - if typestring == '.inta' or typestring == '.rgba': - alpha = 1 - except: - pass - - if face_desc.billboard: - alpha = 2 - - if face_desc.subface: - if face_desc.subface == 'Push': - self.header.fw.write_short(19) - self.header.fw.write_ushort(4) - sublevel += 1 - else: - self.header.fw.write_short(20) - self.header.fw.write_ushort(4) - sublevel -= 1 - self.header.fw.write_short(5) # Face opcode - self.header.fw.write_ushort(80) # Length of record - self.header.fw.write_string(face_name, 8) # ASCII ID - self.header.fw.write_int(-1) # IR color code - self.header.fw.write_short(0) # Relative priority - self.header.fw.write_char(face_desc.renderstyle) # Draw type - self.header.fw.write_char(0) # Draw textured white. - self.header.fw.write_ushort(0) # Color name index - self.header.fw.write_ushort(0) # Alt color name index - self.header.fw.write_char(0) # Reserved - self.header.fw.write_char(alpha) # Template - self.header.fw.write_short(-1) # Detail tex pat index - if face_desc.texture_index == -1: - self.header.fw.write_ushort(65535) - else: - self.header.fw.write_ushort(face_desc.texture_index) # Tex pattern index - if face_desc.material_index == -1: - self.header.fw.write_ushort(65535) - else: - self.header.fw.write_ushort(face_desc.material_index) # material index - self.header.fw.write_short(0) # SMC code - self.header.fw.write_short(0) # Feature code - self.header.fw.write_int(0) # IR material code - self.header.fw.write_ushort(0) # transparency 0 = opaque - self.header.fw.write_uchar(0) # LOD generation control - self.header.fw.write_uchar(0) # line style index - self.header.fw.write_int(0) # Flags - self.header.fw.write_uchar(2) # Light mode - #self.header.fw.write_uchar(3) # Light mode - - self.header.fw.pad(7) # Reserved - self.header.fw.write_uint(0) # Packed color - self.header.fw.write_uint(0) # Packed alt color - self.header.fw.write_short(-1) # Tex map index - self.header.fw.write_short(0) # Reserved - self.header.fw.write_uint(face_desc.color_index) # Color index - self.header.fw.write_uint(127) # Alt color index - self.header.fw.write_short(0) # Reserved - self.header.fw.write_short(-1) # Shader index - - self.write_longid(face_name) - - - #Write Multitexture field if appropriate - mtex = len(face_desc.mtex) - if mtex: - uvmask = 0 - for layername in face_desc.mtex: - mask = mtexmasks[tex_layers.index(layername)-1] - uvmask |= mask - self.header.fw.write_ushort(52) # MultiTexture Opcode - self.header.fw.write_ushort(8 + (mtex * 8)) # Length - self.header.fw.write_uint(uvmask) # UV mask - for i in xrange(mtex): - if face_desc.images[i] == -1: - self.header.fw.write_ushort(65535) - else: - self.header.fw.write_ushort(face_desc.images[i]) # Tex pattern index - self.header.fw.write_ushort(0) # Tex effect - self.header.fw.write_ushort(0) # Tex Mapping index - self.header.fw.write_ushort(0) # Tex data. User defined - - self.write_push() - - # Vertex list record - self.header.fw.write_short(72) # Vertex list opcode - num_verts = len(face_desc.vertex_index_lst) - self.header.fw.write_ushort(4*num_verts+4) # Length of record - - for vert_index in face_desc.vertex_index_lst: - # Offset into vertex palette - self.header.fw.write_int(vert_index*64+8) - - #UV list record - if mtex: - #length = 8 + (numverts * multitex * 8) - self.header.fw.write_ushort(53) # UV List Ocode - self.header.fw.write_ushort(8 + (num_verts*mtex*8)) # Record Length - self.header.fw.write_uint(uvmask) # UV mask - for i, vert_index in enumerate(face_desc.vertex_index_lst): - for uv in face_desc.uvlayer[i]: - self.header.fw.write_float(uv[0]) #U coordinate - self.header.fw.write_float(uv[1]) #V coordinate - self.write_pop() - #clean up faces at the end of meshes.... - if sublevel: - self.header.fw.write_short(20) - self.header.fw.write_ushort(4) - - def write_lps(self): - # Vertex list record - self.write_push() - self.header.fw.write_short(72) # Vertex list opcode - num_verts = len(self.vert_lst) - self.header.fw.write_ushort(4*num_verts+4) # Length of record - - for vert_index in self.vert_lst: - # Offset into vertex palette - self.header.fw.write_int(vert_index*64+8) - self.write_pop() - def write(self): - self.header.fw.write_short(self.opcode) - self.header.fw.write_ushort(recordlen[self.opcode]) - exportdict = FLT_Records[self.opcode].copy() - if self.object: - self.props['3t8!id'] = self.object.name[:7] - for key in exportdict.keys(): - if self.props.has_key(key): - exportdict[key] = self.props[key] - - if self.opcode == 63 and options.state['externalspath']: - try: - exportdict['3t200!filename'] = os.path.join(options.state['externalspath'],self.object.DupGroup.name+'.flt').replace("\\", "/") - self.header.xrefnames.append(self.object.DupGroup.name) - except: - pass - - for key in records[self.opcode]: - (ftype,length,propname) = records[self.opcode][key] - write_prop(self.header.fw,ftype,exportdict[propname],length) - - if self.props.has_key('comment'): - self.write_comment(self.props['comment']) - - if self.object and self.object.properties.has_key('FLT') and self.object.properties['FLT'].has_key('EXT'): - datalen = len(self.object.properties['FLT']['EXT']['data']) - self.write_push_extension() - self.header.fw.write_short(100) - self.header.fw.write_ushort(24 + datalen) - for key in records[100]: - (ftype,length,propname) = records[100][key] - write_prop(self.header.fw,ftype,self.object.properties['FLT']['EXT'][propname],length) - #write extension data - for i in xrange(datalen): - self.header.fw.write_uchar(struct.unpack('>B', struct.pack('>B', self.object.properties['FLT']['EXT']['data'][i]))[0]) - self.write_pop_extension() - - - self.write_longid(self.name) #fix this! - - if options.state['transform'] or self.opcode == 63: - #writing transform matrix.... - self.write_matrix() - - if self.opcode == 111: - self.write_lps() - elif self.face_lst != [] or self.children: - self.write_push() - if self.face_lst != []: - #self.write_push() - self.write_faces() - #self.write_pop() - - if self.children: - #self.write_push() - for child in self.children: - child.write() - #self.write_pop() - self.write_pop() - - def __init__(self, parent, header, object,props,ftype): - self.opcode = ftype #both these next two lines need to be in the node class.... - self.childtypes = childtypes[self.opcode] - Node.__init__(self, parent, header, object,props) - self.face_lst = [] - self.vert_lst = [] #for light points. - self.mesh = None - self.uvlayer = 0 - self.flipx = False - self.flipy = False - self.flipz = False - - - if self.object.type == 'Mesh': - self.mesh = self.object.getData(mesh=True) - if(self.mesh.faceUV): - self.uvLayer = len(self.mesh.getUVLayerNames()) - -class Database(Node): - def write_header(self): - if options.verbose >= 2: - print 'Writing header.' - self.fw.write_short(1) # Header opcode - self.fw.write_ushort(324) # Length of record - self.fw.write_string('db', 8) # ASCII ID - self.fw.write_int(1600) # Revision Number - self.fw.pad(44) - self.fw.write_short(1) # Unit multiplier. - self.fw.write_char(0) # Units, 0 = meters - self.fw.write_char(0) # texwhite on new faces 0 = false - self.fw.write_uint(0x80000000) # misc flags set to saving vertex normals - self.fw.pad(24) - self.fw.write_int(0) # projection type, 0 = flat earth - self.fw.pad(30) - self.fw.write_short(1) # double precision - self.fw.write_int(100) # database origin type - self.fw.pad(88) - try: - self.fw.write_double(self.header.scene.properties['FLT']['origin lat']) #database origin lattitude - except: - self.fw.write_double(0) - try: - self.fw.write_double(self.header.scene.properties['FLT']['origin lon']) #database origin longitude - except: - self.fw.write_double(0) - self.fw.pad(32) - self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 - - self.fw.pad(52) - - def write_vert_pal(self): - if options.verbose >= 2: - print 'Writing vertex palette.' - # Write record for vertex palette - self.fw.write_short(67) # Vertex palette opcode. - self.fw.write_short(8) # Length of record - self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. - # Write records for individual vertices. - for i in xrange(self.GRR.vertex_count()): - desc = self.GRR.request_vertex_desc(i) - self.fw.write_short(70) # Vertex with color normal and uv opcode. - self.fw.write_ushort(64) # Length of record - self.fw.write_ushort(0) # Color name index - self.fw.write_short(1 << 14) # Frozen Normal - self.fw.write_double(desc.x) - self.fw.write_double(desc.y) - self.fw.write_double(desc.z) - self.fw.write_float(desc.nx) - self.fw.write_float(desc.ny) - self.fw.write_float(desc.nz) - self.fw.write_float(desc.u) - self.fw.write_float(desc.v) - self.fw.pad(4) - self.fw.write_uint(desc.cindex) - self.fw.pad(4) - - def write_tex_pal(self): - if options.verbose >= 2: - print 'Writing texture palette.' - # Write record for texture palette - for i, img in enumerate(self.GRR.texture_lst): - filename = tex_files[img.name] - self.fw.write_short(64) # Texture palette opcode. - self.fw.write_short(216) # Length of record - self.fw.write_string(filename, 200) # Filename - self.fw.write_int(i) # Texture index - self.fw.write_int(0) # X - self.fw.write_int(0) # Y - - def write_mat_pal(self): - if options.verbose >= 2: - print 'Writing material palette.' - for i in xrange(self.GRR.material_count()): - desc = self.GRR.request_material_desc(i) - self.fw.write_short(113) # Material palette opcode. - self.fw.write_short(84) # Length of record - self.fw.write_int(i) # Material index - self.fw.write_string(desc.name, 12) # Material name - self.fw.write_uint(0x80000000) # Flags - self.fw.write_float(desc.ambient[0]) # Ambient color. - self.fw.write_float(desc.ambient[1]) # Ambient color. - self.fw.write_float(desc.ambient[2]) # Ambient color. - self.fw.write_float(desc.diffuse[0]) # Diffuse color. - self.fw.write_float(desc.diffuse[1]) # Diffuse color. - self.fw.write_float(desc.diffuse[2]) # Diffuse color. - self.fw.write_float(desc.specular[0]) # Specular color. - self.fw.write_float(desc.specular[1]) # Specular color. - self.fw.write_float(desc.specular[2]) # Specular color. - self.fw.write_float(desc.emissive[0]) # Emissive color. - self.fw.write_float(desc.emissive[1]) # Emissive color. - self.fw.write_float(desc.emissive[2]) # Emissive color. - self.fw.write_float(desc.shininess) - self.fw.write_float(desc.alpha) - self.fw.write_int(0) # Reserved - - def write_col_pal(self): - if options.verbose >= 2: - print 'Writing color palette.' - self.fw.write_short(32) # Color palette opcode. - self.fw.write_short(4228) # Length of record - self.fw.pad(128) - try: - cpalette = self.scene.properties['FLT']['Color Palette'] - except: - cpalette = defaultp.pal - count = len(cpalette) - for i in xrange(count): - color = struct.unpack('>BBBB',struct.pack('>i',cpalette[i])) - self.fw.write_uchar(color[3]) # alpha - self.fw.write_uchar(color[2]) # b - self.fw.write_uchar(color[1]) # g - self.fw.write_uchar(color[0]) # r - self.fw.pad(max(4096-count*4, 0)) - - def write(self): - self.write_header() - self.write_vert_pal() - self.write_tex_pal() - self.write_mat_pal() - self.write_col_pal() - - self.write_push() - - for child in self.children: - child.write() - self.write_pop() - - def export_textures(self,texturepath): - for i in xrange(self.GRR.texture_count()): - texture = self.GRR.texture_lst[i] - - if options.state['copytex']: - filename = os.path.normpath(os.path.join(options.state['texturespath'], os.path.basename(self.GRR.request_texture_filename(i)))) - else: - filename = os.path.normpath(self.GRR.request_texture_filename(i)) - - tex_files[texture.name] = filename - - def blender_export(self): - Node.blender_export(self) - self.export_textures(self) - return self.xrefnames - def __init__(self, scene, fw): - self.fw = fw - self.opcode = 1 - self.childtypes = [73,14,2,63] - self.scene = scene - self.childhash = dict() - self.parenthash = dict() - self.child_objects = list() - self.mnodes = list() - self.xrefnames = list() - for i in self.scene.objects: - self.parenthash[i.name] = list() - self.childhash[i.name] = False - for i in self.scene.objects: - if i.parent: - self.childhash[i.parent.name] = True - self.parenthash[i.parent.name].append(i) - else: - self.child_objects.append(i) - - self.GRR = GlobalResourceRepository() - Node.__init__(self, None, self, None,None) - -def write_attribute_files(): - for imgname in tex_files: - blentex = Blender.Image.Get(imgname) - exportdict = FLT_Records['Image'].copy() - - if blentex.properties.has_key('FLT'): - for key in exportdict.keys(): - if blentex.properties.has_key(key): - exportdict[key] = blentex.properties['FLT'][key] - - # ClampX/Y override - if blentex.clampX: - exportdict['11i!WrapU'] = 1 - if blentex.clampY: - exportdict['12i!WrapV'] = 1 - - exportdict['16i!Enviorment'] = 0 - - # File type - typecode = 0 - try: - typestring = os.path.splitext(blentex.getFilename())[1] - - if typestring == '.rgba': - typecode = 5 - elif typestring == '.rgb': - typecode = 4 - elif typestring == '.inta': - typecode = 3 - elif typestring == '.int': - typecode = 2 - except: - pass - - exportdict['7i!File Format'] = typecode - - fw = FltOut(tex_files[imgname] + '.attr') - size = blentex.getSize() - fw.write_int(size[0]) - fw.write_int(size[1]) - for key in records['Image']: - (ftype,length,propname) = records['Image'][key] - write_prop(fw,ftype,exportdict[propname],length) - fw.close_file() - -#globals used by the scene export function -exportlevel = None -xrefsdone = None - -def dbexport_internal(scene): - global exportlevel - global xrefsdone - global options - - if exportlevel == 0 or not options.state['externalspath']: - fname = os.path.join(options.state['basepath'],scene.name + '.flt') - else: - fname = os.path.join(options.state['externalspath'],scene.name + '.flt') - - fw = FltOut(fname) - db = Database(scene,fw) - - if options.verbose >= 1: - print 'Pass 1: Exporting ', scene.name,'.flt from Blender.\n' - - xreflist = db.blender_export() - if options.verbose >= 1: - print 'Pass 2: Writing %s\n' % fname - db.write() - fw.close_file() - - if options.state['doxrefs']: - for xname in xreflist: - try: - xrefscene = Blender.Scene.Get(xname) - except: - xrefscene = None - if xrefscene and xname not in xrefsdone: - xrefsdone.append(xname) - exportlevel+=1 - dbexport_internal(xrefscene) - exportlevel-=1 - return fname -#main database export function -def dbexport(): - global exportlevel - global xrefsdone - exportlevel = 0 - xrefsdone = list() - - Blender.Window.WaitCursor(True) - time1 = Blender.sys.time() # Start timing - - if options.verbose >= 1: - print '\nOpenFlight Exporter' - print 'Version:', __version__ - print 'Author: Greg MacDonald, Geoffrey Bantle' - print __url__[2] - print - - fname = dbexport_internal(Blender.Scene.GetCurrent()) - if options.verbose >=1: - print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) - Blender.Window.WaitCursor(False) - - #optional: Copy textures - if options.state['copytex']: - for imgname in tex_files: - #Check to see if texture exists in target directory - if not os.path.exists(tex_files[imgname]): - #Get original Blender file name - origpath = Blender.sys.expandpath(Blender.Image.Get(imgname).getFilename()) - #copy original to new - if os.path.exists(origpath): - shutil.copyfile(origpath,tex_files[imgname]) - - #optional: Write attribute files - if options.state['attrib']: - write_attribute_files() - - if options.state['xapp']: - cmd= options.state['xappath'] + " " + fname - status = os.system(cmd) - - -#Begin UI code -FLTExport = None -FLTClose = None -FLTLabel = None - -FLTBaseLabel = None -FLTTextureLabel = None -FLTXRefLabel = None - -FLTBaseString = None -FLTTextureString = None -FLTXRefString = None - -FLTBasePath = None -FLTTexturePath = None -FLTXRefPath = None - -FLTShadeExport = None -FLTShadeDefault = None - -FLTCopyTex = None -FLTDoXRef = None -FLTGlobal = None - -FLTScale = None - -FLTXAPP = None -FLTXAPPath = None -FLTXAPPString = None -FLTXAPPLabel = None -FLTXAPPChooser = None - -FLTAttrib = None - - -FLTWarn = None - -def setshadingangle(ID,val): - global options - options.state['shading_default'] = val -def setBpath(fname): - global options - options.state['basepath'] = os.path.dirname(fname) - #update xref and textures path too.... - if(os.path.exists(os.path.join(options.state['basepath'],'externals'))): - options.state['externalspath'] = os.path.join(options.state['basepath'],'externals') - if(os.path.exists(os.path.join(options.state['basepath'],'textures'))): - options.state['texturespath'] = os.path.join(options.state['basepath'],'textures') -def setexportscale(ID,val): - global options - options.state['scale'] = val - -def setTpath(fname): - global options - options.state['texturespath'] = os.path.dirname(fname) -def setXpath(fname): - global options - options.state['externalspath'] = os.path.dirname(fname) -def setXApath(fname): - global options - options.state['xappath'] = fname -def event(evt, val): - x = 1 -def but_event(evt): - global options - - global FLTExport - global FLTClose - global FLTLabel - - global FLTBaseLabel - global FLTTextureLabel - global FLTXRefLabel - - global FLTBaseString - global FLTTextureString - global FLTXRefString - - global FLTBasePath - global FLTTexturePath - global FLTXRefPath - - global FLTShadeExport - global FLTShadeDefault - - global FLTCopyTex - global FLTDoXRef - global FLTGlobal - - global FLTScale - - - global FLTXAPP - global FLTXAPPath - global FLTXAPPString - global FLTXAPPLabel - global FLTXAPPChooser - - global FLTAttrib - - global FLTWarn - - #choose base path for export - if evt == 4: - Blender.Window.FileSelector(setBpath, "DB Root", options.state['basepath']) - - #choose XREF path - if evt == 6: - Blender.Window.FileSelector(setXpath,"DB Externals",options.state['externalspath']) - - #choose texture path - if evt == 8: - Blender.Window.FileSelector(setTpath,"DB Textures",options.state['texturespath']) - - #export shading toggle - if evt == 9: - options.state['export_shading'] = FLTShadeExport.val - #export Textures - if evt == 11: - options.state['copytex']= FLTCopyTex.val - #export XRefs - if evt == 13: - options.state['doxrefs'] = FLTDoXRef.val - #export Transforms - if evt == 12: - options.state['transform'] = FLTGlobal.val - - if evt == 14: - options.state['xapp'] = FLTXAPP.val - if evt == 16: - Blender.Window.FileSelector(setXApath,"External Application",options.state['xappath']) - if evt == 20: - options.state['attrib'] = FLTAttrib.val - - #Export DB - if evt == 1: - try: - dbexport() - except Exception, inst: - import traceback - FLTWarn = Draw.PupBlock("Export Error", ["See console for output!"]) - traceback.print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback) - - #exit - if evt == 2: - Draw.Exit() - - options.write_state() - -from Blender.BGL import * -from Blender import Draw -def gui(): - - global options - - global FLTExport - global FLTClose - global FLTLabel - - global FLTBaseLabel - global FLTTextureLabel - global FLTXRefLabel - - global FLTBaseString - global FLTTextureString - global FLTXRefString - - global FLTBasePath - global FLTTexturePath - global FLTXRefPath - - global FLTShadeExport - global FLTShadeDefault - - global FLTCopyTex - global FLTDoXRef - global FLTGlobal - - global FLTScale - - global FLTXAPP - global FLTXAPPath - global FLTXAPPString - global FLTXAPPLabel - global FLTXAPPChooser - - global FLTAttrib - - glClearColor(0.880,0.890,0.730,1.0 ) - glClear(GL_COLOR_BUFFER_BIT) - - areas = Blender.Window.GetScreenInfo() - curarea = Blender.Window.GetAreaID() - curRect = None - - for area in areas: - if area['id'] == curarea: - curRect = area['vertices'] - break - - width = curRect[2] - curRect[0] - height = curRect[3] - curRect[1] - #draw from top to bottom.... - cx = 50 - #Draw Title Bar... - #glRasterPos2d(cx, curRect[3]-100) - #FLTLabel = Draw.Text("FLT Exporter V2.0",'large') - cy = height - 80 - - FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20) - FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.state['basepath'],255,"Folder to export to") - FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") - - cy = cy-40 - - #externals path - FLTXRefLabel = Draw.Label("XRefs:",cx,cy,100,20) - FLTXRefString = Draw.String("",5,cx+100,cy,300,20,options.state['externalspath'],255,"Folder for external references") - FLTXRefChooser = Draw.PushButton("...",6,cx+400,cy,20,20,"Choose Folder") - cy = cy-40 - #Textures path - FLTTextureLabel = Draw.Label("Textures:",cx,cy,100,20) - FLTTextureString = Draw.String("",7,cx+100,cy,300,20,options.state['texturespath'],255,"Folder for texture files") - FLTTextureChooser = Draw.PushButton("...",8,cx+400,cy,20,20,"Choose Folder") - cy=cy-40 - #External application path - FLTXAPPLabel = Draw.Label("XApp:",cx,cy,100,20) - FLTXAPPString = Draw.String("",15,cx+100,cy,300,20,options.state['xappath'],255,"External application to launch when done") - FLTXAPPChooser = Draw.PushButton("...",16,cx+400, cy,20,20,"Choose Folder") - - cy = cy-60 - #Shading Options - FLTShadeExport = Draw.Toggle("Default Shading",9,cx,cy,100,20,options.state['export_shading'],"Turn on export of custom shading") - FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.state['shading_default'],0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle) - - cy = cy-40 - FLTScale = Draw.Number("Export Scale",14,cx,cy,220,20,options.state['scale'],0.0,100.0,"Export scaling factor",setexportscale) - - cy = cy-40 - #misc Options - FLTCopyTex = Draw.Toggle("Copy Textures",11,cx,cy,220,20,options.state['copytex'],"Copy textures to folder indicated above") - cy = cy-40 - FLTGlobal = Draw.Toggle("Export Transforms",12,cx,cy,220,20,options.state['transform'],"If unchecked, Global coordinates are used (recommended)") - cy = cy-40 - FLTDoXRef = Draw.Toggle("Export XRefs", 13,cx,cy,220,20,options.state['doxrefs'],"Export External references (only those below current scene!)") - cy = cy-40 - FLTXAPP = Draw.Toggle("Launch External App", 14, cx,cy,220,20,options.state['xapp'],"Launch External Application on export") - cy = cy-40 - FLTAttrib = Draw.Toggle("Write Attribute Files", 20, cx, cy, 220,20,options.state['attrib'], "Write Texture Attribute files") - #FLTXAPPATH = Draw.String("",15,cx,cy,300,20,options.xappath,255,"External application path") - - - #Draw export/close buttons - FLTExport = Draw.PushButton("Export",1,cx,20,100,20,"Export to FLT") - FLTClose = Draw.PushButton("Close", 2, cx+120,20,100,20,"Close window") - - -Draw.Register(gui,event,but_event) \ No newline at end of file diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py deleted file mode 100644 index 4a9b86c45d2..00000000000 --- a/release/scripts/flt_filewalker.py +++ /dev/null @@ -1,286 +0,0 @@ -#!BPY - -# flt_filewalker.py is an utility module for OpenFlight IO scripts for blender. -# Copyright (C) 2005 Greg MacDonald -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -__bpydoc__ ="""\ -File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. -""" - -import Blender -from struct import * -import re - -class FltIn: - def __init__(self, filename): - self.file = open(filename, 'rb') - self.position = 0 - self.next_position = 100000 - self.opcode = 0 - self.length = 0 - self.level = 0 - self.repeat = False # Repeat the last record. - - def begin_record(self): - if self.repeat == True: - self.repeat = False - else: - self.position += self.length - try: - self.file.seek(self.position) - input = self.file.read(4) - except: - print 'Parse Error!' - return False - - if not input: - self.close_file() - return False - - self.opcode = unpack('>h', input[:2])[0] - self.length = unpack('>H', input[-2:])[0] - - self.next_position = self.position + self.length - - return True - - def repeat_record(self): - self.repeat = True - - def get_opcode(self): - return self.opcode - - def get_level(self): - return self.level - - def up_level(self): - self.level += 1 - - def down_level(self): - self.level -= 1 - - def read_string(self, length): - s = '' - if self.file.tell() + length <= self.next_position: - start = self.file.tell() - for i in xrange(length): - char = self.file.read(1) - if char == '\x00': - break - s = s + char - - self.file.seek(start+length) -# else: -# print 'Warning: string truncated' - - return s - - def read_int(self): - if self.file.tell() + 4 <= self.next_position: - return unpack('>i', self.file.read(4))[0] - else: - #print 'Warning: int truncated' - return 0 - - def read_uint(self): - if self.file.tell() + 4 <= self.next_position: - return unpack('>I', self.file.read(4))[0] - else: - #print 'Warning: uint truncated' - return 0 - - def read_double(self): - if self.file.tell() + 8 <= self.next_position: - return unpack('>d', self.file.read(8))[0] - else: - #print 'Warning: double truncated' - return 0.0 - - def read_float(self): - if self.file.tell() + 4 <= self.next_position: - return unpack('>f', self.file.read(4))[0] - else: - #print 'Warning: float truncated' - return 0.0 - - def read_ushort(self): - if self.file.tell() + 2 <= self.next_position: - return unpack('>H', self.file.read(2))[0] - else: - #print 'Warning: ushort truncated' - return 0 - - def read_short(self): - if self.file.tell() + 2 <= self.next_position: - return unpack('>h', self.file.read(2))[0] - else: - #print 'Warning: short trunated' - return 0 - - def read_uchar(self): - if self.file.tell() + 1 <= self.next_position: - return unpack('>B', self.file.read(1))[0] - else: - #print 'Warning: uchar truncated' - return 0 - - def read_char(self): - if self.file.tell() + 1 <= self.next_position: - return unpack('>b', self.file.read(1))[0] - else: - #print 'Warning: char truncated' - return 0 - - def read_ahead(self, i): - if self.file.tell() + i <= self.next_position: - self.file.seek(i, 1) -# else: -# print 'Warning: attempt to seek past record' - - def get_length(self): - return self.length - - def close_file(self): - self.file.close() - -class FltOut: - # Length includes terminating null - def write_string(self, string, length): - if len(string) > length - 1: - str_len = length - 1 - else: - str_len = len(string) - - pad_len = length - str_len - - self.file.write(string[:str_len]) - - self.pad(pad_len) - - def write_int(self, a): - self.file.write( pack('>i', a) ) - - def write_uint(self, a): - self.file.write( pack('>I', a) ) - - def write_double(self, a): - self.file.write( pack('>d', a) ) - - def write_float(self, a): - self.file.write( pack('>f', a) ) - - def write_ushort(self, a): - self.file.write( pack('>H', a) ) - - def write_short(self, a): - self.file.write( pack('>h', a) ) - - def write_uchar(self, a): - self.file.write( pack('>B', a) ) - - def write_char(self, a): - self.file.write( pack('>b', a) ) - - def pad(self, reps): - for i in xrange(reps): - self.file.write('\x00') - - def close_file(self): - self.file.close() - - def __init__(self, filename): - self.file = open(filename, 'wb') - self.filename = filename - - -class FileFinder: - def add_file_to_search_path(self, filename): - dir = Blender.sys.dirname(filename) - if dir != None and dir != '': - self.search_dirs.append(dir) - - def strip_path(self, full_path): - # One of my flt files had a windows path with unix seperation. Basename - # returned the whole path + filename, which isn't expected. So my - # attempt to fix it is to replace all / or \ with the platform specific - # dir seperator. - # - # note: \\\\ is actually just one \ indirected twice, once for python - # then again for re.sub - if Blender.sys.sep == '\\': - full_path = re.sub('/', '\\\\', full_path) - elif Blender.sys.sep == '/': - full_path = re.sub('\\\\', '/', full_path) - - filename = Blender.sys.basename(full_path) - return filename - - def find(self, full_path): - if full_path == '': - return None - - # Seperate out the path. - dirname = Blender.sys.dirname(full_path) - - # Try it first. - if Blender.sys.exists(full_path): - if not dirname in self.search_dirs: - self.search_dirs.append(dirname) - return full_path - - # Maybe it's relative. - for path in self.search_dirs: - rel_full_path = Blender.sys.join(path, full_path) - if Blender.sys.exists(rel_full_path): - return rel_full_path - - # Search previous directories that have worked. - filename = self.strip_path(full_path) - for path in self.search_dirs: - t = Blender.sys.join(path, filename) - if Blender.sys.exists(t): - return t - - # Ask user where it is. - self.user_input = Blender.Draw.PupStrInput(filename + "? ", '', 100) - #self.user_input = None - if self.user_input != None: - t = Blender.sys.join(self.user_input, filename) - if Blender.sys.exists(t): - user_dirname = Blender.sys.dirname(t) - if not user_dirname in self.search_dirs: - self.search_dirs.append(user_dirname) - return t - - # Couldn't find it. - return None - - def __init__(self): - self.user_input = '' - self.current_file = '' - self.search_dirs = [] - - dir = Blender.Get('texturesdir') - if dir != None and dir != '': - self.search_dirs.append(dir) - - dir = Blender.sys.dirname(Blender.Get('filename')) - if dir != None and dir != '': - print dir - self.search_dirs.append(dir) - \ No newline at end of file diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py deleted file mode 100644 index f8d31f7bb57..00000000000 --- a/release/scripts/flt_import.py +++ /dev/null @@ -1,2534 +0,0 @@ -#!BPY -""" Registration info for Blender menus: -Name: 'OpenFlight (.flt)...' -Blender: 245 -Group: 'Import' -Tip: 'Import OpenFlight (.flt)' -""" - - - -__author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle" -__version__ = "2.0 11/21/07" -__url__ = ("blender", "blenderartists.org", "Author's homepage, http://sourceforge.net/projects/blight/") -__bpydoc__ = """\ -This script imports OpenFlight files into Blender. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_fltss - -Note: This file is a grab-bag of old and new code. It needs some cleanup still. -""" - -# flt_import.py is an OpenFlight importer for blender. -# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -import Blender -import os -import BPyMesh -import BPyImage -import flt_filewalker -import flt_properties -import sys -reload(flt_properties) -from flt_properties import * - -#Globals. Should Clean these up and minimize their usage. - -typecodes = ['c','C','s','S','i','I','f','d','t'] -records = dict() - -FLTBaseLabel = None -FLTBaseString = None -FLTBaseChooser = None -FLTExport = None -FLTClose = None -FLTDoXRef = None -FLTScale = None -FLTShadeImport = None -FLTAttrib = None -FLTWarn = None - -Vector= Blender.Mathutils.Vector -FLOAT_TOLERANCE = 0.01 - -FF = flt_filewalker.FileFinder() -current_layer = 0x01 - -global_prefs = dict() -global_prefs['verbose']= 4 -global_prefs['get_texture'] = True -global_prefs['get_diffuse'] = True -global_prefs['get_specular'] = False -global_prefs['get_emissive'] = False -global_prefs['get_alpha'] = True -global_prefs['get_ambient'] = False -global_prefs['get_shininess'] = True -global_prefs['color_from_face'] = True -global_prefs['fltfile']= '' -global_prefs['smoothshading'] = 1 -global_prefs['doxrefs'] = 1 -global_prefs['scale'] = 1.0 -global_prefs['attrib'] = 0 -msg_once = False - -reg = Blender.Registry.GetKey('flt_import',1) -if reg: - for key in global_prefs: - if reg.has_key(key): - global_prefs[key] = reg[key] - - - -throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent. -do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] - -#Process FLT record definitions -for record in FLT_Records: - props = dict() - for prop in FLT_Records[record]: - position = '' - slice = 0 - (format,name) = prop.split('!') - for i in format: - if i not in typecodes: - position = position + i - slice = slice + 1 - else: - break - type = format[slice:] - length = type[1:] - if len(length) == 0: - length = 1 - else: - type = type[0] - length = int(length) - - props[int(position)] = (type,length,prop) - records[record] = props - -def col_to_gray(c): - return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] -class MaterialDesc: - # Was going to use int(f*1000.0) instead of round(f,3), but for some reason - # round produces better results, as in less dups. - def make_key(self): - key = list() - if global_prefs['get_texture']: - if self.tex0: - key.append(self.tex0.getName()) - else: - key.append(None) - - if global_prefs['get_alpha']: - key.append(round(self.alpha, 3)) - else: - key.append(None) - - if global_prefs['get_shininess']: - key.append(round(self.shininess, 3)) - else: - key.append(None) - - if global_prefs['get_emissive']: - key.append(round(self.emissive, 3)) - else: - key.append(None) - - if global_prefs['get_ambient']: - key.append(round(self.ambient, 3)) - else: - key.append(None) - - if global_prefs['get_specular']: - for n in self.specular: - key.append(round(n, 3)) - else: - key.extend([None, None, None]) - - if global_prefs['get_diffuse']: - for n in self.diffuse: - key.append(round(n, 3)) - else: - key.extend([None, None, None]) - -# key.extend(self.face_props.values()) - - return tuple(key) - - def __init__(self): - self.name = 'Material' - # Colors, List of 3 floats. - self.diffuse = [1.0, 1.0, 1.0] - self.specular = [1.0, 1.0, 1.0] - - # Scalars - self.ambient = 0.0 # [0.0, 1.0] - self.emissive = 0.0 # [0.0, 1.0] - self.shininess = 0.5 # Range is [0.0, 2.0] - self.alpha = 1.0 # Range is [0.0, 1.0] - - self.tex0 = None - - # OpenFlight Face attributes - self.face_props = dict.fromkeys(['comment', 'ir color', 'priority', - 'draw type', 'texture white', 'template billboard', - 'smc', 'fid', 'ir material', 'lod generation control', - 'flags', 'light mode']) - -class VertexDesc: - def make_key(self): - return round(self.x, 6), round(self.y, 6), round(self.z, 6) - - def __init__(self): - - # Assign later, save memory, all verts have a loc - self.x = 0.0 - self.y = 0.0 - self.z = 0.0 - - - self.nx = 0.0 - self.ny = 0.0 - self.nz = 0.0 - - self.uv= Vector(0,0) - self.cindex = 127 #default/lowest - self.cnorm = False - -class LightPointAppDesc: - def make_key(self): - d = dict(self.props) - del d['id'] - del d['type'] - - if d['directionality'] != 0: # not omni - d['nx'] = 0.0 - d['ny'] = 0.0 - d['nz'] = 0.0 - - return tuple(d.values()) - - def __init__(self): - self.props = dict() - self.props.update({'type': 'LPA'}) - self.props.update({'id': 'ap'}) - # Attribs not found in inline lightpoint. - self.props.update({'visibility range': 0.0}) - self.props.update({'fade range ratio': 0.0}) - self.props.update({'fade in duration': 0.0}) - self.props.update({'fade out duration': 0.0}) - self.props.update({'LOD range ratio': 0.0}) - self.props.update({'LOD scale': 0.0}) - -class GlobalResourceRepository: - def request_lightpoint_app(self, desc, scene): - match = self.light_point_app.get(desc.make_key()) - - if match: - return match.getName() - else: - # Create empty and fill with properties. - name = desc.props['type'] + ': ' + desc.props['id'] - object = Blender.Object.New('Empty', name) - scene.objects.link(object) - object.Layers= current_layer - object.sel= 1 - - # Attach properties - for name, value in desc.props.iteritems(): - object.addProperty(name, value) - - self.light_point_app.update({desc.make_key(): object}) - - return object.getName() - - # Dont use request_vert - faster to make it from the vector direct. - """ - def request_vert(self, desc): - match = self.vert_dict.get(desc.make_key()) - - if match: - return match - else: - vert = Blender.Mathutils.Vector(desc.x, desc.y, desc.z) - ''' IGNORE_NORMALS - vert.no[0] = desc.nx - vert.no[1] = desc.ny - vert.no[2] = desc.nz - ''' - self.vert_dict.update({desc.make_key(): vert}) - return vert - """ - def request_mat(self, mat_desc): - match = self.mat_dict.get(mat_desc.make_key()) - if match: return match - - mat = Blender.Material.New(mat_desc.name) - - if mat_desc.tex0 != None: - mat.setTexture(0, mat_desc.tex0, Blender.Texture.TexCo.UV) - - mat.setAlpha(mat_desc.alpha) - mat.setSpec(mat_desc.shininess) - mat.setHardness(255) - mat.setEmit(mat_desc.emissive) - mat.setAmb(mat_desc.ambient) - mat.setSpecCol(mat_desc.specular) - mat.setRGBCol(mat_desc.diffuse) - - # Create a text object to store openflight face attribs until - # user properties can be set on materials. -# t = Blender.Text.New('FACE: ' + mat.getName()) -# -# for name, value in mat_desc.face_props.items(): -# t.write(name + '\n' + str(value) + '\n\n') - - self.mat_dict.update({mat_desc.make_key(): mat}) - - return mat - - def request_image(self, filename_with_path): - if not global_prefs['get_texture']: return None - return BPyImage.comprehensiveImageLoad(filename_with_path, global_prefs['fltfile']) # Use join in case of spaces - - def request_texture(self, image): - if not global_prefs['get_texture']: - return None - - tex = self.tex_dict.get(image.filename) - if tex: return tex - - tex = Blender.Texture.New(Blender.sys.basename(image.filename)) - tex.setImage(image) - tex.setType('Image') - self.tex_dict.update({image.filename: tex}) - return tex - - def __init__(self): - - #list of scenes xrefs belong to. - self.xrefs = dict() - # material - self.mat_dict = dict() - mat_lst = Blender.Material.Get() - for mat in mat_lst: - mat_desc = MaterialDesc() - mapto_lst = mat.getTextures() - if mapto_lst[0]: - mat_desc.tex0 = mapto_lst[0].tex - else: - mat_desc.tex0 = None - mat_desc.alpha = mat.getAlpha() - mat_desc.shininess = mat.getSpec() - mat_desc.emissive = mat.getEmit() - mat_desc.ambient = mat.getAmb() - mat_desc.specular = mat.getSpecCol() - mat_desc.diffuse = mat.getRGBCol() - - self.mat_dict.update({mat_desc.make_key(): mat}) - - # texture - self.tex_dict = dict() - tex_lst = Blender.Texture.Get() - - for tex in tex_lst: - img = tex.getImage() - # Only interested in textures with images. - if img: - self.tex_dict.update({img.filename: tex}) - - # vertex - # self.vert_dict = dict() - - # light point - self.light_point_app = dict() - -class Handler: - def in_throw_back_lst(self, opcode): - return opcode in self.throw_back_lst - - def handle(self, opcode): - return self.handler[opcode]() - - def handles(self, opcode): - return opcode in self.handler.iterkeys() - - def throws_back_all_unhandled(self): - return self.throw_back_unhandled - - def set_throw_back_lst(self, a): - self.throw_back_lst = a - - def set_throw_back_all_unhandled(self): - self.throw_back_unhandled = True - - def set_only_throw_back_specified(self): - self.throw_back_unhandled = False - - def set_handler(self, d): - self.handler = d - - def __init__(self): - # Dictionary of opcodes to handler methods. - self.handler = dict() - # Send all opcodes not handled to the parent node. - self.throw_back_unhandled = False - # If throw_back_unhandled is False then only throw back - # if the opcodes in throw_back are encountered. - self.throw_back_lst = list() - -class Node: - def blender_import(self): - if self.opcode in opcode_name and global_prefs['verbose'] >= 2: - for i in xrange(self.get_level()): - print ' ', - print opcode_name[self.opcode], - print '-', self.props['id'], - print '-', self.props['comment'], - - print - - for child in self.children: - child.blender_import() - -# Import comment. -# if self.props['comment'] != '': -# name = 'COMMENT: ' + self.props['id'] -# t = Blender.Text.New(name) -# t.write(self.props['comment']) -# self.props['comment'] = name - - # Always ignore extensions and anything in between them. - def parse_push_extension(self): - self.saved_handler = self.active_handler - self.active_handler = self.extension_handler - return True - - def parse_pop_extension(self): - self.active_handler = self.saved_handler - return True - - def parse_push(self): - self.header.fw.up_level() - # Ignore unknown children. - self.ignore_unhandled = True - # Don't do child records that might overwrite parent info. ex: longid - self.active_handler = self.child_handler - return True - - def parse_pop(self): - self.header.fw.down_level() - - if self.header.fw.get_level() == self.level: - return False - - return True - - def parse(self): - while self.header.fw.begin_record(): - opcode = self.header.fw.get_opcode() - - # Print out info on opcode and tree level. - if global_prefs['verbose'] >= 3: - p = '' - for i in xrange(self.header.fw.get_level()): - p = p + ' ' - if opcode in opcode_name: - p = p + opcode_name[opcode] - else: - if global_prefs['verbose'] >= 1: - print 'undocumented opcode', opcode - continue - - if self.global_handler.handles(opcode): - if global_prefs['verbose'] >= 3: - print p + ' handled globally' - if self.global_handler.handle(opcode) == False: - break - - elif self.active_handler.handles(opcode): - if global_prefs['verbose'] >= 4: - print p + ' handled' - if self.active_handler.handle(opcode) == False: - break - - else: - if self.active_handler.throws_back_all_unhandled(): - if global_prefs['verbose'] >= 3: - print p + ' handled elsewhere' - self.header.fw.repeat_record() - break - - elif self.active_handler.in_throw_back_lst(opcode): - if global_prefs['verbose'] >= 3: - print p + ' handled elsewhere' - self.header.fw.repeat_record() - break - - else: - if global_prefs['verbose'] >= 3: - print p + ' ignored' - elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: - print 'not handled' - - def get_level(self): - return self.level - - def parse_long_id(self): - self.props['id'] = self.header.fw.read_string(self.header.fw.get_length()-4) - return True - - def parse_comment(self): - self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4) - return True - - def parse_extension(self): - extension = dict() - props = records[100] - propkeys = props.keys() - propkeys.sort() - for position in propkeys: - (type,length,name) = props[position] - extension[name] = read_prop(self.header.fw,type,length) - #read extension data. - dstring = list() - for i in xrange(self.header.fw.get_length()-24): - dstring.append(self.header.fw.read_char()) - extension['data'] = dstring - self.extension = extension - def parse_record(self): - self.props['type'] = self.opcode - props = records[self.opcode] - propkeys = props.keys() - propkeys.sort() - for position in propkeys: - (type,length,name) = props[position] - self.props[name] = read_prop(self.header.fw,type,length) - try: #remove me! - self.props['id'] = self.props['3t8!id'] - except: - pass - def __init__(self, parent, header): - self.root_handler = Handler() - self.child_handler = Handler() - self.extension_handler = Handler() - self.global_handler = Handler() - - self.global_handler.set_handler({21: self.parse_push_extension}) - self.active_handler = self.root_handler - - # used by parse_*_extension - self.extension_handler.set_handler({22: self.parse_pop_extension}) - self.saved_handler = None - - self.header = header - self.children = list() - - self.parent = parent - - if parent: - parent.children.append(self) - - self.level = self.header.fw.get_level() - self.opcode = self.header.fw.get_opcode() - - self.props = {'id': 'unnamed', 'comment': '', 'type': 'untyped'} - -class VertexPalette(Node): - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - self.root_handler.set_handler({68: self.parse_vertex_c, - 69: self.parse_vertex_cn, - 70: self.parse_vertex_cnuv, - 71: self.parse_vertex_cuv}) - self.root_handler.set_throw_back_all_unhandled() - - self.vert_desc_lst = list() - self.blender_verts = list() - self.offset = 8 - # Used to create a map from byte offset to vertex index. - self.index = dict() - - - def blender_import(self): - self.blender_verts.extend([Vector(vert_desc.x, vert_desc.y, vert_desc.z) for vert_desc in self.vert_desc_lst ]) - - def parse_vertex_common(self): - # Add this vertex to an offset to index dictionary. - #self.index_lst.append( (self.offset, self.next_index) ) - self.index[self.offset]= len(self.index) - - # Get ready for next record. - self.offset += self.header.fw.get_length() - - v = VertexDesc() - - self.header.fw.read_ahead(2) - v.flags = self.header.fw.read_short() - - v.x = self.header.fw.read_double() - v.y = self.header.fw.read_double() - v.z = self.header.fw.read_double() - - return v - - def parse_vertex_post_common(self, v): - #if not v.flags & 0x2000: # 0x2000 = no color - #if v.flags & 0x1000: # 0x1000 = packed color - # v.a = self.header.fw.read_uchar() - # v.b = self.header.fw.read_uchar() - # v.g = self.header.fw.read_uchar() - # v.r = self.header.fw.read_uchar() - #else: - self.header.fw.read_ahead(4) #skip packed color - v.cindex = self.header.fw.read_uint() - self.vert_desc_lst.append(v) - return True - - def parse_vertex_c(self): - v = self.parse_vertex_common() - - self.parse_vertex_post_common(v) - - return True - - def parse_vertex_cn(self): - v = self.parse_vertex_common() - v.cnorm = True - v.nx = self.header.fw.read_float() - v.ny = self.header.fw.read_float() - v.nz = self.header.fw.read_float() - - self.parse_vertex_post_common(v) - - return True - - def parse_vertex_cuv(self): - v = self.parse_vertex_common() - - v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() - - self.parse_vertex_post_common(v) - - return True - - def parse_vertex_cnuv(self): - v = self.parse_vertex_common() - v.cnorm = True - v.nx = self.header.fw.read_float() - v.ny = self.header.fw.read_float() - v.nz = self.header.fw.read_float() - - v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() - - self.parse_vertex_post_common(v) - - return True - - def parse(self): # Run once per import - Node.parse(self) - - -class InterNode(Node): - def __init__(self): - self.object = None - self.mesh = None - self.swapmesh = None - self.hasMesh = False - self.faceLs= [] - self.matrix = None - self.vis = True - self.hasmtex = False - self.uvlayers = dict() - self.blayernames = dict() - self.subfacelevel = 0 - self.extension = None - - mask = 2147483648 - for i in xrange(7): - self.uvlayers[mask] = False - mask = mask / 2 - - ####################################################### - ## Begin Remove Doubles Replacement ## - ####################################################### - def __xvertsort(self,__a,__b): - (__vert, __x1) = __a - (__vert2,__x2) = __b - - if __x1 > __x2: - return 1 - elif __x1 < __x2: - return -1 - return 0 - def __calcFaceNorm(self,__face): - if len(__face) == 3: - return Blender.Mathutils.TriangleNormal(__face[0].co, __face[1].co, __face[2].co) - elif len(__face) == 4: - return Blender.Mathutils.QuadNormal(__face[0].co, __face[1].co, __face[2].co, __face[3].co) - - def __replaceFaceVert(self,__weldface, __oldvert, __newvert): - __index = None - for __i, __v in enumerate(__weldface): - if __v == __oldvert: - __index = __i - break - __weldface[__index] = __newvert - - def __matchEdge(self,__weldmesh, __edge1, __edge2): - if __edge1[0] in __weldmesh['Vertex Disk'][__edge2[1]] and __edge1[1] in __weldmesh['Vertex Disk'][__edge2[0]]: - return True - return False - #have to compare original faces! - def __faceWinding(self, __weldmesh, __face1, __face2): - - __f1edges = list() - __f2edges = list() - - __f1edges.append((__face1.verts[0], __face1.verts[1])) - __f1edges.append((__face1.verts[1], __face1.verts[2])) - if len(__face1.verts) == 3: - __f1edges.append((__face1.verts[2], __face1.verts[0])) - else: - __f1edges.append((__face1.verts[2], __face1.verts[3])) - __f1edges.append((__face1.verts[3], __face1.verts[0])) - - __f2edges.append((__face2.verts[0], __face2.verts[1])) - __f2edges.append((__face2.verts[1], __face2.verts[2])) - if len(__face2.verts) == 3: - __f2edges.append((__face2.verts[2], __face2.verts[0])) - else: - __f2edges.append((__face2.verts[2], __face2.verts[3])) - __f2edges.append((__face2.verts[3], __face2.verts[0])) - - - #find a matching edge - for __edge1 in __f1edges: - for __edge2 in __f2edges: - if self.__matchEdge(__weldmesh, __edge1, __edge2): #no more tests nessecary - return True - - return False - - def __floatcompare(self, __f1, __f2): - epsilon = 0.1 - if ((__f1 + epsilon) > __f2) and ((__f1 - epsilon) < __f2): - return True - return False - def __testFace(self,__weldmesh,__v1face, __v2face, __v1bface, __v2bface): - limit = 0.01 - __matchvert = None - #frst test (for real this time!). Are the faces the same face? - if __v1face == __v2face: - return False - - #first test: Do the faces possibly geometrically share more than two vertices? we should be comparing original faces for this? - Yes..... - __match = 0 - for __vert in __v1bface.verts: - for __vert2 in __v2bface.verts: - #if (abs(__vert.co[0] - __vert2.co[0]) <= limit) and (abs(__vert.co[1] - __vert2.co[1]) <= limit) and (abs(__vert.co[2] - __vert2.co[2]) <= limit): #this needs to be fixed! - if __vert2 in __weldmesh['Vertex Disk'][__vert] or __vert == __vert2: - __match += 1 - __matchvert = __vert2 - #avoid faces sharing more than two verts - if __match > 2: - return False - - #consistent winding for face normals - if __match == 2: - if not self.__faceWinding(__weldmesh, __v1bface, __v2bface): - return False - - #second test: Compatible normals.Anything beyond almost exact opposite is 'ok' - __v1facenorm = self.__calcFaceNorm(__v1face) - __v2facenorm = self.__calcFaceNorm(__v2face) - - #dont even mess with zero length faces - if __v1facenorm.length < limit: - return False - if __v2facenorm.length < limit: - return False - - __v1facenorm.normalize() - __v2facenorm.normalize() - - if __match == 1: - #special case, look for comparison of normals angle - __angle = Blender.Mathutils.AngleBetweenVecs(__v1facenorm, __v2facenorm) - if __angle > 70.0: - return False - - - - __v2facenorm = __v2facenorm.negate() - - if self.__floatcompare(__v1facenorm[0], __v2facenorm[0]) and self.__floatcompare(__v1facenorm[1], __v2facenorm[1]) and self.__floatcompare(__v1facenorm[2], __v2facenorm[2]): - return False - - #next test: dont weld a subface to a non-subface! - if __v1bface.getProperty("FLT_SFLEVEL") != __v2bface.getProperty("FLT_SFLEVEL"): - return False - - #final test: edge test - We dont want to create a non-manifold edge through our weld operation - - return True - - def __copyFaceData(self, __source, __target): - #copy vcolor layers. - __actColLayer = self.mesh.activeColorLayer - for __colorlayer in self.mesh.getColorLayerNames(): - self.mesh.activeColorLayer = __colorlayer - for __i, __col in enumerate(__source.col): - __target.col[__i].r = __col.r - __target.col[__i].g = __col.g - __target.col[__i].b = __col.b - - self.mesh.activeColorLayer = __actColLayer - #copy uv layers. - __actUVLayer = self.mesh.activeUVLayer - for __uvlayer in self.mesh.getUVLayerNames(): - self.mesh.activeUVLayer = __uvlayer - __target.image = __source.image - __target.mode = __source.mode - __target.smooth = __source.smooth - __target.transp = __source.transp - for __i, __uv in enumerate(__source.uv): - __target.uv[__i][0] = __uv[0] - __target.uv[__i][1] = __uv[1] - - self.mesh.activeUVLayer = __actUVLayer - #copy property layers - for __property in self.mesh.faces.properties: - __target.setProperty(__property, __source.getProperty(__property)) - - def findDoubles(self): - limit = 0.01 - sortblock = list() - double = dict() - for vert in self.mesh.verts: - double[vert] = None - sortblock.append((vert, vert.co[0] + vert.co[1] + vert.co[2])) - sortblock.sort(self.__xvertsort) - - a = 0 - while a < len(self.mesh.verts): - (vert,xsort) = sortblock[a] - b = a+1 - if not double[vert]: - while b < len(self.mesh.verts): - (vert2, xsort2) = sortblock[b] - if not double[vert2]: - #first test, simple distance - if (xsort2 - xsort) > limit: - break - #second test, more expensive - if (abs(vert.co[0] - vert2.co[0]) <= limit) and (abs(vert.co[1] - vert2.co[1]) <= limit) and (abs(vert.co[2] - vert2.co[2]) <= limit): - double[vert2] = vert - b+=1 - a+=1 - - return double - - def buildWeldMesh(self): - - weldmesh = dict() - weldmesh['Vertex Disk'] = dict() #this is geometric adjacency - weldmesh['Vertex Faces'] = dict() #topological adjacency - - #find the doubles for this mesh - double = self.findDoubles() - - for vert in self.mesh.verts: - weldmesh['Vertex Faces'][vert] = list() - - #create weld faces - weldfaces = list() - originalfaces = list() - for face in self.mesh.faces: - weldface = list() - for vert in face.verts: - weldface.append(vert) - weldfaces.append(weldface) - originalfaces.append(face) - for i, weldface in enumerate(weldfaces): - for vert in weldface: - weldmesh['Vertex Faces'][vert].append(i) - weldmesh['Weld Faces'] = weldfaces - weldmesh['Original Faces'] = originalfaces - - #Now we need to build the vertex disk data. first we do just the 'target' vertices - for vert in self.mesh.verts: - if not double[vert]: #its a target - weldmesh['Vertex Disk'][vert] = list() - for vert in self.mesh.verts: - if double[vert]: #its a double - weldmesh['Vertex Disk'][double[vert]].append(vert) - - #Now we need to create the disk information for the remaining vertices - targets = weldmesh['Vertex Disk'].keys() - for target in targets: - for doublevert in weldmesh['Vertex Disk'][target]: - weldmesh['Vertex Disk'][doublevert] = [target] - for othervert in weldmesh['Vertex Disk'][target]: - if othervert != doublevert: - weldmesh['Vertex Disk'][doublevert].append(othervert) - - return weldmesh - - def weldFuseFaces(self,weldmesh): - - #retain original loose vertices - looseverts = dict() - for vert in self.mesh.verts: - looseverts[vert] = 0 - for edge in self.mesh.edges: - looseverts[edge.v1] += 1 - looseverts[edge.v2] += 1 - - - - #slight modification here: we need to walk around the mesh as many times as it takes to have no more matches - done = 0 - while not done: - done = 1 - for windex, weldface in enumerate(weldmesh['Weld Faces']): - for vertex in weldface: - #we walk around the faces of the doubles of this vertex and if possible, we weld them. - for doublevert in weldmesh['Vertex Disk'][vertex]: - removeFaces = list() #list of faces to remove from doubleverts face list - for doublefaceindex in weldmesh['Vertex Faces'][doublevert]: - doubleface = weldmesh['Weld Faces'][doublefaceindex] - oface1 = self.mesh.faces[windex] - oface2 = self.mesh.faces[doublefaceindex] - ok = self.__testFace(weldmesh, weldface, doubleface, oface1, oface2) - if ok: - done = 0 - removeFaces.append(doublefaceindex) - self.__replaceFaceVert(doubleface, doublevert, vertex) - for doublefaceindex in removeFaces: - weldmesh['Vertex Faces'][doublevert].remove(doublefaceindex) - #old faces first - oldindices = list() - for face in self.mesh.faces: - oldindices.append(face.index) - #make our new faces. - newfaces = list() - for weldface in weldmesh['Weld Faces']: - newfaces.append(weldface) - newindices = self.mesh.faces.extend(newfaces, indexList=True, ignoreDups=True) - #copy custom data over - for i, newindex in enumerate(newindices): - try: - self.__copyFaceData(self.mesh.faces[oldindices[i]], self.mesh.faces[newindex]) - except: - print "warning, could not copy face data!" - #delete the old faces - self.mesh.faces.delete(1, oldindices) - - #Clean up stray vertices - vertuse = dict() - for vert in self.mesh.verts: - vertuse[vert] = 0 - for face in self.mesh.faces: - for vert in face.verts: - vertuse[vert] += 1 - delverts = list() - for vert in self.mesh.verts: - if not vertuse[vert] and vert.index != 0 and looseverts[vert]: - delverts.append(vert) - - self.mesh.verts.delete(delverts) - - - ####################################################### - ## End Remove Doubles Replacement ## - ####################################################### - - def blender_import_my_faces(self): - - # Add the verts onto the mesh - blender_verts= self.header.vert_pal.blender_verts - vert_desc_lst= self.header.vert_pal.vert_desc_lst - - vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing? - face_edges= [] - face_verts= [] - self.mesh.verts.extend([blender_verts[i] for i in vert_list]) - - new_faces= [] - new_faces_props= [] - ngon= BPyMesh.ngon - vert_index= 1 - - #add vertex color layer for baked face colors. - self.mesh.addColorLayer("FLT_Fcol") - self.mesh.activeColorLayer = "FLT_Fcol" - - FLT_OrigIndex = 0 - for flt_face in self.faceLs: - if flt_face.tex_index != -1: - try: - image= self.header.tex_pal[flt_face.tex_index][1] - except KeyError: - image= None - else: - image= None - face_len= len(flt_face.indices) - - #create dummy uvert dicts - if len(flt_face.uverts) == 0: - for i in xrange(face_len): - flt_face.uverts.append(dict()) - #May need to patch up MTex info - if self.hasmtex: - #For every layer in mesh, there should be corresponding layer in the face - for mask in self.uvlayers.keys(): - if self.uvlayers[mask]: - if not flt_face.uvlayers.has_key(mask): #Does the face have this layer? - #Create Layer info for this face - flt_face.uvlayers[mask] = dict() - flt_face.uvlayers[mask]['texture index'] = -1 - flt_face.uvlayers[mask]['texture enviorment'] = 3 - flt_face.uvlayers[mask]['texture mapping'] = 0 - flt_face.uvlayers[mask]['texture data'] = 0 - - #now go through and create dummy uvs for this layer - for uvert in flt_face.uverts: - uv = Vector(0.0,0.0) - uvert[mask] = uv - - # Get the indicies in reference to the mesh. - uvs= [vert_desc_lst[j].uv for j in flt_face.indices] - if face_len == 1: - pass - elif face_len == 2: - face_edges.append((vert_index, vert_index+1)) - elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3: - i = 0 - while i < (face_len-1): - face_edges.append((vert_index + i, vert_index + i + 1)) - i = i + 1 - if flt_face.props['draw type'] == 2: - face_edges.append((vert_index + i,vert_index)) - elif face_len == 3 or face_len == 4: # tri or quad - #if face_len == 1: - # pass - #if face_len == 2: - # face_edges.append((vert_index, vert_index+1)) - new_faces.append( [i+vert_index for i in xrange(face_len)] ) - new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel)) - - else: # fgon - mesh_face_indicies = [i+vert_index for i in xrange(face_len)] - tri_ngons= ngon(self.mesh, mesh_face_indicies) - if len(tri_ngons) != 1: - new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons]) - new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ]) - - vert_index+= face_len - FLT_OrigIndex+=1 - - self.mesh.faces.extend(new_faces) - self.mesh.edges.extend(face_edges) - - #add in the FLT_ORIGINDEX layer - if len(self.mesh.faces): - try: self.mesh.faceUV= True - except: pass - - if self.mesh.faceUV == True: - self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0') - - #create name layer for faces - self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"]) - #create layer for face color indices - self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) - #create index layer for faces. This is needed by both FGONs and subfaces - self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) - #create temporary FGON flag layer. Delete after remove doubles - self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"]) - self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"]) - - for i, f in enumerate(self.mesh.faces): - props = new_faces_props[i] - if props[6]['template billboard'] > 0: - f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] - if props[6]['template billboard'] == 2: - f.mode |= Blender.Mesh.FaceModes["BILLBOARD"] - f.mode |= Blender.Mesh.FaceModes["LIGHT"] - if props[6]['draw type'] == 1: - f.mode |= Blender.Mesh.FaceModes["TWOSIDE"] - - #f.mat = props[0] - f.image = props[1] - f.uv = props[2] - #set vertex colors - color = self.header.get_color(props[5]) - if not color: - color = [255,255,255,255] - for mcol in f.col: - mcol.a = color[3] - mcol.r = color[0] - mcol.g = color[1] - mcol.b = color[2] - - f.setProperty("FLT_SFLEVEL", props[9]) - f.setProperty("FLT_ORIGINDEX",i) - f.setProperty("FLT_ID",props[6]['id']) - #if props[5] > 13199: - # print "Warning, invalid color index read in! Using default!" - # f.setProperty("FLT_COL",127) - #else: - if(1): #uh oh.... - value = struct.unpack('>i',struct.pack('>I',props[5]))[0] - f.setProperty("FLT_COL",value) - - #if props[8]: - # f.setProperty("FLT_FGON",1) - #else: - # f.setProperty("FLT_FGON",0) - - - #Create multitex layers, if present. - actuvlayer = self.mesh.activeUVLayer - if(self.hasmtex): - #For every multi-tex layer, we have to add a new UV layer to the mesh - for i,mask in enumerate(reversed(sorted(self.uvlayers))): - if self.uvlayers[mask]: - self.blayernames[mask] = "Layer" + str(i+1) - self.mesh.addUVLayer(self.blayernames[mask]) - - #Cycle through availible multi-tex layers and add face UVS - for mask in self.uvlayers: - if self.uvlayers[mask]: - self.mesh.activeUVLayer = self.blayernames[mask] - for j, f in enumerate(self.mesh.faces): - if props[6]['draw type'] == 1: - f.mode |= Blender.Mesh.FaceModes["TWOSIDE"] - f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] - f.mode |= Blender.Mesh.FaceModes["LIGHT"] - props = new_faces_props[j] - uvlayers = props[4] - if uvlayers.has_key(mask): #redundant - uverts = props[3] - for k, uv in enumerate(f.uv): - uv[0] = uverts[k][mask][0] - uv[1] = uverts[k][mask][1] - - uvlayer = uvlayers[mask] - tex_index = uvlayer['texture index'] - if tex_index != -1: - try: - f.image = self.header.tex_pal[tex_index][1] - except KeyError: - f.image = None - - if global_prefs['smoothshading'] == True and len(self.mesh.faces): - #We need to store per-face vertex normals in the faces as UV layers and delete them later. - self.mesh.addUVLayer("FLTNorm1") - self.mesh.addUVLayer("FLTNorm2") - self.mesh.activeUVLayer = "FLTNorm1" - for f in self.mesh.faces: - f.smooth = 1 - #grab the X and Y components of normal and store them in UV - for i, uv in enumerate(f.uv): - vert = f.v[i].index - vert_desc = vert_desc_lst[vert_list[vert-1]] - if vert_desc.cnorm: - uv[0] = vert_desc.nx - uv[1] = vert_desc.ny - else: - uv[0] = 0.0 - uv[1] = 0.0 - - #Now go through and populate the second UV Layer with the z component - self.mesh.activeUVLayer = "FLTNorm2" - for f in self.mesh.faces: - for i, uv in enumerate(f.uv): - vert = f.v[i].index - vert_desc = vert_desc_lst[vert_list[vert-1]] - if vert_desc.cnorm: - uv[0] = vert_desc.nz - uv[1] = 0.0 - else: - uv[0] = 0.0 - uv[1] = 0.0 - - - - #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier. - Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) - self.mesh.sel= 1 - self.header.scene.update(1) #slow! - - #self.mesh.remDoubles(0.0001) - weldmesh = self.buildWeldMesh() - welded = self.weldFuseFaces(weldmesh) - self.mesh.verts.delete(0) # remove the dummy vert - - edgeHash = dict() - - for edge in self.mesh.edges: - edgeHash[edge.key] = edge.index - - - if global_prefs['smoothshading'] == True and len(self.mesh.faces): - - #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way. - facenorms = [] - self.mesh.activeUVLayer = "FLTNorm1" - for face in self.mesh.faces: - facenorm = [] - for uv in face.uv: - facenorm.append(Vector(uv[0],uv[1],0.0)) - facenorms.append(facenorm) - self.mesh.activeUVLayer = "FLTNorm2" - for i, face in enumerate(self.mesh.faces): - facenorm = facenorms[i] - for j, uv in enumerate(face.uv): - facenorm[j][2] = uv[0] - self.mesh.removeUVLayer("FLTNorm1") - self.mesh.removeUVLayer("FLTNorm2") - - #find hard edges - #store edge data for lookup by faces - #edgeHash = dict() - #for edge in self.mesh.edges: - # edgeHash[edge.key] = edge.index - - edgeNormHash = dict() - #make sure to align the edgenormals to key value! - for i, face in enumerate(self.mesh.faces): - - facenorm = facenorms[i] - faceEdges = [] - faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0])) - faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1])) - if len(face.v) == 3: - faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2])) - elif len(face.v) == 4: - faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2])) - faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3])) - - #check to see if edgeNormal has been placed in the edgeNormHash yet - #this is a redundant test, and should be optimized to not be called as often as it is. - for j, faceEdge in enumerate(faceEdges): - #the value we are looking for is (faceEdge[2],faceEdge[3]) - hashvalue = (faceEdge[2],faceEdge[3]) - if (faceEdge[0],faceEdge[1]) != faceEdge[4]: - hashvalue = (hashvalue[1],hashvalue[0]) - assert (faceEdge[1],faceEdge[0]) == faceEdge[4] - if edgeNormHash.has_key(faceEdge[4]): - #compare value in the hash, if different, mark as sharp - edgeNorm = edgeNormHash[faceEdge[4]] - if\ - abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\ - abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\ - abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\ - abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\ - abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\ - abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE: - edge = self.mesh.edges[edgeHash[faceEdge[4]]] - edge.flag |= Blender.Mesh.EdgeFlags.SHARP - - else: - edgeNormHash[faceEdge[4]] = hashvalue - - #add in edgesplit modifier - mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT) - mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True - mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False - - if(actuvlayer): - self.mesh.activeUVLayer = actuvlayer - - def blender_import(self): - if self.vis and self.parent.object: - self.vis = self.parent.vis - name = self.props['id'] - - - if self.hasMesh: - self.mesh = Blender.Mesh.New() - self.mesh.name = 'FLT_FaceList' - self.mesh.fakeUser = True - self.mesh.verts.extend( Vector()) #DUMMYVERT - self.object = self.header.scene.objects.new(self.mesh) - else: - self.object = self.header.scene.objects.new('Empty') - - self.object.name = name - self.header.group.objects.link(self.object) - - #id props import - self.object.properties['FLT'] = dict() - for key in self.props: - try: - self.object.properties['FLT'][key] = self.props[key] - except: #horrible... - pass - - - if self.extension: - self.object.properties['FLT']['EXT'] = dict() - for key in self.extension: - self.object.properties['FLT']['EXT'][key] = self.extension[key] - - if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene): - self.parent.object.makeParent([self.object],1) - - if self.matrix: - self.object.setMatrix(self.matrix) - - if self.vis == False: - self.object.restrictDisplay = True - self.object.restrictRender = True - - else: #check for LOD children and set the proper flags - lodlist = list() - for child in self.children: - if child.props.has_key('type') and child.props['type'] == 73: - if child.props['6d!switch out'] != 0.0: - child.vis = False - #lodlist.append(child) - - #def LODmin(a,b): - # if a.props['5d!switch in'] < b.props['5d!switch in']: - # return a - # return b - - #min= None - #if len(lodlist) > 1: - # for lod in lodlist: - # lod.vis = False - # min = lodlist[0] - # for i in xrange(len(lodlist)): - # min= LODmin(min,lodlist[i]) - # min.vis = True - - - Node.blender_import(self) # Attach faces to self.faceLs - - if self.hasMesh: - # Add all my faces into the mesh at once - self.blender_import_my_faces() - - def parse_face(self): - child = Face(self, self.subfacelevel) - child.parse() - return True - - def parse_group(self): - child = Group(self) - child.parse() - return True - - def move_to_next_layer(self): - global current_layer - current_layer = current_layer << 1 - if current_layer > 0x80000: - current_layer = 1 - - def parse_lod(self): - child = LOD(self) - child.parse() - return True - - def parse_unhandled(self): - child = Unhandled(self) - child.parse() - return True - - def parse_object(self): - child = Object(self) - child.parse() - return True - - def parse_xref(self): - child = XRef(self) - child.parse() - return True - - def parse_dof(self): - child = DOF(self) - child.parse() - return True - - def parse_indexed_light_point(self): - child = IndexedLightPoint(self) - child.parse() - return True - - def parse_inline_light_point(self): - child = InlineLightPoint(self) - child.parse() - return True - - def parse_matrix(self): - m = list() - for i in xrange(4): - m.append([]) - for j in xrange(4): - f = self.header.fw.read_float() - m[i].append(f) - self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3]) - - def parse_subpush(self): - self.parse_push() - self.subfacelevel+= 1 - return True - def parse_subpop(self): - self.parse_pop() - self.subfacelevel -= 1 - return True - - - -class Face(Node): - def __init__(self, parent,subfacelevel): - Node.__init__(self, parent, parent.header) - self.root_handler.set_handler({31: self.parse_comment, - 10: self.parse_push, - 52: self.parse_multitex}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({72: self.parse_vertex_list, - 10: self.parse_push, - 11: self.parse_pop, - 53: self.parse_uvlist}) - - if parent: - parent.hasMesh = True - - self.subfacelevel = subfacelevel - self.indices = list() # face verts here - self.uvlayers = dict() # MultiTexture layers keyed to layer bitmask. - self.uverts = list() # Vertex aligned list of dictionaries keyed to layer bitmask. - self.uvmask = 0 # Bitfield read from MTex record - - self.comment = '' - self.props = dict() - self.props['id'] = self.header.fw.read_string(8) - # Load face. - self.props['ir color'] = self.header.fw.read_int() - self.props['priority'] = self.header.fw.read_short() - self.props['draw type'] = self.header.fw.read_char() - self.props['texture white'] = self.header.fw.read_char() - self.header.fw.read_ahead(4) # color name indices - self.header.fw.read_ahead(1) # reserved - self.props['template billboard'] = self.header.fw.read_uchar() - self.detail_tex_index = self.header.fw.read_short() - self.tex_index = self.header.fw.read_short() - self.mat_index = self.header.fw.read_short() - self.props['smc'] = self.header.fw.read_short() - self.props['fid'] = self.header.fw.read_short() - self.props['ir material'] = self.header.fw.read_int() - self.alpha = 1.0 - float(self.header.fw.read_ushort()) / 65535.0 - self.props['lod generation control'] = self.header.fw.read_uchar() - self.header.fw.read_ahead(1) # line style index - self.props['flags'] = self.header.fw.read_int() - self.props['light mode'] = self.header.fw.read_uchar() - self.header.fw.read_ahead(7) - a = self.header.fw.read_uchar() - b = self.header.fw.read_uchar() - g = self.header.fw.read_uchar() - r = self.header.fw.read_uchar() - self.packed_color = [r, g, b, a] - a = self.header.fw.read_uchar() - b = self.header.fw.read_uchar() - g = self.header.fw.read_uchar() - r = self.header.fw.read_uchar() - self.alt_packed_color = [r, g, b, a] - self.tex_map_index = self.header.fw.read_short() - self.header.fw.read_ahead(2) - self.color_index = self.header.fw.read_uint() - self.alt_color_index = self.header.fw.read_uint() - #self.header.fw.read_ahead(2) - #self.shader_index = self.header.fw.read_short() - - def parse_comment(self): - self.comment = self.header.fw.read_string(self.header.fw.get_length()-4) - return True - - def blender_import(self): - vert_count = len(self.indices) - if vert_count < 1: - if global_prefs['verbose'] >= 2: - print 'Warning: Ignoring face with no vertices.' - return - - # Assign material and image - - self.parent.faceLs.append(self) - #need to store comment in mesh prop layer! - - # Store comment info in parent. - #if self.comment != '': - # if self.parent.props['comment'] != '': - # self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment - # else: - # self.parent.props['comment'] = self.comment - - if self.uvlayers: - #Make sure that the mesh knows about the layers that this face uses - self.parent.hasmtex = True - for mask in self.uvlayers.keys(): - self.parent.uvlayers[mask] = True - - def parse_vertex_list(self): - length = self.header.fw.get_length() - fw = self.header.fw - vert_pal = self.header.vert_pal - - count = (length-4)/4 - - # If this ever fails the chunk below does error checking - self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] - ''' - for i in xrange(count): - byte_offset = fw.read_int() - if byte_offset in vert_pal.index: - index = vert_pal.index[byte_offset] - self.indices.append(index) - elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to map byte offset %s' + \ - ' to vertex index.' % byte_offset - ''' - return True - - def parse_multitex(self): - #Parse MultiTex Record. - length = self.header.fw.get_length() - fw = self.header.fw - #num layers == (length - 8) / 4 - uvmask = fw.read_uint() - mask = 2147483648 - for i in xrange(7): - if mask & uvmask: - uvlayer = dict() - self.uvlayers[mask] = uvlayer - mask = mask / 2 - - #read in record for each individual layer. - for key in reversed(sorted(self.uvlayers)): - uvlayer = self.uvlayers[key] - uvlayer['texture index'] = fw.read_ushort() - uvlayer['texture enviorment'] = fw.read_ushort() - uvlayer['texture mapping'] = fw.read_ushort() - uvlayer['texture data'] = fw.read_ushort() - - self.uvmask = uvmask - - def parse_uvlist(self): - #for each uvlayer, add uv vertices - length = self.header.fw.get_length() - fw = self.header.fw - uvmask = fw.read_uint() - if uvmask != self.uvmask: #This should never happen! - fw.read_ahead(self.length - 4) #potentially unnessecary? - else: - #need to store in uvverts dictionary for each vertex. - totverts = len(self.indices) - for i in xrange(totverts): - uvert = dict() - for key in reversed(sorted(self.uvlayers)): - uv = Vector(0.0,0.0) - uv[0] = fw.read_float() - uv[1] = fw.read_float() - uvert[key] = uv - self.uverts.append(uvert) - -class Object(InterNode): - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({33: self.parse_long_id, - 21: self.parse_push_extension, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({5: self.parse_face, - 19: self.parse_subpush, - 20: self.parse_subpop, - 111: self.parse_inline_light_point, - 10: self.parse_push, - 11: self.parse_pop}) - self.extension_handler.set_handler({22: self.parse_pop_extension, - 100: self.parse_extension}) - - self.extension = dict() - self.props = dict() - self.props['comment'] = '' - self.parse_record() - -class Group(InterNode): - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix, - 21: self.parse_push_extension}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({5: self.parse_face, - 19: self.parse_subpush, - 20: self.parse_subpop, - 111: self.parse_inline_light_point, - 2: self.parse_group, - 73: self.parse_lod, - 4: self.parse_object, - 10: self.parse_push, - 11: self.parse_pop, - 96: self.parse_unhandled, - 14: self.parse_dof, - 91: self.parse_unhandled, - 98: self.parse_unhandled, - 63: self.parse_xref}) - - self.extension_handler.set_handler({22: self.parse_pop_extension, - 100: self.parse_extension}) - - self.props = dict.fromkeys(['type', 'id', 'comment', 'priority', 'flags', 'special1', - 'special2', 'significance', 'layer code', 'loop count', - 'loop duration', 'last frame duration']) - - self.props['comment'] = '' - self.parse_record() - - #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode] - #props = records[self.opcode] - #propkeys = props.keys() - #propkeys.sort() - #for position in propkeys: - # (type,length,name) = props[position] - # self.props[name] = read_prop(self.header.fw,type,length) - #self.props['id'] = self.props['3t8!id'] - -class DOF(InterNode): - def blender_import(self): - InterNode.blender_import(self) - - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix, - 21: self.parse_push_extension}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({#130: self.parse_indexed_light_point, - 111: self.parse_inline_light_point, - 2: self.parse_group, - 73: self.parse_lod, - 4: self.parse_object, - 10: self.parse_push, - 11: self.parse_pop, - 96: self.parse_unhandled, - 14: self.parse_dof, - 91: self.parse_unhandled, - 98: self.parse_unhandled, - 63: self.parse_xref}) - self.extension_handler.set_handler({22: self.parse_pop_extension, - 100: self.parse_extension}) - self.props = dict() - self.props['comment'] = '' - self.parse_record() - - -class XRef(InterNode): - def parse(self): - if self.xref: - self.xref.parse() - Node.parse(self) - - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.props = dict() - self.props['comment'] = '' - self.parse_record() - - xref_filename = self.props['3t200!filename'] #I dont even think there is a reason to keep this around... - - if not os.path.isabs(xref_filename): - absname = os.path.join(os.path.dirname(self.header.filename), xref_filename) - else: - absname = xref_filename - - self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well.... - - if global_prefs['doxrefs'] and os.path.exists(absname) and not self.header.grr.xrefs.has_key(xref_filename): - self.xref = Database(absname, self.header.grr, self) - self.header.grr.xrefs[xref_filename] = self.xref - else: - self.xref = None - - - def blender_import(self): - #name = self.props['type'] + ': ' + self.props['id'] - name = self.props['id'] - self.object = self.header.scene.objects.new('Empty') - self.object.name = name - self.object.enableDupGroup = True - self.header.group.objects.link(self.object) - - #for broken links its ok to leave this empty! they purely for visual purposes anyway..... - try: - self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group - except: - pass - - - - - if self.parent and self.parent.object: - self.parent.object.makeParent([self.object],1) - - if self.matrix: - self.object.setMatrix(self.matrix) - - - #id props import - self.object.properties['FLT'] = dict() - for key in self.props: - try: - self.object.properties['FLT'][key] = self.props[key] - except: #horrible... - pass - - self.object.Layer = current_layer - self.object.sel = 1 - - Node.blender_import(self) - - -class LOD(InterNode): - def blender_import(self): - #self.move_to_next_layer() - InterNode.blender_import(self) - #self.object.properties['FLT'] = self.props.copy() - - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix, - 21: self.parse_push_extension}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({2: self.parse_group, - 111: self.parse_inline_light_point, - 73: self.parse_lod, - 4: self.parse_object, - 10: self.parse_push, - 11: self.parse_pop, - 96: self.parse_unhandled, # switch - 14: self.parse_dof, # DOF - 91: self.parse_unhandled, # sound - 98: self.parse_unhandled, # clip - 63: self.parse_xref}) - self.extension_handler.set_handler({22: self.parse_pop_extension, - 100: self.parse_extension}) - - - self.props = dict() - self.props['comment'] = '' - self.parse_record() - -class InlineLightPoint(InterNode): - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 21: self.parse_push_extension, - 49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({72: self.parse_vertex_list, - 10: self.parse_push, - 11: self.parse_pop}) - self.extension_handler.set_handler({22: self.parse_pop_extension, - 100: self.parse_extension}) - - self.indices = list() - self.props = dict() - self.props['comment'] = '' - self.parse_record() - - - def blender_import(self): - - - name = self.props['id'] - self.mesh= Blender.Mesh.New() - self.mesh.name = 'FLT_LP' - self.object = self.header.scene.objects.new(self.mesh) - self.object.name = name - #self.mesh.verts.extend(Vector() ) # DUMMYVERT - self.object.Layer = current_layer - self.object.sel= 1 - - self.object.properties['FLT'] = dict() - for key in self.props: - try: - self.object.properties['FLT'][key] = self.props[key] - except: #horrible... - pass - - if self.extension: - self.object.properties['FLT']['EXT'] = dict() - for key in self.extension: - self.object.properties['FLT']['EXT'][key] = self.extension[key] - - if self.parent and self.parent.object and self.header.scene == self.parent.header.scene: - self.parent.object.makeParent([self.object]) - - if self.matrix: - self.object.setMatrix(self.matrix) - - self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices]) - - #add color index information. - self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) - for i, vindex in enumerate(self.indices): - vdesc = self.header.vert_pal.vert_desc_lst[vindex] - v = self.mesh.verts[i] - v.setProperty("FLT_VCOL",vdesc.cindex) - #for i, v in enumerate(self.mesh.verts): - # vdesc = self.header.vert_pal.vert_desc_lst[i] - # v.setProperty("FLT_VCOL",vdesc.cindex) - self.mesh.update() - - def parse_vertex_list(self): - length = self.header.fw.get_length() - fw = self.header.fw - vert_pal = self.header.vert_pal - - count = (length-4)/4 - - # If this ever fails the chunk below does error checking - self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] - - ''' - for i in xrange(count): - byte_offset = fw.read_int() - if byte_offset in vert_pal.index: - index = vert_pal.index[byte_offset] - self.indices.append(index) - elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to map byte offset %s' + \ - ' to vertex index.' % byte_offset - ''' - - return True - - - -class IndexedLightPoint(InterNode): - # return dictionary: lp_app name => index list - def group_points(self, props): - - name_to_indices = {} - - for i in self.indices: - vert_desc = self.header.vert_pal.vert_desc_lst[i] - app_desc = LightPointAppDesc() - app_desc.props.update(props) - # add vertex normal and color - app_desc.props.update({'nx': vert_desc.nx}) - app_desc.props.update({'ny': vert_desc.ny}) - app_desc.props.update({'nz': vert_desc.nz}) - - app_desc.props.update({'r': vert_desc.r}) - app_desc.props.update({'g': vert_desc.g}) - app_desc.props.update({'b': vert_desc.b}) - app_desc.props.update({'a': vert_desc.a}) - - app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene) - - if name_to_indices.get(app_name): - name_to_indices[app_name].append(i) - else: - name_to_indices.update({app_name: [i]}) - - return name_to_indices - - def blender_import(self): - name = self.props['type'] + ': ' + self.props['id'] - - name_to_indices = self.group_points(self.header.lightpoint_appearance_pal[self.index]) - - for app_name, indices in name_to_indices.iteritems(): - self.object = Blender.Object.New('Mesh', name) - self.mesh= Blender.Mesh.New() - self.mesh.verts.extend( Vector() ) # DUMMYVERT - self.object.link(self.mesh) - - if self.parent: - self.parent.object.makeParent([self.object]) - - for i in indices: - vert = self.header.vert_pal.blender_verts[i] - self.mesh.verts.append(vert) - - self.header.scene.objects.link(self.object) - - self.object.Layer = current_layer - - if self.matrix: - self.object.setMatrix(self.matrix) - - # Import comment. - if self.props['comment'] != '': - name = 'COMMENT: ' + self.props['id'] - t = Blender.Text.New(name) - t.write(self.props['comment']) - self.props['comment'] = name - - # Attach properties. - self.props.update({'appearance': app_name}) - for name, value in self.props.iteritems(): - self.object.addProperty(name, value) - - self.mesh.update() - - def parse_vertex_list(self): - length = self.header.fw.get_length() - fw = self.header.fw - vert_pal = self.header.vert_pal - - count = (length-4)/4 - - # If this ever fails the chunk below does error checking - self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] - - ''' - for i in xrange(count): - byte_offset = fw.read_int() - if byte_offset in vert_pal.index: - index = vert_pal.index[byte_offset] - self.indices.append(index) - elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to map byte offset %s' + \ - ' to vertex index.' % byte_offset - ''' - return True - - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({72: self.parse_vertex_list, - 10: self.parse_push, - 11: self.parse_pop}) - - self.indices = list() - - self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) - self.props['comment'] = '' - self.props['type'] = 'Light Point' - self.props['id'] = self.header.fw.read_string(8) - self.index = self.header.fw.read_int() - self.header.fw.read_ahead(4) # animation index - self.props['draw order'] = self.header.fw.read_int() - -class Unhandled(InterNode): - def __init__(self, parent): - Node.__init__(self, parent, parent.header) - InterNode.__init__(self) - - self.root_handler.set_handler({33: self.parse_long_id, - 31: self.parse_comment, - 10: self.parse_push, - 49: self.parse_matrix}) - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({2: self.parse_group, - 73: self.parse_lod, - 4: self.parse_object, - 10: self.parse_push, - 11: self.parse_pop, - 96: self.parse_unhandled, # switch - 14: self.parse_dof, # DOF - 91: self.parse_unhandled, # sound - 98: self.parse_unhandled, # clip - 63: self.parse_xref}) - - self.props['id'] = self.header.fw.read_string(8) - -class Database(InterNode): - def blender_import(self): - for key in self.tex_pal.keys(): - path_filename= FF.find(self.tex_pal[key][0]) - if path_filename != None: - img = self.grr.request_image(path_filename) - if img: - self.tex_pal[key][1] = img - elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to find', self.tex_pal[key][0] - - self.scene.properties['FLT'] = dict() - for key in self.props: - try: - self.scene.properties['FLT'][key] = self.props[key] - except: #horrible... - pass - - self.scene.properties['FLT']['Main'] = 0 - self.scene.properties['FLT']['Filename'] = self.bname - - for child in self.children: - if child.props.has_key('type') and child.props['type'] == 73: - if child.props['6d!switch out'] != 0.0: - child.vis = False - - #import color palette - carray = list() - for color in self.col_pal: - carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0]) - self.scene.properties['FLT']['Color Palette'] = carray - Node.blender_import(self) - - def parse_appearance_palette(self): - props = dict() - self.fw.read_ahead(4) # reserved - props.update({'id': self.fw.read_string(256)}) - index = self.fw.read_int() - props.update({'smc': self.fw.read_short()}) - props.update({'fid': self.fw.read_short()}) - props.update({'back color: a': self.fw.read_uchar()}) - props.update({'back color: b': self.fw.read_uchar()}) - props.update({'back color: g': self.fw.read_uchar()}) - props.update({'back color: r': self.fw.read_uchar()}) - props.update({'display mode': self.fw.read_int()}) - props.update({'intensity': self.fw.read_float()}) - props.update({'back intensity': self.fw.read_float()}) - props.update({'minimum defocus': self.fw.read_float()}) - props.update({'maximum defocus': self.fw.read_float()}) - props.update({'fading mode': self.fw.read_int()}) - props.update({'fog punch mode': self.fw.read_int()}) - props.update({'directional mode': self.fw.read_int()}) - props.update({'range mode': self.fw.read_int()}) - props.update({'min pixel size': self.fw.read_float()}) - props.update({'max pixel size': self.fw.read_float()}) - props.update({'actual size': self.fw.read_float()}) - props.update({'trans falloff pixel size': self.fw.read_float()}) - props.update({'trans falloff exponent': self.fw.read_float()}) - props.update({'trans falloff scalar': self.fw.read_float()}) - props.update({'trans falloff clamp': self.fw.read_float()}) - props.update({'fog scalar': self.fw.read_float()}) - props.update({'fog intensity': self.fw.read_float()}) - props.update({'size threshold': self.fw.read_float()}) - props.update({'directionality': self.fw.read_int()}) - props.update({'horizontal lobe angle': self.fw.read_float()}) - props.update({'vertical lobe angle': self.fw.read_float()}) - props.update({'lobe roll angle': self.fw.read_float()}) - props.update({'dir falloff exponent': self.fw.read_float()}) - props.update({'dir ambient intensity': self.fw.read_float()}) - props.update({'significance': self.fw.read_float()}) - props.update({'flags': self.fw.read_int()}) - props.update({'visibility range': self.fw.read_float()}) - props.update({'fade range ratio': self.fw.read_float()}) - props.update({'fade in duration': self.fw.read_float()}) - props.update({'fade out duration': self.fw.read_float()}) - props.update({'LOD range ratio': self.fw.read_float()}) - props.update({'LOD scale': self.fw.read_float()}) - - self.lightpoint_appearance_pal.update({index: props}) - - def parse_header(self): - self.props['type'] = 'Header' - self.props['comment'] = '' - self.props['id'] = self.fw.read_string(8) - self.props['version'] = self.fw.read_int() - self.fw.read_ahead(46) - self.props['units'] = self.fw.read_char() - self.props['set white'] = bool(self.fw.read_char()) - self.props['flags'] = self.fw.read_int() - self.fw.read_ahead(24) - self.props['projection type'] = self.fw.read_int() - self.fw.read_ahead(36) - self.props['sw x'] = self.fw.read_double() - self.props['sw y'] = self.fw.read_double() - self.props['dx'] = self.fw.read_double() - self.props['dy'] = self.fw.read_double() - self.fw.read_ahead(24) - self.props['sw lat'] = self.fw.read_double() - self.props['sw lon'] = self.fw.read_double() - self.props['ne lat'] = self.fw.read_double() - self.props['ne lon'] = self.fw.read_double() - self.props['origin lat'] = self.fw.read_double() - self.props['origin lon'] = self.fw.read_double() - self.props['lambert lat1'] = self.fw.read_double() - self.props['lambert lat2'] = self.fw.read_double() - self.fw.read_ahead(16) - self.props['ellipsoid model'] = self.fw.read_int() - self.fw.read_ahead(4) - self.props['utm zone'] = self.fw.read_short() - self.fw.read_ahead(6) - self.props['dz'] = self.fw.read_double() - self.props['radius'] = self.fw.read_double() - self.fw.read_ahead(8) - self.props['major axis'] = self.fw.read_double() - self.props['minor axis'] = self.fw.read_double() - - if global_prefs['verbose'] >= 1: - print 'OpenFlight Version:', float(self.props['version']) / 100.0 - print - - return True - - def parse_mat_palette(self): - mat_desc = MaterialDesc() - index = self.fw.read_int() - - name = self.fw.read_string(12) - if len(mat_desc.name) > 0: - mat_desc.name = name - - flag = self.fw.read_int() - # skip material if not used - if not flag & 0x80000000: - return True - - ambient_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] - mat_desc.diffuse = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] - mat_desc.specular = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] - emissive_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] - - mat_desc.shininess = self.fw.read_float() / 64.0 # [0.0, 128.0] => [0.0, 2.0] - mat_desc.alpha = self.fw.read_float() - - # Convert ambient and emissive colors into intensitities. - mat_desc.ambient = col_to_gray(ambient_col) - mat_desc.emissive = col_to_gray(emissive_col) - - self.mat_desc_pal_lst.append( (index, mat_desc) ) - - return True - - def get_color(self, color_index): - color = None - index = color_index / 128 - intensity = float(color_index - 128.0 * index) / 127.0 - - if index >= 0 and index <= 1023: - brightest = self.col_pal[index] - r = int(brightest[0] * intensity) - g = int(brightest[1] * intensity) - b = int(brightest[2] * intensity) - a = int(brightest[3]) - - color = [r, g, b, a] - - return color - - def parse_color_palette(self): - self.header.fw.read_ahead(128) - for i in xrange(1024): - a = self.header.fw.read_uchar() - b = self.header.fw.read_uchar() - g = self.header.fw.read_uchar() - r = self.header.fw.read_uchar() - self.col_pal.append((r, g, b, a)) - return True - - def parse_vertex_palette(self): - self.vert_pal = VertexPalette(self) - self.vert_pal.parse() - return True - - def parse_texture_palette(self): - name = self.fw.read_string(200) - index = self.fw.read_int() - self.tex_pal[index]= [name, None] - return True - - def read_attribute_files(self): - for tex in self.tex_pal.keys(): - [name,image] = self.tex_pal[tex] - basename = os.path.basename(name) - if(image): - basename = basename + ".attr" - dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link - newpath = os.path.join(dirname, basename) - if os.path.exists(newpath) and not image.properties.has_key('FLT'): - fw = flt_filewalker.FltIn(newpath) - fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions - image.properties['FLT']={} - - #need to steal code from parse records.... - props = records['Image'] - propkeys = props.keys() - propkeys.sort() - for position in propkeys: - (type,length,name) = props[position] - image.properties['FLT'][name] = read_prop(fw,type,length) - fw.close_file() - - #copy clamp settings - wrap = image.properties['FLT']['10i!Wrap'] - wrapu = image.properties['FLT']['11i!WrapU'] - wrapv = image.properties['FLT']['12i!WrapV'] - - if wrapu == 3 or wrapv == 3: - wrapuv = (wrap,wrap) - else: - wrapuv = (wrapu, wrapv) - image.clampX = wrapuv[0] - image.clampY = wrapuv[1] - - elif not os.path.exists(newpath): - print "Cannot read attribute file:" + newpath - - def __init__(self, filename, grr, parent=None): - if global_prefs['verbose'] >= 1: - print 'Parsing:', filename - print - - #check to see if filename is a relative path - #filename = os.path.abspath(filename) - - self.fw = flt_filewalker.FltIn(filename) - self.filename = filename - self.bname = os.path.splitext(os.path.basename(filename))[0] - self.grr = grr - - Node.__init__(self, parent, self) - InterNode.__init__(self) - - self.root_handler.set_handler({1: self.parse_header, - 67: self.parse_vertex_palette, - 33: self.parse_long_id, - 31: self.parse_comment, - 64: self.parse_texture_palette, - 32: self.parse_color_palette, - 113: self.parse_mat_palette, - 128: self.parse_appearance_palette, - 10: self.parse_push}) - if parent: - self.root_handler.set_throw_back_lst(throw_back_opcodes) - - self.child_handler.set_handler({#130: self.parse_indexed_light_point, - 111: self.parse_inline_light_point, - 2: self.parse_group, - 73: self.parse_lod, - 4: self.parse_object, - 10: self.parse_push, - 11: self.parse_pop, - 96: self.parse_unhandled, - 14: self.parse_dof, - 91: self.parse_unhandled, - 98: self.parse_unhandled, - 63: self.parse_xref}) - - self.scene = Blender.Scene.New(self.bname) - self.group = Blender.Group.New(self.bname) - - self.vert_pal = None - self.lightpoint_appearance_pal = dict() - self.tex_pal = dict() - #self.tex_pal_lst = list() - #self.bl_tex_pal = dict() - self.col_pal = list() - self.mat_desc_pal_lst = list() - self.mat_desc_pal = dict() - self.props = dict.fromkeys(['id', 'type', 'comment', 'version', 'units', 'set white', - 'flags', 'projection type', 'sw x', 'sw y', 'dx', 'dy', 'dz', 'sw lat', - 'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1', - 'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis']) - - -def clearparent(root,childhash): - for child in childhash[root]: - clearparent(child,childhash) - root.clrParent(2,0) - -def fixscale(root,childhash): - for child in childhash[root]: - fixscale(child,childhash) - location = Blender.Mathutils.Vector(root.getLocation('worldspace')) - if location[0] != 0.0 or location[1] != 0.0 or location[2] != 0.0: - #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector - smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) - root.setLocation(location * smat) - #if its a mesh, we need to scale all of its vertices too - if root.type == 'Mesh': - smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) - rmesh = root.getData(mesh=True) - for v in rmesh.verts: - v.co = v.co * smat - -def reparent(root,childhash,sce): - for child in childhash[root]: - reparent(child,childhash,sce) - - root.makeParent(childhash[root]) - sce.update(1) - -def update_scene(root,sdone): - for object in root.objects: - if object.DupGroup: - try: - child = Blender.Scene.Get(object.DupGroup.name) - except: - child = None - if child and child not in sdone: - update_scene(child,sdone) - root.makeCurrent() - #create a list of children for each object - childhash = dict() - for object in root.objects: - childhash[object] = list() - - for object in root.objects: - if object.parent: - childhash[object.parent].append(object) - - for object in root.objects: - if not object.parent: - #recursivley go through and clear all the children of their transformation, starting at deepest level first. - clearparent(object,childhash) - #now fix the location of everything - fixscale(object,childhash) - #now fix the parenting - reparent(object,childhash,root) - - for object in root.objects: - object.makeDisplayList() - root.update(1) - sdone.append(root) - - -def select_file(filename, grr): - if not Blender.sys.exists(filename): - msg = 'Error: File ' + filename + ' does not exist.' - Blender.Draw.PupMenu(msg) - return - - if not filename.lower().endswith('.flt'): - msg = 'Error: Not a flight file.' - Blender.Draw.PupMenu(msg) - print msg - print - return - - global_prefs['fltfile']= filename - global_prefs['verbose']= 1 - global_prefs['get_texture'] = True - global_prefs['get_diffuse'] = True - global_prefs['get_specular'] = False - global_prefs['get_emissive'] = False - global_prefs['get_alpha'] = True - global_prefs['get_ambient'] = False - global_prefs['get_shininess'] = True - global_prefs['color_from_face'] = True - global_prefs['log to blender'] = True - - - - Blender.Window.WaitCursor(True) - Blender.Window.EditMode(0) - - - FF.add_file_to_search_path(filename) - - if global_prefs['verbose'] >= 1: - print 'Pass 1: Loading.' - print - - load_time = Blender.sys.time() - db = Database(filename,grr) - db.parse() - load_time = Blender.sys.time() - load_time - - if global_prefs['verbose'] >= 1: - print - print 'Pass 2: Importing to Blender.' - print - - import_time = Blender.sys.time() - db.blender_import() - - if global_prefs['attrib']: - print "reading attribute files" - db.read_attribute_files() - - Blender.Window.ViewLayer(range(1,21)) - - update_scene(db.scene,[]) - import_time = Blender.sys.time() - import_time - if global_prefs['verbose'] >= 1: - print 'Done.' - print - print 'Time to parse file: %.3f seconds' % load_time - print 'Time to import to blender: %.3f seconds' % import_time - print 'Total time: %.3f seconds' % (load_time + import_time) - - Blender.Window.WaitCursor(False) - -def setimportscale(ID,val): - global global_prefs - global_prefs['scale'] = val -def setBpath(fname): - global_prefs['fltfile'] = fname - d = dict() - for key in global_prefs: - d[key] = global_prefs[key] - Blender.Registry.SetKey('flt_import', d, 1) - -def event(evt,val): - pass - -from Blender.BGL import * -from Blender import Draw - -def but_event(evt): - - global FLTBaseLabel - global FLTBaseString - global FLTBaseChooser - - global FLTExport - global FLTClose - - global FLTDoXRef - global FLTShadeImport - global FLTAttrib - - global FLTWarn - - #Import DB - if evt == 1: - if global_prefs['verbose'] >= 1: - print - print 'OpenFlight Importer' - print 'Version:', __version__ - print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle' - print __url__[2] - print - - GRR = GlobalResourceRepository() - - try: - select_file(global_prefs['fltfile'], GRR) - except: - import traceback - FLTWarn = Draw.PupBlock("Ixport Error", ["See console for output!"]) - traceback.print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback) - - #choose base path for export - if evt == 4: - Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile']) - #Import custom shading? - if evt == 9: - global_prefs['smoothshading'] = FLTShadeImport.val - #Import Image attribute files - if evt == 10: - global_prefs['attrib'] = FLTAttrib.val - #export XRefs - if evt == 13: - global_prefs['doxrefs'] = FLTDoXRef.val - - if evt == 2: - Draw.Exit() - - d = dict() - for key in global_prefs: - d[key] = global_prefs[key] - Blender.Registry.SetKey('flt_import', d, 1) - -def gui(): - - global FLTBaseLabel - global FLTBaseString - global FLTBaseChooser - - global FLTExport - global FLTClose - - global FLTDoXRef - global FLTShadeImport - - global FLTAttrib - - - glClearColor(0.772,0.832,0.847,1.0) - glClear(GL_COLOR_BUFFER_BIT) - - areas = Blender.Window.GetScreenInfo() - curarea = Blender.Window.GetAreaID() - curRect = None - - for area in areas: - if area['id'] == curarea: - curRect = area['vertices'] - break - - width = curRect[2] - curRect[0] - height = curRect[3] - curRect[1] - cx = 50 - cy = height - 80 - - FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20) - FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file") - FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") - - cy = cy-40 - FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale) - - cy = cy-40 - FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references") - - cy = cy-40 - FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers") - - cy = cy-40 - FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files") - - cy = cy - 40 - FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database") - FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window") - - - -Draw.Register(gui,event,but_event) \ No newline at end of file diff --git a/release/scripts/flt_lodedit.py b/release/scripts/flt_lodedit.py deleted file mode 100644 index 58319b9e525..00000000000 --- a/release/scripts/flt_lodedit.py +++ /dev/null @@ -1,502 +0,0 @@ -#!BPY - -""" -Name: 'FLT LOD Editor' -Blender: 240 -Group: 'Misc' -Tooltip: 'Level of Detail Edtior for FLT nodes' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/07" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# 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 Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -reload(flt_properties) -from flt_properties import * - -#event codes -evcode = { - "LOD_MAKE" : 100, - "LOD_DELETE" : 101, - "LOD_CALC_CENTER" : 102, - "LOD_GRAB_CENTER" : 103, - "LOD_X" : 104, - "LOD_Y" : 105, - "LOD_Z" : 106, - "LOD_FREEZE" : 107, - "LOD_SIG" : 108, - "LOD_IN" : 109, - "LOD_OUT" : 110, - "LOD_TRANS" : 111, - "LOD_PREVIOUS" : 112 -} - - -#system -LOD_MAKE = None #PushButton -LOD_DELETE = None #PushButton -LOD_CALC_CENTER = None #PushButton -LOD_GRAB_CENTER = None #Pushbutton -LOD_FREEZE = None #Toggle -LOD_PREVIOUS = None #Toggle - -LOD_X = None #Input -LOD_Y = None #Input -LOD_Z = None #Input - -LOD_SIG = None #Input -LOD_IN = None #Input -LOD_OUT = None #Input -LOD_TRANS = None #Input - -#labels -LOD_EDITLABEL = None -LOD_SWITCHLABEL = None -LOD_CENTERLABEL = None - -LOD_XLABEL = None -LOD_YLABEL = None -LOD_ZLABEL = None -LOD_SIGLABEL = None -LOD_INLABEL = None -LOD_OUTLABEL = None -LOD_TRANSLABEL = None - - -#ID Props -switch_in = '5d!switch in' -switch_out = '6d!switch out' -xco = '10d!X co' -yco = '11d!Y co' -zco = '12d!Z co' -trans = '13d!Transition' -sig_size = '14d!Sig Size' - -#Flags -lodflag = '9I!flags' -previous_mask = (1 << 31) -freeze_mask = (1 << 29) - -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.GetCurrent() - state["activeObject"] = state["activeScene"].objects.active - if state["activeObject"] and not state["activeObject"].sel: - state["activeObject"] = None - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - - #update editmode - state["editmode"] = Blender.Window.EditMode() - - return state - -def idprops_append(object, typecode, props): - object.properties["FLT"] = dict() - object.properties["FLT"]['type'] = typecode - for prop in props: - object.properties["FLT"][prop] = props[prop] - object.properties["FLT"]['3t8!id'] = object.name - -def idprops_kill(): - state = update_state() - if state["activeObject"] and state["activeObject"].properties.has_key('FLT'): - state["activeObject"].properties.pop('FLT') - -def idprops_copy(source): - state = update_state() - if source.properties.has_key('FLT'): - for object in state["activeScene"].objects: - if object.sel and object != source and (state["activeScene"].Layers & object.Layers): - idprops_kill(object) - object.properties['FLT'] = dict() - for key in source.properties['FLT']: - object.properties['FLT'][key] = source.properties['FLT'][key] - -def select_by_typecode(typecode): - state = update_state() - - for object in state["activeScene"].objects: - if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: - object.select(1) - -def idprops_type(object, typecode): - if object.properties.has_key('FLT') and object.properties['FLT'].has_key('type') and object.properties['FLT']['type'] == typecode: - return True - return False - -#ui type code -def get_prop(typecode, prop): - - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], typecode): - props = state["activeObject"].properties['FLT'] - else: - props = flt_properties.FLTLOD - - return props[prop] - -def set_prop(typecode, prop, value): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"],typecode): - state["activeObject"].properties['FLT'][prop] = value - - - -def get_lockmask(mask): - global lodflag - state = update_state() - if state["activeObject"]: - flag = get_prop(73,lodflag) - if flag & mask: - return True - return False - -def set_lockmask(mask): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 73): - oldvalue = state["activeObject"].properties['FLT'][lodflag] - oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0] - oldvalue |= mask - state["activeObject"].properties['FLT'][lodflag] = struct.unpack('>i', struct.pack(">I", oldvalue))[0] - -def clear_lockmask(mask): - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 73): - oldvalue = state["activeObject"].properties['FLT'][lodflag] - oldvalue = struct.unpack('>I', struct.pack('>i', oldvalue))[0] - oldvalue &= ~mask - state["activeObject"].properties['FLT'][lodflag] = struct.unpack('>i',struct.pack('>I',oldvalue))[0] - -def findchildren(object): - state = update_state() - children = list() - for candidate in state["activeScene"].objects: - if candidate.parent == object: - children.append(candidate) - retlist = list(children) - for child in children: - retlist = retlist + findchildren(child) - return retlist - -def get_object_center(object): - bbox = object.getBoundBox(1) - average = Blender.Mathutils.Vector(0.0, 0.0, 0.0) - - for point in bbox: - average[0] += point[0] - average[1] += point[1] - average[2] += point[2] - - average[0] = average[0] / 8.0 - average[1] = average[1] / 8.0 - average[2] = average[2] / 8.0 - - return average - - -def calc_center(): - - global xco - global yco - global zco - - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 73): - average = Blender.Mathutils.Vector(0.0, 0.0, 0.0) - children = findchildren(state["activeObject"]) #get children objects - if children: - for child in children: - center = get_object_center(child) - average[0] += center[0] - average[1] += center[1] - average[2] += center[2] - - average[0] = average[0] / len(children) - average[1] = average[1] / len(children) - average[2] = average[2] / len(children) - - set_prop(73, xco, average[0]) - set_prop(73, yco, average[1]) - set_prop(73, zco, average[2]) - - -def grab_center(): - - global xco - global yco - global zco - - state = update_state() - if state["activeObject"] and idprops_type(state["activeObject"], 73): - center = Blender.Window.GetCursorPos() - - set_prop(73, xco, center[0]) - set_prop(73, yco, center[1]) - set_prop(73, zco, center[2]) - - -def create_lod(): - state = update_state() - actobj = state["activeObject"] - if actobj and not idprops_type(actobj, 73): - idprops_kill() - idprops_append(actobj,73, flt_properties.FLTLOD) - calc_center() - - - -def event(evt,val): - if evt == Draw.ESCKEY: - Draw.Exit() - -def but_event(evt): - - global LOD_MAKE - global LOD_DELETE - global LOD_CALC_CENTER - global LOD_GRAB_CENTER - global LOD_FREEZE - global LOD_PREVIOUS - global LOD_X - global LOD_Y - global LOD_Z - global LOD_SIG - global LOD_IN - global LOD_OUT - global LOD_TRANS - - global switch_in - global switch_out - global xco - global yco - global zco - global trans - global sig_size - - global lodflag - global previous_mask - global freeze_mask - - global evcode - - #do "system" events - if evt == evcode["LOD_MAKE"]: - create_lod() - - if evt == evcode["LOD_CALC_CENTER"]: - calc_center() - - if evt == evcode["LOD_DELETE"]: - idprops_kill() - - if evt == evcode["LOD_GRAB_CENTER"]: - grab_center() - - #do mask events - if evt == evcode["LOD_FREEZE"]: - if LOD_FREEZE.val == True: - set_lockmask(freeze_mask) - else: - clear_lockmask(freeze_mask) - - if evt == evcode["LOD_PREVIOUS"]: - if LOD_PREVIOUS.val == True: - set_lockmask(previous_mask) - else: - clear_lockmask(previous_mask) - - #do input events - if evt == evcode["LOD_X"]: - set_prop(73, xco, LOD_X.val) - if evt == evcode["LOD_Y"]: - set_prop(73, yco, LOD_Y.val) - if evt == evcode["LOD_Z"]: - set_prop(73, zco, LOD_Z.val) - if evt == evcode["LOD_SIG"]: - set_prop(73, sig_size, LOD_SIG.val) - if evt == evcode["LOD_IN"]: - set_prop(73, switch_in, LOD_IN.val) - if evt == evcode["LOD_OUT"]: - set_prop(73, switch_out, LOD_OUT.val) - if evt == evcode["LOD_TRANS"]: - set_prop(73, trans, LOD_TRANS.val) - - - Draw.Redraw(1) - Blender.Window.RedrawAll() - -def draw_propsheet(x,y): - - global LOD_MAKE - global LOD_DELETE - global LOD_CALC_CENTER - global LOD_GRAB_CENTER - global LOD_FREEZE - global LOD_PREVIOUS - global LOD_X - global LOD_Y - global LOD_Z - global LOD_SIG - global LOD_IN - global LOD_OUT - global LOD_TRANS - - #labels - global LOD_EDITLABEL - global LOD_SWITCHLABEL - global LOD_CENTERLABEL - global LOD_XLABEL - global LOD_YLABEL - global LOD_ZLABEL - global LOD_SIGLABEL - global LOD_INLABEL - global LOD_OUTLABEL - global LOD_TRANSLABEL - - - global switch_in - global switch_out - global xco - global yco - global zco - global trans - global sig_size - - global lodflag - global previous_mask - global freeze_mask - - global evcode - - - global evcode - - state = update_state() - - label_width = 100 - row_height = 20 - toggle_width = 50 - input_width = 100 - pad = 10 - origx = x - origy = (row_height * 16) + (pad * 16) - - - #editor label - x = origx - y = origy - LOD_EDITLABEL = Blender.Draw.Label("FLT Level of Detail Editor", x, y, 250, row_height) - - - #Center inputs - x = origx - y = y- (row_height + pad) - LOD_CENTERLABEL = Blender.Draw.Label("LOD center", x, y, label_width, row_height) - y = y- (row_height + pad) - LOD_XLABEL = Blender.Draw.Label("X Coordinate", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_X = Blender.Draw.Number("", evcode["LOD_X"], x, y, input_width, row_height,get_prop(73,xco), -1000000.0, 1000000.0, "") - x = origx - y = y- (row_height + pad) - LOD_YLABEL = Blender.Draw.Label("Y Coordinate", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_Y = Blender.Draw.Number("", evcode["LOD_Y"], x, y, input_width, row_height,get_prop(73,yco), -1000000.0, 1000000.0, "") - x = origx - y = y- (row_height + pad) - LOD_ZLABEL = Blender.Draw.Label("Z Coordinate", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_Z = Blender.Draw.Number("", evcode["LOD_Z"], x, y, input_width, row_height,get_prop(73,zco), -1000000.0, 1000000.0, "") - - - #Switch inputs - x = origx - y = y- (row_height + pad) - LOD_SWITCHLABEL = Blender.Draw.Label("Switch Settings", x, y, input_width, row_height) - y = y- (row_height + pad) - LOD_SIGLABEL = Blender.Draw.Label("Significant Size", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_SIG = Blender.Draw.Number("", evcode["LOD_SIG"], x, y, input_width, row_height, get_prop(73,sig_size), -1000000.0, 1000000.0, "") - x = origx - y = y- (row_height + pad) - LOD_INLABEL = Blender.Draw.Label("Switch In", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_IN = Blender.Draw.Number("", evcode["LOD_IN"], x, y, input_width, row_height, get_prop(73,switch_in), -1000000.0, 1000000.0, "") - x = origx - y = y- (row_height + pad) - LOD_OUTLABEL = Blender.Draw.Label("Switch Out", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_OUT = Blender.Draw.Number("", evcode["LOD_OUT"], x, y, input_width, row_height, get_prop(73,switch_out), -1000000.0, 1000000.0, "") - x = origx - y = y- (row_height + pad) - LOD_TRANSLABEL = Blender.Draw.Label("Transition", x, y, label_width, row_height) - x = origx + (label_width + pad) - LOD_TRANS = Blender.Draw.Number("", evcode["LOD_TRANS"], x, y, input_width, row_height, get_prop(73,trans), -1000000.0, 1000000.0, "") - - - x = origx - y = y - (row_height + pad) - LOD_MAKE = Blender.Draw.PushButton("Make LOD", evcode["LOD_MAKE"], x, y, input_width + label_width + pad, row_height, "Make a LOD Node out of Active Object") - y = y - (row_height + pad) - LOD_DELETE = Blender.Draw.PushButton("Delete LOD", evcode["LOD_DELETE"], x, y, input_width + label_width + pad, row_height, "Delete the LOD Node properties") - y = y - (row_height + pad) - LOD_CALC_CENTER = Blender.Draw.PushButton("Calculate Center", evcode["LOD_CALC_CENTER"], x, y, input_width + label_width + pad, row_height, "Calculate the center of this LOD") - y = y - (row_height + pad) - LOD_GRAB_CENTER = Blender.Draw.PushButton("Grab Center", evcode["LOD_GRAB_CENTER"], x, y, input_width + label_width + pad, row_height, "Grab center from 3d cursor") - y = y - (row_height + pad) - LOD_FREEZE = Blender.Draw.Toggle("Freeze Center", evcode["LOD_FREEZE"], x, y, input_width + label_width + pad, row_height, get_lockmask(freeze_mask), "") - y = y - (row_height + pad) - LOD_PREVIOUS = Blender.Draw.Toggle("Previous Range", evcode["LOD_PREVIOUS"], x, y, input_width + label_width + pad, row_height, get_lockmask(previous_mask), "") - -def gui(): - #draw the propsheet/toolbox. - psheety = 800 - #psheetx = psheety + 10 - draw_propsheet(20,psheety) - -Draw.Register(gui,event,but_event) - \ No newline at end of file diff --git a/release/scripts/flt_palettemanager.py b/release/scripts/flt_palettemanager.py deleted file mode 100644 index c2f1380a6fa..00000000000 --- a/release/scripts/flt_palettemanager.py +++ /dev/null @@ -1,505 +0,0 @@ -#!BPY - -""" -Name: 'FLT Palette Manager' -Blender: 240 -Group: 'Misc' -Tooltip: 'Manage FLT colors' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/2007" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ - -This script manages colors in OpenFlight databases. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Todo: --Figure out whats causing the PC speaker to beep when initializing... - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 1.0 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# 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 Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -import flt_defaultp as defaultp -from flt_properties import * - -def RGBtoHSV( r, g, b): - minc = min( r, g, b ) - maxc = max( r, g, b ) - v = maxc - - delta = maxc - minc - - if( max != 0 ): - s = delta / maxc - else: - s = 0 - h = -1 - return (h,s,v) - - if( r == maxc ): - h = ( g - b ) / delta - elif( g == maxc ): - h = 2 + ( b - r ) / delta - else: - h = 4 + ( r - g ) / delta - - h *= 60 - if( h < 0 ): - h += 360 - - return(h,s,v) - -def HSVtoRGB(h,s,v): - - if( s == 0 ): - return (v,v,v) - - - h /= 60 - i = math.floor( h) - f = h - i - p = v * ( 1 - s ) - q = v * ( 1 - s * f ) - t = v * ( 1 - s * ( 1 - f ) ) - - if i == 0: - r = v - g = t - b = p - elif i == 1: - r = q - g = v - b = p - - elif i== 2: - r = p - g = v - b = t - elif i==3: - r = p - g = q - b = v - elif i==4: - r = t - g = p - b = v - - else: - r = v - g = p - b = q - - return(r,g,b) - - -palette_size = 12 -palette_x = 0 -palette_y = 0 - -colors = list() -curint = 1.0 -curswatch = 0 -#make a default palette, not very useful. -cinc = 1.0 / 1024.0 -cstep = 0.0 -picker = None -ptt = "" - - -ts1=None -ts2=None -ts3=None -ts4=None -ts5=None - -for i in xrange(1024): - colors.append([cstep,cstep,cstep]) - cstep = cstep + cinc -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.getCurrent() - state["activeObject"] = state["activeScene"].getActiveObject() - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - return state - -def pack_face_index(index, intensity): - return ((127*intensity)+(128*index)) -def unpack_face_index(face_index): - index = face_index / 128 - intensity = float(face_index - 128.0 * index) / 127.0 - return(index,intensity) - -def event(evt,val): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - - areas = Blender.Window.GetScreenInfo() - curarea = Blender.Window.GetAreaID() - curRect = None - editmode = 0 - - for area in areas: - if area['id'] == curarea: - curRect = area['vertices'] - break - - if evt == Draw.LEFTMOUSE: - mval = Blender.Window.GetMouseCoords() - rastx = mval[0] - curRect[0] - rasty = mval[1] - curRect[1] - - swatchx = (rastx -palette_x) / palette_size #+state["palette_x"] - swatchy = (rasty -palette_y) / palette_size #+state["palette_y"] - if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32): - if swatchx < 32 and swatchy < 32: - curswatch = (swatchx * 32) + swatchy - Draw.Redraw(1) - - elif swatchy < 34 and swatchx < 32: - curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0)) - Draw.Redraw(1) - - #copy current color and intensity to selected faces. - elif evt == Draw.VKEY: - - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - #retrieve color from palette - color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch])) - actmesh = state["activeMesh"] - if actmesh: - if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]): - selfaces = list() - for face in actmesh.faces: - if face.sel: - selfaces.append(face) - - if not "FLT_COL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) - for face in actmesh.faces: - face.setProperty("FLT_COL",127) #default - try: - actmesh.activeColorLayer = "FLT_Fcol" - except: - actmesh.addColorLayer("FLT_Fcol") - actmesh.activeColorLayer = "FLT_Fcol" - - - for face in selfaces: - #First append packed index + color and store in face property - face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint))) - #Save baked color to face vertex colors - for col in face.col: - col.r = int(color[0] * curint) - col.g = int(color[1] * curint) - col.b = int(color[2] * curint) - col.a = int(color[3] * curint) - else: - if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']: - if not 'FLT_VCOL' in actmesh.verts.properties: - actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) - for vert in actmesh.verts: - vert.setProperty("FLT_VCOL",127) - else: - for vert in actmesh.verts: - if vert.sel: - vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint))) - - if editmode: - Blender.Window.EditMode(1) - - Blender.Window.RedrawAll() - - #grab color and intensity from active face - elif evt == Draw.CKEY: - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - - - if activeFace: - if not "FLT_COL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) - for face in actmesh.faces: - face.setProperty("FLT_COL",127) #default - try: - actmesh.activeColorLayer = "FLT_Fcol" - except: - actmesh.addColorLayer("FLT_Fcol") - actmesh.activeColorLayer = "FLT_Fcol" - tcol = activeFace.getProperty("FLT_COL") - (index,intensity) = unpack_face_index(tcol) - curswatch = index - curint = intensity - - if editmode: - Blender.Window.EditMode(1) - - Blender.Window.RedrawAll() - - elif evt == Draw.GKEY: - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode =1 - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - - if activeFace and "FLT_COL" in actmesh.faces.properties: - (index,intensity) = unpack_face_index(activeFace.getProperty("FLT_COL")) - for face in actmesh.faces: - (index2, intensity2) = unpack_face_index(face.getProperty("FLT_COL")) - if index == index2: - face.sel = 1 - - - elif evt == Draw.ESCKEY: - Draw.Exit() - - if editmode: - Blender.Window.EditMode(1) - -def update_all(): - global colors - state = update_state() - #update the baked FLT colors for all meshes. - for object in state["activeScene"].objects: - if object.type == "Mesh": - mesh = object.getData(mesh=True) - if 'FLT_COL' in mesh.faces.properties and "FLT_Fcol" in mesh.getColorLayerNames(): - mesh.activeColorLayer = "FLT_Fcol" - for face in mesh.faces: - (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) - color = struct.unpack('>BBBB',struct.pack('>i',colors[index])) - #update the vertex colors for this face - for col in face.col: - col.r = int(color[0] * intensity) - col.g = int(color[1] * intensity) - col.b = int(color[2] * intensity) - col.a = 255 - - -def but_event(evt): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - global picker - state = update_state() - - if evt == 1: - if picker.val: - rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255) - rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3]) - rval = struct.unpack('>i',rval) - colors[curswatch] = rval[0] - #go cd through all meshes and update their FLT colors - update_all() - - Draw.Redraw(1) -def init_pal(): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - - state = update_state() - - if not state["activeScene"].properties.has_key('FLT'): - state["activeScene"].properties['FLT'] = dict() - - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal - colors = state["activeScene"].properties['FLT']['Color Palette'] - -def draw_palette(): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - global picker - global ts1 - global ts2 - global ts3 - global ts4 - global ts5 - - state = update_state() - init_pal() - - ssize = palette_size - xpos = palette_x - cid = 0 - - highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)] - for x in xrange(32): - ypos = palette_y - for y in xrange(32): - color = struct.unpack('>BBBB',struct.pack('>i',colors[cid])) - glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0) - glBegin(GL_POLYGON) - glVertex2i(xpos,ypos) - glVertex2i(xpos+ssize,ypos) - glVertex2i(xpos+ssize,ypos+ssize) - glVertex2i(xpos,ypos+ssize) - glEnd() - - if curswatch == cid: - highlight[0] = (xpos,ypos) - highlight[1] = (xpos+ssize,ypos) - highlight[2] = (xpos+ssize,ypos+ssize) - highlight[3] = (xpos,ypos+ssize) - - glColor3f(0.0,0.0,0.0) - glBegin(GL_LINE_LOOP) - glVertex2i(xpos,ypos) - glVertex2i(xpos+ssize,ypos) - glVertex2i(xpos+ssize,ypos+ssize) - glVertex2i(xpos,ypos+ssize) - glVertex2i(xpos,ypos) - glEnd() - - - cid = cid + 1 - ypos = ypos + ssize - - xpos = xpos + ssize - - #draw intensity gradient - color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch])) - color = [color[0]/255.0,color[1]/255.0,color[2]/255.0] - colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0] - stripwidth = (palette_size * 32.0) / 256 - strippad = palette_size / 2.0 - - xpos = palette_x - grady = (palette_y + (palette_size * 32.0)) + strippad - for x in xrange(256): - color[0] = color[0] - colsteps[0] - color[1] = color[1] - colsteps[1] - color[2] = color[2] - colsteps[2] - - glColor3f(color[0], color[1] ,color[2]) - glBegin(GL_POLYGON) - glVertex2f(xpos,grady) - glVertex2f(xpos+stripwidth,grady) - glVertex2f(xpos+stripwidth,grady+palette_size) - glVertex2f(xpos,grady+palette_size) - glEnd() - xpos = xpos + stripwidth - - #draw intensity slider bar - #xposition == 512 - ((curint) * 512) - xpos = ((palette_size*32) * (1.0 - curint)) + palette_x - glColor3f(1.0,1.0,1.0) - glBegin(GL_LINE_LOOP) - glVertex2i(int(xpos-6),int(grady-1)) - glVertex2i(int(xpos+6),int(grady-1)) - glVertex2i(int(xpos+6),int(grady+palette_size+1)) - glVertex2i(int(xpos-6),int(grady+palette_size+1)) - #glVertex2i(xpos-6,grady+7) - glEnd() - - #draw color picker - color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch])) - pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0) - picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt) - - #draw highlight swatch - glColor3f(1.0,1.0,1.0) - glBegin(GL_LINE_LOOP) - glVertex2i(highlight[0][0],highlight[0][1]) - glVertex2i(highlight[1][0],highlight[1][1]) - glVertex2i(highlight[2][0],highlight[2][1]) - glVertex2i(highlight[3][0],highlight[3][1]) - glVertex2i(highlight[0][0],highlight[0][1]) - glEnd() - - #draw text string explanations - xpos = palette_size*32+20 - ypos = palette_size*32+10 - glRasterPos2d(xpos,ypos) - ts1 = Blender.Draw.Text("FLT Palette Manager V 1.0") - ypos = ypos - 20 - glRasterPos2d(xpos,ypos) - ts3 = Blender.Draw.Text("CKEY - Copy Active Face Color*") - ypos = ypos - 20 - glRasterPos2d(xpos,ypos) - ts2 = Blender.Draw.Text("VKEY - Paste Color to Selected Faces") - ypos = ypos - 20 - glRasterPos2d(xpos,ypos) - ts4 = Blender.Draw.Text("GKEY - Select Faces With Same Color") - ypos = ypos - 15 - glRasterPos2d(xpos,ypos) - ts5 = Blender.Draw.Text("(*Requires mesh with UV coordinates)", 'small') - -def gui(): - glClearColor(0.5,0.5,0.5,1.0) - glClear(GL_COLOR_BUFFER_BIT) - draw_palette() - - -init_pal() -Draw.Register(gui,event,but_event) - \ No newline at end of file diff --git a/release/scripts/flt_properties.py b/release/scripts/flt_properties.py deleted file mode 100644 index b9d93b5f52d..00000000000 --- a/release/scripts/flt_properties.py +++ /dev/null @@ -1,630 +0,0 @@ -# flt_properties.py. For setting default OpenFLight ID property types -# Copyright (C) 2007 Blender Foundation -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -__bpydoc__ ="""\ -Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. -""" - - -import struct - -bitsLSB = [2147483648] -for i in xrange(31): - bitsLSB.append(bitsLSB[-1]/2) -bitsRSB = bitsLSB[:] -bitsRSB.reverse() - -def pack_color(col): - return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0]) - -def unpack_color(col): - string = struct.pack('>I', col) - r = struct.unpack('>B',string[3:4]) - g = struct.unpack('>B',string[2:3]) - b = struct.unpack('>B',string[1:2]) - a = struct.unpack('>B',string[0:1]) - return [r,g,b,a] - -def reverse_bits(len,num): - bitbucket = list() - rval = 0 - - for i in xrange(len): - if num & bitsRSB[i]: - bitbucket.append(1) - else: - bitbucket.append(0) - - bitbucket.reverse() - - for i, bit in enumerate(bitbucket): - if bit: - rval |= bitsLSB[i] - - return rval - - -opcode_name = { 0: 'db', - 1: 'head', - 2: 'grp', - 4: 'obj', - 5: 'face', - 10: 'push', - 11: 'pop', - 14: 'dof', - 19: 'push sub', - 20: 'pop sub', - 21: 'push ext', - 22: 'pop ext', - 23: 'cont', - 31: 'comment', - 32: 'color pal', - 33: 'long id', - 49: 'matrix', - 50: 'vector', - 52: 'multi-tex', - 53: 'uv lst', - 55: 'bsp', - 60: 'rep', - 61: 'inst ref', - 62: 'inst def', - 63: 'ext ref', - 64: 'tex pal', - 67: 'vert pal', - 68: 'vert w col', - 69: 'vert w col & norm', - 70: 'vert w col, norm & uv', - 71: 'vert w col & uv', - 72: 'vert lst', - 73: 'lod', - 74: 'bndin box', - 76: 'rot edge', - 78: 'trans', - 79: 'scl', - 80: 'rot pnt', - 81: 'rot and/or scale pnt', - 82: 'put', - 83: 'eyepoint & trackplane pal', - 84: 'mesh', - 85: 'local vert pool', - 86: 'mesh prim', - 87: 'road seg', - 88: 'road zone', - 89: 'morph vert lst', - 90: 'link pal', - 91: 'snd', - 92: 'rd path', - 93: 'snd pal', - 94: 'gen matrix', - 95: 'txt', - 96: 'sw', - 97: 'line styl pal', - 98: 'clip reg', - 100: 'ext', - 101: 'light src', - 102: 'light src pal', - 103: 'reserved', - 104: 'reserved', - 105: 'bndin sph', - 106: 'bndin cyl', - 107: 'bndin hull', - 108: 'bndin vol cntr', - 109: 'bndin vol orient', - 110: 'rsrvd', - 111: 'light pnt', - 112: 'tex map pal', - 113: 'mat pal', - 114: 'name tab', - 115: 'cat', - 116: 'cat dat', - 117: 'rsrvd', - 118: 'rsrvd', - 119: 'bounding hist', - 120: 'rsrvd', - 121: 'rsrvd', - 122: 'push attrib', - 123: 'pop attrib', - 124: 'rsrvd', - 125: 'rsrvd', - 126: 'curv', - 127: 'road const', - 128: 'light pnt appear pal', - 129: 'light pnt anim pal', - 130: 'indexed lp', - 131: 'lp sys', - 132: 'indx str', - 133: 'shdr pal'} - - -typecodes = ['c','C','s','S','i','I','f','d','t'] - -FLT_GRP = 2 -FLT_OBJ = 4 -FLT_LOD = 73 -FLT_XRF = 63 -FLT_DOF = 14 -FLT_ILP = 111 -FLT_DB = 1 -FLT_FCE = 5 - -#not actual opcodes -FLT_NUL = 0 -FLT_EXP = -1 - -#valid childtypes for each FLT node type -FLT_CHILDTYPES = { - FLT_GRP : [111,2,73,4,14,63], - FLT_OBJ : [111], - FLT_LOD : [111,2,73,4,14,63], - FLT_XRF : [], - FLT_DOF : [111,2,73,4,14,63], - FLT_ILP : [] -} - -#List of nodes that can have faces as children -FLT_FACETYPES = [ - FLT_GRP, - FLT_OBJ, - FLT_LOD, - FLT_DOF -] - -def write_prop(fw,type,value,length): - if type == 'c': - fw.write_char(value) - elif type == 'C': - fw.write_uchar(value) - elif type == 's': - fw.write_short(value) - elif type == 'S': - fw.write_ushort(value) - elif type == 'i': - fw.write_int(value) - elif type == 'I': - #NOTE!: - #there is no unsigned int type in python, but we can only store signed ints in ID props - newvalue = struct.unpack('>I', struct.pack('>i', value))[0] - fw.write_uint(newvalue) - elif type == 'd': - fw.write_double(value) - elif type == 'f': - fw.write_float(value) - elif type == 't': - fw.write_string(value,length) - -def read_prop(fw,type,length): - rval = None - if type == 'c': - rval = fw.read_char() - elif type == 'C': - rval = fw.read_uchar() - elif type == 's': - rval = fw.read_short() - elif type == 'S': - rval = fw.read_ushort() - elif type == 'i': - rval = fw.read_int() - elif type == 'I': - rval = fw.read_uint() - elif type == 'd': - rval = fw.read_double() - elif type == 'f': - rval = fw.read_float() - elif type == 't': - rval = fw.read_string(length) - return rval - - -FLTExt = { - '3t8!id' : 'Ext', - '4t8!sid' : '', - '5c!reserved': 0, - '6c!revision' : 0, - '7S!recordcode' : 0 -} -FLTGroup = { - '3t8!id' : 'G', - '4s!priority' : 0, - '5s!reserved1' : 0, - '6i!flags' : 0, - '7s!special1' : 0, - '8s!special2' : 0, - '9s!significance' : 0, - '10c!layer code' : 0, - '11c!reserved2' : 0, - '12i!reserved3' : 0, - '13i!loop count' : 0, - '14f!loop duration' : 0, - '15f!last frame duration' : 0 -} -FLTGroupDisplay = [5,11,12] - -FLTObject = { - '3t8!id' : 'O', - '4I!flags' : 0, - '5s!priority' : 0, - '6S!transp' : 0, - '7s!SFX1' : 0, - '8s!SFX2' : 0, - '9s!significance' : 0, - '10s!reserved' : 0 -} -FLTObjectDisplay = [10] - -FLTLOD = { - '3t8!id' : 'L', - '4i!reserved' : 0, - '5d!switch in' : 0.0, - '6d!switch out' : 0.0, - '7s!sfx ID1' : 0, - '8s!sfx ID2' : 0, - '9I!flags' : 0, - '10d!X co' : 0.0, - '11d!Y co' : 0.0, - '12d!Z co' : 0.0, - '13d!Transition' : 0.0, - '14d!Sig Size' : 0.0 -} -FLTLODDisplay = [4] - -FLTInlineLP = { - '3t8!id' : 'Lp', - '4s!smc' : 0, - '5s!fid' : 0, - '6C!back color: a' : 255, - '7C!back color: b' : 255, - '8C!back color: g' : 255, - '9C!back color: r' : 255, - '10i!display mode' : 0, - '11f!intensity' : 1.0, - '12f!back intensity' : 0.0, - '13f!minimum defocus' : 0.0, - '14f!maximum defocus' : 1.0, - '15i!fading mode' : 0, - '16i!fog punch mode' : 0, - '17i!directional mode' : 1, - '18i!range mode' : 0, - '19f!min pixel size' : 1.0, - '20f!max pixel size' : 1024, - '21f!actual size' : 0.25, - '22f!trans falloff pixel size' : 0.25, - '23f!trans falloff exponent' : 1.0, - '24f!trans falloff scalar' : 1.0, - '25f!trans falloff clamp' : 1.0, - '26f!fog scalar' : 0.25, - '27f!fog intensity' : 1.0, - '28f!size threshold' : 0.1, - '29i!directionality' : 0, - '30f!horizontal lobe angle' : 180.0, - '31f!vertical lobe angle' : 180.0, - '32f!lobe roll angle' : 0.0, - '33f!dir falloff exponent' : 1.0, - '34f!dir ambient intensity' : 0.1, - '35f!anim period' : 2, - '36f!anim phase' : 0, - '37f!anim enabled' : 1.0, - '38f!significance' : 0.0, - '39i!draw order' : 0, - '40I!flags' : 277004288, - '41f!roti' : 0, - '42f!rotj' : 0, - '43f!rotk' : 1.0 -} - -FLTInlineLPDisplay = [35,36,37,41,42,43] - -FLTXRef = { - '3t200!filename' : '', #we dont actually use this value on export - '4i!reserved' : 0, - '5I!flag' : -478150656, - '6s!bbox' : 0, - '7s!reserved' : 0 -} - -FLTXRefDisplay = [4,7,3] - -FLTDOF = { - '3t8!id' : 'D', - '4i!reserved' : 0, - '5d!ORIGX' : 0.0, - '6d!ORIGY' : 0.0, - '7d!ORIGZ' : 0.0, - '8d!XAXIS-X' : 10.0, - '9d!XAXIS-Y' : 0.0, - '10d!XAXIS-Z' : 0.0, - '11d!XYPLANE-X' : 0.0, - '12d!XYPLANE-Y' : 10.0, - '13d!XZPLANE-Z' : 0.0, - '14d!ZMIN' : 0.0, - '15d!ZMAX' : 0.0, - '16d!ZCUR' : 0.0, - '17d!ZSTEP' : 0.0, - '18d!YMIN' : 0.0, - '19d!YMAX' : 0.0, - '20d!YCUR' : 0.0, - '21d!YSTEP' : 0.0, - '22d!XMIN' : 0.0, - '23d!XMAX' : 0.0, - '24d!XCUR' : 0.0, - '25d!XSTEP' : 0.0, - '26d!PITCH-MIN' : 0.0, - '27d!PITCH-MAX' : 0.0, - '28d!PITCH-CUR' : 0.0, - '29d!PITCH-STEP' : 0.0, - '30d!ROLL-MIN' : 0.0, - '31d!ROLL-MAX' : 0.0, - '32d!ROLL-CUR' : 0.0, - '33d!ROLL-STEP' : 0.0, - '34d!YAW-MIN' : 0.0, - '35d!YAW-MAX' : 0.0, - '36d!YAW-CUR' : 0.0, - '37d!YAW-STEP' : 0.0, - '38d!ZSIZE-MIN' : 0.0, - '39d!ZSIZE-MAX' : 0.0, - '40d!ZSIZE-CUR' : 1.0, - '41d!ZSIZE-STEP' : 0.0, - '42d!YSIZE-MIN' : 0.0, - '43d!YSIZE-MAX' : 0.0, - '44d!YSIZE-CUR' : 1.0, - '45d!YSIZE-STEP' : 0.0, - '46d!XSIZE-MIN' : 0.0, - '47d!XSIZE-MAX' : 0.0, - '48d!XSIZE-CUR' : 1.0, - '49d!XSIZE-STEP' : 0.0, - '50I!FLAG' : 1897582, - '51i!reserved2' : 0 -} - -FLTDOFDisplay = [4] - -FLTImage = { - '3i!RealU Direction' : 0, - '4i!RealV Direction' : 0, - '5i!UpX' : 0, - '6i!UpY' : 0, - '7i!File Format' : 0, - '8i!Min Filter' : 6, - '9i!Mag Filter' : 1, - '10i!Wrap' : 0, - '11i!WrapU' : 0, - '12i!WrapV' : 0, - '13i!Modified' : 0, - '14i!PivotX' : 0, - '15i!PivotY' : 0, - '16i!Enviorment' : 0, - '17i!WhiteAlpha' : 0, - '18i!reserved1' : 0, - '19i!reserved2' : 0, - '20i!reserved3' : 0, - '21i!reserved4' : 0, - '22i!reserved5' : 0, - '23i!reserved6' : 0, - '24i!reserved7' : 0, - '25i!reserved8' : 0, - '26i!reserved9' : 0, - '27d!RealU Direction' : 0, - '28d!RealV Direction' : 0, - '29i!Origin' : 0, - '30i!Kernel no.' : 0, - '31i!Internal Format' : 0, - '32i!External Format' : 0, - '33i!MipMap Filter?' : 0, - '34f!MMF1' : 0.0, - '35f!MMF2' : 0.0, - '36f!MMF3' : 0.0, - '37f!MMF4' : 0.0, - '38f!MMF5' : 0.0, - '39f!MMF6' : 0.0, - '40f!MMF7' : 0.0, - '41f!MMF8' : 0.0, - '42i!Tex CPs?' : 0, - '43f!LOD0 CP' : 0.0, - '44f!Scale0 CP' : 0.0, - '45f!LOD1 CP' : 0.0, - '46f!Scale1 CP' : 0.0, - '47f!LOD2 CP' : 0.0, - '48f!Scale2 CP' : 0.0, - '49f!LOD3 CP' : 0.0, - '50f!Scale3 CP' : 0.0, - '51f!LOD4 CP' : 0.0, - '52f!Scale4 CP' : 0.0, - '53f!LOD5 CP' : 0.0, - '54f!Scale5 CP' : 0.0, - '55f!LOD6 CP' : 0.0, - '56f!Scale6 CP' : 0.0, - '57f!LOD7 CP' : 0.0, - '58f!Scale7 CP' : 0.0, - '59f!Control Clamp' : 0.0, - '60i!Mag Alpha Filter' : 0, - '61i!Mag Color Filter' : 0, - '62f!reserved10' : 0, - '63f!reserved11' : 0, - '64f!reserved12' : 0, - '65f!reserved13' : 0, - '66f!reserved14' : 0, - '67f!reserved15' : 0, - '68f!reserved16' : 0, - '69f!reserved17' : 0, - '70f!reserved18' : 0, - '71d!Lambert Central' : 0.0, - '72d!Lambert Upper' : 0.0, - '73d!Lambert Lower' : 0.0, - '74d!reserved19' : 0, - '75f!reserved20' : 0, - '76f!reserved21' : 0, - '77f!reserved22' : 0, - '78f!reserved23' : 0, - '79f!reserved24' : 0, - '80i!Tex Detail?' : 0, - '81i!Tex J' : 0, - '82i!Tex K' : 0, - '83i!Tex M' : 0, - '84i!Tex N' : 0, - '85i!Tex Scramble' : 0, - '86i!Tex Tile?' : 0, - '87f!Tex Tile LLU' : 0.0, - '88f!Tex Tile LLV' : 0.0, - '89f!Tex Tile URU' : 0.0, - '90f!Tex Tile URV' : 0.0, - '91i!Projection' : 0, - '92i!Earth Model' : 0, - '93i!reserved25' : 0, - '94i!UTM Zone' : 0, - '95i!Image Origin' : 0, - '96i!GPU' : 0, - '97i!reserved26' : 0, - '98i!reserved27' : 0, - '99i!GPU Hemi' : 0, - '100i!reserved41' : 0, - '101i!reserved42' : 0, - '102i!reserved43' : 0, - '103i!Cubemap' : 0, - '104t588!reserved44' : '', - '105t512!Comments' : '', - '106i!reserved28' : 0, - '107i!reserved29' : 0, - '108i!reserved30' : 0, - '109i!reserved31' : 0, - '110i!reserved32' : 0, - '111i!reserved33' : 0, - '112i!reserved34' : 0, - '113i!reserved35' : 0, - '114i!reserved36' : 0, - '115i!reserved37' : 0, - '116i!reserved38' : 0, - '117i!reserved39' : 0, - '118i!reserved40' : 0, - '119i!reserved45' : 0, - '120i!Format Version' : 0, - '121i!GPU num' : 0, -} - -FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114] - -FLTHeader = { - '3t8!id' : 'db', - '4i!version' : 1620, - '5i!editversion' : 0, - '6t32!date' : 0, - '7s!NGID' : 0, - '8s!NLID' : 0, - '9s!NOID' : 0, - '10s!NFID' : 0, - '11s!UMULT' : 1, - '12c!units' : 0, - '13c!set white' : 0, - '14I!flags' : 0x80000000, - '15i!reserved1' : 0, - '16i!reserved2' : 0, - '17i!reserved3' : 0, - '18i!reserved4' : 0, - '19i!reserved5' : 0, - '20i!reserved6' : 0, - '21i!projection type' : 0, - '22i!reserved7' : 0, - '23i!reserved8' : 0, - '24i!reserved9' : 0, - '25i!reserved10' : 0, - '26i!reserved11' : 0, - '27i!reserved12' : 0, - '28i!reserved13' : 0, - '29s!NDID' : 0, - '30s!vstore' : 1, - '31i!origin' : 0, - '32d!sw x' : 0, - '33d!sw y' : 0, - '34d!dx' : 0, - '35d!dy' : 0, - '36s!NSID' : 0, - '37s!NPID' : 0, - '38i!reserved14' : 0, - '39i!reserved15' : 0, - '40s!NCID' : 0, - '41s!NTID' : 0, - '42s!NBID' : 0, - '43s!NWID' : 0, - '44i!reserved14' : 0, - '45d!sw lat' : 0, - '46d!sw lon' : 0, - '47d!ne lat' : 0, - '48d!ne lon' : 0, - '49d!origin lat' : 0, - '50d!origin lon' : 0, - '51d!lambert lat1' : 0, - '52d!lambert lat2' : 0, - '53s!NLSID' : 0, - '54s!NLPID' : 0, - '55s!NRID' : 0, - '56s!NCATID' : 0, - '57s!reserved15' : 0, - '58s!reserved16' : 0, - '59s!reserved17' : 0, - '60s!reserved18' : 0, - '61i!ellipsoid model' : 1, - '62s!NAID' : 0, - '63s!NCVID' : 0, - '64s!utm zone' : 0, - '65t6!reserved19' : 0, - '66d!dz' : 0, - '67d!radius' : 0, - '68S!NMID' : 0, - '69S!NLPSID' : 0, - '70i!reserved20' : 0, - '71d!major axis' : 0, - '72d!minor axis' : 0, -} - -FLT_Records = { - 2 : FLTGroup, - 4 : FLTObject, - 73 : FLTLOD, - 63 : FLTXRef, - 14 : FLTDOF, - 1 : FLTHeader, - 111 : FLTInlineLP, - 100 : FLTExt, - 'Image' : FLTImage -} - -def process_recordDefs(): - records = dict() - for record in FLT_Records: - props = dict() - for prop in FLT_Records[record]: - position = '' - slice = 0 - (format,name) = prop.split('!') - for i in format: - if i not in typecodes: - position = position + i - slice = slice + 1 - else: - break - type = format[slice:] - length = type[1:] - if len(length) == 0: - length = 1 - else: - type = type[0] - length = int(length) - - props[int(position)] = (type,length,prop) - records[record] = props - return records - - diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py deleted file mode 100644 index a707b87f846..00000000000 --- a/release/scripts/flt_toolbar.py +++ /dev/null @@ -1,809 +0,0 @@ -#!BPY - -""" -Name: 'FLT Toolbar' -Blender: 240 -Group: 'Misc' -Tooltip: 'Tools for working with FLT databases' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/07" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# 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 Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -reload(flt_properties) -from flt_properties import * - -xrefprefix = "" -xrefstack = list() -vofsstack = list() -vquatstack = list() -prop_w = 256 -prop_h = 256 - - -#event codes -evcode = { - "XREF_MAKE" : 100, - "XREF_EDIT" : 101, - "XREF_FILE" : 102, - "XREF_PICK" : 103, - "XREF_SELECT" : 104, - "XREF_POP" : 105, - "XREF_PREFIX" : 106, - "FACE_NAME" : 200, - "FACE_MAKESUB" : 201, - "FACE_KILLSUB" : 202, - "FACE_SELSUB" : 203, - "SCENE_UPDATE" : 303, - "IDPROP_COPY" : 501, - "IDPROP_KILL" : 502, - "CLIGHT_MAKE" : 700, - "DFROMACT" : 701, - "FIXCOL" : 702 -} - -XREF_PREFIX = None -XREF_MAKE = None -XREF_EDIT = None -XREF_SELECT = None -XREF_POP = None -FACE_MAKESUB = None -FACE_SELSUB = None -FACE_KILLSUB = None -IDPROP_KILL = None -IDPROP_COPY = None -SCENE_UPDATE = None -CLIGHT_MAKE = None -DFROMACT = None -FIXCOL = None - - -def RGBtoHSV( r, g, b): - cmin = min( r, g, b ) - cmax = max( r, g, b ) - v = cmax - - if(cmax!=0.0): - s = (cmax-cmin)/cmax - else: - s = 0.0 - h = 0.0 - - if(s == 0.0): - h = -1.0 - else: - cdelta = cmax-cmin - rc = (cmax-r)/cdelta - gc = (cmax-g)/cdelta - bc = (cmax-b)/cdelta - if(r==cmax): - h = bc-gc - else: - if(g==cmax): - h = 2.0+rc-bc - else: - h = 4.0+gc-rc - h = h*60.0 - if(h<0.0): - h += 360.0 - - - h = h/360.0 - if(h < 0.0): - h = 0.0 - return (h,s,v) - - -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.GetCurrent() - state["activeObject"] = state["activeScene"].objects.active - if state["activeObject"] and not state["activeObject"].sel: - state["activeObject"] = None - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - #update editmode - state["editmode"] = Blender.Window.EditMode() - - return state -def pack_face_index(index, intensity): - return ((127*intensity)+(128*index)) -def unpack_face_index(face_index): - index = face_index / 128 - intensity = float(face_index - 128.0 * index) / 127.0 - return(index,intensity) - -def idprops_append(object, typecode, props): - object.properties["FLT"] = dict() - object.properties["FLT"]['type'] = typecode - for prop in props: - object.properties["FLT"][prop] = props[prop] - object.properties["FLT"]['3t8!id'] = object.name - -def idprops_kill(object): - state = update_state() - if object and object.properties.has_key('FLT'): - object.properties.pop('FLT') - -def idprops_copy(source): - state = update_state() - if source.properties.has_key('FLT'): - for object in state["activeScene"].objects: - if object.sel and object != source and (state["activeScene"].Layers & object.Layers): - idprops_kill(object) - object.properties['FLT'] = dict() - for key in source.properties['FLT']: - object.properties['FLT'][key] = source.properties['FLT'][key] - -def unpack_color(color): - return struct.unpack('>BBBB',struct.pack('>I',color)) - - -def findColorKey(colordict, hsv): - hdelta = 0.001 - for key in colordict: - if not (((hsv[0] < (key[0] + hdelta)) and (hsv[0] > (key[0] - hdelta))) and ((hsv[1] < (key[1] + hdelta)) and (hsv[1] > (key[1] - hdelta)))): - return key - return None - -def hsvsort(a, b): - (index1, mag1) = a - (index2, mag2) = b - if mag1 > mag2: - return 1 - elif mag1 < mag2: - return -1 - return 0 - -def fix_colors(): - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - scene = state["activeScene"] - colors = None - if state["activeScene"].properties.has_key('FLT'): - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - pass - if not colors: - return - - #first build a HSV version of our palette - hsvpalette = list() - for swatch in colors: - color = unpack_color(swatch) - hsv = RGBtoHSV(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0) - hsvpalette.append(hsv) - - #collect all of our meshes - meshes = list() - for object in scene.objects.context: - if object.sel and object.type == 'Mesh': - mesh = object.getData(mesh=True) - if "FLT_COL" in mesh.faces.properties: - meshes.append(mesh) - - - #Now go through our meshes, and build a dictionary of face lists keyed according to (hue,saturation) of the baked color - colordict = dict() - for mesh in meshes: - for face in mesh.faces: - hsv = RGBtoHSV(face.col[0].r/255.0, face.col[0].g/255.0, face.col[0].b/255.0) #retrieve baked color - if colordict.has_key((hsv[0],hsv[1])): - colordict[(hsv[0],hsv[1])].append(face) - else: - colordict[(hsv[0],hsv[1])] = [face] - - - #for each color key in the color dict, build a list of distances from it to the values in hsvpalette and then quicksort them for closest match - for key in colordict: - maglist = list() - for i, hsv in enumerate(hsvpalette): - norm = Blender.Mathutils.Vector(hsv[0], hsv[1]) - Blender.Mathutils.Vector(key[0],key[1]) - maglist.append((i,norm.length)) - maglist.sort(hsvsort) - print maglist[0] - for face in colordict[key]: - (index, intensity) = unpack_face_index(face.getProperty("FLT_COL")) - newfindex = pack_face_index(maglist[0][0],intensity) - face.setProperty("FLT_COL", int(newfindex)) - - for mesh in meshes: - update_mesh_colors(colors,mesh) - - if editmode: - Blender.Window.EditMode(1) - - -def update_mesh_colors(colors, mesh): - if 'FLT_COL' in mesh.faces.properties: - mesh.activeColorLayer = "FLT_Fcol" - for face in mesh.faces: - (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) - color = struct.unpack('>BBBB',struct.pack('>I',colors[index])) - - if index == 0 and intensity == 0: - color = (255,255,255) - intensity = 1.0 - #update the vertex colors for this face - for col in face.col: - col.r = int(color[0] * intensity) - col.g = int(color[1] * intensity) - col.b = int(color[2] * intensity) - col.a = 255 - - -def update_all(): - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - colors = None - if state["activeScene"].properties.has_key('FLT'): - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - pass - if colors: - #update the baked FLT colors for all meshes. - for object in state["activeScene"].objects: - if object.type == "Mesh": - mesh = object.getData(mesh=True) - update_mesh_colors(colors,mesh) - if editmode: - Blender.Window.EditMode(1) - -#Change this to find the deep parent -def xref_create(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - def findchildren(object): - children = list() - for candidate in state["activeScene"].objects: - if candidate.parent == object: - children.append(candidate) - retlist = list(children) - for child in children: - retlist = retlist + findchildren(child) - return retlist - - actObject = state["activeObject"] - if actObject and xrefprefix: - scenenames = list() - for scene in Blender.Scene.Get(): - scenenames.append(scene.name) - - if xrefprefix in scenenames: - #build a unique name for the xref... - suffix = 1 - found = False - while not found: - candidate = xrefprefix + str(suffix) - if not candidate in scenenames: - xrefname = candidate - found = True - suffix+=1 - else: - xrefname = xrefprefix - #create our XRef node - xnode = state["activeScene"].objects.new('Empty') - xnode.name = 'X:' + xrefname - xnode.properties['FLT'] = dict() - for prop in FLTXRef: - xnode.properties['FLT'][prop] = FLTXRef[prop] - xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt' - xnode.properties['FLT']['type'] = 63 - xnode.enableDupGroup = True - xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful! - - #copy rot and loc of actObject - xnode.setLocation(actObject.getLocation()) - xnode.setEuler(actObject.getEuler()) - - #build the new scene - xrefscene = Blender.Scene.New(xrefname) - xrefscene.properties['FLT'] = dict() - xrefscene.properties['FLT']['Filename'] = xrefname - xrefscene.properties['FLT']['Main'] = 0 - - #find the children of actObject so that we can add them to the group - linkobjects = findchildren(actObject) - linkobjects.append(actObject) - for object in linkobjects: - xrefscene.objects.link(object) - state["activeScene"].objects.unlink(object) - xnode.DupGroup.objects.link(object) - #clear rotation of actObject and location - actObject.setLocation(0.0,0.0,0.0) - actObject.setEuler(0.0,0.0,0.0) - - xrefscene.update(1) - state["activeScene"].update(1) - -def xref_select(): - state = update_state() - candidates = list() - scenelist = [scene.name for scene in Blender.Scene.Get()] - for object in state["activeScene"].objects: - if object.type == 'Empty' and object.enableDupGroup == True and object.DupGroup: - candidates.append(object) - - for object in candidates: - if object.DupGroup.name in scenelist: - object.sel = 1 - -def xref_edit(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - actObject = state["activeObject"] - - if actObject and actObject.type == 'Empty' and actObject.DupGroup: -# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63: - for FLTscene in Blender.Scene.Get(): - if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name: - actObject.sel = 0 - xrefstack.append(state["activeScene"]) - vofsstack.append(Blender.Window.GetViewOffset()) - vquatstack.append(Blender.Window.GetViewQuat()) - FLTscene.makeCurrent() - Blender.Window.SetViewOffset(0.0,0.0,0.0) - -def xref_finish(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - if xrefstack: - scene = xrefstack.pop() - Blender.Window.SetViewQuat(vquatstack.pop()) - Blender.Window.SetViewOffset(vofsstack.pop()) - scene.makeCurrent() - - -def sortSub(a,b): - aindex = a.getProperty("FLT_ORIGINDEX") - bindex = b.getProperty("FLT_ORIGINDEX") - - if aindex > bindex: - return 1 - elif aindex < bindex: - return -1 - return 0 - -def subface_make(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - if actmesh: - if not "FLT_ORIGINDEX" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) - for i, face in enumerate(actmesh.faces): - face.setProperty("FLT_ORIGINDEX",i) - if not "FLT_SFLEVEL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"]) - - #attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level! - if activeFace: - #steps: - #remove actface and selected faces from the facelist - #quicksort facelist - #append actface and subfaces to end of facelist. - #generate new indices - facelist = list() - sublist = list() - for face in actmesh.faces: - facelist.append(face) - for face in facelist: - if face == activeFace: - face.setProperty("FLT_SFLEVEL",0) - sublist.insert(0,face) - elif face.sel: - face.setProperty("FLT_SFLEVEL",1) - sublist.append(face) - for face in sublist: - facelist.remove(face) - facelist.sort(sortSub) - for face in sublist: - facelist.append(face) - for i, face in enumerate(facelist): - face.setProperty("FLT_ORIGINDEX",i) - else: - pass - - if editmode: - Blender.Window.EditMode(1) - -def subface_kill(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - if actmesh: - if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: - for i,face in enumerate(actmesh.faces): - face.setProperty("FLT_ORIGINDEX",i) - face.setProperty("FLT_SFLEVEL",0) - if editmode: - Blender.Window.EditMode(1) - -def subface_select(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - if actmesh and activeFace: - if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: - facelist = list() - actIndex = None - sublevel = None - for face in actmesh.faces: - facelist.append(face) - facelist.sort(sortSub) - for i, face in enumerate(facelist): - if face == activeFace: - actIndex = i - sublevel = face.getProperty("FLT_SFLEVEL")+1 - break - leftover = facelist[actIndex+1:] - for face in leftover: - if face.getProperty("FLT_SFLEVEL") == sublevel: - face.sel = 1 - else: - break - if editmode: - Blender.Window.EditMode(1) - -def select_by_typecode(typecode): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - for object in state["activeScene"].objects: - if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: - object.select(1) -def clight_make(): - state = update_state() - actmesh = state["activeMesh"] - actobj = state["activeObject"] - - if actobj and actmesh: - actobj.properties['FLT'] = dict() - actobj.properties['FLT']['type'] = 111 - for prop in FLTInlineLP: - actobj.properties['FLT'][prop] = FLTInlineLP[prop] - - actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"]) - for v in actmesh.verts: - v.setProperty("FLT_VCOL", 83815) - -def dfromact(): - state = update_state() - actobj = state["activeObject"] - actscene = state["activeScene"] - dof = None - - for object in actscene.objects.context: - if object.sel and (object != actobj): - if not dof: - dof = object - else: - break - - if not dof: - return - - if 'FLT' not in dof.properties: - dof.properties['FLT'] = dict() - - #Warning! assumes 1 BU == 10 meters. - #do origin - dof.properties['FLT']['5d!ORIGX'] = actobj.getLocation('worldspace')[0]*10.0 - dof.properties['FLT']['6d!ORIGY'] = actobj.getLocation('worldspace')[1]*10.0 - dof.properties['FLT']['7d!ORIGZ'] = actobj.getLocation('worldspace')[2]*10.0 - #do X axis - x = Blender.Mathutils.Vector(1.0,0.0,0.0) - x = x * actobj.getMatrix('worldspace') - x = x * 10.0 - dof.properties['FLT']['8d!XAXIS-X'] = x[0] - dof.properties['FLT']['9d!XAXIS-Y'] = x[1] - dof.properties['FLT']['10d!XAXIS-Z'] = x[2] - #do X/Y plane - x = Blender.Mathutils.Vector(1.0,1.0,0.0) - x.normalize() - x = x * actobj.getMatrix('worldspace') - x = x * 10.0 - dof.properties['FLT']['11d!XYPLANE-X'] = x[0] - dof.properties['FLT']['12d!XYPLANE-Y'] = x[1] - dof.properties['FLT']['13d!XZPLANE-Z'] = x[2] - - - - - -def event(evt,val): - if evt == Draw.ESCKEY: - Draw.Exit() - -def but_event(evt): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - #do Xref buttons - if evt == evcode["XREF_PREFIX"]: - xrefprefix = XREF_PREFIX.val - if evt == evcode["XREF_EDIT"]: - xref_edit() - if evt == evcode["XREF_SELECT"]: - xref_select() - if evt == evcode["XREF_MAKE"]: - xref_create() - #do scene buttons - if evt == evcode["SCENE_UPDATE"]: - update_all() - #do face buttons - if evt == evcode["FACE_MAKESUB"]: - subface_make() - if evt== evcode["FACE_KILLSUB"]: - subface_kill() - if evt== evcode["FACE_SELSUB"]: - subface_select() - #common buttons - if evt == evcode["IDPROP_KILL"]: - if state["activeObject"]: - idprops_kill(state["activeObject"]) - if evt == evcode["IDPROP_COPY"]: - if state["activeObject"]: - idprops_copy(state["activeObject"]) - if evt == evcode["XREF_POP"]: - xref_finish() - if evt == evcode["CLIGHT_MAKE"]: - clight_make() - if evt == evcode["DFROMACT"]: - dfromact() - if evt == evcode["FIXCOL"]: - fix_colors() - Draw.Redraw(1) - Blender.Window.RedrawAll() - - -def box(x,y,w,h,c,mode): - glColor3f(c[0],c[1],c[2]) - if mode == "outline": - glBegin(GL_LINE_LOOP) - else: - glBegin(GL_POLYGON) - glVertex2i(x,y) - glVertex2i(x+w,y) - glVertex2i(x+w,y+h) - glVertex2i(x,y+h) - glEnd() - -def draw_postcommon(x,y,finaly): - global sheetlabel - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - width = prop_w - height = prop_h - - #draw the header - glColor3f(0.15,0.15,0.15) - glBegin(GL_POLYGON) - glVertex2i(x-1,y) - glVertex2i(x+width+1,y) - glVertex2i(x+width+1,y-25) - glVertex2i(x-1,y-25) - glEnd() - glColor3f(1,1,1) - glRasterPos2i(x,y-20) - sheetlabel = Blender.Draw.Text("FLT Tools Panel") - #draw the box outline - glColor3f(0,0,0) - glBegin(GL_LINE_LOOP) - glVertex2i(x-1,y) - glVertex2i(x+1+width,y) - glVertex2i(x+1+width,finaly-1) - glVertex2i(x-1,finaly-1) - glEnd() - return finaly - - -def draw_propsheet(x,y): - global XREF_PREFIX - global XREF_MAKE - global XREF_EDIT - global XREF_SELECT - global XREF_POP - global FACE_MAKESUB - global FACE_SELSUB - global FACE_KILLSUB - global IDPROP_KILL - global IDPROP_COPY - global SCENE_UPDATE - global DFROMACT - global FIXCOL - - global CLIGHT_MAKE - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - width = prop_w - height = prop_h - origx = x - origy = y - - #draw Xref tools - y = y-20 - XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this") - y = y-20 - XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference") - y = y-20 - XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference") - y = y-20 - XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References") - y = y - 20 - XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy") - - #Draw facetools - y = y-20 - FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces") - y = y-20 - FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces") - y = y-20 - FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces") - - #Draw ID Property tools - y = y - 20 - IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props") - y = y - 20 - IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected") - - y= y - 20 - CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh") - #General tools - y = y-20 - SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors") - - y=y-20 - DFROMACT = Blender.Draw.PushButton("Dof from Active", evcode["DFROMACT"],x,y,width,20,"Get Dof origin from active object") - y=y-20 - FIXCOL = Blender.Draw.PushButton("Fix Colors", evcode["FIXCOL"],x,y,width,20,"Fix baked FLT colors of selected meshes") - draw_postcommon(origx, origy,y) - -def gui(): - #draw the propsheet/toolbox. - psheety = 300 - #psheetx = psheety + 10 - draw_propsheet(0,psheety) -Draw.Register(gui,event,but_event) - \ No newline at end of file diff --git a/release/scripts/help_bpy_api.py b/release/scripts/help_bpy_api.py deleted file mode 100644 index e8d77ed8452..00000000000 --- a/release/scripts/help_bpy_api.py +++ /dev/null @@ -1,47 +0,0 @@ -#!BPY -""" -Name: 'Blender/Python Scripting API' -Blender: 248 -Group: 'Help' -Tooltip: 'The Blender Python API reference manual' -""" - -__author__ = "Matt Ebb" -__url__ = ("blender", "blenderartist") -__version__ = "1.0.1" -__bpydoc__ = """\ -This script opens the user's default web browser at http://www.blender.org's -"Blender Python API Reference" page. -""" - -# -------------------------------------------------------------------------- -# Blender/Python Scripting Reference Help Menu Item -# -------------------------------------------------------------------------- -# ***** 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 Blender -try: import webbrowser -except: webbrowser = None - -if webbrowser: - version = str(int(Blender.Get('version'))) - webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/') -else: - Blender.Draw.PupMenu("Error%t|This script requires a full python installation") diff --git a/release/scripts/help_browser.py b/release/scripts/help_browser.py deleted file mode 100644 index c207a12068f..00000000000 --- a/release/scripts/help_browser.py +++ /dev/null @@ -1,814 +0,0 @@ -#!BPY - -""" -Name: 'Scripts Help Browser' -Blender: 234 -Group: 'Help' -Tooltip: 'Show help information about a chosen installed script.' -""" - -__author__ = "Willian P. Germano" -__version__ = "0.3 01/21/09" -__email__ = ('scripts', 'Author, wgermano:ig*com*br') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script shows help information for scripts registered in the menus. - -Usage: - -- Start Screen: - -To read any script's "user manual" select a script from one of the -available category menus. If the script has help information in the format -expected by this Help Browser, it will be displayed in the Script Help -Screen. Otherwise you'll be offered the possibility of loading the chosen -script's source file in Blender's Text Editor. The programmer(s) may have -written useful comments there for users. - -Hotkeys:
- ESC or Q: [Q]uit - -- Script Help Screen: - -This screen shows the user manual page for the chosen script. If the text -doesn't fit completely on the screen, you can scroll it up or down with -arrow keys or a mouse wheel. There may be link and email buttons that if -clicked should open your default web browser and email client programs for -further information or support. - -Hotkeys:
- ESC: back to Start Screen
- Q: [Q]uit
- S: view script's [S]ource code in Text Editor
- UP, DOWN Arrows and mouse wheel: scroll text up / down -""" - -# $Id$ -# -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br -# -# 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 ***** -# -------------------------------------------------------------------------- -# Thanks: Brendon Murphy (suggestion) and Kevin Morgan (implementation) -# for the "run" button; Jean-Michel Soler for pointing a parsing error -# with multilines using triple single quotes. - -import Blender -from Blender import sys as bsys, Draw, Window, Registry - -WEBBROWSER = True -try: - import webbrowser -except: - WEBBROWSER = False - -DEFAULT_EMAILS = { - 'scripts': ['Bf-scripts-dev', 'bf-scripts-dev@blender.org'] -} - -DEFAULT_LINKS = { - 'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"] -} - -PADDING = 15 -COLUMNS = 1 -TEXT_WRAP = 100 -WIN_W = WIN_H = 200 -SCROLL_DOWN = 0 - -def screen_was_resized(): - global WIN_W, WIN_H - - w, h = Window.GetAreaSize() - if WIN_W != w or WIN_H != h: - WIN_W = w - WIN_H = h - return True - return False - -def fit_on_screen(): - global TEXT_WRAP, PADDING, WIN_W, WIN_H, COLUMNS - - COLUMNS = 1 - WIN_W, WIN_H = Window.GetAreaSize() - TEXT_WRAP = int((WIN_W - PADDING) / 6) - if TEXT_WRAP < 40: - TEXT_WRAP = 40 - elif TEXT_WRAP > 100: - if TEXT_WRAP > 110: - COLUMNS = 2 - TEXT_WRAP /= 2 - else: TEXT_WRAP = 100 - -def cut_point(text, length): - "Returns position of the last space found before 'length' chars" - l = length - c = text[l] - while c != ' ': - l -= 1 - if l == 0: return length # no space found - c = text[l] - return l - -def text_wrap(text, length = None): - global TEXT_WRAP - - wrapped = [] - lines = text.split('
') - llen = len(lines) - if llen > 1: - if lines[-1] == '': llen -= 1 - for i in range(llen - 1): - lines[i] = lines[i].rstrip() + '
' - lines[llen-1] = lines[llen-1].rstrip() - - if not length: length = TEXT_WRAP - - for l in lines: - while len(l) > length: - cpt = cut_point(l, length) - line, l = l[:cpt], l[cpt + 1:] - wrapped.append(line) - wrapped.append(l) - return wrapped - -def load_script_text(script): - global PATHS, SCRIPT_INFO - - if script.userdir: - path = PATHS['uscripts'] - else: - path = PATHS['scripts'] - - fname = bsys.join(path, script.fname) - - source = Blender.Text.Load(fname) - if source: - Draw.PupMenu("File loaded%%t|Please check the file \"%s\" in the Text Editor window" % source.name) - - -# for theme colors: -def float_colors(cols): - return map(lambda x: x / 255.0, cols) - -# globals - -SCRIPT_INFO = None - -PATHS = { - 'home': Blender.Get('homedir'), - 'scripts': Blender.Get('scriptsdir'), - 'uscripts': Blender.Get('uscriptsdir') -} - -if not PATHS['home']: - errmsg = """ -Can't find Blender's home dir and so can't find the -Bpymenus file automatically stored inside it, which -is needed by this script. Please run the -Help -> System -> System Information script to get -information about how to fix this. -""" - raise SystemError, errmsg - -BPYMENUS_FILE = bsys.join(PATHS['home'], 'Bpymenus') - -f = file(BPYMENUS_FILE, 'r') -lines = f.readlines() -f.close() - -AllGroups = [] - -class Script: - - def __init__(self, data): - self.name = data[0] - self.version = data[1] - self.fname = data[2] - self.userdir = data[3] - self.tip = data[4] - -# End of class Script - - -class Group: - - def __init__(self, name): - self.name = name - self.scripts = [] - - def add_script(self, script): - self.scripts.append(script) - - def get_name(self): - return self.name - - def get_scripts(self): - return self.scripts - -# End of class Group - - -class BPy_Info: - - def __init__(self, script, dict): - - self.script = script - - self.d = dict - - self.header = [] - self.len_header = 0 - self.content = [] - self.len_content = 0 - self.spaces = 0 - self.fix_urls() - self.make_header() - self.wrap_lines() - - def make_header(self): - - sc = self.script - d = self.d - - header = self.header - - title = "Script: %s" % sc.name - version = "Version: %s for Blender %1.2f or newer" % (d['__version__'], - sc.version / 100.0) - - if len(d['__author__']) == 1: - asuffix = ':' - else: asuffix = 's:' - - authors = "%s%s %s" % ("Author", asuffix, ", ".join(d['__author__'])) - - header.append(title) - header.append(version) - header.append(authors) - self.len_header = len(header) - - - def fix_urls(self): - - emails = self.d['__email__'] - fixed = [] - for a in emails: - if a in DEFAULT_EMAILS.keys(): - fixed.append(DEFAULT_EMAILS[a]) - else: - a = a.replace('*','.').replace(':','@') - ltmp = a.split(',') - if len(ltmp) != 2: - ltmp = [ltmp[0], ltmp[0]] - fixed.append(ltmp) - - self.d['__email__'] = fixed - - links = self.d['__url__'] - fixed = [] - for a in links: - if a in DEFAULT_LINKS.keys(): - fixed.append(DEFAULT_LINKS[a]) - else: - ltmp = a.split(',') - if len(ltmp) != 2: - ltmp = [ltmp[0], ltmp[0]] - fixed.append([ltmp[0].strip(), ltmp[1].strip()]) - - self.d['__url__'] = fixed - - - def wrap_lines(self, reset = 0): - - lines = self.d['__bpydoc__'].split('\n') - self.content = [] - newlines = [] - newline = [] - - if reset: - self.len_content = 0 - self.spaces = 0 - - for l in lines: - if l == '' and newline: - newlines.append(newline) - newline = [] - newlines.append('') - else: newline.append(l) - if newline: newlines.append(newline) - - for lst in newlines: - wrapped = text_wrap(" ".join(lst)) - for l in wrapped: - self.content.append(l) - if l: self.len_content += 1 - else: self.spaces += 1 - - if not self.content[-1]: - self.len_content -= 1 - - -# End of class BPy_Info - -def parse_pyobj_close(closetag, lines, i): - i += 1 - l = lines[i] - while l.find(closetag) < 0: - i += 1 - l = "%s%s" % (l, lines[i]) - return [l, i] - -def parse_pyobj(var, lines, i): - "Bad code, was in a hurry for release" - - l = lines[i].replace(var, '').replace('=','',1).strip() - - i0 = i - 1 - - if l[0] == '"': - if l[1:3] == '""': # """ - if l.find('"""', 3) < 0: # multiline - l2, i = parse_pyobj_close('"""', lines, i) - if l[-1] == '\\': l = l[:-1] - l = "%s%s" % (l, l2) - elif l[-1] == '"' and l[-2] != '\\': # single line: "..." - pass - else: - l = "ERROR" - - elif l[0] == "'": - if l[1:3] == "''": # ''' - if l.find("'''", 3) < 0: # multiline - l2, i = parse_pyobj_close("'''", lines, i) - if l[-1] == '\\': l = l[:-1] - l = "%s%s" % (l, l2) - elif l[-1] == '\\': - l2, i = parse_pyobj_close("'", lines, i) - l = "%s%s" % (l, l2) - elif l[-1] == "'" and l[-2] != '\\': # single line: '...' - pass - else: - l = "ERROR" - - elif l[0] == '(': - if l[-1] != ')': - l2, i = parse_pyobj_close(')', lines, i) - l = "%s%s" % (l, l2) - - elif l[0] == '[': - if l[-1] != ']': - l2, i = parse_pyobj_close(']', lines, i) - l = "%s%s" % (l, l2) - - return [l, i - i0] - -# helper functions: - -def parse_help_info(script): - - global PATHS, SCRIPT_INFO - - if script.userdir: - path = PATHS['uscripts'] - else: - path = PATHS['scripts'] - - fname = bsys.join(path, script.fname) - - if not bsys.exists(fname): - Draw.PupMenu('IO Error: couldn\'t find script %s' % fname) - return None - - f = file(fname, 'r') - lines = f.readlines() - f.close() - - # fix line endings: - if lines[0].find('\r'): - unixlines = [] - for l in lines: - unixlines.append(l.replace('\r','')) - lines = unixlines - - llen = len(lines) - has_doc = 0 - - doc_data = { - '__author__': '', - '__version__': '', - '__url__': '', - '__email__': '', - '__bpydoc__': '', - '__doc__': '' - } - - i = 0 - while i < llen: - l = lines[i] - incr = 1 - for k in doc_data.keys(): - if l.find(k, 0, 20) == 0: - value, incr = parse_pyobj(k, lines, i) - exec("doc_data['%s'] = %s" % (k, value)) - has_doc = 1 - break - i += incr - - # fix these to seqs, simplifies coding elsewhere - for w in ['__author__', '__url__', '__email__']: - val = doc_data[w] - if val and type(val) == str: - doc_data[w] = [doc_data[w]] - - if not doc_data['__bpydoc__']: - if doc_data['__doc__']: - doc_data['__bpydoc__'] = doc_data['__doc__'] - - if has_doc: # any data, maybe should confirm at least doc/bpydoc - info = BPy_Info(script, doc_data) - SCRIPT_INFO = info - return True - - else: - return False - - -def parse_script_line(l): - - tip = 'No tooltip' - try: - pieces = l.split("'") - name = pieces[1].replace('...','') - data = pieces[2].strip().split() - version = data[0] - userdir = data[-1] - fname = data[1] - i = 1 - while not fname.endswith('.py'): - i += 1 - fname = '%s %s' % (fname, data[i]) - if len(pieces) > 3: tip = pieces[3] - except: - return None - - return [name, int(version), fname, int(userdir), tip] - - -def parse_bpymenus(lines): - - global AllGroups - - llen = len(lines) - - for i in range(llen): - l = lines[i].strip() - if not l: continue - if l[-1] == '{': - group = Group(l[:-2]) - AllGroups.append(group) - i += 1 - l = lines[i].strip() - while l != '}': - if l[0] != '|': - data = parse_script_line(l) - if data: - script = Script(data) - group.add_script(script) - i += 1 - l = lines[i].strip() - -# AllGroups.reverse() - - -def create_group_menus(): - - global AllGroups - menus = [] - - for group in AllGroups: - - name = group.get_name() - menu = [] - scripts = group.get_scripts() - for s in scripts: menu.append(s.name) - menu = "|".join(menu) - menu = "%s%%t|%s" % (name, menu) - menus.append([name, menu]) - - return menus - - -# Collecting data: -fit_on_screen() -parse_bpymenus(lines) -GROUP_MENUS = create_group_menus() - - -# GUI: - -from Blender import BGL -from Blender.Window import Theme - -# globals: - -START_SCREEN = 0 -SCRIPT_SCREEN = 1 - -SCREEN = START_SCREEN - -# gui buttons: -len_gmenus = len(GROUP_MENUS) - -BUT_GMENU = range(len_gmenus) -for i in range(len_gmenus): - BUT_GMENU[i] = Draw.Create(0) - -# events: -BEVT_LINK = None # range(len(SCRIPT_INFO.links)) -BEVT_EMAIL = None # range(len(SCRIPT_INFO.emails)) -BEVT_GMENU = range(100, len_gmenus + 100) -BEVT_VIEWSOURCE = 1 -BEVT_EXIT = 2 -BEVT_BACK = 3 -BEVT_EXEC = 4 # Executes Script - -# gui callbacks: - -def gui(): # drawing the screen - - global SCREEN, START_SCREEN, SCRIPT_SCREEN - global SCRIPT_INFO, AllGroups, GROUP_MENUS - global BEVT_EMAIL, BEVT_LINK - global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU, BEVT_EXEC - global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE - - theme = Theme.Get()[0] - tui = theme.get('ui') - ttxt = theme.get('text') - - COL_BG = float_colors(ttxt.back) - COL_TXT = ttxt.text - COL_TXTHI = ttxt.text_hi - - BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) - BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) - BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) - - resize = screen_was_resized() - if resize: fit_on_screen() - - if SCREEN == START_SCREEN: - x = PADDING - bw = 85 - bh = 25 - hincr = 50 - - butcolumns = (WIN_W - 2*x)/ bw - if butcolumns < 2: butcolumns = 2 - elif butcolumns > 7: butcolumns = 7 - - len_gm = len(GROUP_MENUS) - butlines = len_gm / butcolumns - if len_gm % butcolumns: butlines += 1 - - h = hincr * butlines + 20 - y = h + bh - - BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) - BGL.glRasterPos2i(x, y) - Draw.Text('Scripts Help Browser') - - y -= bh - - BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) - - i = 0 - j = 0 - for group_menu in GROUP_MENUS: - BGL.glRasterPos2i(x, y) - Draw.Text(group_menu[0]+':') - BUT_GMENU[j] = Draw.Menu(group_menu[1], BEVT_GMENU[j], - x, y-bh-5, bw, bh, 0, - 'Choose a script to read its help information') - if i == butcolumns - 1: - x = PADDING - i = 0 - y -= hincr - else: - i += 1 - x += bw + 3 - j += 1 - - x = PADDING - y = 10 - BGL.glRasterPos2i(x, y) - Draw.Text('Select script for its help. Press Q or ESC to leave.') - - elif SCREEN == SCRIPT_SCREEN: - if SCRIPT_INFO: - - if resize: - SCRIPT_INFO.wrap_lines(1) - SCROLL_DOWN = 0 - - h = 18 * SCRIPT_INFO.len_content + 12 * SCRIPT_INFO.spaces - x = PADDING - y = WIN_H - bw = 38 - bh = 16 - - BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) - for line in SCRIPT_INFO.header: - y -= 18 - BGL.glRasterPos2i(x, y) - size = Draw.Text(line) - - for line in text_wrap('Tooltip: %s' % SCRIPT_INFO.script.tip): - y -= 18 - BGL.glRasterPos2i(x, y) - size = Draw.Text(line) - - i = 0 - y -= 28 - for data in SCRIPT_INFO.d['__url__']: - Draw.PushButton('link %d' % (i + 1), BEVT_LINK[i], - x + i*bw, y, bw, bh, data[0]) - i += 1 - y -= bh + 1 - - i = 0 - for data in SCRIPT_INFO.d['__email__']: - Draw.PushButton('email', BEVT_EMAIL[i], x + i*bw, y, bw, bh, data[0]) - i += 1 - y -= 18 - - y0 = y - BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) - for line in SCRIPT_INFO.content[SCROLL_DOWN:]: - if line: - line = line.replace('
', '') - BGL.glRasterPos2i(x, y) - Draw.Text(line) - y -= 18 - else: y -= 12 - if y < PADDING + 20: # reached end, either stop or go to 2nd column - if COLUMNS == 1: break - elif x == PADDING: # make sure we're still in column 1 - x = 6*TEXT_WRAP + PADDING / 2 - y = y0 - - x = PADDING - Draw.PushButton('source', BEVT_VIEWSOURCE, x, 17, 45, bh, - 'View this script\'s source code in the Text Editor (hotkey: S)') - Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh, - 'Exit from Scripts Help Browser (hotkey: Q)') - if not FMODE: - Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh, - 'Back to scripts selection screen (hotkey: ESC)') - Draw.PushButton('run script', BEVT_EXEC, x + 3*45, 17, 60, bh, 'Run this script') - - BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) - BGL.glRasterPos2i(x, 5) - Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small') - -def fit_scroll(): - global SCROLL_DOWN - if not SCRIPT_INFO: - SCROLL_DOWN = 0 - return - max = SCRIPT_INFO.len_content + SCRIPT_INFO.spaces - 1 - if SCROLL_DOWN > max: SCROLL_DOWN = max - if SCROLL_DOWN < 0: SCROLL_DOWN = 0 - - -def event(evt, val): # input events - - global SCREEN, START_SCREEN, SCRIPT_SCREEN - global SCROLL_DOWN, FMODE - - if not val: return - - if evt == Draw.ESCKEY: - if SCREEN == START_SCREEN or FMODE: Draw.Exit() - else: - SCREEN = START_SCREEN - SCROLL_DOWN = 0 - Draw.Redraw() - return - elif evt == Draw.QKEY: - Draw.Exit() - return - elif evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE] and SCREEN == SCRIPT_SCREEN: - SCROLL_DOWN += 1 - fit_scroll() - Draw.Redraw() - return - elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE] and SCREEN == SCRIPT_SCREEN: - SCROLL_DOWN -= 1 - fit_scroll() - Draw.Redraw() - return - elif evt == Draw.SKEY: - if SCREEN == SCRIPT_SCREEN and SCRIPT_INFO: - load_script_text(SCRIPT_INFO.script) - return - -def button_event(evt): # gui button events - - global SCREEN, START_SCREEN, SCRIPT_SCREEN - global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO - global SCROLL_DOWN, FMODE - - if evt >= 100: # group menus - for i in range(len(BUT_GMENU)): - if evt == BEVT_GMENU[i]: - group = AllGroups[i] - index = BUT_GMENU[i].val - 1 - if index < 0: return # user didn't pick a menu entry - script = group.get_scripts()[BUT_GMENU[i].val - 1] - if parse_help_info(script): - SCREEN = SCRIPT_SCREEN - BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) - BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) - Draw.Redraw() - else: - res = Draw.PupMenu("No help available%t|View Source|Cancel") - if res == 1: - load_script_text(script) - elif evt >= 20: - if not WEBBROWSER: - Draw.PupMenu('Missing standard Python module%t|You need module "webbrowser" to access the web') - return - - if evt >= 50: # script screen email buttons - email = SCRIPT_INFO.d['__email__'][evt - 50][1] - webbrowser.open("mailto:%s" % email) - else: # >= 20: script screen link buttons - link = SCRIPT_INFO.d['__url__'][evt - 20][1] - webbrowser.open(link) - elif evt == BEVT_VIEWSOURCE: - if SCREEN == SCRIPT_SCREEN: load_script_text(SCRIPT_INFO.script) - elif evt == BEVT_EXIT: - Draw.Exit() - return - elif evt == BEVT_BACK: - if SCREEN == SCRIPT_SCREEN and not FMODE: - SCREEN = START_SCREEN - SCRIPT_INFO = None - SCROLL_DOWN = 0 - Draw.Redraw() - elif evt == BEVT_EXEC: # Execute script - exec_line = '' - if SCRIPT_INFO.script.userdir: - exec_line = bsys.join(Blender.Get('uscriptsdir'), SCRIPT_INFO.script.fname) - else: - exec_line = bsys.join(Blender.Get('scriptsdir'), SCRIPT_INFO.script.fname) - - Blender.Run(exec_line) - -keepon = True -FMODE = False # called by Blender.ShowHelp(name) API function ? - -KEYNAME = '__help_browser' -rd = Registry.GetKey(KEYNAME) -if rd: - rdscript = rd['script'] - keepon = False - Registry.RemoveKey(KEYNAME) - for group in AllGroups: - for script in group.get_scripts(): - if rdscript == script.fname: - parseit = parse_help_info(script) - if parseit == True: - keepon = True - SCREEN = SCRIPT_SCREEN - BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) - BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) - FMODE = True - elif parseit == False: - Draw.PupMenu("ERROR: script doesn't have proper help data") - break - -if not keepon: - Draw.PupMenu("ERROR: couldn't find script") -else: - Draw.Register(gui, event, button_event) diff --git a/release/scripts/hotkeys.py b/release/scripts/hotkeys.py deleted file mode 100644 index 187cba964bc..00000000000 --- a/release/scripts/hotkeys.py +++ /dev/null @@ -1,944 +0,0 @@ -#!BPY -# coding: utf-8 -""" Registration info for Blender menus: -Name: 'HotKey and MouseAction Reference' -Blender: 242 -Group: 'Help' -Tip: 'All the hotkeys/short keys' -""" - -__author__ = "Jean-Michel Soler (jms)" -__url__ = ("blender", "blenderartist", -"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm", -"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "21/01/2007" - -__bpydoc__ = """\ -This script is a reference about all hotkeys and mouse actions in Blender. - -Usage: - -Open the script from the Help menu and select group of keys to browse. - -Notes:
- Additional entries in the database (c) 2004 by Bart. - Additional entries in the database for blender 2.37 --> 2.43 (c) 2003-2007/01 by jms. - -""" - -#------------------------ -# Hotkeys script -# (c) jm soler (2003-->01/2007) -# ----------------------- -# Page officielle : -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm -# Communiquer les problemes et les erreurs sur: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -#--------------------------------------------- -# ce script est proposé sous licence GPL pour etre associe -# a la distribution de Blender 2.33 et suivant -# -------------------------------------------------------------------------- -# this script is released under GPL licence -# for the Blender 2.33 scripts package -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) 2003, 2004: Jean-Michel Soler -# Additionnal entries in the original data base (c) 2004 by Bart (bart@neeneenee.de) -# -# 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 Blender -from Blender.Draw import * -from Blender.BGL import * - -# INTERNATIONAL={0:'English','1':'French'} -# LANGUAGE=0 - -hotkeys={ -'Search ':[['', '']], -'Specials 1 ':[ -[',', 'Set Bounding Box rotation scaling pivot'], -['Ctrl-,', 'Set Median Point rotation scaling pivot'], -['.', 'Set 3D cursor as rotation scaling pivot'], -['.', 'Outliner : to get the current active data in center of view'], -['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'], -['~', 'Display all layers (German keys: ö,french keyboard: ù)'], -['Shift-~', 'Display all/previous layers (German keys: Shift-ö, french keyboard: shift-ù)'], -['ENTER', 'Outliner : to open a subtree, works on entire item line. '], -['HOME', 'Outliner : to show the entire Object hierarchy. '], -['SHIFT+BACKSPACE',' Text edit mode: Clear text '], -['SPACE', 'Popup menu'], -['SPACE', '3D View: camera selected'], -['Ctrl-SPACE', 'Manipulator (transform widget) Menu'], -['TAB', 'Enter/exit Edit Mode'], -['TAB', 'Edit Mode and Numerical Edit (see N key) : move to next input value'], -['TAB', 'Sequencer: Edit meta strip'], -['TAB', 'IPO: Edit selected'], -['TAB', 'Text Editor : indent'], -['TAB', 'NODE window : Edit group'], #243 -['Shift-TAB', 'Text Editor : unindent'], -['Shift-TAB', 'Edit Mode: Toggle snaping'], -['Ctrl-TAB', 'ARMATURE : Enter/exit Pose Mode'], -['Ctrl-TAB','MESH : all views, enter exit weight paint mode.'], -['Shift-TAB', 'Edit Mode : Enter Object Mode'], -['Ctrl-Open menu /', ''], -['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images'], -['.', '...'] -], - -'Mouse ':[ -['Actions:', ''], -['LMB', '3D View: Set 3D Cursor'], -['LMB', '3D View: camera selected'], -['LMB drag', 'Border select circle: add to selection'], -['LMB hold down', 'Popup menu'], -['LMB hold down drag', 'Gesture'], -['Ctrl-LMB', 'IPO: Add key'], -['Ctrl-LMB', '3D View: OBJECT or EDIT mode, select with the Lasso tool'], -['Ctrl-LMB', '3D View: ARMATURE EDIT mode, add a new bone to the selected end '], -['Shift-LMB','MANIPULATOR (transform widget): select the axe to remove in the current'], -['Shift-LMB','MANIPULATOR transformation ( if there is a problem with small step adjustment'], -['Shift-LMB','MANIPULATOR first select the axe or axes with LBM alone)'], -['Shift-LMB', 'Outliner : Hold Shift while clicking on a triangle arrow to open/close the subtree below'], -['MMB', 'Rotate'], -['Ctrl-MMB', 'Zoom view'], -['Ctrl-LMB', 'Outliner : Hold CTRL while clicking on a name allows you to edit a name.'], -['Ctrl-LMB', 'Outliner : This works for all visualized data, including bones or vertex groups,'], -['Ctrl-LMB', 'Outliner : but not for \'nameless\' items that draw the links to Hooks, Deform '], -['Ctrl-LMB', 'Outliner : Groups or Constraints.'], -['Shift-MMB', 'Move view'], -['RMB', 'Select'], -['RMB drag', 'Border select circle: subtract from selection'], -['RMB hold down', 'Popup menu'], -['Alt-RMB', 'Object Mode :Select but in a displayed list of objects located under the mouse cursor'], -['Alt-RMB', 'Edit Mode: Select EDGES LOOP '], -['Alt-Ctrl-RMB', 'Edit Mode: Select FACES LOOP'], -['Alt-Ctrl-RMB', 'UV Image Editor: Select face'], -['Shift-RMB', 'Add/subtract to/from selection'], -['Wheel', 'Zoom view'], -['Transformations:', ''], -['Drag+Ctrl', 'Step adjustment'], -['Drag+Ctrl-Shift', 'Small step adjustment (Transform Widget : first select the axe or axes with LBM alone)'], -['Drag+Shift', 'Fine adjustment (Transform Widget : first select the axe or axes with LBM alone)'], -['LMB', 'Confirm transformation'], -['MMB', 'Toggle optional transform feature'], -['RMB', 'Abort transformation'], -['LMB', 'Grease Pencil: when "Draw Mode On", draw new stroke'], -['RMB', 'Grease Pencil: when "Draw Mode On", eraser tool for stroke segments'], -['Shift-LMB', 'Grease Pencil: draw new stroke'], -['Alt-RMB', 'Grease Pencil: eraser tool for stroke segments'], -['.', '...'] -], - -'F-Keys ':[ -['F1', 'Open File'], -['Shift-F1', 'Library Data Select'], -['F2', 'Save File'], -['Shift-F2', 'Export DXF'], -['Ctrl-F2', 'Save/export in vrml 1.0 format' ], -['F3', 'Save image'], -['Ctrl-F3', 'Save image : dump 3d view'], -['Ctrl-Shift-F3', 'Save image : dump screen'], -['F4', 'Logic Window (may change)'], -['Shift-F4', 'Object manager Data Select '], -['F5', 'Material Window'], -['Shift-F5', '3D Window'], -['F6', 'Texture Window'], -['Shift-F6', 'IPO Window'], -['F7', 'Object Window'], -['Shift-F7', 'Buttons Window'], -['F8', 'World Window'], -['Shift-F8', 'Video Sequencer Window'], -['F9', 'Edit Mode Window'], -['Shift-F9', 'OOP Window'], -['Alt-Shift-F9', 'OutLiner Window'], -['F10', 'Render Window'], -['Shift-F10', 'UV Image Editor'], -['F11', 'Recall the last rendered image'], -['Shift-F11', 'Text Editor'], -['ctrl-F11', 'replay the last rendered animation'], -['F12', 'Render current Scene'], -['Ctrl-F12', 'Render animation'], -['Ctrl-Shift-F12', 'NLA Editor'], -['Shift-F12', 'Action Editor'], -['Shift-F12', 'Action Editor'], -['.', '...'] -], - -'Numbers ':[ -['1..2..0-=', 'Show layer 1..2..12'], -['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'], -['Alt-1..2..0', 'Show layer 11..12..20'], -['Shift-1..2..0', 'Toggle layer 1..2..12'], -['Ctrl-1..4', 'Object/Edit Mode : change subsurf level to the selected value'], -['Shift-ALT-...', 'Toggle layer 11..12..20'], -['Crtl-Shift-ALT-3', 'Edit Mode & Face Mode : Triangle faces'], -['Crtl-Shift-ALT-4', 'Edit Mode & Face Mode : Quad faces'], -['Crtl-Shift-ALT-5', 'Edit Mode & Face Mode : Non quad or triangle faces'], -['.', '...'] -], - -'Numpad ':[ -['Numpad DEL', 'Zoom on object'], -['Numpad /', 'Local view on object (hide others)'], -['Numpad *', 'Rotate view to objects local axes'], -['Numpad +', 'Zoom in (works everywhere)'], -['Numpad -', 'OutLiner window, Collapse one level of the hierarchy'], -['Alt-Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'], -['Ctrl-Numpad +', 'Edit Mode: Select More vertices'], -['Numpad -', 'Zoom out (works everywhere)'], -['Numpad +', 'OutLiner window, Expand one level of the hierarchy'], -['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'], -['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'], -['Numpad 0', 'Set Camera view'], -['Ctrl-Numpad 0', 'Set active object as camera'], -['Alt-Numbad 0', 'Restore old camera'], -['Ctrl-Alt-Numpad 0', 'Align active camera to view'], -['Numpad 1', 'Front view'], -['Ctrl-Numpad 1', 'Back view'], -['Numpad 3', 'Right view'], -['Ctrl-Numpad 3', 'Left view'], -['Numpad 7', 'Top view'], -['Ctrl-Numpad 7', 'Bottom view '], -['Numpad 5', 'Toggle orthogonal/perspective view'], -['Numpad 9', 'Redraw view'], -['Numpad 4', 'Rotate view left'], -['ctrl-Shift-Numpad 4', 'Previous Screen'], -['Numpad 6', 'Rotate view right'], -['ctrl-Shift-Numpad 6', 'Next Screen'], -['Numpad 8', 'Rotate view up'], -['Numpad 2', 'Rotate view down'], -['.', '...'] -], - -'Arrows ':[ -['Home/Pos1', 'View all',''], -['Home', 'OutLiner Windows, Show hierarchy'], -['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'], -['PgUp', 'Strip Editor, Move Down'], -['PgUp', 'TimeLine: Jump to next marker'], -['PgUp', 'IPO: Select next keyframe'], -['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'], -['Ctrl-PgUn', 'TimeLine: Jump to next key'], -['PgDn', 'Edit Mode and Proportionnal Editing Tools, decrease influence'], -['PgDn', 'Strip Editor, Move Up'], -['PgDn', 'TimeLine: Jump to prev marker'], -['PgDn', 'IPO: Select previous keyframe'], -['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'], -['Ctrl-PgDn', 'TimeLine: Jump to prev key'], -['Left', 'One frame backwards'], -['Right', 'One frame forwards'], -['Down', '10 frames backwards'], -['Up', '10 frames forwards'], -['Alt-Down', 'Blender in Window mode'], -['Alt-Up', 'Blender in Fullscreen mode'], -['Ctrl-Left', 'Previous screen'], -['Ctrl-Right', 'Next screen'], -['Ctrl-Down', 'Maximize window toggle'], -['Ctrl-Up', 'Maximize window toggle'], -['Shift-Arrow', 'Toggle first frame/ last frame'], -['.', '...'] -], - -'Letters ':[ -{ -"A":[ -['A', 'Select all/Deselect all'], -['A', 'Outliner : Select all/Deselect all'], -['A', 'Ipo Editor : Object mode, Select all/Deselect all displayed Curves'], #243 -['A', 'Ipo Editor : Edit mode, Select all/Deselect all vertices'], #243 -['A', 'Render window (F12) : Display alpha plane'], -['Alt-A', 'Play animation in current window'], -['Ctrl-A', 'Apply objects size/rotation to object data'], -['Ctrl-A', 'Text Editor: Select all'], -['Ctrl-ALT-A', '3D-View: Armature Edit mode, align selected bones to active bone'], -['Shift-A', 'Sequencer: Add menu'], -['Shift-A', '3D-View: Add menu'], -['Shift-A', 'Sculpt Mode: Keep the brush center anchored to the initial location'], -['Shift-ALT-A', 'Play animation in all windows'], -['Shift-CTRL-A', 'Apply lattice / Make dupliverts real'], -['Shift-CTRL-A', 'Apply Deform '], -['.', '...'] -], - -"B":[ -['B', 'Border select'], -['BB', 'Circle select'], -['Alt-B', 'Object Mode: Select visible view section in 3D space'], -['Shift-B', 'Set render border (in active camera view)'], -['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake (on an image in the uv editor window) the selected Meshes'], #243 -['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Full render of selected Meshes'], #243 -['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Ambient Occlusion of selected Meshes'], #243 -['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Normals of the selected Meshes'], #243 -['Ctrl-Alt-B', 'Object Mode: in 3D view, Bake Texture Only of selected Meshes'], #243 -['.', '...'] -], - -"C":[ -['C', 'Center view on cursor'], -['C', 'UV Image Editor: Active Face Select toggle'], -['C', 'Sequencer: Change content of the strip '], #243 -['C', 'IPO: Snap current frame to selected key'], -['C', 'TimeLine: Center View'], -['C', 'File Selector : Copy file'], -['C', 'NODE window : Show cyclic referencies'], #243 -['Alt-C', 'Object Mode: Convert menu'], -['Alt-C', 'Text Editor: Copy '], -['Ctrl-Alt-C', 'Object Mode : Add Constraint'], -['Ctrl-Shift-C', 'Text Editor: Copy selection to clipboard'], -['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'], -['Ctrl-C', 'UV Image Editor: Stick UVs to mesh vertex'], -['Ctrl-C','ARMATURE : posemode, Copy pose attributes'], -['Ctrl-Alt-C',' ARMATURE : posemode, add constraint to new empty object.'], -['Shift-C', 'Center and zoom view on selected objects'], -['Shift-C', 'UV Image Editor: Stick local UVs to mesh vertex'], -['.', '...'] -], - -"D":[ -['D', 'Set 3d draw mode'], -['Alt-D', 'Object Mode: Create new instance of object'], -['Ctrl-D', 'Display alpha of image texture as wire'], -['Ctrl-D', 'Text Editor : uncomment'], -['Shift-D', 'Create full copy of object'], -['Shift-D', 'NODE window : duplicate'], #243 -['CTRL-SHIFT-D', 'NLA editor : Duplicate markers'], -['CTRL-SHIFT-D', 'Action editor : Duplicate markers'], -['CTRL-SHIFT-D', 'IPO editor : Duplicate markers'], -['.', '...'] -], - -"E":[ -['E', 'Edit Mode: Extrude'], -['E', 'UV Image Editor: LSCM Unwrap'], -['E', 'TimeLine: Set current frame as End '], -['E', 'NODE window : Execute composite'], #243 -['ER', 'Edit Mode: Extrude Rotate'], -['ES', 'Edit Mode: Extrude Scale'], -['ESX', 'Edit Mode: Extrude Scale X axis'], -['ESY', 'Edit Mode: Extrude Scale Y axis'], -['ESZ', 'Edit Mode: Extrude Scale Z axis'], -['EX', 'Edit Mode: Extrude along X axis'], -['EY', 'Edit Mode: Extrude along Y axis'], -['EZ', 'Edit Mode: Extrude along Z axis'], -['Alt-E', 'Edit Mode: exit Edit Mode'], -['Ctrl-E', 'Edit Mode: Edge Specials menu'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Mark seams'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Clear seams'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CW'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CCW'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Loop Cut'], -['Ctrl-E', 'Edit Mode: Edge Specials menu, Edge Slide'], -['Shift-E', 'Edit Mode: SubSurf Edge Sharpness'], -['.', '...'] -], - -"F":[ -['F', 'Edit mode: Make edge/face'], -['F', 'Sequencer: Set Filter Y'], -['F', 'Object Mode: UV/Face Select mode'], -['Alt-F', 'Edit Mode: Beautify fill'], -['Alt-F,','Text editor : find again '], -['Alt-Ctrl-F,','Text editor : find '], -['Ctrl-F', 'Object Mode: Sort faces in Z direction'], -['Ctrl-F', 'Edit Mode: Flip triangle edges'], -['Shift-F', 'Edit Mode: Fill with triangles'], -['Shift-F', 'Object Mode: fly mode (see header for fly mode keys)'], -['.', '...'] -], - -"G":[ -['G', 'Grab (move)'], -['G', 'Timeline : Grab (move) Marker'], -['Alt-G', 'Clear location (this does only make sense in Object mode)'], -['Alt-G', 'NODE window : ungroup'], #243 -['Shift-ALT-G', 'Object mode: Remove selected objects from group'], -['Ctrl-G', 'NODE window : group'], #243 -['Ctrl-G', 'Add selected objects to group'], -['Ctrl-G', 'IPO editor, Grab/move marker'], -['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Grab Mode'], -['Shift-G', 'Object mode: Selected Group menu'], -['Shift-G', 'Object mode: Selected Group menu 1, Children'], -['Shift-G', 'Object mode: Selected Group menu 2, Immediate Children'], -['Shift-G', 'Object mode: Selected Group menu 3, Parent'], -['Shift-G', 'Object mode: Selected Group menu 4, Sibling'], -['Shift-G', 'Object mode: Selected Group menu 5, Object of same type'], -['Shift-G', 'Object mode: Selected Group menu 6, Object in same shared layers'], -['Shift-G', 'Object mode: Selected Group menu 7, Objects in same group'], -['.', '...'] -], - -"H":[ -['H', 'Hide selected vertices/faces'], -['H', 'Curves: Set handle type'], -['H', 'Action editor: Handle type aligned'], -['H', 'Action editor: Handle type free'], -['H', 'NODE window : hide/unhide'], #243 -['Alt-H', 'Edit Mode : Show Hidden vertices/faces'], -['Shift-H', 'Curves: Automatic handle calculation'], -['Shift-H', 'Action editor: Handle type auto'], -['Shift-H', 'Edit Mode : Hide deselected vertices/faces'], -['Ctrl-H', 'Edit Mode : Add a hook on selected points or show the hook menu .'], -['.', '...'] -], - -"I":[ -['I', 'Insert Keyframe menu'], -['Alt-I','Delete Keyframe menu'], -['Ctrl-I','Select Inverse'], -['Shift-I','ARMATURE : add IK constraint'], -['Ctrl-Alt-I','ARMATURE : posemode, remove IK constraints.'], -['.', '...'] -], - -"J":[ -['J', 'IPO: Join menu'], -['J', 'Mesh: Join all adjacent triangles to quads'], -['J', 'Render Window: Swap render buffer'], -['Alt-J,','Text editor : Jump '], -['Ctrl-J', 'Join selected objects'], -['Ctrl-J', 'Nurbs: Add segment'], -['Ctrl-J', 'IPO: Join keyframes menu'], -['.', '...'] -], - -"K":[ -['K', '3d Window: Show keyframe positions'], -['K', 'Edit Mode: Loop/Cut menu'], -['K', 'IPO: Show keyframe positions'], -['K', 'Nurbs: Print knots'], -['K', 'VIDEO editor : cut at current frame'], #243 -['Ctrl-K', 'Make skeleton from armature'], -['Shift-K', 'Show and select all keyframes for object'], -['Shift-K', 'Edit Mode: Knife Mode select'], -['Shift-K', 'UV Face Select: Clear vertex colours'], -['Shift-K', 'Vertex Paint: All vertex colours are erased; they are changed to the current drawing colour.'], -['.', '...'] -], - -"L":[ -['L', 'Make local menu'], -['L', 'Edit Mode: Select linked vertices (near mouse pointer)'], -['L', 'NODE window: Select linked from '], #243 -['L', 'OOPS window: Select linked objects'], -['L', 'UV Face Select: Select linked faces'], -['Ctrl-L', 'Make links menu (for instance : to scene...)'], -['Shift-L', 'Select links menu'], -['Shift-L', 'NODE window: Select linked to '], #243 -['Ctrl-L', 'POSELIB: browse poses'], -['Shift-L', 'POSELIB: add/replace pose'], -['Ctrl-Shift-L', 'POSELIB: rename pose'], -['Alt-L', 'POSELIB: remove pose'], -['.', '...'] -], - -"M":[ -['M', 'Object mode : Move object to different layer'], -['M', 'Sequencer: Make meta strip (group) from selected strips'], -['M', 'Edit Mode: Mirros Axis menu'], -['M', 'File Selector: rename file'], -['M', 'Video Sequence Editor : Make Meta strip...'], -['M', 'NLA editor: Add marker'], -['M', 'Action editor: Add marker'], -['M', 'IPO editor: Add marker'], -['M', 'TimeLine: Add marker'], -['Alt-M', 'Edit Mode: Merge vertices menu'], -['Alt-M', 'Video Sequence Editor : Separate Meta strip...'], -['Ctrl-M', 'Object Mode: Mirros Axis menu'], -['Shift-M', 'TimeLine: Name marker'], -['Shift-M', 'IPO editor : Name marker'], -['Shift-M', 'NLA editor : Name marker'], -['Shift-M', 'Actions editor : Name marker'], -['.', '...'] -], - -"N":[ -['N', 'Transform Properties panel'] , -['N', 'OOPS window: Rename object'], -['N', 'VIDEO SEQUENCE editor : display strip properties '], #243 -['Alt-N', 'Text Editor : New text '], -['Ctrl-N', 'Armature: Recalculate bone roll angles'] , -['Ctrl-N', 'Edit Mode: Recalculate normals to outside'] , -['Ctrl-Shift-N', 'Edit Mode: Recalculate normals to inside'], -['.', '...'] -], - -"O":[ -['O', 'Edit Mode/UV Image Editor: Toggle proportional vertex editing'], -['O', 'IPO editor: Clean ipo curves (beware to the thresold needed value)'], #243 -['Alt-O', 'Clear object origin'], -['Alt-O', 'Edit mode, 3dview with prop-edit-mode, enables/disables connected'], -['Alt-O', 'Text Editor : Open file '], -['Ctrl-O', 'Open a panel with the ten most recent projets files'], #243 -['Shift-O', 'Proportional vertex Edit Mode: Toggle smooth/steep falloff'], -['Shift-O', 'Object Mode: Add a subsurf modifier to the selected mesh'], -['Shift-O', 'IPO editor: Smooth ipo curves'], #243 -['.', '...'] -], - -"P":[ -['P', 'Object Mode: Start realtime engine'], -['P', 'Edit mode: Seperate vertices to new object'], -['Shift-P', 'Edit mode: Push-Pull'], -['Shift-P', 'Object mode: Add a preview window in the D window'], -['P', 'UV Image Editor: Pin selected vertices. Pinned vertices will stay in place on the UV editor when executing an LSCM unwrap.'], -['Alt-P', 'Clear parent relationship'], -['Alt-P', 'UV Image Editor: Unpin UVs'], -['Alt-P', 'Text Editor : Run current script '], -['Ctrl-P', 'Make active object parent of selected object'], -['Ctrl-Shift-P', 'Make active object parent of selected object without inverse'], -['Ctrl-P', 'Edit mode: Make active vertex parent of selected object'], -['Ctrl-P', 'ARMATURE : editmode, make bone parent.'], -['Ctrl-Alt-P', 'ARMATURE: edimode, separate bones to new object'], -['.', '...'] -], - -"Q":[['Ctrl-Q', 'Quit'], - ['.', '...'] - ], - -"R":[ -['R', 'FileSelector : remove file'], -['R', 'Rotate'], -['R', 'IPO: Record mouse movement as IPO curve'], -['R', 'UV Face Select: Rotate menu uv coords or vertex colour'], -['R', 'NODE window : read saved render result'], #243 -['R', 'SEQUENCER window : re-assign entries to another strip '], #243 -['RX', 'Rotate around X axis'], -['RXX', "Rotate around object's local X axis"], -['RY', 'Rotate around Y axis'], -['RYY', "Rotate around object's local Y axis"], -['RZ', 'Rotate around Z axis'], -['RZZ', "Rotate around object's local Z axis"], -['Alt-R', 'Clear object rotation'], -['Alt-R', 'Text editor : reopen text.'], -['Ctrl-R', 'Edit Mode: Knife, cut selected edges, accept left mouse/ cancel right mouse'], -['Ctrl-Alt-R', 'MANIPULATOR (transform widget): set in Rotate Mode'], -['Shift-R', 'Edit Mode: select Face Loop'], -['Shift-R', 'Nurbs: Select row'], -['.', '...'] -], - -"S":[ -['S', 'Scale'] , -['S', 'TimeLine: Set Start'], -['SX', 'Flip around X axis'] , -['SY', 'Flip around Y axis'] , -['SZ', 'Flip around Z axis'] , -['SXX', 'Flip around X axis and show axis'] , -['SYY', 'Flip around Y axis and show axis'] , -['SZZ', 'Flip around Z axis and show axis'] , -['Alt-S', 'Edit mode: Shrink/fatten (Scale along vertex normals)'] , -['Alt-S', 'Text Editor : Save the current text to file '], -['Alt-S',' ARMATURE : posemode editmode: Scale envalope.'], -['Ctrl-Shift-S', 'Edit mode: To Sphere'] , -['Ctrl-Alt-Shift-S', 'Edit mode: Shear'] , -['Alt-S', 'Clear object size'] , -['Ctrl-S', 'Edit mode: Shear'] , -['Alt-Shift-S,','Text editor : Select the line '], -['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Size Mode'], -['Shift-S', 'Cursor/Grid snap menu'], -['Shift-S', 'Sculpt Mode: Smooth Stroke.'], -['Shift-S+1', 'VIDEO SEQUENCE editor : jump to the current frame '], -['.', '...'] -], - -"T":[ -['T', 'Adjust texture space'], -['T', 'Edit mode: Flip 3d curve'], -['T', 'IPO: Menu Change IPO type, 1 Constant'], -['T', 'IPO: Menu Change IPO type, 2 Linear'], -['T', 'IPO: Menu Change IPO type, 3 Bezier'], -['T', 'TimeLine: Show second'], -['T', 'VIDEO SEQUENCE editor : toggle between show second andd show frame'], #243 -['Alt-T', 'Clear tracking of object'], -['Ctrl-T', 'Make selected object track active object'], -['Ctrl-T', 'Edit Mode: Convert to triangles'], -['Ctrl-Alt-T', 'Benchmark'], -['.', '...'] -], - -"U":[ -['U', 'Make single user menu (for import completly linked object to another scene for instance) '] , -['U', '3D View: Make Single user Menu'] , -['U', 'UV Face Select: Automatic UV calculation menu'] , -['U', 'Vertex-/Weightpaint mode: Undo'] , -['Ctrl-U', 'Save current state as user default'], -['Shift-U', 'Edit Mode: Redo Menu'], -['Alt-U', 'Edit Mode & Object Mode: Undo Menu'], -['.', '...'] -], - -"V":[ -['V', 'Curves/Nurbs: Vector handle'], -['V', 'Edit Mode : Rip selected vertices'], -['V', 'Vertexpaint mode'], -['V', 'UV Image Editor: Stitch UVs'], -['Ctrl-V',' UV Image Editor: maximize stretch.'], -['V', 'Action editor: Vector'], -['Alt-V', "Scale object to match image texture's aspect ratio"], -['Alt-V', 'Text Editor : Paste '], -['Alt-Shift-V', 'Text Editor : View menu'], -['Alt-Shift-V', 'Text Editor : View menu 1, Top of the file '], -['Alt-Shift-V', 'Text Editor : View menu 2, Bottom of the file '], -['Alt-Shift-V', 'Text Editor : View menu 3, PageUp'], -['Alt-Shift-V', 'Text Editor : View menu 4, PageDown'], -['Ctrl-Shift-V', 'Text Editor: Paste from clipboard'], -['Shift-V', 'Edit mode: Align view to selected vertices'], -['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'], -['.', '...'] -], - -"W":[ -['W', 'Edit Mode: Specials menu'], -['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'], -['W', 'Edit Mode: Specials menu, ARMATURE 2 Subdivide Multi'], -['W', 'Edit Mode: Specials menu, ARMATURE 3 Switch Direction'], -['W', 'Edit Mode: Specials menu, ARMATURE 4 Flip Left-Right Name'], -['W', 'Edit Mode: Specials menu, ARMATURE 5 AutoName Left-Right'], -['W', 'Edit Mode: Specials menu, ARMATURE 6 AutoName Front-Back'], -['W', 'Edit Mode: Specials menu, ARMATURE 7 AutoName Top-Bottom'], -['W', 'Edit Mode: Specials menu, CURVE 1 Subdivide'], -['W', 'Edit Mode: Specials menu, CURVE 2 Swich Direction'], -['W', 'Edit Mode: Specials menu, CURVE 3 Set Goal Weight'], -['W', 'Edit Mode: Specials menu, CURVE 4 Set Radius'], -['W', 'Edit Mode: Specials menu, CURVE 5 Smooth'], -['W', 'Edit Mode: Specials menu, CURVE 6 Smooth Radius'], -['W', 'Edit Mode: Specials menu, MESH 1 Subdivide'], -['W', 'Edit Mode: Specials menu, MESH 2 Subdivide Multi'], -['W', 'Edit Mode: Specials menu, MESH 3 Subdivide Multi Fractal'], -['W', 'Edit Mode: Specials menu, MESH 4 Subdivide Smooth'], -['W', 'Edit Mode: Specials menu, MESH 5 Merge'], -['W', 'Edit Mode: Specials menu, MESH 6 Remove Double'], -['W', 'Edit Mode: Specials menu, MESH 7 Hide'], -['W', 'Edit Mode: Specials menu, MESH 8 Reveal'], -['W', 'Edit Mode: Specials menu, MESH 9 Select Swap'], -['W', 'Edit Mode: Specials menu, MESH 10 Flip Normal'], -['W', 'Edit Mode: Specials menu, MESH 11 Smooth'], -['W', 'Edit Mode: Specials menu, MESH 12 Bevel'], -['W', 'Edit Mode: Specials menu, MESH 13 Set Smooth'], -['W', 'Edit Mode : Specials menu, MESH 14 Set Solid'], -['W', 'Object Mode : on MESH objects, Boolean Tools menu'], -['W', 'Object Mode : on MESH objects, Boolean Tools 1 Intersect'], -['W', 'Object Mode : on MESH objects, Boolean Tools 2 union'], -['W', 'Object Mode : on MESH objects, Boolean Tools 3 difference'], -['W', 'Object Mode : on MESH objects, Boolean Tools 4 Add an intersect Modifier'], -['W', 'Object Mode : on MESH objects, Boolean Tools 5 Add an union Modifier'], -['W', 'Object Mode : on MESH objects, Boolean Tools 6 Add a difference Modifier'], -['W', 'Object mode : on TEXT object, Split characters, a new TEXT object by character in the selected string '], -['W', 'UV Image Editor: Weld/Align'], -['WX', 'UV Image Editor: Weld/Align X axis'], -['WY', 'UV Image Editor: Weld/Align Y axis'], -['Ctrl-W', 'Save current file'] , -['Shift-W', 'Warp/bend selected vertices around cursor'], -['.', '...'] - ], - -"X":[ -['X', 'Delete menu'] , -['X', 'TimeLine : Remove marker'], -['X', 'NLA : Remove marker'], -['X', 'IPO : Remove marker'], -['X', 'NODE window : delete'], #243 -['Alt-X', 'Text Editor : Cut '], -['Alt-X', 'Grease Pencil: Delete menu'], -['Ctrl-X', 'Restore default state (Erase all)'], -['.', '...'] - ], - -"Y":[ -['Y', 'Edit Mode & Mesh : Split selected vertices/faces from the rest'], -['Ctrl-Y', 'Object Mode : Redo'], -['.', '...'] -], - -"Z":[ -['Z', 'Render Window: 200% zoom from mouse position'], -['Z', 'Switch 3d draw type : solide/ wireframe (see also D)'], -['Alt-Z', 'Switch 3d draw type : solid / textured (see also D)'], -['Alt-Z,','Text editor : undo '], -['Ctrl-Z', 'Object Mode : Undo'], -['Ctrl-Z,','Text editor : undo '], -['Ctrl-Shift-Z,','Text editor : Redo '], -['Shift-Z', 'Switch 3d draw type : shaded / wireframe (see also D)'], -['.', '...'] -]}]} - -up=128 -down=129 -UP=0 -SEARCH=131 -OLDSEARCHLINE='' -SEARCHLINE=Create('') -LINE=130 -FINDED=[] -LEN=0 - -for k in hotkeys.keys(): - hotkeys[k].append(Create(0)) - -for k in hotkeys['Letters '][0]: - hotkeys['Letters '][0][k].append(Create(0)) - -hotL=hotkeys['Letters '][0].keys() -hotL.sort() - -hot=hotkeys.keys() -hot.sort() - -def searchfor(SEARCHLINE): - global hotkeys, hot - FINDLIST=[] - for k in hot: - if k not in ['Letters ', 'Search '] : - for l in hotkeys[k][:-1]: - #print 'k, l : ', k, l, l[1] - if l[1].upper().find(SEARCHLINE.upper())!=-1: - FINDLIST.append(l) - - elif k == 'Letters ': - for l in hotL : - for l0 in hotkeys['Letters '][0][l][:-1]: - #print 'k, l : ',l, k, l0 - if l0[1].upper().find(SEARCHLINE.upper())!=-1: - FINDLIST.append(l0) - #print 'FINDLIST',FINDLIST - FINDLIST.append(['Find list','Entry']) - return FINDLIST - - -glCr=glRasterPos2d -glCl3=glColor3f -glCl4=glColor4f -glRct=glRectf - -cf=[0.95,0.95,0.9,0.0] -c1=[0.95,0.95,0.9,0.0] -c=cf -r=[0,0,0,0] - -def trace_rectangle4(r,c): - glCl4(c[0],c[1],c[2],c[3]) - glRct(r[0],r[1],r[2],r[3]) - -def trace_rectangle3(r,c,c1): - glCl3(c[0],c[1],c[2]) - glRct(r[0],r[1],r[2],r[3]) - glCl3(c1[0],c1[1],c1[2]) - -def draw(): - global r,c,c1,hotkeys, hot, hotL, up, down, UP, SEARCH, SEARCHLINE,LINE - global OLDSEARCHLINE, FINDED, SCROLL, LEN - size=Buffer(GL_FLOAT, 4) - glGetFloatv(GL_SCISSOR_BOX, size) - size= size.list - - for s in [0,1,2,3]: size[s]=int(size[s]) - - c=[0.75,0.75,0.75,0] - c1=[0.6,0.6,0.6,0] - - r=[0,size[3],size[2],0] - trace_rectangle4(r,c) - - c=[0.64,0.64,0.64,0] - c1=[0.95,0.95,0.9,0.0] - - r=[0,size[3],size[2],size[3]-40] - trace_rectangle4(r,c) - - c1=[0.7,0.7,0.9,0.0] - c=[0.2,0.2,0.4,0.0] - c2=[0.71,0.71,0.71,0.0] - - glColor3f(1, 1, 1) - glRasterPos2f(42, size[3]-25) - - Text("HotKey and MouseAction Reference") - - l=0 - listed=0 - Llisted=0 - size[3]=size[3]-18 - - BeginAlign() - for i, k in enumerate(hot): - hotkeys[k][-1]=Toggle(k, i+10, 78*i, size[3]-(47), 78, 24, hotkeys[k][-1].val ) - l+=len(k) - if hotkeys[k][-1].val==1.0: - listed= i - EndAlign() - l=0 - size[3]=size[3]-4 - - if hot[listed]!='Letters ' and hot[listed]!='Search ' : - size[3]=size[3]-8 - SCROLL=size[3]/21 - END=-1 - if SCROLL < len(hotkeys[hot[listed]][:-1]): - BeginAlign() - Button('/\\',up,4,size[3]+8,20,14,'Scroll up') - Button('\\/',down,4,size[3]-8,20,14,'Scroll down') - EndAlign() - if (SCROLL+UP)0: - LEN=len(FINDED) - size[3]=size[3]-8 - SCROLL=size[3]/21 - END=-1 - - if SCROLL < len(FINDED): - BeginAlign() - Button('/\\',up,4,size[3]+8,20,14,'Scroll up') - Button('\\/',down,4,size[3]-8,20,14,'Scroll down') - EndAlign() - if (SCROLL+UP)4: - UP-=5 - elif (evt== UPARROWKEY): - if (UP+SCROLL)0: - UP-=1 - Redraw() - -def bevent(evt): - global hotkeysmhot, hotL, up,down,UP, FINDED - global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE - - if (evt== 1): - Exit() - - elif 9 < evt < 20: - for i, k in enumerate(hot): - if i+10!=evt: - hotkeys[k][-1].val=0 - UP=0 - Blender.Window.Redraw() - - elif 19 < evt < 46: - for i, k in enumerate(hotL): - if i+20!=evt: - hotkeys['Letters '][0][k][-1].val=0 - UP=0 - Blender.Window.Redraw() - - elif (evt==up): - UP+=1 - Blender.Window.Redraw() - - elif (evt==down): - if UP>0: UP-=1 - Blender.Window.Redraw() - - elif (evt==LINE): - if SEARCHLINE.val!='' and SEARCHLINE.val!=OLDSEARCHLINE: - OLDSEARCHLINE=SEARCHLINE.val - FINDED=searchfor(OLDSEARCHLINE) - Blender.Window.Redraw() - -if __name__ == '__main__': - Register(draw, event, bevent) diff --git a/release/scripts/image_2d_cutout.py b/release/scripts/image_2d_cutout.py deleted file mode 100644 index 16d0805256b..00000000000 --- a/release/scripts/image_2d_cutout.py +++ /dev/null @@ -1,559 +0,0 @@ -#!BPY - -""" -Name: '2D Cutout Image Importer' -Blender: 249 -Group: 'Image' -Tooltip: 'Batch UV Map images to Planes' -""" - -__author__ = "Kevin Morgan (forTe)" -__url__ = ("Home page, http://gamulabs.freepgs.com") -__version__ = "1.2.1" -__bpydoc__ = """\ -This Script will take an image and -UV map it to a plane sharing the same width to height ratio as the image. -Import options allow for the image to be a still or sequence type image -

-Imports can be single images or whole directories of images depending on the chosen -option. -""" - -#################################################### -#Copyright (C) 2008: Kevin Morgan -#################################################### -#-------------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 3 of the License, or -#(at your option) any later version. -# -#This program is distributed in the hopes 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, see . -#################################################### -#################################################### -#V1.0 -#Basic Functionality -#Published June 28, 2007 -#################################################### -#V1.1 -#Added Support for enabling viewport transparency -#Added more options to the UI for materials -#Added Proportionality code (Pixels per unit) -#Added GPL License Block -#Published June 29, 2007 -#################################################### -#V1.2 -#Added Support for Copying Existing Materials -#Import Images as Sequences -#Refreshed GUI - now with more clutter :( -#Miscellaneous and Housekeeping -#Published June 16, 2008 -#################################################### -#V1.2.1 -#Added Extend Texture Mode option at request of a user -#Published September 24, 2008 -#################################################### - -import Blender -from Blender import BGL, Draw, Image, Mesh, Material, Texture, Window -from Blender.Mathutils import * -import bpy - -# Global Constants -DIR = 0 -SINGLE = 1 -CUROFFS = 0 - -# GUI CONSTANTS -NO_EVT = 0 -SINGLE_IMG = 1 -DIRECTORY_IMG = 2 -CLR_PATH = 3 -CHG_EXT = 4 -EXIT = 5 -DO_SCRIPT = 6 - -VERSIONSTRING = '1.2.1' - -# Note the two parameter dicts could be combined, I just, liked them seperate... -# GUI Buttons Dict -GUIPARAMS = { - 'Path': Draw.Create(''), - 'ImageExt': Draw.Create(''), - 'Seq': Draw.Create(0), - 'PackImage': Draw.Create(0), - 'PPU': Draw.Create(50), - 'VPTransp': Draw.Create(1), - 'XOff': Draw.Create(0.0), - 'YOff': Draw.Create(0.0), - 'ZOff': Draw.Create(0.0), - 'CopyMat': Draw.Create(0), - 'MatId': Draw.Create(0), - 'MatCol': Draw.Create(1.0, 0.0, 0.0), - 'Ref': Draw.Create(0.8), - 'Spec': Draw.Create(0.5), - 'Hard': Draw.Create(50), - 'Alpha': Draw.Create(1.0), - 'ZTransp': Draw.Create(1), - 'Shadeless': Draw.Create(0), - 'TexChan': Draw.Create(1), - 'MPTCol': Draw.Create(1), - 'MPTAlpha': Draw.Create(1), - 'UseAlpha': Draw.Create(1), - 'CalcAlpha': Draw.Create(0), - 'ExtendMode': Draw.Create(0), - 'AutoRefresh': Draw.Create(0), - 'Cyclic': Draw.Create(0), - 'Frames': Draw.Create(100), - 'Offs': Draw.Create(0), - 'StartFr': Draw.Create(1), - 'RedrawImp': Draw.Create(0) -} - -# Script Execution Paramaters -PARAMS = { - 'ImagePaths': [], # Path to images to import - 'ImportType': SINGLE, # Import a Directory or a Single Image? - 'ImageProp': Image.Sources.STILL, # What sources for the image, still or sequence - 'PackImage': 0, # Pack the Image(s)? - 'PPU': 20, # Pixels Per Blender Unit - 'MakeTransp': 1, # Make face transparent in viewport - - 'NewMat': 1, # If true make a new material, otherwise duplicate an existing one, replacing appropriate attributes - 'MaterialId': 0, # ID to take from the Materials list upon copy - 'Materials': None, # Materials in Scene - 'MatProps': {'Col': [1.0, 0.0, 0.0], 'Shadeless': 1, 'Ref': 0.5, 'Spec': 0.5, 'Hard': 200, 'Alpha': 1.0, 'ZTransp': 1}, - - 'TexProps': {'UseAlpha': 1, 'CalcAlpha': 0, 'ExtendMode': 0}, # Texture Properties - 'TexChannel': 0, # Texture Channel - 'TexMapTo': {'Col': 1, 'Alpha': 1}, # Map to Col and/or Alpha - 'SeqProps': {'AutoRefresh': 0, 'Cyclic': 0, 'Frames': 100, 'Offs': 0, 'StartFr': 1}, - 'ObOffset': Vector(1, 0, 0) # Offset by this vector upon creation for multifile import -} - -# Get the Active Scene, of course -scn = bpy.data.scenes.active - -########################################## -# MAIN SCRIPT FUNCTIONS -########################################## - -def imgImport(imgPath): - global CUROFFS, PARAMS - ###################################### - # Load the image - ###################################### - try: - img = Image.Load(imgPath) - imgDimensions = img.getSize() # do this to ensure the data is available - except: - Blender.Draw.PupMenu('Error%t|Unsupported image format for "'+ imgPath.split('\\')[-1].split('/')[-1] +'"') - return - - if PARAMS['PackImage']: - img.pack() - name = Blender.sys.makename(imgPath, strip = 1) - - ###################################### - # Construct the mesh - ###################################### - - me = Mesh.New(name) - - # Calculate Dimensions from Image Size - dim = [float(i)/PARAMS['PPU'] for i in imgDimensions] - v = [[dim[0], dim[1], 0], [-dim[0], dim[1], 0], [-dim[0], -dim[1], 0], [dim[0], -dim[1], 0]] - me.verts.extend(v) - me.faces.extend([0, 1, 2, 3]) - - me.faces[0].image = img - me.faces[0].uv = [Vector(1.0, 1.0), Vector(0.0, 1.0), Vector(0.0, 0.0), Vector(1.0, 0.0)] - - if PARAMS['MakeTransp']: - me.faces[0].transp = Mesh.FaceTranspModes.ALPHA - - ###################################### - # Modify the Material - ###################################### - - mat = None - if not PARAMS['NewMat']: - mat = PARAMS['Materials'][PARAMS['MaterialId']].__copy__() - mat.setName(name) - else: - mat = Material.New(name) - properties = PARAMS['MatProps'] - mat.setRGBCol(properties['Col']) - mat.setRef(properties['Ref']) - mat.setSpec(properties['Spec']) - mat.setHardness(properties['Hard']) - mat.setAlpha(properties['Alpha']) - - if properties['Shadeless']: - mat.mode |= Material.Modes.SHADELESS - if properties['ZTransp']: - mat.mode |= Material.Modes.ZTRANSP - - properties = PARAMS['TexProps'] - - tex = Texture.New(name) - tex.setType('Image') - tex.setImage(img) - if properties['UseAlpha']: - tex.useAlpha = Texture.ImageFlags.USEALPHA - - if properties['CalcAlpha']: - tex.calcAlpha = Texture.ImageFlags.CALCALPHA - - if properties['ExtendMode']: - tex.setExtend('Extend') - - if PARAMS['ImageProp'] == Image.Sources.SEQUENCE: - properties = PARAMS['SeqProps'] - - img.source = PARAMS['ImageProp'] # Needs to be done here, otherwise an error with earlier getSize() - - tex.animStart = properties['StartFr'] - tex.animOffset = properties['Offs'] - tex.animFrames = properties['Frames'] - tex.autoRefresh = properties['AutoRefresh'] - tex.cyclic = properties['Cyclic'] - - texMapSetters = Texture.TexCo.UV - - # PARAMS['TexMapTo']['Col'] (and alpha) will either be 0 or 1 because its from a toggle, otherwise this line doesn't work - texChanSetters = Texture.MapTo.COL * PARAMS['TexMapTo']['Col'] | Texture.MapTo.ALPHA * PARAMS['TexMapTo']['Alpha'] - - mat.setTexture(PARAMS['TexChannel'], tex, texMapSetters, texChanSetters) - me.materials += [mat] - - ###################################### - # Object Construction - ###################################### - - ob = scn.objects.new(me, name) - p = Vector(ob.getLocation()) # Should be the origin, but just to be safe, get it - ob.setLocation((CUROFFS * PARAMS['ObOffset']) + p) - - return - -def translateParams(): - # Translates (or assigns for the most part) GUI values to those that can be read by the - # Import Function - - global GUIPARAMS, PARAMS - - if GUIPARAMS['Seq'].val and PARAMS['ImportType'] != DIR: - PARAMS['ImageProp'] = Image.Sources.SEQUENCE - - PARAMS['PackImage'] = GUIPARAMS['PackImage'].val - PARAMS['PPU'] = GUIPARAMS['PPU'].val - PARAMS['MakeTransp'] = GUIPARAMS['VPTransp'].val - PARAMS['ObOffset'] = Vector(GUIPARAMS['XOff'].val, GUIPARAMS['YOff'].val, GUIPARAMS['ZOff'].val) - - PARAMS['NewMat'] = not GUIPARAMS['CopyMat'].val - PARAMS['MaterialId'] = GUIPARAMS['MatId'].val - PARAMS['MatProps']['Col'] = list(GUIPARAMS['MatCol'].val) - PARAMS['MatProps']['Ref'] = GUIPARAMS['Ref'].val - PARAMS['MatProps']['Spec'] = GUIPARAMS['Spec'].val - PARAMS['MatProps']['Hard'] = GUIPARAMS['Hard'].val - PARAMS['MatProps']['Alpha'] = GUIPARAMS['Alpha'].val - PARAMS['MatProps']['ZTransp'] = GUIPARAMS['ZTransp'].val - PARAMS['MatProps']['Shadeless'] = GUIPARAMS['Shadeless'].val - - PARAMS['TexChannel'] = GUIPARAMS['TexChan'].val - 1 #Channels are 0-9, but GUI shows 1-10 - PARAMS['TexProps']['UseAlpha'] = GUIPARAMS['UseAlpha'].val - PARAMS['TexProps']['CalcAlpha'] = GUIPARAMS['CalcAlpha'].val - PARAMS['TexProps']['ExtendMode'] = GUIPARAMS['ExtendMode'].val - PARAMS['TexMapTo']['Col'] = GUIPARAMS['MPTCol'].val - PARAMS['TexMapTo']['Alpha'] = GUIPARAMS['MPTAlpha'].val - - PARAMS['SeqProps']['AutoRefresh'] = GUIPARAMS['AutoRefresh'].val - PARAMS['SeqProps']['Cyclic'] = GUIPARAMS['Cyclic'].val - PARAMS['SeqProps']['Frames'] = GUIPARAMS['Frames'].val - PARAMS['SeqProps']['Offs'] = GUIPARAMS['Offs'].val - PARAMS['SeqProps']['StartFr'] = GUIPARAMS['StartFr'].val - return - -def doScript(): - # Main script Function - # Consists of choosing between 2 loops, one with a redraw, one without, see comments for why - - global CUROFFS - - translateParams() - - total = len(PARAMS['ImagePaths']) - broken = 0 - - if GUIPARAMS['RedrawImp'].val: # Reduces the need to compare on every go through the loop - for i, path in enumerate(PARAMS['ImagePaths']): - CUROFFS = i # Could be passed to the import Function, but I chose a global instead - Window.DrawProgressBar(float(i)/total, "Importing %i of %i Images..." %(i+1, total)) - imgImport(path) - Blender.Redraw() - if Blender.Get('version') >= 246: - if Window.TestBreak(): - broken = 1 - break - else: - for i, path in enumerate(PARAMS['ImagePaths']): - CUROFFS = i - Window.DrawProgressBar(float(i)/total, "Importing %i of %i Images..." %(i+1, total)) - imgImport(path) - if Blender.Get('version') >= 246: - if Window.TestBreak(): - broken = 1 - break - - if broken: - Window.DrawProgressBar(1.0, "Script Execution Aborted") - else: - Window.DrawProgressBar(1.0, "Finished Importing") - - Blender.Redraw() # Force a refresh, since the user may have chosen to not refresh as they go along - - return - -########################################## -# PATH SETTERS AND CHANGERS -########################################## - -def setSinglePath(filename): - global GUIPARAMS, PARAMS - GUIPARAMS['Path'].val = filename - PARAMS['ImagePaths'] = [filename] - return - -def setDirPath(filename): - global GUIPARAMS, PARAMS - - try: - import os - except: - Draw.PupMenu('Full install of python required to be able to set Directory Paths') - Draw.Exit() - return - - path = os.path.dirname(filename) # Blender.sys.dirname fails on '/' - GUIPARAMS['Path'].val = path - - ext_lower = GUIPARAMS['ImageExt'].val.lower() - for f in os.listdir(path): - if f.lower().endswith(ext_lower): - PARAMS['ImagePaths'].append(os.path.join(path, f)) - - return - -def changeExtension(): - global GUIPARAMS, PARAMS - - if PARAMS['ImportType'] == SINGLE: - return - - try: - import os - except: - Draw.PupMenu('Full install of python required to be able to set Directory Paths') - Draw.Exit() - return - - PARAMS['ImagePaths'] = [] - - ext_lower = GUIPARAMS['ImageExt'].val.lower() - for f in os.listdir(GUIPARAMS['Path'].val): - if f.lower().endswith(ext_lower): - PARAMS['ImagePaths'].append(os.path.join(GUIPARAMS['Path'].val, f)) - - return - -########################################## -# INTERFACE FUNCTIONS -########################################## -def compileMaterialList(): - # Pretty straight forward, just grabs the materials in the blend file and constructs - # an appropriate string for use as a menu - - mats = [mat for mat in bpy.data.materials] - PARAMS['Materials'] = mats - title = 'Materials%t|' - menStrs = [mat.name + '%x' + str(i) + '|' for i, mat in enumerate(mats)] - return title + ''.join(menStrs) - -def event(evt, val): - # Disabled, since Esc is often used from the file browser - #if evt == Draw.ESCKEY: - # Draw.Exit() - - return - -def bevent(evt): - global GUIPARAMS, PARAMS - - if evt == NO_EVT: - Draw.Redraw() - - elif evt == SINGLE_IMG: - Window.FileSelector(setSinglePath, 'Image', Blender.sys.expandpath('//')) - Draw.Redraw() - PARAMS['ImportType'] = SINGLE - - elif evt == DIRECTORY_IMG: - Window.FileSelector(setDirPath, 'Directory', Blender.sys.expandpath('//')) - Draw.Redraw() - PARAMS['ImportType'] = DIR - - elif evt == CLR_PATH: - GUIPARAMS['Path'].val = '' - PARAMS['ImagePaths'] = [] - GUIPARAMS['ImageExt'].val = '' - Draw.Redraw() - - elif evt == CHG_EXT: - changeExtension() - Draw.Redraw() - - elif evt == EXIT: - Draw.Exit() - - elif evt == DO_SCRIPT: - doScript() - - else: - print "ERROR: UNEXPECTED BUTTON EVENT" - - return - -# GUI Colors ###### -ScreenColor = [0.7, 0.7, 0.7] -BackgroundColor = [0.8, 0.8, 0.8] -TitleBG = [0.6, 0.6, 0.6] -TitleCol = [1.0, 1.0, 1.0] -ErrCol = [1.0, 0.0, 0.0] -TextCol = [0.4, 0.4, 0.5] -################### - -def GUI(): - global GUIPARAMS, PARAMS - - BGL.glClearColor(*(ScreenColor + [1.0])) - BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) - - minx = 5 - maxx = 500 - miny = 5 - maxy = 450 - - lineheight = 24 - buPad = 5 # Generic Button Padding, most buttons should have 24-19 (or 5) px space around them - - lP = 5 # Left Padding - rP = 5 # Right Padding - - # Draw Background Box - BGL.glColor3f(*BackgroundColor) - BGL.glRecti(minx, miny, maxx, maxy) - - # Draw Title - BGL.glColor3f(*TitleBG) - BGL.glRecti(minx, maxy - (lineheight), maxx, maxy) - BGL.glColor3f(*TitleCol) - - title = "2D Cutout Image Importer v" + VERSIONSTRING - BGL.glRasterPos2i(minx + lP, maxy - 15) - Draw.Text(title, 'large') - - Draw.PushButton('Exit', EXIT, maxx-50-rP, maxy - lineheight + 2, 50, 19, "Exit Script") - - # Path Buttons - if GUIPARAMS['Path'].val == '': - Draw.PushButton('Single Image', SINGLE_IMG, minx + lP, maxy - (2*lineheight), 150, 19, "Select a Single Image to Import") - Draw.PushButton('Directory', DIRECTORY_IMG, minx + lP + 150, maxy - (2*lineheight), 150, 19, "Select a Directory of Images to Import") - - else: - Draw.PushButton('Clear', CLR_PATH, minx+lP, maxy - (2*lineheight), 50, 19, "Clear Path and Change Import Options") - - GUIPARAMS['Path'] = Draw.String('Path: ', NO_EVT, minx + lP, maxy - (3*lineheight), (maxx-minx-lP-rP), 19, GUIPARAMS['Path'].val, 399, 'Path to Import From') - if PARAMS['ImportType'] == DIR: - GUIPARAMS['ImageExt'] = Draw.String('Image Ext: ', CHG_EXT, minx + lP, maxy - (4*lineheight), 110, 19, GUIPARAMS['ImageExt'].val, 6, 'Image extension for batch directory importing (case insensitive)') - GUIPARAMS['PackImage'] = Draw.Toggle('Pack', NO_EVT, maxx - rP - 50, maxy - (4*lineheight), 50, 19, GUIPARAMS['PackImage'].val, 'Pack Image(s) into .Blend File') - - # Geometry and Viewport Options - BGL.glColor3f(*TextCol) - BGL.glRecti(minx+lP, maxy - (5*lineheight), maxx-rP, maxy - (5*lineheight) + 1) - BGL.glRasterPos2i(minx + lP, maxy-(5*lineheight) + 3) - Draw.Text('Geometry and Display Options', 'small') - - GUIPARAMS['PPU'] = Draw.Slider('Pixels Per Unit: ', NO_EVT, minx + lP, maxy - (6*lineheight), (maxx-minx)/2 - lP, 19, GUIPARAMS['PPU'].val, 1, 5000, 0, 'Set the Number of Pixels Per Blender Unit to preserve Image Size Relations') - GUIPARAMS['VPTransp'] = Draw.Toggle('Viewport Transparency', NO_EVT, minx + lP, maxy - (8*lineheight), (maxx-minx)/2 - lP, 2*lineheight - buPad, GUIPARAMS['VPTransp'].val, 'Display Alpha Transparency in the Viewport') - - GUIPARAMS['XOff'] = Draw.Slider('Offs X: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (6*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['XOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the X-Direction if Importing Multiple Images') - GUIPARAMS['YOff'] = Draw.Slider('Offs Y: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (7*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['YOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the Y-Direction if Importing Multiple Images') - GUIPARAMS['ZOff'] = Draw.Slider('Offs Z: ', NO_EVT, minx + lP + (maxx-minx)/2, maxy - (8*lineheight), (maxx-minx)/2 - lP - rP, 19, GUIPARAMS['ZOff'].val, 0, 5.0, 0, 'Amount to Offset Each Imported in the Z-Direction if Importing Multiple Images') - - # Material and Texture Options - BGL.glColor3f(*TextCol) - BGL.glRecti(minx+lP, maxy - (9*lineheight), maxx-rP, maxy - (9*lineheight) + 1) - BGL.glRasterPos2i(minx + lP, maxy-(9*lineheight) + 3) - Draw.Text('Material and Texture Options', 'small') - - half = (maxx-minx-lP-rP)/2 - GUIPARAMS['CopyMat'] = Draw.Toggle('Copy Existing Material', NO_EVT, minx + lP, maxy-(10*lineheight), half, 19, GUIPARAMS['CopyMat'].val, 'Copy an Existing Material') - if GUIPARAMS['CopyMat'].val: - menStr = compileMaterialList() - GUIPARAMS['MatId'] = Draw.Menu(menStr, NO_EVT, minx + lP, maxy - (11*lineheight), half, 19, GUIPARAMS['MatId'].val, 'Material to Copy Settings From') - else: - GUIPARAMS['MatCol'] = Draw.ColorPicker(NO_EVT, minx+lP, maxy - (13*lineheight), 40, (3*lineheight) - buPad, GUIPARAMS['MatCol'].val, 'Color of Newly Created Material') - GUIPARAMS['Ref'] = Draw.Slider('Ref: ', NO_EVT, minx +lP+45, maxy - (11*lineheight), half-45, 19, GUIPARAMS['Ref'].val, 0.0, 1.0, 0, 'Set the Ref Value for Created Materials') - GUIPARAMS['Spec'] = Draw.Slider('Spec: ', NO_EVT, minx +lP+45, maxy - (12*lineheight), half-45, 19, GUIPARAMS['Spec'].val, 0.0, 2.0, 0, 'Set the Spec Value for Created Materials') - GUIPARAMS['Hard'] = Draw.Slider('Hard: ', NO_EVT, minx +lP+45, maxy - (13*lineheight), half-45, 19, GUIPARAMS['Hard'].val, 1, 500, 0, 'Set the Hardness Value for Created Materials') - GUIPARAMS['Alpha'] = Draw.Slider('A: ', NO_EVT, minx +lP, maxy - (14*lineheight), half, 19, GUIPARAMS['Alpha'].val, 0.0, 1.0, 0, 'Set the Alpha Value for Created Materials') - - GUIPARAMS['ZTransp'] = Draw.Toggle('ZTransparency', NO_EVT, minx + lP, maxy - (15*lineheight), half, 19, GUIPARAMS['ZTransp'].val, 'Enable ZTransparency') - GUIPARAMS['Shadeless'] = Draw.Toggle('Shadeless', NO_EVT, minx + lP, maxy - (16*lineheight), half, 19, GUIPARAMS['Shadeless'].val, 'Enable Shadeless') - - GUIPARAMS['TexChan'] = Draw.Number('Texture Channel: ', NO_EVT, minx + lP+ half + buPad, maxy - (10*lineheight), half-rP, 19, GUIPARAMS['TexChan'].val, 1, 10, 'Texture Channel for Image Texture') - - GUIPARAMS['MPTCol'] = Draw.Toggle('Color', NO_EVT, minx + lP + half + buPad, maxy - (11*lineheight), half/2, 19, GUIPARAMS['MPTCol'].val, 'Map To Color Channel') - GUIPARAMS['MPTAlpha'] = Draw.Toggle('Alpha', NO_EVT, minx + lP + int((1.5)*half) + buPad, maxy - (11*lineheight), half/2 - rP, 19, GUIPARAMS['MPTAlpha'].val, 'Map To Alpha Channel') - - third = int((maxx-minx-lP-rP)/6) - GUIPARAMS['UseAlpha'] = Draw.Toggle('Use Alpha', NO_EVT, minx + lP + half + buPad, maxy - (12*lineheight), third, 19, GUIPARAMS['UseAlpha'].val, "Use the Images' Alpha Values") - GUIPARAMS['CalcAlpha'] = Draw.Toggle('Calc Alpha', NO_EVT, minx + lP + half + third + buPad, maxy - (12*lineheight), third, 19, GUIPARAMS['CalcAlpha'].val, "Calculate Images' Alpha Values") - GUIPARAMS['ExtendMode'] = Draw.Toggle('Extend', NO_EVT, minx+lP+half+third+third+buPad, maxy - (12*lineheight), third-3, 19, GUIPARAMS['ExtendMode'].val, "Use Extend texture mode. If deselected, Repeat is used") - GUIPARAMS['Seq'] = Draw.Toggle('Sequence', NO_EVT, minx + lP + half + buPad, maxy - (13*lineheight), half-rP, 19, GUIPARAMS['Seq'].val, 'Set the Image(s) to use a Sequence instead of a Still') - - if GUIPARAMS['Seq'].val and not PARAMS['ImportType'] == DIR: - GUIPARAMS['AutoRefresh'] = Draw.Toggle('Auto Refresh', NO_EVT, minx + lP + half + buPad, maxy - (14*lineheight), half/2, 19, GUIPARAMS['AutoRefresh'].val, 'Use Auto Refresh') - GUIPARAMS['Cyclic'] = Draw.Toggle('Cyclic', NO_EVT, minx + lP + half + buPad + half/2, maxy - (14*lineheight), half/2 - rP, 19, GUIPARAMS['Cyclic'].val, 'Repeat Frames Cyclically`') - - GUIPARAMS['Frames'] = Draw.Number('Frames: ', NO_EVT, minx +lP + half + buPad, maxy - (15*lineheight), half - rP, 19, GUIPARAMS['Frames'].val, 1, 30000, 'Sets the Number of Images of a Movie to Use') - GUIPARAMS['Offs'] = Draw.Number('Offs: ', NO_EVT, minx +lP + half + buPad, maxy - (16*lineheight), half/2, 19, GUIPARAMS['Offs'].val, -30000, 30000, 'Offsets the Number of the Frame to use in the Animation') - GUIPARAMS['StartFr'] = Draw.Number('StartFr: ', NO_EVT, minx +lP + half + buPad + half/2, maxy - (16*lineheight), half/2 - rP, 19, GUIPARAMS['StartFr'].val, 1, 30000, 'Sets the Global Starting Frame of the Movie') - elif GUIPARAMS['Seq'].val and PARAMS['ImportType'] == DIR: - BGL.glColor3f(*ErrCol) - BGL.glRasterPos2i(minx + lP + half + buPad + 7, maxy-(14 * lineheight) + 5) - Draw.Text('Sequence only available for Single Image Import', 'small') - - # Import Options - BGL.glColor3f(*TextCol) - BGL.glRecti(minx+lP, maxy - (17*lineheight), maxx-rP, maxy - (17*lineheight) + 1) - BGL.glRasterPos2i(minx + lP, maxy-(17*lineheight) + 3) - Draw.Text('Import', 'small') - - if GUIPARAMS['Path'].val and GUIPARAMS['ImageExt'].val or GUIPARAMS['Path'].val and PARAMS['ImportType'] == SINGLE: - Draw.PushButton('Import', DO_SCRIPT, minx + lP, maxy - (18*lineheight), 75, 19, "Import Image(s)") - else: - BGL.glColor3f(*ErrCol) - BGL.glRasterPos2i(minx+lP, maxy - (18*lineheight) + 5) - Draw.Text('A path and image type must be specified to import images') - - GUIPARAMS['RedrawImp'] = Draw.Toggle('Redraw During Import', NO_EVT, maxx - rP - 150, maxy - (18*lineheight), 150, 19, GUIPARAMS['RedrawImp'].val, 'Redraw the View as Images Import') - -Draw.Register(GUI, event, bevent) \ No newline at end of file diff --git a/release/scripts/image_auto_layout.py b/release/scripts/image_auto_layout.py deleted file mode 100644 index d19ba1da662..00000000000 --- a/release/scripts/image_auto_layout.py +++ /dev/null @@ -1,455 +0,0 @@ -#!BPY - -""" -Name: 'Consolidate into one image' -Blender: 243 -Group: 'Image' -Tooltip: 'Pack all texture images into 1 image and remap faces.' -""" - -__author__ = "Campbell Barton" -__url__ = ("blender", "blenderartists.org") -__version__ = "1.1a 2009/04/01" - -__bpydoc__ = """\ -This script makes a new image from the used areas of all the images mapped to the selected mesh objects. -Image are packed into 1 new image that is assigned to the original faces. -This is usefull for game models where 1 image is faster then many, and saves the labour of manual texture layout in an image editor. - -""" -# -------------------------------------------------------------------------- -# Auto Texture Layout v1.0 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 ***** -# -------------------------------------------------------------------------- - - -# Function to find all the images we use -import Blender as B -from Blender.Mathutils import Vector, RotationMatrix -from Blender.Scene import Render -import BPyMathutils -BIGNUM= 1<<30 -TEXMODE= B.Mesh.FaceModes.TEX - -def pointBounds(points): - ''' - Takes a list of points and returns the - area, center, bounds - ''' - ymax= xmax= -BIGNUM - ymin= xmin= BIGNUM - - for p in points: - x= p.x - y= p.y - - if x>xmax: xmax=x - if y>ymax: ymax=y - - if x 0.1: - mat_pos= RotationMatrix( rot_angle, 2) - mat_neg= RotationMatrix( -rot_angle, 2) - - new_points_pos= [v*mat_pos for v in current_points] - area_pos, cent_pos, bounds_pos= pointBounds(new_points_pos) - - # 45d rotations only need to be tested in 1 direction. - if rot_angle == 45: - area_neg= area_pos - else: - new_points_neg= [v*mat_neg for v in current_points] - area_neg, cent_neg, bounds_neg= pointBounds(new_points_neg) - - - # Works! - #print 'Testing angle', rot_angle, current_area, area_pos, area_neg - - best_area= min(area_pos, area_neg, current_area) - if area_pos == best_area: - current_area= area_pos - cent= cent_pos - bounds= bounds_pos - current_points= new_points_pos - total_rot_angle+= rot_angle - elif rot_angle != 45 and area_neg == best_area: - current_area= area_neg - cent= cent_neg - bounds= bounds_neg - current_points= new_points_neg - total_rot_angle-= rot_angle - - rot_angle *= 0.5 - - # Return the optimal rotation. - return total_rot_angle - - -class faceGroup(object): - ''' - A Group of faces that all use the same image, each group has its UVs packed into a square. - ''' - __slots__= 'xmax', 'ymax', 'xmin', 'ymin',\ - 'image', 'faces', 'box_pack', 'size', 'ang', 'rot_mat', 'cent'\ - - def __init__(self, mesh_list, image, size, PREF_IMAGE_MARGIN): - self.image= image - self.size= size - self.faces= [f for me in mesh_list for f in me.faces if f.mode & TEXMODE and f.image == image] - - # Find the best rotation. - all_points= [uv for f in self.faces for uv in f.uv] - bountry_indicies= BPyMathutils.convexHull(all_points) - bountry_points= [all_points[i] for i in bountry_indicies] - - # Pre Rotation bounds - self.cent= pointBounds(bountry_points)[1] - - # Get the optimal rotation angle - self.ang= bestBoundsRotation(bountry_points) - self.rot_mat= RotationMatrix(self.ang, 2), RotationMatrix(-self.ang, 2) - - # Post rotation bounds - bounds= pointBounds([\ - ((uv-self.cent) * self.rot_mat[0]) + self.cent\ - for uv in bountry_points])[2] - - # Break the bounds into useable values. - xmin, ymin, xmax, ymax= bounds - - # Store the bounds, include the margin. - # The bounds rect will need to be rotated to the rotation angle. - self.xmax= xmax + (PREF_IMAGE_MARGIN/size[0]) - self.xmin= xmin - (PREF_IMAGE_MARGIN/size[0]) - self.ymax= ymax + (PREF_IMAGE_MARGIN/size[1]) - self.ymin= ymin - (PREF_IMAGE_MARGIN/size[1]) - - self.box_pack=[\ - 0.0, 0.0,\ - size[0]*(self.xmax - self.xmin),\ - size[1]*(self.ymax - self.ymin),\ - image.name] - - ''' - # default. - self.scale= 1.0 - - def set_worldspace_scale(self): - scale_uv= 0.0 - scale_3d= 0.0 - for f in self.faces: - for i in xrange(len(f.v)): - scale_uv+= (f.uv[i]-f.uv[i-1]).length * 0.1 - scale_3d+= (f.v[i].co-f.v[i-1].co).length * 0.1 - self.scale= scale_3d/scale_uv - ''' - - - - def move2packed(self, width, height): - ''' - Moves the UV coords to their packed location - using self.box_pack as the offset, scaler. - box_pack must be set to its packed location. - width and weight are the w/h of the overall packed area's bounds. - ''' - # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] - # Width and height in float pixel space. - - # X Is flipped :/ - #offset_x= (1-(self.box_pack[1]/d)) - (((self.xmax-self.xmin) * self.image.size[0])/d) - offset_x= self.box_pack[0]/width - offset_y= self.box_pack[1]/height - - for f in self.faces: - for uv in f.uv: - uv_rot= ((uv-self.cent) * self.rot_mat[0]) + self.cent - uv.x= offset_x+ (((uv_rot.x-self.xmin) * self.size[0])/width) - uv.y= offset_y+ (((uv_rot.y-self.ymin) * self.size[1])/height) - -def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True): - ''' - Main packing function - - All meshes from mesh_list must have faceUV else this function will fail. - ''' - face_groups= {} - - for me in mesh_list: - for f in me.faces: - if f.mode & TEXMODE: - image= f.image - if image: - try: - face_groups[image.name] # will fail if teh groups not added. - except: - try: - size= image.size - except: - B.Draw.PupMenu('Aborting: Image cold not be loaded|' + image.name) - return - - face_groups[image.name]= faceGroup(mesh_list, image, size, PREF_IMAGE_MARGIN) - - if not face_groups: - B.Draw.PupMenu('No Images found in mesh(es). Aborting!') - return - - if len(face_groups)<2: - B.Draw.PupMenu('Only 1 image found|Select a mesh(es) using 2 or more images.') - return - - ''' - if PREF_SIZE_FROM_UV: - for fg in face_groups.itervalues(): - fg.set_worldspace_scale() - ''' - - # RENDER THE FACES. - render_scn= B.Scene.New() - render_scn.makeCurrent() - render_context= render_scn.getRenderingContext() - render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. - - PREF_IMAGE_PATH_EXPAND= B.sys.expandpath(PREF_IMAGE_PATH) + '.png' - - # TEST THE FILE WRITING. - try: - # Can we write to this file??? - f= open(PREF_IMAGE_PATH_EXPAND, 'w') - f.close() - except: - B.Draw.PupMenu('Error%t|Could not write to path|' + PREF_IMAGE_PATH_EXPAND) - return - - render_context.imageSizeX(PREF_IMAGE_SIZE) - render_context.imageSizeY(PREF_IMAGE_SIZE) - render_context.enableOversampling(True) - render_context.setOversamplingLevel(16) - render_context.setRenderWinSize(100) - render_context.setImageType(Render.PNG) - render_context.enableExtensions(True) - render_context.enablePremultiply() # No alpha needed. - render_context.enableRGBAColor() - render_context.threads = 2 - - #Render.EnableDispView() # Broken?? - - # New Mesh and Object - render_mat= B.Material.New() - render_mat.mode |= \ - B.Material.Modes.SHADELESS | \ - B.Material.Modes.TEXFACE | \ - B.Material.Modes.TEXFACE_ALPHA | \ - B.Material.Modes.ZTRANSP - - render_mat.setAlpha(0.0) - - render_me= B.Mesh.New() - render_me.verts.extend([Vector(0,0,0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/ - render_ob= B.Object.New('Mesh') - render_ob.link(render_me) - render_scn.link(render_ob) - render_me.materials= [render_mat] - - - # New camera and object - render_cam_data= B.Camera.New('ortho') - render_cam_ob= B.Object.New('Camera') - render_cam_ob.link(render_cam_data) - render_scn.link(render_cam_ob) - render_scn.objects.camera = render_cam_ob - - render_cam_data.type= 'ortho' - render_cam_data.scale= 1.0 - - - # Position the camera - render_cam_ob.LocZ= 1.0 - render_cam_ob.LocX= 0.5 - render_cam_ob.LocY= 0.5 - - # List to send to to boxpack function. - boxes2Pack= [ fg.box_pack for fg in face_groups.itervalues()] - packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) - - if PREF_KEEP_ASPECT: - packWidth= packHeight= max(packWidth, packHeight) - - - # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] - # Re assign the face groups boxes to the face_group. - for box in boxes2Pack: - face_groups[ box[4] ].box_pack= box # box[4] is the ID (image name) - - - # Add geometry to the mesh - for fg in face_groups.itervalues(): - # Add verts clockwise from the bottom left. - _x= fg.box_pack[0] / packWidth - _y= fg.box_pack[1] / packHeight - _w= fg.box_pack[2] / packWidth - _h= fg.box_pack[3] / packHeight - - render_me.verts.extend([\ - Vector(_x, _y, 0),\ - Vector(_x, _y +_h, 0),\ - Vector(_x + _w, _y +_h, 0),\ - Vector(_x + _w, _y, 0),\ - ]) - - render_me.faces.extend([\ - render_me.verts[-1],\ - render_me.verts[-2],\ - render_me.verts[-3],\ - render_me.verts[-4],\ - ]) - - target_face= render_me.faces[-1] - target_face.image= fg.image - target_face.mode |= TEXMODE - - # Set the UV's, we need to flip them HOZ? - target_face.uv[0].x= target_face.uv[1].x= fg.xmax - target_face.uv[2].x= target_face.uv[3].x= fg.xmin - - target_face.uv[0].y= target_face.uv[3].y= fg.ymin - target_face.uv[1].y= target_face.uv[2].y= fg.ymax - - for uv in target_face.uv: - uv_rot= ((uv-fg.cent) * fg.rot_mat[1]) + fg.cent - uv.x= uv_rot.x - uv.y= uv_rot.y - - render_context.render() - Render.CloseRenderWindow() - render_context.saveRenderedImage(PREF_IMAGE_PATH_EXPAND) - - #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): - # raise 'Error!!!' - - - # NOW APPLY THE SAVED IMAGE TO THE FACES! - #print PREF_IMAGE_PATH_EXPAND - try: - target_image= B.Image.Load(PREF_IMAGE_PATH_EXPAND) - except: - B.Draw.PupMenu('Error: Could not render or load the image at path|' + PREF_IMAGE_PATH_EXPAND) - return - - # Set to the 1 image. - for me in mesh_list: - for f in me.faces: - if f.mode & TEXMODE and f.image: - f.image= target_image - - for fg in face_groups.itervalues(): - fg.move2packed(packWidth, packHeight) - - scn.makeCurrent() - render_me.verts= None # free a tiny amount of memory. - B.Scene.Unlink(render_scn) - target_image.makeCurrent() - - -def main(): - scn= B.Scene.GetCurrent() - scn_objects = scn.objects - ob= scn_objects.active - - if not ob or ob.type != 'Mesh': - B.Draw.PupMenu('Error, no active mesh object, aborting.') - return - - # Create the variables. - # Filename without path or extension. - newpath= B.Get('filename').split('/')[-1].split('\\')[-1].replace('.blend', '') - - PREF_IMAGE_PATH = B.Draw.Create('//%s_grp' % newpath) - PREF_IMAGE_SIZE = B.Draw.Create(1024) - PREF_IMAGE_MARGIN = B.Draw.Create(6) - PREF_KEEP_ASPECT = B.Draw.Create(0) - PREF_ALL_SEL_OBS = B.Draw.Create(0) - - pup_block = [\ - 'Image Path: (no ext)',\ - ('', PREF_IMAGE_PATH, 3, 100, 'Path to new Image. "//" for curent blend dir.'),\ - 'Image Options', - ('Pixel Size:', PREF_IMAGE_SIZE, 64, 4096, 'Image Width and Height.'),\ - ('Pixel Margin:', PREF_IMAGE_MARGIN, 0, 64, 'Use a margin to stop mipmapping artifacts.'),\ - ('Keep Aspect', PREF_KEEP_ASPECT, 'If disabled, will stretch the images to the bounds of the texture'),\ - 'Texture Source',\ - ('All Sel Objects', PREF_ALL_SEL_OBS, 'Combine all selected objects into 1 texture, otherwise active object only.'),\ - ] - - if not B.Draw.PupBlock('Consolidate images...', pup_block): - return - - PREF_IMAGE_PATH= PREF_IMAGE_PATH.val - PREF_IMAGE_SIZE= PREF_IMAGE_SIZE.val - PREF_IMAGE_MARGIN= float(PREF_IMAGE_MARGIN.val) # important this is a float otherwise division wont work properly - PREF_KEEP_ASPECT= PREF_KEEP_ASPECT.val - PREF_ALL_SEL_OBS= PREF_ALL_SEL_OBS.val - - if PREF_ALL_SEL_OBS: - mesh_list= [ob.getData(mesh=1) for ob in scn_objects.context if ob.type=='Mesh'] - # Make sure we have no doubles- dict by name, then get the values back. - - for me in mesh_list: me.tag = False - - mesh_list_new = [] - for me in mesh_list: - if me.faceUV and me.tag==False: - me.tag = True - mesh_list_new.append(me) - - # replace list with possible doubles - mesh_list = mesh_list_new - - else: - mesh_list= [ob.getData(mesh=1)] - if not mesh_list[0].faceUV: - B.Draw.PupMenu('Error, active mesh has no images, Aborting!') - return - - consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN) - B.Window.RedrawAll() - -if __name__=='__main__': - main() diff --git a/release/scripts/image_billboard.py b/release/scripts/image_billboard.py deleted file mode 100644 index 54f0f7c5c55..00000000000 --- a/release/scripts/image_billboard.py +++ /dev/null @@ -1,269 +0,0 @@ -#!BPY -""" -Name: 'Billboard Render on Active' -Blender: 242 -Group: 'Image' -Tooltip: 'Selected objects and lamps to rendered faces on the act mesh' -""" -__author__= "Campbell Barton" -__url__= ["blender", "blenderartist"] -__version__= "1.0" - -__bpydoc__= """\ -Render Billboard Script -This can texture a simple billboard mesh from any number of selected objects. - -Renders objects in the selection to quad faces on the active mesh. - -Usage -* Light your model or enable the shadless flag so it is visible -* Make a low poly mesh out of quads with 90d corners. (this will be you billboard mesh) -* Select the model and any lamps that light it -* Select the billboard mesh so that it is active -* Run this script, Adjust settings such as image size or oversampling. -* Select a place to save the PNG image. -* Once the script has finished running return to the 3d view by pressing Shift+F5 -* To see the newly applied textures change the drawtype to 'Textured Solid' -""" -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton 2006 -# -# 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 Blender -from Blender import Mesh, Material, Draw -import BPyMathutils -import bpy -import BPyRender -from Blender.Scene import Render - -# reload(BPyRender) -# reload(BPyMathutils) - -import os -Vector= Blender.Mathutils.Vector - -def alpha_mat(image): - # returns a material useable for - mtl= bpy.data.materials.new() - mtl.mode |= (Material.Modes.SHADELESS | Material.Modes.ZTRANSP | Material.Modes.FULLOSA | Material.Modes.TEXFACE | Material.Modes.TEXFACE_ALPHA ) - return mtl - -# PupBlock Settings -GLOBALS= {} -PREF_RES= Draw.Create(512) -PREF_TILE_RES= Draw.Create(256) -PREF_AA = Draw.Create(1) -PREF_ALPHA= Draw.Create(1) -PREF_Z_OFFSET = Draw.Create(10.0) -PREF_IMG_PACK= Draw.Create(1) - - -def save_billboard(PREF_IMAGE_PATH): - Blender.Window.WaitCursor(1) - # remove png, add it later - PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '') - - ob_sel= GLOBALS['ob_sel'] - me_ob = GLOBALS['me_ob'] - me_data = GLOBALS['me_data'] - - time= Blender.sys.time() - - me_mat= me_ob.matrixWorld - - # Render images for all faces - face_data= [] # Store faces, images etc - boxes2Pack= [] - me_data.faceUV= True - - for i, f in enumerate(me_data.faces): - no= f.no - - # Offset the plane by the zoffset on the faces normal - plane= [v.co * me_mat for v in f] - - # Horizontal stacking, make sure 0,1 and 2,3 are the longest - if\ - (plane[0]-plane[1]).length + (plane[2]-plane[3]).length < \ - (plane[1]-plane[2]).length + (plane[3]-plane[0]).length: - plane.append(plane.pop(0)) - rot90= True - else: - rot90= False - - no= Blender.Mathutils.QuadNormal(*plane) - plane= [v + no*PREF_Z_OFFSET.val for v in plane] - - cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 - camera_matrix= BPyMathutils.plane2mat(plane) - tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i) - img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix) - img.reload() - #img.pack() # se we can keep overwriting the path - #img.filename= "" - - if rot90: - f.uv=Vector(1,1), Vector(0,1), Vector(0,0), Vector(1,0) - else: - f.uv= Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1) - - if not PREF_IMG_PACK.val: - f.mode |= Mesh.FaceModes.TEX - f.image = img - - if PREF_ALPHA.val: - f.transp |= Mesh.FaceTranspModes.ALPHA - else: - w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2 - h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2 - - face_data.append( (f, img) ) - boxes2Pack.append( [0.0,0.0,h, w, i] ) - - if PREF_IMG_PACK.val: - # pack the quads into a square - packWidth, packHeight = Blender.Geometry.BoxPack2D(boxes2Pack) - - render_obs= [] - - render_mat= alpha_mat(img) - - # Add geometry to the mesh - for box in boxes2Pack: - i= box[4] - - orig_f, img= face_data[i] - - # New Mesh and Object - - render_me= bpy.data.meshes.new() - - render_ob= Blender.Object.New('Mesh') - render_me.materials= [render_mat] - render_ob.link(render_me) - - render_obs.append(render_ob) - - # Add verts clockwise from the bottom left. - _x= box[0] / packWidth - _y= box[1] / packHeight - _w= box[2] / packWidth - _h= box[3] / packHeight - - - render_me.verts.extend([\ - Vector(_x, _y, 0),\ - Vector(_x, _y +_h, 0),\ - Vector(_x + _w, _y +_h, 0),\ - Vector(_x + _w, _y, 0),\ - ]) - - render_me.faces.extend(list(render_me.verts)) - render_me.faceUV= True - - render_me.faces[0].uv = [Vector(0,0), Vector(0,1), Vector(1,1), Vector(1,0)] - render_me.faces[0].image = img - - # Set the UV's, we need to flip them HOZ? - for uv in orig_f.uv: - uv.x = _x + (uv.x * _w) - uv.y = _y + (uv.y * _h) - - target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None) - target_image.reload() # incase your overwriting an existing image. - - # Set to the 1 image. - for f in me_data.faces: - f.image= target_image - if PREF_ALPHA.val: - f.transp |= Mesh.FaceTranspModes.ALPHA - - # Free the images data and remove - for data in face_data: - img= data[1] - os.remove(img.filename) - img.reload() - - # Finish pack - - me_data.update() - me_ob.makeDisplayList() - Blender.Window.WaitCursor(0) - print '%.2f secs taken' % (Blender.sys.time()-time) - - -def main(): - scn= bpy.data.scenes.active - ob_sel= list(scn.objects.context) - - PREF_KEEP_ASPECT= False - - # Error Checking - if len(ob_sel) < 2: - Draw.PupMenu("Error%t|Select 2 mesh objects") - return - - me_ob= scn.objects.active - - if not me_ob: - Draw.PupMenu("Error%t|No active mesh selected.") - - try: - ob_sel.remove(me_ob) - except: - pass - - if me_ob.type != 'Mesh': - Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too") - return - - me_data= me_ob.getData(mesh=1) - - for f in me_data.faces: - if len(f) != 4: - Draw.PupMenu("Error%t|Active mesh must have only quads") - return - - - # Get user input - block = [\ - 'Image Pixel Size',\ - ("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\ - ("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\ - 'Render Settings',\ - ("Pack Final", PREF_IMG_PACK , "Pack the image for each face into images into a single image"),\ - ("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\ - ("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\ - ("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\ - ] - - if not Draw.PupBlock("Billboard Render", block): - return - - # Set globals - GLOBALS['ob_sel'] = ob_sel - GLOBALS['me_ob'] = me_ob - GLOBALS['me_data'] = me_data - - Blender.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', Blender.sys.makename(ext='.png')) - # save_billboard('/tmp/test.png') - -if __name__=='__main__': - main() diff --git a/release/scripts/image_edit.py b/release/scripts/image_edit.py deleted file mode 100644 index cae40b74097..00000000000 --- a/release/scripts/image_edit.py +++ /dev/null @@ -1,158 +0,0 @@ -#!BPY -""" -Name: 'Edit Externally' -Blender: 242a -Group: 'Image' -Tooltip: 'Open in an application for editing. (hold Shift to configure)' -""" - -__author__ = "Campbell Barton" -__url__ = ["blender", "blenderartists.org"] -__version__ = "1.0" -__bpydoc__ = """\ -This script opens the current image in an external application for editing. - -Usage: -Choose an image for editing in the UV/Image view. - -To configure the application to open the image with, hold Shift as you -click on this menu item. - -For first time users try running the default application for your -operating system. If the application does not open you can type in -the full path. You can choose that the last entered application will -be saved as a default. - -* Note, default commants for opening an image are "start" for win32 -and "open" for macos. This will use the system default associated -application. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton 2006 -# -# 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 Blender -from Blender import Image, sys, Draw, Registry - -try: - import subprocess - import sys as py_sys - platform = py_sys.platform -except: - Draw.PupMenu('Error: Recent version of Python not installed.') - subprocess=None - -def os_run(appstring, filename): - ''' - Run the app, take into account different python versions etc - looks like python 2.6 wants a list for - ''' - - # evil trick, temp replace spaces so we can allow spaces in filenames - # also allows multiple instances of %f - appstring = appstring.replace(' ', '\t') - appstring = appstring.replace('%f', filename) - appstring = appstring.split('\t') - - print ' '.join(appstring) - - try: # only python 2.6 wants a list? - p = subprocess.Popen(appstring) - except: - p = subprocess.Popen(' '.join(appstring)) - - -def edit_extern(image=None): - - if not image: - image = Image.GetCurrent() - - if not image: # Image is None - Draw.PupMenu('ERROR: Please select active Image.') - return - if image.packed: - Draw.PupMenu('ERROR: Image is packed, unpack before editing.') - return - - imageFileName = sys.expandpath( image.filename ) - - if not sys.exists(imageFileName): - Draw.PupMenu('ERROR: Image path does not exist.') - return - - pupblock = [imageFileName.split('/')[-1].split('\\')[-1]] - - new_text= False - try: - appstring = Registry.GetKey('ExternalImageEditor', True) - appstring = appstring['path'] - - # for ZanQdo if he removed the path from the textbox totaly. ;) - Cam - if not appstring or appstring.find('%f')==-1: - new_text= True - except: - new_text= True - - if new_text: - pupblock.append('first time, set path.') - if platform == 'win32': - # Example of path to popular image editor... ;-) - # appstring = '"C:\\Program Files\\Adobe\\Photoshop CS\\photoshop.exe" "%f"' - # Have to add "cmd /c" to make sure we're using Windows shell. - appstring = 'cmd /c start "" /B "%f"' - elif platform == 'darwin': - appstring = 'open "%f"' - else: - appstring = 'gimp %f' - - appstring_but = Draw.Create(appstring) - save_default_but = Draw.Create(0) - - pupblock.append(('editor: ', appstring_but, 0, 99, 'Path to application, %f will be replaced with the image path.')) - pupblock.append(('Set Default', save_default_but, 'Store this path in the blender registry.')) - - # Only configure if Shift is held, - if Blender.Window.GetKeyQualifiers() & Blender.Window.Qual.SHIFT: - if not Draw.PupBlock('External Image Editor...', pupblock): - return - - appstring = appstring_but.val - save_default= save_default_but.val - - if save_default: - Registry.SetKey('ExternalImageEditor', {'path':appstring}, True) - - if appstring.find('%f') == -1: - Draw.PupMenu('ERROR: No filename specified! ("%f")') - return - - # ------------------------------- - - os_run(appstring, imageFileName) - - - -def main(): - edit_extern() - - -if __name__ == '__main__' and subprocess: - main() diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py deleted file mode 100644 index b3bee11c464..00000000000 --- a/release/scripts/import_dxf.py +++ /dev/null @@ -1,6225 +0,0 @@ -#!BPY - -""" -Name: 'Autodesk DXF (.dxf .dwg)' -Blender: 249 -Group: 'Import' -Tooltip: 'Import for DWG/DXF geometry data.' -""" -__author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' -__version__ = '1.12 - 2009.06.16 by migius' -__url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", - "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] -__email__ = ["migius(at)4d-vectors.de","Kitsune_e(at)yahoo.com"] -__bpydoc__ = """\ -This script imports objects from DWG/DXF (2d/3d) into Blender. - -This script imports 2d and 3d geometery from DXF files. -It supports DWG format too, with help of an external converter. -Supported DXF format versions: from (r2.5) r12 up to r2008. -Enhanced features are: -- configurable object filtering and geometry manipulation, -- configurable material pre-processing, -- DXF-code analyze and reporting. - -Supported DXF r12 objects: -LINE, -POINT, -SOLID, -TRACE, -TEXT, -INSERT (=block), -MINSERT (=array of blocks), -CIRCLE, -ARC, -3DFACE, -2d-POLYLINE (=in plane, incl. arc, variable-width, curve, spline), -3d-POLYLINE (=non-plane), -3d-POLYMESH, -3d-POLYFACE, -VIEW, VPORT -XREF (External Reference). - -Supported DXF>r12 objects: -ELLIPSE, -LWPOLYLINE (LightWeight Polyline), -SPLINE, -(todo v1.13) MLINE, -(todo v1.13) MTEXT - -Unsupported objects: -DXF r12: DIMENSION. -DXF>r12: GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK - -Supported geometry: 2d and 3d DXF-objects. -Curves imported as Blender curves or meshes optionally. - -Supported layout modes: -"model space" is default, -"paper space" as option (= "layout views") - -Supported scene definition objects produced with AVE_RENDER: -scene: selection of lights assigned to the camera, -lights: DIRECT, OVERHEAD, SH_SPOT, -(wip v1.13 import of AVE_RENDER material definitions) - -Hierarchy: -Entire DXF BLOCK hierarchy is preserved after import into Blender -(BLOCKs as groups on layer19, INSERTs as dupliGroups on target layer). - -Supported properties: -visibility status, -frozen status, -thickness, -width, -color, -layer, -(todo v1.13: XDATA, grouped status) -It is recommended to use DXF-object properties for assign Blender materials. - -Notes: -- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script -- Blocks are created on layer 19 then referenced at each insert point. -- support for DXF-files up to 160MB on systems with 1GB RAM -- DXF-files with over 1500 objects decrease import performance. -The problem is not the inefficiency of python-scripting but Blenders performance -in creating new objects in scene database - probably a database management problem. - -""" - -""" -History: - v1.0 - 2007/2008/2009 by migius - planned tasks: - -- (to see more, search for "--todo--" in script code) - -- command-line-mode/batch-mode - -- in-place-editing for dupliGroups - -- support for MLINE (is exported to r12 as BLOCK*Unnamed with LINEs) - -- support for MTEXT (is exported to r12 as TEXT???) - -- blender_object.properties['dxf_layer_name'] - -- better support for long dxf-layer-names - -- add configuration file.ini handles multiple material setups - -- added f_layerFilter - -- to-check: obj/mat/group/_mapping-idea from ideasman42 - -- curves: added "fill/non-fill" option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs - -- "normalize Z" option to correct non-planar figures - -- LINEs need "width" in 3d-space incl vGroups - -- support width_force for LINEs/ELLIPSEs = "solidify" - -- add better support for color_index BYLAYER=256, BYBLOCK=0 - -- bug: "oneMesh" produces irregularly errors - -- bug: Registry recall from hd_cache ?? only win32 bug?? - -- support DXF-definitions of autoshade: scene, lights and cameras - -- support ortho mode for VIEWs and VPORTs as cameras - - v1.12 - 2009.06.16 by migius - d7 fix for ignored BLOCKs (e.g. *X) which are members of other BLOCKs - v1.12 - 2009.05.27 by migius - d6 bugfix negative scaled INSERTs - isLeftHand(Matrix) check - v1.12 - 2009.05.26 by migius - d5 changed to the new 2.49 method Vector.cross() - d5 bugfix WORLDY(1,1,0) to (0,1,0) - v1.12 - 2009.04.11 by migius - d4 added DWG support, Stani Michiels idea for binding an extern DXF-DWG-converter - v1.12 - 2009.03.14 by migius - d3 removed all set()functions (problem with osx/python<2.4 reported by Blinkozo) - d3 code-cleaning - v1.12 - 2009.01.14 by migius - d2 temp patch for noname BLOCKS (*X,*U,*D) - v1.12 - 2008.11.16 by migius - d1 remove try_finally: cause not supported in python <2.5 - d1 add Bezier curves bevel radius support (default 1.0) - v1.12 - 2008.08.03 by migius - c2 warningfix: relocating of globals: layersmap, oblist - c2 modif UI: buttons newScene+targetLayer moved to start panel - v1.12 - 2008.07.04 by migius - c1 added control Curve's OrderU parameter - c1 modif UI: preset buttons X-2D-3D moved to start panel - b6 added handling exception of not registered LAYERs (Hammer-HL-editor DXF output) - b5 rebuild UI: global preset 2D for Curve-Import - b5 added UI-options: PL-MESH N+N plmesh_flip and normals_out - b5 added support for SPLINEs, added control OrderU parameter - b5 rewrote draw module for NURBS_curve and Bezier_curve - v1.12 - 2008.06.22 by migius - b4 change versioning system 1.0.12 -> 1.12 - b4 print at start version-info to console - b3 bugfix: ob.name conflict with existing meshes (different ob.name/mesh.name) - v1.0.12: 2008.05.24 by migius - b2 added support for LWPOLYLINEs - b2 added support for ProE in readerDXF.py - v1.0.12: 2008.02.08 by migius - b1 update: object = Object.Get(obname) -> f_getSceChild().getChildren() - a9 bugfix by non-existing tables views, vports, layers (Kai reported) - v1.0.12: 2008.01.17 by migius - a8 lately used INI-dir/filename persistently stored in Registry - a8 lately used DXF-dir/filename persistently stored in Registry - a7 fix missing layersmap{} for dxf-files without "section:layer" - a6 added support for XREF external referenced BLOCKs - a6 check for bug in AutoCAD2002:DXFr12export: ELLIPSE->POLYLINE_ARC fault angles - a6 support VIEWs and VPORTs as cameras: ortho and perspective mode - a6 save resources through ignoring unused BLOCKs (not-inserted or on frozen/blocked layers) - a6 added try_finally: f.close() for all IO-files - a6 added handling for TypeError raise - a5 bugfix f_getOCS for (0,0,z!=1.0) (ellipse in Kai's dxf) - a4 added to analyzeTool: report about VIEWs, VPORTs, unused/xref BLOCKs - a4 bugfix: individual support for 2D/3DPOLYLINE/POLYMESH - a4 added to UI: (*wip)BLOCK-(F): name filtering for BLOCKs - a4 added to UI: BLOCK-(n): filter noname/hatch BLOCKs *X... - a2 g_scale_as is no more GUI_A-variable - a2 bugfix "material": negative sign color_index - a2 added support for BLOCKs defined with origin !=(0,0,0) - a1 added 'global.reLocation-vector' option - - v1.0.11: 2007.11.24 by migius - c8 added 'curve_resolution_U' option - c8 added context_sensitivity for some UI-buttons - c8 bugfix ELLIPSE rotation, added closed_variant and caps - c7 rebuild UI: new layout, grouping and meta-buttons - c6 rewritten support for ELLIPSE mesh & curve representation - c6 restore selector-buttons for DXF-drawTypes: LINE & Co - c6 change header of INI/INF-files: # at begin - c6 apply scale(1,1,1) after glob.Scale for all mesh objects, not for curve objects. - c5 fixing 'material_on' option - c4 added "analyze DXF-file" UI-option: print LAYER/BLOCK-dependences into a textfile - c3 human-formating of data in INI-Files - c2 added "caps" for closed Bezier-curves - c2 added "set elevation" UI-option - c1 rewrite POLYLINE2d-arc-segments Bezier-interpreter - b9 many bugs fixed - b9 rewrite POLYLINE2d-arc-segments trimming (clean-trim) - b8 added "import from frozen layers" UI-option - b8 added "import from paper space" UI-option - b8 support Bezier curves for LINEs incl.thickness(0.0-10.0) - b8 added meshSmooth_on for circle/arc/polyline - b8 added vertexGroups for circle/arc - b7 added width_force for ARCs/CIRCLEs = "thin_box" option - b3 cleanup code, rename f_drawArc/Bulg->f_calcArc/Bulg - b2 fixing material assignment by LAYER+COLOR - b1 fixing Bezier curves representation of POLYLINEs-arc-segments - b0 added global_scale_presets: "yard/feet/inch to meter" - - v1.0.10: 2007.10.18 by migius - a6 bugfix CircleDrawCaps for OSX - a5 added two "curve_res" UI-buttons for Bezier curves representation - a5 improved Bezier curves representation of circles/arcs: correct handlers - a4 try to fix malformed endpoints of Blender curves of ARC/POLYLINE-arc segments. - a3 bugfix: open-POLYLINEs with end_point.loc==start_point.loc - a2 bugfix: f_transform for OCS=(0,0,-1) oriented objects - a1 added "fill_on=caps" option to draw top and bottom sides of CIRCLEs and ELLIPSEs - a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh - a1 bugfix "newScene"-mode: all Cylinders/Arcs were drawn at <0,0,0>location - - v1.0.beta09: 2007.09.02 by migius - g5 redesign UI: grouping of buttons - g3 update multi-import-mode: <*.*> button - g- added multi-import-mode: (path/*) for importing many dxf-files at once - g- added import into newScene - g- redesign UI: user presets, into newScene-import - f- cleanup code - f- bugfix: thickness for Bezier/Bsplines into Blender-curves - f- BlenderWiki documentation, on-line Manual - f- added import POLYLINE-Bsplines into Blender-NURBSCurves - f- added import POLYLINE-arc-segments into Blender-BezierCurves - f- added import POLYLINE-Bezier-curves into Blender-Curves - d5 rewrite: Optimization Levels, added 'directDrawing' - d4 added: f_set_thick(controlled by ini-parameters) - d4 bugfix: face-normals in objects with minus thickness - d4 added: placeholder'Empty'-size in f_Insert.draw - d3 rewrite f_Text.Draw: added support for all Text's parameters - d2 redesign: progressbar - e- tuning by ideasman42: better use of the Py API. - c- tuning by ideasman42 - b- rewrite f_Text.Draw rotation/transform - b- bugfix: POLYLINE-segment-intersection more reliable now - b- bugfix: circle:_thic, 'Empties':no material_assignment - b- added material assignment (from layer and/or color) - a- added empty, cylinder and UVsphere for POINTs - a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces - a- redesign f_Drawer for block_definitions - a- rewrite import into Blender-Curve-Object - - v1.0.beta08 - 2007.07.27 by migius: "full 3d"-release - l- bugfix: solid_vgroups, clean:scene.objects.new() - l- redesign UI to standard Draw.Register+FileSelector, advanced_config_option - k- bugfix UI:fileSelect() for MacOSX os.listdir() - k- added reset/save/load for config-data - k- redesign keywords/drawTypes/Draw.Create_Buttons - j- new UI using UIBlock() with own FileSelector, cause problem Window.FileSelector() - i- rewritten Class:Settings for better config-parameter management - h- bugfix: face-normals in objects with minus thickness - h- added Vertex-Groups in POLYLINE and SOLID meshes, for easy material assignment - h- beautify code, whitespace->tabs - h- added settings.thic_force switch for forcing thickness - h- added "one Mesh" option for all entities from the same Layer, sorted in
- Vertex-Groups(color_name) (fewer objects = better import performance) - g- rewrote: insert-point-handle-object is a small tetrahedron - e- bugfix: closed-polymesh3d - - rewrote: UI, type_map.keys, f_drawer, all class_f_draw(added "settings" as attribut) - - added 2d/3d-support for Polyline_Width incl. angle intersection - beta07: 2007.06.19 by migius - - added 3d-support for LWPolylines - - added 2d/3d-support for Points - beta06: 2007.06.15 by migius - - cleanup code - - added 2d/3d-support for MINSERT=BlockArray in f_drawer, added f_rotXY_Vec - beta05: 2007.06.14 by migius - - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace - - added Global-Scale for size control of imported scenes - beta04: 2007.06.12 by migius - - rewrote the f_drawBulge for correct import the arc-segments of Polylines - beta03: 2007.06.10 by migius - - rewrote interface - beta02: 2007.06.09 by migius - - added 3d-support for Arcs and Circles - - added support for Object_Thickness(=height) - beta01: 2007.06.08 by migius - - added 3d-support for Blocks/Inserts within nested-structures - - rewrote f_transform for correct 3d-location/3d-rotation - - added 3d-support Lines, 3dFaces - - added 2d+3d-support for Solids and Traces - - v0.9 - 2007.01 by kitsu: (for 2.43) - - first draft of true POLYLINE import - - - - v0.8 - 2006.12 by kitsu: - - first draft of object space coordinates OCS import - - - - v0.5b - 2006.10 by kitsu: (for 2.42a) - - dxfReader.py - - color_map.py - -""" - -# -------------------------------------------------------------------------- -# DXF Import v1.0 by Ed Blake (AKA kitsu) and Remigiusz Fiedler (AKA migius) -# -------------------------------------------------------------------------- -# ***** 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 Blender -from Blender import Mathutils, BezTriple, Draw, Registry, sys,\ -Text3d, Window, Mesh, Material, Group, Curve -#from Blender.Mathutils import Vector, Matrix -#import bpy #not used yet -#import BPyMessages - -from dxfReader import readDXF -#from dxfReader import get_name, get_layer -from dxfReader import Object as dxfObject -from dxfColorMap import color_map -from math import log10, sqrt, radians, degrees, atan, cos, sin - -# osx-patch by Blinkozo -#todo: avoid additional modules, prefer Blender-build-in test routines -#import platform -#if platform.python_version() < '2.4': -# from sets import Set as set -#from sys import version_info -#ver = '%s.%s' % version_info[0:2] -# end osx-patch - -import subprocess -import os -if os.name != 'mac': - try: - import psyco - psyco.log(Blender.Get('tempdir')+"/blender.log-psyco") - #psyco.log() - psyco.full(memory=100) - psyco.profile(0.05, memory=100) - psyco.profile(0.2) - #print 'psyco imported' - except ImportError: - print 'psyco not imported' - -print '\n\n\n' -print 'DXF/DWG-Importer v%s *** start ***' %(__version__) #--------------------- - -SCENE = None -WORLDX = Mathutils.Vector((1,0,0)) -WORLDY = Mathutils.Vector((0,1,0)) -WORLDZ = Mathutils.Vector((0,0,1)) - -G_SCALE = 1.0 #(0.0001-1000) global scaling factor for all dxf data -G_ORIGIN_X = 0.0 #global translation-vector (x,y,z) in DXF units -G_ORIGIN_Y = 0.0 -G_ORIGIN_Z = 0.0 -MIN_DIST = 0.001 #cut-off value for sort out short-distance polyline-"duoble_vertex" -ARC_RESOLUTION = 64 #(4-500) arc/circle resolution - number of segments -ARC_RADIUS = 1.0 #(0.01-100) arc/circle radius for number of segments algorithm -CURV_RESOLUTION = 12 #(1-128) Bezier curves U-resolution -CURVARC_RESOLUTION = 4 #(3-32) resolution of circle represented as Bezier curve -THIN_RESOLUTION = 8 #(4-64) thin_cylinder arc_resolution - number of segments -MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness -MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width -TRIM_LIMIT = 3.0 #limit for triming of polylines-wide-segments (values:0.0 - 5.0) -ELEVATION = 0.0 #standard elevation = coordinate Z value - -BYBLOCK = 0 -BYLAYER = 256 -TARGET_LAYER = 3 #target blender_layer -GROUP_BYLAYER = 0 #(0/1) all entities from same layer import into one blender-group -LAYER_DEF_NAME = 'AAAA' #default layer name -LAYER_DEF_COLOR = 4 #default layer color -E_M = 0 -LAB = ". wip .. todo" #"*) parts under construction" -M_OBJ = 0 - -FILENAME_MAX = 180 #max length of path+file_name string (FILE_MAXDIR + FILE_MAXFILE) -MAX_NAMELENGTH = 17 #max_effective_obnamelength in blender =21=17+(.001) -INIFILE_DEFAULT_NAME = 'importDXF' -INIFILE_EXTENSION = '.ini' -INIFILE_HEADER = '#ImportDXF.py ver.1.0 config data' -INFFILE_HEADER = '#ImportDXF.py ver.1.0 analyze of DXF-data' - -AUTO = BezTriple.HandleTypes.AUTO -FREE = BezTriple.HandleTypes.FREE -VECT = BezTriple.HandleTypes.VECT -ALIGN = BezTriple.HandleTypes.ALIGN - -UI_MODE = True #activates UI-popup-print, if not multiple files imported - -#---- migration to 2.49------------------------------------------------- -if 'cross' in dir(Mathutils.Vector()): - #Draw.PupMenu('DXF exporter: Abort%t|This script version works for Blender up 2.49 only!') - def M_CrossVecs(v1,v2): - return v1.cross(v2) #for up2.49 - def M_DotVecs(v1,v2): - return v1.dot(v2) #for up2.49 -else: - def M_CrossVecs(v1,v2): - return Mathutils.CrossVecs(v1,v2) #for pre2.49 - def M_DotVecs(v1,v2): - return Mathutils.DotVecs(v1,v2) #for pre2.49 - - -#-------- DWG support ------------------------------------------ -extCONV_OK = True -extCONV = 'DConvertCon.exe' -extCONV_PATH = os.path.join(Blender.Get('scriptsdir'),extCONV) -if not os.path.isfile(extCONV_PATH): - extCONV_OK = False - extCONV_TEXT = 'DWG-Importer cant find external DWG-converter (%s) in Blender script directory.|\ -More details in online Help.' %extCONV -else: - if not os.sys.platform.startswith('win'): - # check if Wine installed: - if subprocess.Popen(('which', 'winepath'), stdout=subprocess.PIPE).stdout.read().strip(): - extCONV_PATH = 'wine %s'%extCONV_PATH - else: - extCONV_OK = False - extCONV_TEXT = 'The external DWG-converter (%s) needs Wine installed on your system.|\ -More details in online Help.' %extCONV -#print 'extCONV_PATH = ', extCONV_PATH - - - -class View: #----------------------------------------------------------------- - """Class for objects representing dxf VIEWs. - """ - def __init__(self, obj, active=None): - """Expects an object of type VIEW as input. - """ - if not obj.type == 'view': - raise TypeError, "Wrong type %s for VIEW object!" %obj.type - - self.type = obj.type - self.name = obj.get_type(2)[0] -# self.data = obj.data[:] - - - self.centerX = getit(obj, 10, 0.0) #view center pointX (in DCS) - self.centerY = getit(obj, 20, 0.0) #view center pointY (in DCS) - self.height = obj.get_type(40)[0] #view height (in DCS) - self.width = obj.get_type(41)[0] #view width (in DCS) - - self.dir = [0,0,0] - self.dir[0] = getit(obj, 11, 0.0) #view directionX from target (in WCS) - self.dir[1] = getit(obj, 21, 0.0) # - self.dir[2] = getit(obj, 31, 0.0) # - - self.target = [0,0,0] - self.target[0] = getit(obj, 12, 0.0) #target pointX(in WCS) - self.target[1] = getit(obj, 22, 0.0) # - self.target[2] = getit(obj, 32, 0.0) # - - self.length = obj.get_type(42)[0] #Lens length - self.clip_front = getit(obj, 43) #Front clipping plane (offset from target point) - self.clip_back = getit(obj, 44) #Back clipping plane (offset from target point) - self.twist = obj.get_type(50)[0] #view twist angle in degrees - - self.flags = getit(obj, 70, 0) - self.paperspace = self.flags & 1 # - - self.mode = obj.get_type(71)[0] #view mode (VIEWMODE system variable) - - def __repr__(self): - return "%s: name - %s, focus length - %s" %(self.__class__.__name__, self.name, self.length) - - - def draw(self, settings): - """for VIEW: generate Blender_camera. - """ - obname = 'vw_%s' %self.name # create camera object name - #obname = 'ca_%s' %self.name # create camera object name - obname = obname[:MAX_NAMELENGTH] - - if self.target == [0,0,0] and Mathutils.Vector(self.dir).length == 1.0: - cam= Camera.New('ortho', obname) - ob= SCENE.objects.new(cam) - cam.type = 'ortho' - cam.scale = 1.0 # for ortho cameras - else: - cam= Camera.New('persp', obname) - ob= SCENE.objects.new(cam) - cam.type = 'persp' - cam.angle = 60.0 # for persp cameras - if self.length: - #cam.angle = 2 * atan(17.5/self.length) * 180/pi - cam.lens = self.length #for persp cameras - # hack to update Camera>Lens setting (inaccurate as a focal length) - #curLens = cam.lens; cam.lens = curLens - # AutoCAD gets clip distance from target: - dist = Mathutils.Vector(self.dir).length - cam.clipEnd = dist - self.clip_back - cam.clipStart = dist - self.clip_front - - cam.drawLimits = 1 - cam.drawSize = 10 - - v = Mathutils.Vector(self.dir) -# print 'deb:view cam:', cam #------------ -# print 'deb:view self.target:', self.target #------------ -# print 'deb:view self.dir:', self.dir #------------ -# print 'deb:view self.twist:', self.twist #------------ -# print 'deb:view self.clip_front=%s, self.clip_back=%s, dist=%s' %(self.clip_front, self.clip_back, dist) #------------ - transform(v.normalize(), -self.twist, ob) - ob.loc = Mathutils.Vector(self.target) + Mathutils.Vector(self.dir) - return ob - - -class Vport: #----------------------------------------------------------------- - """Class for objects representing dxf VPORTs. - """ - def __init__(self, obj, active=None): - """Expects an object of type VPORT as input. - """ - if not obj.type == 'vport': - raise TypeError, "Wrong type %s for VPORT object!" %obj.type - - self.type = obj.type - self.name = obj.get_type(2)[0] -# self.data = obj.data[:] - #print 'deb:vport name, data:', self.name #------- - #print 'deb:vport data:', self.data #------- - - self.height = obj.get_type(40)[0] #vport height (in DCS) - self.centerX = getit(obj, 12, 0.0) #vport center pointX (in DCS) - self.centerY = getit(obj, 22, 0.0) #vport center pointY (in DCS) - self.width = self.height * obj.get_type(41)[0] #vport aspect ratio - width (in DCS) - - self.dir = [0,0,0] - self.dir[0] = getit(obj, 16, 0.0) #vport directionX from target (in WCS) - self.dir[1] = getit(obj, 26, 0.0) # - self.dir[2] = getit(obj, 36, 0.0) # - - self.target = [0,0,0] - self.target[0] = getit(obj, 17, 0.0) #target pointX(in WCS) - self.target[1] = getit(obj, 27, 0.0) # - self.target[2] = getit(obj, 37, 0.0) # - - self.length = obj.get_type(42)[0] #Lens length - self.clip_front = getit(obj, 43) #Front clipping plane (offset from target point) - self.clip_back = getit(obj, 44) #Back clipping plane (offset from target point) - self.twist = obj.get_type(51)[0] #view twist angle - - self.flags = getit(obj, 70, 0) - self.paperspace = self.flags & 1 # - - self.mode = obj.get_type(71)[0] #view mode (VIEWMODE system variable) - - def __repr__(self): - return "%s: name - %s, focus length - %s" %(self.__class__.__name__, self.name, self.length) - - def draw(self, settings): - """for VPORT: generate Blender_camera. - """ - obname = 'vp_%s' %self.name # create camera object name - #obname = 'ca_%s' %self.name # create camera object name - obname = obname[:MAX_NAMELENGTH] - - if self.target == [0,0,0] and Mathutils.Vector(self.dir).length == 1.0: - cam= Camera.New('ortho', obname) - ob= SCENE.objects.new(cam) - cam.type = 'ortho' - cam.scale = 1.0 # for ortho cameras - else: - cam= Camera.New('persp', obname) - ob= SCENE.objects.new(cam) - cam.type = 'persp' - cam.angle = 60.0 # for persp cameras - if self.length: - #cam.angle = 2 * atan(17.5/self.length) * 180/pi - cam.lens = self.length #for persp cameras - # hack to update Camera>Lens setting (inaccurate as a focal length) - #curLens = cam.lens; cam.lens = curLens - # AutoCAD gets clip distance from target: - dist = Mathutils.Vector(self.dir).length - cam.clipEnd = dist - self.clip_back - cam.clipStart = dist - self.clip_front - - cam.drawLimits = 1 - cam.drawSize = 10 - - v = Mathutils.Vector(self.dir) -# print 'deb:view cam:', cam #------------ -# print 'deb:view self.target:', self.target #------------ -# print 'deb:view self.dir:', self.dir #------------ -# print 'deb:view self.twist:', self.twist #------------ -# print 'deb:view self.clip_front=%s, self.clip_back=%s, dist=%s' %(self.clip_front, self.clip_back, dist) #------------ - transform(v.normalize(), -self.twist, ob) - ob.loc = Mathutils.Vector(self.target) + Mathutils.Vector(self.dir) - return ob - - - -class Layer: #----------------------------------------------------------------- - """Class for objects representing dxf LAYERs. - """ - def __init__(self, obj, name=None, color=None, frozen=None): - """Expects an dxfobject of type layer as input. - if no dxfobject - creates surogate layer with default parameters - """ - - if obj==None: - self.type = 'layer' - if name: self.name = name - else: self.name = LAYER_DEF_NAME - - if color: self.color = color - else: self.color = LAYER_DEF_COLOR - - if frozen!=None: self.frozen = frozen - else: self.frozen = 0 - else: - if obj.type=='layer': - self.type = obj.type - #self.data = obj.data[:] - if name: self.name = name - #self.bfname = name #--todo---see layernamesmap in f_getLayersmap --- - else: self.name = obj.get_type(2)[0] #layer name of object - - if color: self.color = color - else: self.color = obj.get_type(62)[0] #color of object - - if frozen!=None: self.frozen = frozen - else: - self.flags = obj.get_type(70)[0] - self.frozen = self.flags & 1 - - def __repr__(self): - return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) - - - -def getit(obj, typ, default=None): #------------------------------------------ - """Universal procedure for geting data from list/objects. - """ - it = default - if type(obj) == list: #if obj is a list, then searching in a list - for item in obj: - #print 'deb:getit item, type(item)', item, type(item) - try: - if item[0] == typ: - it = item[1] - break #as soon as the first found - except: - # --todo-- I found one case where item was a text instance - # that failed with no __getitem__ - pass - else: #else searching in Object with get_type-Methode - item = obj.get_type(typ) - if item: - it = item[0] - #print 'deb:getit:typ, it', typ, it #---------- - return it - - - -def get_extrusion(data): #------------------------------------------------- - """Find the axis of extrusion. - - Used to get from object_data the objects Object_Coordinate_System (ocs). - """ - #print 'deb:get_extrusion: data: \n', data #--------------- - vec = [0,0,1] - vec[0] = getit(data, 210, 0) # 210 = x - vec[1] = getit(data, 220, 0) # 220 = y - vec[2] = getit(data, 230, 1) # 230 = z - #print 'deb:get_extrusion: vec: ', vec #--------------- - return vec - - -#------------------------------------------ -def getSceneChild(name): - dudu = [i for i in SCENE.objects if i.name==name] -# dudu = [i for i in SCENE.getChildren() if i.name==name] - #print 'deb:getSceneChild %s -result: %s:' %(name,dudu) #----------------- - if dudu!=[]: return dudu[0] - return None - - -class Solid: #----------------------------------------------------------------- - """Class for objects representing dxf SOLID or TRACE. - """ - def __init__(self, obj): - """Expects an entity object of type solid or trace as input. - """ - if obj.type == 'trace': - obj.type = 'solid' - if not obj.type == 'solid': - raise TypeError, "Wrong type \'%s\' for solid/trace object!" %obj.type - - self.type = obj.type -# self.data = obj.data[:] - - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - self.points = self.get_points(obj) - - - - def get_points(self, data): - """Gets start and end points for a solid type object. - - Solids have 3 or 4 points and fixed codes for each value. - """ - - # start x, y, z and end x, y, z = 0 - a = [0, 0, 0] - b = [0, 0, 0] - c = [0, 0, 0] - d = [0, 0, 0] - a[0] = getit(data, 10, None) # 10 = x - a[1] = getit(data, 20, None) # 20 = y - a[2] = getit(data, 30, 0) # 30 = z - b[0] = getit(data, 11, None) - b[1] = getit(data, 21, None) - b[2] = getit(data, 31, 0) - c[0] = getit(data, 12, None) - c[1] = getit(data, 22, None) - c[2] = getit(data, 32, 0) - out = [a,b,c] - - d[0] = getit(data, 13, None) - if d[0] != None: - d[1] = getit(data, 23, None) - d[2] = getit(data, 33, 0) - out.append(d) - #print 'deb:solid.vertices:---------\n', out #----------------------- - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - def draw(self, settings): - """for SOLID: generate Blender_geometry. - """ - points = self.points - if not points: return - edges, faces = [], [] - l = len(self.points) - - obname = 'so_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - - vg_left, vg_right, vg_top, vg_bottom, vg_start, vg_end = [], [], [], [], [], [] - thic = set_thick(self.thic, settings) - if thic != 0: - thic_points = [[v[0], v[1], v[2] + thic] for v in points[:]] - if thic < 0.0: - thic_points.extend(points) - points = thic_points - else: - points.extend(thic_points) - - if l == 4: - faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1], - [1,5,7,3], [3,7,6,2], [2,6,4,0]] - vg_left = [2,6,4,0] - vg_right = [1,5,7,3] - vg_top = [4,6,7,5] - vg_bottom = [0,1,3,2] - vg_start = [0,4,5,1] - vg_end = [3,7,6,2] - elif l == 3: - faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]] - vg_top = [3,4,5] - vg_bottom = [0,1,2] - vg_left = [2,5,3,0] - vg_right = [1,4,5,2] - vg_start = [0,3,4,1] - elif l == 2: faces = [[0,1,3,2]] - else: - if l == 4: faces = [[0,1,3,2]] - elif l == 3: faces = [[0,1,2]] - elif l == 2: edges = [[0,1]] - - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(points) # add vertices to mesh - if faces: me.faces.extend(faces) # add faces to the mesh - if edges: me.edges.extend(edges) # add faces to the mesh - - if settings.var['vGroup_on'] and not M_OBJ: - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - replace = Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE - if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) - if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) - if vg_top: me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) - if vg_bottom:me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) - if vg_start:me.addVertGroup('side.start') ; me.assignVertsToGroup('side.start', vg_start, 1.0, replace) - if vg_end: me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', vg_end, 1.0, replace) - - transform(self.extrusion, 0, ob) - - return ob - -class Line: #----------------------------------------------------------------- - """Class for objects representing dxf LINEs. - """ - def __init__(self, obj): - """Expects an entity object of type line as input. - """ - if not obj.type == 'line': - raise TypeError, "Wrong type \'%s\' for line object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0) - #print 'deb:self.thic: ', self.thic #--------------------- - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - self.points = self.get_points(obj) - - - def get_points(self, data): - """Gets start and end points for a line type object. - - Lines have a fixed number of points (two) and fixed codes for each value. - """ - # start x,y,z and end x,y,z = 0 - a = [0, 0, 0] - b = [0, 0, 0] - a[0] = getit(data, 10, None) # 10 = x - a[1] = getit(data, 20, None) # 20 = y - a[2] = getit(data, 30, 0) # 30 = z - b[0] = getit(data, 11, None) - b[1] = getit(data, 21, None) - b[2] = getit(data, 31, 0) - out = [a,b] - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - def draw(self, settings): - """for LINE: generate Blender_geometry. - """ - # Generate the geometery - #settings.var['curves_on']=False - - points = self.points - thic = set_thick(self.thic, settings) - width = 0.0 - if settings.var['lines_as'] == 4: # as thin_box - thic = settings.var['thick_min'] - width = settings.var['width_min'] - elif settings.var['lines_as'] == 3: # as thin cylinder - cyl_rad = 0.5 * settings.var['width_min'] - - elif settings.var['lines_as'] == 5: # LINE curve representation------------------------- - obname = 'li_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - - c = Curve.New(obname) # create new curve data - curve = c.appendNurb(BezTriple.New(points[0])) - curve.append(BezTriple.New(points[1])) - for point in curve: - point.handleTypes = [VECT, VECT] - point.radius = 1.0 - curve.flagU = 0 # 0 sets the curve not cyclic=open - c.setResolu(settings.var['curve_res']) - c.update() #important for handles calculation - - ob = SCENE.objects.new(c) # create a new curve_object - - #if False: # --todo-- better support for 210-group - if thic != 0.0: #hack: Blender2.45 curve-extrusion - t = thic * 0.5 - if abs(t) > 5.0: t = 5.0 * cmp(t,0) # Blender2.45 accepts only (0.0 - 5.0) - e = self.extrusion - c.setExt1(abs(t)) # curve-extrusion - ob.LocX += t * e[0] - ob.LocY += t * e[1] - ob.LocZ += t * e[2] - #c.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0) - #ob.LocZ = t + self.loc[2] - #ob.SizeZ *= abs(t) - return ob - - else: # LINE mesh representation ------------------------------ - global activObjectLayer - global activObjectName - #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- - - if M_OBJ: obname, me, ob = makeNewObject() - else: - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- - ob = getSceneChild(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - #me = Mesh.Get(ob.name) # open objects mesh data - me = ob.getData(name_only=False, mesh=True) - else: - obname = 'li_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - activObjectName = ob.name - activObjectLayer = self.layer - #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #--------------------- - - faces, edges = [], [] - n = len(me.verts) - - #if settings.var['width_force']: #--todo----------- - - if thic != 0: - t, e = thic, self.extrusion - #print 'deb:thic, extr: ', t, e #--------------------- - points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]]) - faces = [[0+n, 1+n, 3+n, 2+n]] - else: - edges = [[0+n, 1+n]] - - me.verts.extend(points) # adds vertices to global mesh - if faces: me.faces.extend(faces) # add faces to the mesh - if edges: me.edges.extend(edges) # add faces to the mesh - - if settings.var['vGroup_on'] and not M_OBJ: - # entities with the same color build one vertexGroup for easier material assignment ---- - ob.link(me) # link mesh to that object - vG_name = 'color_%s' %self.color_index - if edges: faces = edges - replace = Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD - try: - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: existed vGroup:', vG_name #--------------------- - except: - me.addVertGroup(vG_name) - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: create new vGroup:', vG_name #--------------------- - - - #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #--------------------- - return ob - - - -class Point: #----------------------------------------------------------------- - """Class for objects representing dxf POINTs. - """ - def __init__(self, obj): - """Expects an entity object of type point as input. - """ - if not obj.type == 'point': - raise TypeError, "Wrong type %s for point object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0) - #print 'deb:self.thic: ', self.thic #--------------------- - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - self.points = self.get_points(obj) - - - def get_points(self, data): - """Gets coordinates for a point type object. - - Points have fixed codes for each value. - """ - a = [0, 0, 0] - a[0] = getit(data, 10, None) # 10 = x - a[1] = getit(data, 20, None) # 20 = y - a[2] = getit(data, 30, 0) # 30 = z - out = [a] - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - def draw(self, settings): - """for POINT: generate Blender_geometry. - """ - points = self.points - obname = 'po_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - points_as = settings.var['points_as'] - thic = settings.var['thick_min'] - if thic < settings.var['dist_min']: thic = settings.var['dist_min'] - - if points_as in [1,3,4,5]: - if points_as in [1,5]: # as 'empty' - c = 'Empty' - elif points_as == 3: # as 'thin sphere' - res = settings.var['thin_res'] - c = Mesh.Primitives.UVsphere(res,res,thic) - elif points_as == 4: # as 'thin box' - c = Mesh.Primitives.Cube(thic) - ob = SCENE.objects.new(c, obname) # create a new object - transform(self.extrusion, 0, ob) - ob.loc = tuple(points[0]) - - elif points_as == 2: # as 'vertex' - global activObjectLayer - global activObjectName - #print 'deb:draw:point.ob IN activObjectName: ', activObjectName #--------------------- - if M_OBJ: obname, me, ob = makeNewObject() - else: - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:draw:point.ob obname from activObjectName: ', obname #--------------------- - ob = getSceneChild(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - me = ob.getData(name_only=False, mesh=True) - #me = Mesh.Get(ob.name) # open objects mesh data - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - activObjectName = ob.name - activObjectLayer = self.layer - #print ('deb:draw:point new point.ob+mesh:"%s" created!' %ob.name) #--------------------- - me.verts.extend(points) # add vertices to mesh - - return ob - - - -class Polyline: #----------------------------------------------------------------- - """Class for objects representing dxf POLYLINEs. - """ - def __init__(self, obj): - """Expects an entity object of type polyline as input. - """ - #print 'deb:polyline.init.START:----------------' #------------------------ - if not obj.type == 'polyline': - raise TypeError, "Wrong type %s for polyline object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - self.space = getit(obj, 67, 0) - self.elevation = getit(obj, 30, 0) - #print 'deb:elevation: ', self.elevation #--------------- - self.thic = getit(obj, 39, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.flags = getit(obj, 70, 0) - self.closed = self.flags & 1 # closed in the M direction - self.curved = self.flags & 2 # Bezier-curve-fit vertices have been added - self.spline = self.flags & 4 # NURBS-curve-fit vertices have been added - self.poly3d = self.flags & 8 # 3D-polyline - self.plmesh = self.flags & 16 # 3D-polygon mesh - self.closeN = self.flags & 32 # closed in the N direction - self.plface = self.flags & 64 # 3D-polyface mesh - self.contin = self.flags & 128 # the linetype pattern is generated continuously - - self.pltype='poly2d' # default is a 2D-polyline - if self.poly3d: self.pltype='poly3d' - elif self.plface: self.pltype='plface' - elif self.plmesh: self.pltype='plmesh' - - self.swidth = getit(obj, 40, 0) # default start width - self.ewidth = getit(obj, 41, 0) # default end width - #self.bulge = getit(obj, 42, None) # bulge of the segment - self.vectorsM = getit(obj, 71, None) # PolyMesh: expansion in M-direction / PolyFace: number of the vertices - self.vectorsN = getit(obj, 72, None) # PolyMesh: expansion in M-direction / PolyFace: number of faces - #self.resolM = getit(obj, 73, None) # resolution of surface in M direction - #self.resolN = getit(obj, 74, None) # resolution of surface in N direction - self.curvNoFitted = False - self.curvQuadrati = False - self.curvCubicBsp = False - self.curvBezier = False - curvetype = getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier - if curvetype == 0: self.curvNoFitted = True - elif curvetype == 5: self.curvQuadrati = True - elif curvetype == 6: self.curvCubicBsp = True - elif curvetype == 8: self.curvBezier = True - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - - self.points = [] #list with vertices coordinats - self.faces = [] #list with vertices assigment to faces - #print 'deb:polyline.init.ENDinit:----------------' #------------ - - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - - def doubles_out(self, settings, d_points): - """routine to sort out of double.vertices----------------------------- - """ - minimal_dist = settings.var['dist_min'] * 0.1 - dv_count = 0 - temp_points = [] - for i in xrange(len(d_points)-1): - point = d_points[i] - point2 = d_points[i+1] - #print 'deb:double.vertex p1,p2', point, point2 #------------------------ - delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc) - if delta.length > minimal_dist: - temp_points.append(point) - else: - dv_count+=1 - #print 'deb:drawPoly2d double.vertex sort out! count=', dv_count #------------------------ - temp_points.append(d_points[-1]) #------ incl. last vertex ------------- - #if self.closed: temp_points.append(d_points[1]) #------ loop start vertex ------------- - d_points = temp_points #-----vertex.list without "double.vertices" - #print 'deb:drawPoly2d d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ - return d_points - - - def tribles_out(self, settings, d_points): - """routine to sort out of three_in_place.vertices----------------------------- - """ - minimal_dist = settings.var['dist_min'] * 0.1 - dv_count = 0 - temp_points = [] - for i in xrange(len(d_points)-2): - point1 = d_points[i] - point2 = d_points[i+1] - point3 = d_points[i+2] - #print 'deb:double.vertex p1,p2', point, point2 #------------------------ - delta12 = Mathutils.Vector(point2.loc) - Mathutils.Vector(point1.loc) - delta23 = Mathutils.Vector(point3.loc) - Mathutils.Vector(point2.loc) - if delta12.length < minimal_dist and delta23.length < minimal_dist: - dv_count+=1 - else: - temp_points.append(point1) - #print 'deb:drawPoly2d double.vertex sort out! count=', dv_count #------------------------ - point1 = d_points[-2] - point2 = d_points[-1] - delta12 = Mathutils.Vector(point2.loc) - Mathutils.Vector(point1.loc) - if delta12.length > minimal_dist: - temp_points.append(d_points[-2]) #------ incl. 2last vertex ------------- - temp_points.append(d_points[-1]) #------ incl. 1last vertex ------------- - #if self.closed: temp_points.append(d_points[1]) #------ loop start vertex ------------- - d_points = temp_points #-----vertex.list without "double.vertices" - #print 'deb:drawPoly2d d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ - return d_points - - - def draw(self, settings): #-------------%%%% DRAW POLYLINE %%%--------------- - """for POLYLINE: generate Blender_geometry. - """ - #print 'deb:drawPOLYLINE.START:----------------' #------------------------ - #print 'deb:POLYLINEdraw self.pltype:', self.pltype #------------------------ - #print 'deb:POLYLINEdraw self.points:\n', self.points #------------------------ - ob = [] - #---- 3dPolyFace - mesh with free topology - if self.pltype=='plface' and settings.drawTypes['plmesh']: - ob = self.drawPlFace(settings) - #---- 3dPolyMesh - mesh with ortogonal topology - elif self.pltype=='plmesh' and settings.drawTypes['plmesh']: - ob = self.drawPlMesh(settings) - - #---- 2dPolyline - plane polyline with arc/wide/thic segments - elif self.pltype=='poly2d' and settings.drawTypes['polyline']: - if settings.var['plines_as'] in [5,6]: # and self.spline: - ob = self.drawPolyCurve(settings) - else: - ob = self.drawPoly2d(settings) - - #---- 3dPolyline - non-plane polyline (thin segments = without arc/wide/thic) - elif self.pltype=='poly3d' and settings.drawTypes['pline3']: - if settings.var['plines3_as'] in [5,6]: # and self.spline: - ob = self.drawPolyCurve(settings) - else: - ob = self.drawPoly2d(settings) - - #---- Spline - curved polyline (thin segments = without arc/wide/thic) - elif self.pltype=='spline' and settings.drawTypes['spline']: - if settings.var['splines_as'] in [5,6]: - ob = self.drawPolyCurve(settings) - else: - ob = self.drawPoly2d(settings) - return ob - - - def drawPlFace(self, settings): #---- 3dPolyFace - mesh with free topology - """Generate the geometery of polyface. - """ - #print 'deb:drawPlFace.START:----------------' #------------------------ - points = [] - faces = [] - #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ - for point in self.points: - if point.face: - faces.append(point.face) - else: - points.append(point.loc) - - if settings.var['plmesh_flip']: # ---------------------- - for face in faces: - face.reverse() - face = [face[-1]] + face[:-1] - - #print 'deb:drawPlFace: len of points_list:\n', len(points) #----------------------- - #print 'deb:drawPlFace: len of faces_list:\n', len(faces) #----------------------- - #print 'deb:drawPlFace: points_list:\n', points #----------------------- - #print 'deb:drawPlFace: faces_list:\n', faces #----------------------- - obname = 'pf_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(points) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - if settings.var['normals_out']: # ---------------------- - #me.flipNormals() - me.recalcNormals(0) - #me.update() - #print 'deb:drawPlFace: len of me.faces:\n', len(me.faces) #----------------------- - - if settings.var['meshSmooth_on']: # ---------------------- - for i in xrange(len(me.faces)): - me.faces[i].smooth = True - #me.Mode(AUTOSMOOTH) - transform(self.extrusion, 0, ob) - #print 'deb:drawPlFace.END:----------------' #------------------------ - return ob - - - - def drawPlMesh(self, settings): #---- 3dPolyMesh - mesh with orthogonal topology - """Generate the geometery of polymesh. - """ - #print 'deb:polymesh.draw.START:----------------' #------------------------ - #points = [] - #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ - faces = [] - m = self.vectorsM - n = self.vectorsN - for j in xrange(m - 1): - for i in xrange(n - 1): - nn = j * n - faces.append([nn+i, nn+i+1, nn+n+i+1, nn+n+i]) - - if self.closed: #mesh closed in N-direction - nn = (m-1)*n - for i in xrange(n - 1): - faces.append([nn+i, nn+i+1, i+1, i]) - - if self.closeN: #mesh closed in M-direction - for j in xrange(m-1): - nn = j * n - faces.append([nn+n-1, nn, nn+n, nn+n-1+n]) - - if self.closed and self.closeN: #mesh closed in M/N-direction - faces.append([ (n*m)-1, (m-1)*n, 0, n-1]) - - #print 'deb:len of points_list:\n', len(points) #----------------------- - #print 'deb:faces_list:\n', faces #----------------------- - obname = 'pm_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend([point.loc for point in self.points]) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - if settings.var['normals_out']: # ---------------------- - #me.flipNormals() - me.recalcNormals(0) - #me.update() - if settings.var['meshSmooth_on']: # ---------------------- - for i in xrange(len(faces)): - me.faces[i].smooth = True - #me.Mode(AUTOSMOOTH) - - transform(self.extrusion, 0, ob) - #print 'deb:polymesh.draw.END:----------------' #------------------------ - return ob - - - def drawPolyCurve(self, settings): #---- Polyline - draw as Blender-curve - """Generate the geometery of polyline as Blender-curve. - """ - #print 'deb:polyline2dCurve.draw.START:----------------' #--- - if len(self.points) < 2: - #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- - return - - if self.spline: pline_typ = 'ps' # Polyline-NURBSpline - elif self.curved: pline_typ = 'pc' # Polyline-BezierCurve - else: pline_typ = 'pl' # Polyline classic - obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name - obname = obname[:MAX_NAMELENGTH] - d_points = [] - - if settings.var['Z_force_on']: - self.elevation = settings.var['Z_elev'] - for point in self.points: - point.loc[2] = self.elevation - d_points.append(point) - else: #for DXFr10-format: update all points[].loc[2] == None -> 0.0 - for point in self.points: - if point.loc[2] == None: - point.loc[2] = self.elevation - d_points.append(point) - - #d_points = self.tribles_out(settings, d_points) - #d_points = self.doubles_out(settings, d_points) - #print 'deb:drawPolyCurve d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ - - thic = set_thick(self.thic, settings) - if thic != 0.0: #hack: Blender<2.45 curve-extrusion - LocZ = d_points[0].loc[2] - temp_points = [] - for point in d_points: - point.loc[2] = 0.0 - temp_points.append(point) - d_points = temp_points - - #print 'deb:polyline2dCurve.draw d_points=', d_points #--------------- - pline = Curve.New(obname) # create new curve data - #pline.setResolu(24) #--todo----- - - if self.spline: # NURBSplines-----OK----- - #print 'deb:polyline2dCurve.draw self.spline!' #--------------- - nurbs_points = [] - for d in d_points: - pkt = d.loc - pkt.append(d.weight) - nurbs_points.append(pkt) - firstpoint = nurbs_points[0] - curve = pline.appendNurb(firstpoint) - curve.setType(4) # set curve_type NURBS - print 'deb: dir(curve):', dir(curve[-1]) #---------------- - for point in nurbs_points[1:]: - curve.append(point) - #TODO: what is the trick for bevel radius? curve[-1].radius = 1.0 - if self.closed: - curve.flagU = 1+0 # Set curve cyclic=close and uni - else: - curve.flagU = 0+2 # Set curve not cyclic=open - try: curve.orderU = 5 # works only with >2.46svn080625 - except AttributeError: pass - #print 'deb: dir(curve):', dir(curve) #---------------- - - elif self.curved: #--SPLINE as Bezier-curves---wip------ - #print 'deb:polyline2dCurve.draw self.curved!' #--------------- - begtangent, endtangent = None, None - if d_points[0].tangent: - begtangent = d_points[0] - d_points = d_points[1:] - if d_points[-1].tangent: - endtangent = d_points[-1] - d_points = d_points[:-1] - curve = pline.appendNurb(BezTriple.New(d_points[0])) - for p in d_points[1:]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [AUTO, AUTO] - point.radius = 1.0 - #curve.setType(1) #Bezier curve - if self.closed: - curve.flagU = 5 #1 # Set curve cyclic=close - else: - curve.flagU = 4 #0 # Set curve not cyclic=open - if begtangent: - #print 'deb:polyline2dCurve.draw curve[0].vec:', curve[0].vec #----- - #print 'deb:polyline2dCurve.draw begtangent:', begtangent #----- - p0h1,p0,p0h2 = curve[0].vec - p0h1 = [p0h1[i]+begtangent[i] for i in range(3)] - curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2)) - curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- - curve[0].radius = 1.0 - if endtangent: - #print 'deb:polyline2dCurve.draw curve[-1].vec:', curve[-1].vec #----- - #print 'deb:polyline2dCurve.draw endtangent:', endtangent #----- - p0h1,p0,p0h2 = curve[-1].vec - p0h2 = [p0h2[i]+endtangent[i] for i in range(3)] - #print 'deb:drawPlineCurve: p0h2:', p0h2 #---------- - curve.__setitem__(-1,BezTriple.New(p0h1+p0+p0h2)) - #print 'deb:polyline2dCurve.draw curve[-1].vec:', curve[-1].vec #----- - curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- - curve[-1].radius = 1.0 - - - - else: #-- only straight line- and arc-segments----OK------ - #print 'deb:polyline2dCurve.draw curve:', curve #----- - points = [] - arc_res = settings.var['curve_arc'] - prevHandleType = VECT - #d_points.append(d_points[0]) #------ first vertex added at the end of list -------- - #curve.setType(0) #polygon_type of Blender_curve - for i in xrange(len(d_points)): - point1 = d_points[i] - #point2 = d_points[i+1] - #----- optimised Bezier-Handles calculation -------------------------------- - #print 'deb:drawPlineCurve: i:', i #--------- - if point1.bulge and not (i == len(d_points)-1 and point1.bulge and not self.closed): - if i == len(d_points)-1: point2 = d_points[0] - else: point2 = d_points[i+1] - - - # calculate additional points for bulge - VectorTriples = calcBulge(point1, point2, arc_res, triples=True) - - if prevHandleType == FREE: - #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #--------- - VectorTriples[0][:3] = prevHandleVect - #print 'deb:drawPlineCurve: VectorTriples[0]:', VectorTriples[0] #--------- - - if i == 0: curve = pline.appendNurb(BezTriple.New(VectorTriples[0])) - else: curve.append(BezTriple.New(VectorTriples[0])) - curve[-1].handleTypes = [prevHandleType, FREE] - curve[-1].radius = 1.0 - - for p in VectorTriples[1:-1]: - curve.append(BezTriple.New(p)) - curve[-1].handleTypes = [FREE, FREE] - curve[-1].radius = 1.0 - - prevHandleVect = VectorTriples[-1][:3] - prevHandleType = FREE - #print 'deb:drawPlineCurve: prevHandleVect:', prevHandleVect #--------- - else: - #print 'deb:drawPlineCurve: else' #---------- - if prevHandleType == FREE: - VectorTriples = prevHandleVect + list(point1) + list(point1) - #print 'deb:drawPlineCurve: VectorTriples:', VectorTriples #--------- - curve.append(BezTriple.New(VectorTriples)) - curve[-1].handleTypes = [FREE, VECT] - prevHandleType = VECT - curve[-1].radius = 1.0 - else: - if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) - else: curve.append(BezTriple.New(point1.loc)) - curve[-1].handleTypes = [VECT, VECT] - curve[-1].radius = 1.0 - #print 'deb:drawPlineCurve: curve[-1].vec[0]', curve[-1].vec[0] #---------- - - if self.closed: - curve.flagU = 1 # Set curve cyclic=close - if prevHandleType == FREE: - #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #---------- - #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #---------- - prevHandleType2 = curve[0].handleTypes[1] - p0h1,p0,p0h2 = curve[0].vec - #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #---------- - p0h1 = prevHandleVect - #p0h1 = [0,0,0] - #print 'deb:drawPlineCurve:closed p0h1:', p0h1 #---------- - #curve[0].vec = [p0h1,p0,p0h2] - curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2)) - - curve[0].handleTypes = [FREE,prevHandleType2] - curve[0].radius = 1.0 - #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #---------- - #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #---------- - else: - curve[0].handleTypes[0] = VECT - curve[0].radius = 1.0 - else: - curve.flagU = 0 # Set curve not cyclic=open - - if settings.var['fill_on']: - pline.setFlag(6) # 2+4 set top and button caps - else: - pline.setFlag(pline.getFlag() & ~6) # dont set top and button caps - - pline.setResolu(settings.var['curve_res']) - pline.update() - ob = SCENE.objects.new(pline) # create a new curve_object - - if thic != 0.0: #hack: Blender<2.45 curve-extrusion - thic = thic * 0.5 - pline.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) - ob.LocZ = thic + LocZ - - transform(self.extrusion, 0, ob) - if thic != 0.0: - ob.SizeZ *= abs(thic) - - #print 'deb:polyline2dCurve.draw.END:----------------' #----- - return ob - - - def drawPoly2d(self, settings): #---- 2dPolyline - plane lines/arcs with wide/thic - """Generate the geometery of regular polyline. - """ - #print 'deb:polyline2d.draw.START:----------------' #------------------------ - points = [] - d_points = [] - swidths = [] - ewidths = [] - swidth_default = self.swidth #default start width of POLYLINEs segments - ewidth_default = self.ewidth #default end width of POLYLINEs segments - #print 'deb:drawPoly2d self.swidth=', self.swidth #------------------------ - thic = set_thick(self.thic, settings) - if self.spline: pline_typ = 'ps' - elif self.curved: pline_typ = 'pc' - else: pline_typ = 'pl' - obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name - obname = obname[:MAX_NAMELENGTH] - - if len(self.points) < 2: - #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- - return - - if settings.var['Z_force_on']: - self.elevation = settings.var['Z_elev'] - for point in self.points: - point.loc[2] = self.elevation - d_points.append(point) - else: #for DXFr10-format: update all non-existing LocZ points[].loc[2] == None -> 0.0 elevation - for point in self.points: - if point.loc[2] == None: - point.loc[2] = self.elevation - d_points.append(point) - #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ - #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------ - - - #if closed polyline, add duplic of the first vertex at the end of pointslist - if self.closed: #new_b8 - if d_points[-1].loc != d_points[0].loc: # if not equal, then set the first at the end of pointslist - d_points.append(d_points[0]) - else: - if d_points[-1].loc == d_points[0].loc: # if equal, then set to closed, and modify the last point - d_points[-1] = d_points[0] - self.closed = True - #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ - #print 'deb:drawPoly2d d_pointsList ======:\n ', d_points #------------------------ - - d_points = self.doubles_out(settings, d_points) - #print 'deb:drawPolyCurve d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ - - #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ - if len(d_points) < 2: #if too few vertex, then return - #print 'deb:drawPoly2d corrupted Vertices' #--------- - return - - # analyze of straight- and bulge-segments - # generation of additional points for bulge segments - arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) - wide_segment_exist = False - bulg_points = [] # for each point set None (or center for arc-subPoints) - for i in xrange(len(d_points)-1): - point1 = d_points[i] - point2 = d_points[i+1] - #print 'deb:drawPoly2d_bulg tocalc.point1:', point1 #------------------------ - #print 'deb:drawPoly2d_bulg tocalc.point2:', point2 #------------------------ - - swidth = point1.swidth - ewidth = point1.ewidth - #print 'deb:drawPoly2d point1.swidth=', swidth #------------------------ - if swidth == None: swidth = swidth_default - if ewidth == None: ewidth = ewidth_default - if swidth != 0.0 or ewidth != 0.0: wide_segment_exist = True - #print 'deb:drawPoly2d vertex_swidth=', swidth #------------------------ - - if settings.var['width_force']: # force minimal width for thin segments - width_min = settings.var['width_min'] - if swidth < width_min: swidth = width_min - if ewidth < width_min: ewidth = width_min - if not settings.var['width_on']: # then force minimal width for all segments - swidth = width_min - ewidth = width_min - - #if point1.bulge and (i < (len(d_points)-1) or self.closed): - if point1.bulge and i < (len(d_points)-1): #10_b8 - verts, center = calcBulge(point1, point2, arc_res) #calculate additional points for bulge - points.extend(verts) - delta_width = (ewidth - swidth) / len(verts) - width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)] - swidths.extend(width_list[:-1]) - ewidths.extend(width_list[1:]) - bulg_list = [center for ii in xrange(len(verts))] - #the last point in bulge has index False for better indexing of bulg_end! - bulg_list[-1] = None - bulg_points.extend(bulg_list) - - else: - points.append(point1.loc) - swidths.append(swidth) - ewidths.append(ewidth) - bulg_points.append(None) - points.append(d_points[-1].loc) - - - #--calculate width_vectors: left-side- and right-side-points ---------------- - # 1.level:IF width --------------------------------------- - if (settings.var['width_on'] and wide_segment_exist) or settings.var['width_force']: - #new_b8 points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop) - dist_min05 = 0.5 * settings.var['dist_min'] #minimal width for zero_witdh - - pointsLs = [] # list of left-start-points - pointsLe = [] # list of left-end-points - pointsRs = [] # list of right-start-points - pointsRe = [] # list of right-end-points - pointsW = [] # list of all border-points - #rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY - rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) - bulg_in = False - last_bulg_point = False - for i in xrange(len(points)-1): - point1 = points[i] - point2 = points[i+1] - point1vec = Mathutils.Vector(point1) - point2vec = Mathutils.Vector(point2) - swidth05 = swidths[i] * 0.5 - ewidth05 = ewidths[i] * 0.5 - if swidth05 == 0: swidth05 = dist_min05 - if ewidth05 == 0: ewidth05 = dist_min05 - normal_vector = rotMatr90 * (point2vec-point1vec).normalize() - if last_bulg_point: - last_bulg_point = False - bulg_in = True - elif bulg_points[i] != None: - centerVec = Mathutils.Vector(bulg_points[i]) - if bulg_points[i+1] == None: last_bulg_point = True - bulg_in = True - else: bulg_in = False - - if bulg_in: - #makes clean intersections for arc-segments - radius1vec = point1vec - centerVec - radius2vec = point2vec - centerVec - angle = Mathutils.AngleBetweenVecs(normal_vector, radius1vec) - if angle < 90.0: - normal_vector1 = radius1vec.normalize() - normal_vector2 = radius2vec.normalize() - else: - normal_vector1 = - radius1vec.normalize() - normal_vector2 = - radius2vec.normalize() - - swidth05vec = swidth05 * normal_vector1 - ewidth05vec = ewidth05 * normal_vector2 - pointsLs.append(point1vec + swidth05vec) #vertex left start - pointsRs.append(point1vec - swidth05vec) #vertex right start - pointsLe.append(point2vec + ewidth05vec) #vertex left end - pointsRe.append(point2vec - ewidth05vec) #vertex right end - - else: - swidth05vec = swidth05 * normal_vector - ewidth05vec = ewidth05 * normal_vector - pointsLs.append(point1vec + swidth05vec) #vertex left start - pointsRs.append(point1vec - swidth05vec) #vertex right start - pointsLe.append(point2vec + ewidth05vec) #vertex left end - pointsRe.append(point2vec - ewidth05vec) #vertex right end - - # additional last point is also calculated - #pointsLs.append(pointsLs[0]) - #pointsRs.append(pointsRs[0]) - #pointsLe.append(pointsLe[0]) - #pointsRe.append(pointsRe[0]) - - pointsLc, pointsRc = [], [] # lists Left/Right corners = intersection points - - # 2.level:IF width and corner-trim - if settings.var['pl_trim_on']: #optional clean corner-intersections - # loop preset - # set STARTpoints of the first point points[0] - if not self.closed: - pointsLc.append(pointsLs[0]) - pointsRc.append(pointsRs[0]) - else: - pointsLs.append(pointsLs[0]) - pointsRs.append(pointsRs[0]) - pointsLe.append(pointsLe[0]) - pointsRe.append(pointsRe[0]) - points.append(points[0]) - vecL3, vecL4 = pointsLs[0], pointsLe[0] - vecR3, vecR4 = pointsRs[0], pointsRe[0] - lenL = len(pointsLs)-1 - #print 'deb:drawPoly2d pointsLs():\n', pointsLs #---------------- - #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- - bulg_in = False - last_bulg_point = False - - # LOOP: makes (ENDpoints[i],STARTpoints[i+1]) - for i in xrange(lenL): - if bulg_points[i] != None: - if bulg_points[i+1] == None: #makes clean intersections for arc-segments - last_bulg_point = True - if not bulg_in: - bulg_in = True - #pointsLc.extend((points[i], pointsLs[i])) - #pointsRc.extend((points[i], pointsRs[i])) - vecL1, vecL2 = vecL3, vecL4 - vecR1, vecR2 = vecR3, vecR4 - vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1] - vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1] - #compute left- and right-cornerpoints - #cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) - cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) - cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) - #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #------------- - #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #------------- - - # IF not cornerpoint THEN check if identic start-endpoints (=collinear segments) - if cornerpointL == None or cornerpointR == None: - if vecL2 == vecL3 and vecR2 == vecR3: - #print 'deb:drawPoly2d pointVec: ####### identic ##########' #---------------- - pointsLc.append(pointsLe[i]) - pointsRc.append(pointsRe[i]) - else: - pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) - pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) - else: - cornerpointL = cornerpointL[0] # because Mathutils.LineIntersect() -> (pkt1,pkt2) - cornerpointR = cornerpointR[0] - #print 'deb:drawPoly2d cornerpointL: ', cornerpointL #------------- - #print 'deb:drawPoly2d cornerpointR: ', cornerpointR #------------- - pointVec0 = Mathutils.Vector(points[i]) - pointVec = Mathutils.Vector(points[i+1]) - pointVec2 = Mathutils.Vector(points[i+2]) - #print 'deb:drawPoly2d pointVec0: ', pointVec0 #------------- - #print 'deb:drawPoly2d pointVec: ', pointVec #------------- - #print 'deb:drawPoly2d pointVec2: ', pointVec2 #------------- - # if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth) - max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length - is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length - #corner_angle = Mathutils.AngleBetweenVecs((pointVec0 - pointVec),(pointVec - pointVec2)) - #print 'deb:drawPoly2d corner_angle: ', corner_angle #------------- - #print 'deb:drawPoly2d max_cornerDist, is_cornerDist: ', max_cornerDist, is_cornerDist #------------- - #if abs(corner_angle) < 90.0: - # intersection --------- limited by TRIM_LIMIT (1.0 - 5.0) - if is_cornerDist < max_cornerDist * settings.var['pl_trim_max']: - # clean corner intersection - pointsLc.append(cornerpointL) - pointsRc.append(cornerpointR) - else: - pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) - pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) - if not self.closed: - pointsLc.append(pointsLe[-1]) - pointsRc.append(pointsRe[-1]) - - # 2.level:IF width but no-trim - else: - # loop preset - # set STARTpoints of the first point points[0] - if not self.closed: - pointsLc.append(pointsLs[0]) - pointsRc.append(pointsRs[0]) - else: - pointsLs.append(pointsLs[0]) - pointsRs.append(pointsRs[0]) - pointsLe.append(pointsLe[0]) - pointsRe.append(pointsRe[0]) - points.append(points[0]) - vecL3, vecL4 = pointsLs[0], pointsLe[0] - vecR3, vecR4 = pointsRs[0], pointsRe[0] - lenL = len(pointsLs)-1 - #print 'deb:drawPoly2d pointsLs():\n', pointsLs #---------------- - #print 'deb:drawPoly2d lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- - bulg_in = False - last_bulg_point = False - - # LOOP: makes (ENDpoints[i],STARTpoints[i+1]) - for i in xrange(lenL): - vecL1, vecL2 = vecL3, vecL4 - vecR1, vecR2 = vecR3, vecR4 - vecL3, vecL4 = pointsLs[i+1], pointsLe[i+1] - vecR3, vecR4 = pointsRs[i+1], pointsRe[i+1] - if bulg_points[i] != None: - #compute left- and right-cornerpoints - cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) - cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) - pointsLc.append(cornerpointL[0]) - pointsRc.append(cornerpointR[0]) - else: # IF non-bulg - pointsLc.extend((pointsLe[i],points[i+1],pointsLs[i+1])) - pointsRc.extend((pointsRe[i],points[i+1],pointsRs[i+1])) - if not self.closed: - pointsLc.append(pointsLe[-1]) - pointsRc.append(pointsRe[-1]) - - len1 = len(pointsLc) - #print 'deb:drawPoly2d len1:', len1 #----------------------- - #print 'deb:drawPoly2d len1 len(pointsLc),len(pointsRc):', len(pointsLc),len(pointsRc) #----------------------- - pointsW = pointsLc + pointsRc # all_points_List = left_side + right_side - #print 'deb:drawPoly2d pointsW():\n', pointsW #---------------- - - # 2.level:IF width and thickness --------------------- - if thic != 0: - thic_pointsW = [] - thic_pointsW.extend([[point[0], point[1], point[2]+thic] for point in pointsW]) - if thic < 0.0: - thic_pointsW.extend(pointsW) - pointsW = thic_pointsW - else: - pointsW.extend(thic_pointsW) - faces = [] - f_start, f_end = [], [] - f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] - f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] - f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] - f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] - - if self.closed: - f_bottom.append([len1-1, 0, len1, len1+len1-1]) #bottom face - f_top.append( [len1+len1+len1-1, len1+len1+len1+len1-1, len1+len1+len1, len1+len1+0]) #top face - f_left.append( [0, len1-1, len1+len1+len1-1, len1+len1]) #left face - f_right.append( [len1, len1+len1+len1, len1+len1+len1+len1-1, len1+len1-1]) #right face - else: - f_start = [[0, len1, len1+len1+len1, len1+len1]] - f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] - - faces = f_left + f_right + f_bottom + f_top + f_start + f_end - #faces = f_bottom + f_top - #faces = f_left + f_right + f_start + f_end - #print 'deb:faces_list:\n', faces #----------------------- - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(pointsW) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - # The mesh must first be linked to an object so the method knows which object to update. - # This is because vertex groups in Blender are stored in the object -- not in the mesh, - # which may be linked to more than one object. - if settings.var['vGroup_on'] and not M_OBJ: - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - replace = Mesh.AssignModes.REPLACE #or .AssignModes.ADD - vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] - for v in f_left: vg_left.extend(v) - for v in f_right: vg_right.extend(v) - for v in f_top: vg_top.extend(v) - for v in f_bottom: vg_bottom.extend(v) - me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) - me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) - me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) - me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) - if not self.closed: - me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) - me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) - - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - #if self.spline or self.curved: - smooth_len = len(f_left) + len(f_right) - for i in xrange(smooth_len): - me.faces[i].smooth = True - #me.Modes(AUTOSMOOTH) - - # 2.level:IF width, but no-thickness --------------------- - else: - faces = [] - faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] - if self.closed: - faces.append([len1, 0, len1-1, len1+len1-1]) - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(pointsW) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - - # 1.level:IF no-width, but thickness --------------------- - elif thic != 0: - len1 = len(points) - thic_points = [] - thic_points.extend([[point[0], point[1], point[2]+thic] for point in points]) - if thic < 0.0: - thic_points.extend(points) - points = thic_points - else: - points.extend(thic_points) - faces = [] - faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - if self.closed: - faces.append([len1-1, 0, len1, 2*len1-1]) - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(points) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - #if self.spline or self.curved: - for i in xrange(len(faces)): - me.faces[i].smooth = True - #me.Modes(AUTOSMOOTH) - - # 1.level:IF no-width and no-thickness --------------------- - else: - edges = [[num, num+1] for num in xrange(len(points)-1)] - if self.closed: - edges.append([len(points)-1, 0]) - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - me.verts.extend(points) # add vertices to mesh - me.edges.extend(edges) # add edges to the mesh - - transform(self.extrusion, 0, ob) - #print 'deb:polyline.draw.END:----------------' #----------------------- - return ob - - - - -class Vertex(object): #----------------------------------------------------------------- - """Generic vertex object used by POLYLINEs, (and maybe others). - also used by class_LWPOLYLINEs but without obj-parameter - """ - - def __init__(self, obj=None): - """Initializes vertex data. - - The optional obj arg is an entity object of type vertex. - """ - #print 'deb:Vertex.init.START:----------------' #----------------------- - self.loc = [0,0,0] - self.face = [] - self.swidth = None #0 - self.ewidth = None #0 - self.bulge = 0 - self.tangent = False - self.weight = 1.0 - if obj is not None: - if not obj.type == 'vertex': - raise TypeError, "Wrong type %s for vertex object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - self.get_props(obj) - else: - pass - #print 'deb:Vertex.init.END:----------------' #------------------------ - - - def get_props(self, data): - """Gets coords for a VERTEX type object. - - Each vert can have a number of properties. - Verts should be coded as - 10:xvalue - 20:yvalue - 40:startwidth or 0 - 41:endwidth or 0 - 42:bulge or 0 - """ - self.x = getit(data, 10, None) - self.y = getit(data, 20, None) - self.z = getit(data, 30, None) - - self.flags = getit(data, 70, 0) # flags - self.curved = self.flags&1 # Bezier-curve-fit:additional-vertex - self.curved_t = self.flags&2 # Bezier-curve-fit:tangent exists - self.spline = self.flags&8 # NURBSpline-fit:additional-vertex - self.spline_c = self.flags&16 # NURBSpline-fit:control-vertex - self.poly3d = self.flags&32 # polyline3d:control-vertex - self.plmesh = self.flags&64 # polymesh3d:control-vertex - self.plface = self.flags&128 # polyface - - # if PolyFace.Vertex with Face_definition - if self.curved_t: - self.curve_tangent = getit(data, 50, None) # curve_tangent - if not self.curve_tangent==None: - self.tangent = True - #elif self.spline_c: # NURBSpline:control-vertex - # self.weight = getit(data, 41, 1.0) # weight od control point - - elif self.plface and not self.plmesh: - v1 = getit(data, 71, 0) # polyface:Face.vertex 1. - v2 = getit(data, 72, 0) # polyface:Face.vertex 2. - v3 = getit(data, 73, 0) # polyface:Face.vertex 3. - v4 = getit(data, 74, None) # polyface:Face.vertex 4. - self.face = [abs(v1)-1,abs(v2)-1,abs(v3)-1] - if v4 != None: - if abs(v4) != abs(v1): - self.face.append(abs(v4)-1) - else: #--parameter for polyline2d - self.swidth = getit(data, 40, None) # start width - self.ewidth = getit(data, 41, None) # end width - self.bulge = getit(data, 42, 0) # bulge of segment - - - def __len__(self): - return 3 - - - def __getitem__(self, key): - return self.loc[key] - - - def __setitem__(self, key, value): - if key in [0,1,2]: - self.loc[key] - - - def __iter__(self): - return self.loc.__iter__() - - - def __str__(self): - return str(self.loc) - - - def __repr__(self): - return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s, face=%s" %(self.loc, self.swidth, self.ewidth, self.bulge, self.face) - - - def getx(self): - return self.loc[0] - def setx(self, value): - self.loc[0] = value - x = property(getx, setx) - - - def gety(self): - return self.loc[1] - def sety(self, value): - self.loc[1] = value - y = property(gety, sety) - - - def getz(self): - return self.loc[2] - def setz(self, value): - self.loc[2] = value - z = property(getz, setz) - - - -class Spline(Polyline): #----------------------------------------------------------------- - """Class for objects representing dxf SPLINEs. - """ - """Expects an entity object of type spline as input. -100 - Subclass marker (AcDbSpline) -210,220, 230 - Normal vector (omitted if the spline is nonplanar) X,Y,Z values of normal vector -70 - Spline flag (bit coded): - 1 = Closed spline - 2 = Periodic spline - 4 = Rational spline - 8 = Planar - 16 = Linear (planar bit is also set) -71 - Degree of the spline curve -72 - Number of knots -73 - Number of control points -74 - Number of fit points (if any) -42 - Knot tolerance (default = 0.0000001) -43 - Control-point tolerance (default = 0.0000001) -44 - Fit tolerance (default = 0.0000000001) -12,22,32 - Start tangent--may be omitted (in WCS). X,Y,Z values of start tangent--may be omitted (in WCS). -13,23, 33 - End tangent--may be omitted (in WCS). X,Y,Z values of end tangent--may be omitted (in WCS) -40 - Knot value (one entry per knot) -41 - Weight (if not 1); with multiple group pairs, are present if all are not 1 -10,20, 30 - Control points (in WCS) one entry per control point. -DXF: X value; APP: 3D point, Y and Z values of control points (in WCS) (one entry per control point) -11,21, 31 - Fit points (in WCS) one entry per fit point. - X,Y,Z values of fit points (in WCS) (one entry per fit point) - """ - def __init__(self, obj): - #print 'deb:Spline.START:----------------' #------------------------ - if not obj.type == 'spline': - raise TypeError, "Wrong type %s for spline object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.num_points = obj.get_type(73)[0] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - - self.color_index = getit(obj, 62, BYLAYER) - - #self.elevation = getit(obj, 30, 0) - self.thic = 0 # getit(obj, 39, 0) - - width = 0 - self.swidth = width # default start width - self.ewidth = width # default end width - - self.flags = getit(obj, 70, 0) - self.closed = self.flags & 1 # closed spline - self.period = self.flags & 2 # Periodic spline - self.ration = self.flags & 4 # Rational spline - self.planar = self.flags & 8 # Planar - self.linear = self.flags & 16 # Linear (and Planar) - - self.curvNoFitted = False - self.curvQuadrati = False - self.curvCubicBsp = False - self.curvBezier = False - self.degree = getit(obj, 71, 0) # Degree of the spline curve - if self.degree == 0: self.curvNoFitted = True - elif self.degree == 1: self.curvQuadrati = True - elif self.degree == 2: self.curvCubicBsp = True - #elif self.degree == 3: self.curvBezier = True - #elif self.degree == 3: self.spline = True - - self.knotpk_len = getit(obj, 72, 0) # Number of knots - self.ctrlpk_len = getit(obj, 73, 0) # Number of control points - self.fit_pk_len = getit(obj, 74, 0) # Number of fit points (if any) - - #TODO: import SPLINE as Bezier curve directly, possible? - #print 'deb:Spline self.fit_pk_len=', self.fit_pk_len #------------------------ - #self.fit_pk_len = 0 # temp for debug - if self.fit_pk_len and settings.var['splines_as']==5: - self.spline = False - self.curved = True - else: - self.spline = True - self.curved = False - - self.knotpk_tol = getit(obj, 42, 0.0000001) # Knot tolerance (default = 0.0000001) - self.ctrlpk_tol = getit(obj, 43, 0.0000001) # Control-point tolerance (default = 0.0000001) - self.fit_pk_tol = getit(obj, 44, 0.0000000001) # Fit tolerance (default = 0.0000000001) - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - - self.pltype = 'spline' # spline is a 2D- or 3D-polyline - - self.points = self.get_points(obj.data) - #self.knots_val = self.get_knots_val(obj.data) # 40 - Knot value (one entry per knot) - #self.knots_wgh = self.get_knots_wgh(obj.data) # 41 - Weight (default 1) - - #print 'deb:Spline obj.data:\n', obj.data #------------------------ - #print 'deb:Spline self.points:\n', self.points #------------------------ - #print 'deb:Spline.ENDinit:----------------' #------------------------ - - - def get_points(self, data): - """Gets points for a spline type object. - - Splines have fixed number of verts, and - each vert can have a number of properties. - Verts should be coded as - 10:xvalue - 20:yvalue - for each vert - """ - point = None - points = [] - pointend = None - #point = Vertex() - if self.spline: # NURBSpline definition - for item in data: - #print 'deb:Spline.get_points spilne_item:', item #------------------------ - if item[0] == 10: # control point - if point: points.append(point) - point = Vertex() - point.curved = True - point.x = item[1] - elif item[0] == 20: # 20 = y - point.y = item[1] - elif item[0] == 30: # 30 = z - point.z = item[1] - elif item[0] == 41: # 41 = weight - point.weight = item[1] - #print 'deb:Spline.get_points control point:', point #------------------------ - - elif self.curved: # Bezier definition - for item in data: - #print 'deb:Spline.get_points curved_item:', item #------------------------ - if item[0] == 11: # fit point - if point: points.append(point) - point = Vertex() - point.tangent = False - point.x = item[1] - elif item[0] == 21: # 20 = y - point.y = item[1] - elif item[0] == 31: # 30 = z - point.z = item[1] - #print 'deb:Spline.get_points fit point:', point #------------------------ - - elif item[0] == 12: # start tangent - if point: points.append(point) - point = Vertex() - point.tangent = True - point.x = item[1] - elif item[0] == 22: # = y - point.y = item[1] - elif item[0] == 32: # = z - point.z = item[1] - #print 'deb:Spline.get_points fit begtangent:', point #------------------------ - - elif item[0] == 13: # end tangent - if point: points.append(point) - pointend = Vertex() - pointend.tangent = True - pointend.x = item[1] - elif item[0] == 23: # 20 = y - pointend.y = item[1] - elif item[0] == 33: # 30 = z - pointend.z = item[1] - #print 'deb:Spline.get_points fit endtangent:', pointend #------------------------ - points.append(point) - if self.curved and pointend: - points.append(pointend) - #print 'deb:Spline points:\n', points #------------------------ - return points - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class LWpolyline(Polyline): #------------------------------------------------------------- - """Class for objects representing dxf LWPOLYLINEs. - """ - def __init__(self, obj): - """Expects an entity object of type lwpolyline as input. - """ - #print 'deb:LWpolyline.START:----------------' #------------------------ - if not obj.type == 'lwpolyline': - raise TypeError, "Wrong type %s for polyline object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.num_points = obj.get_type(90)[0] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.elevation = getit(obj, 38, 0) - self.thic = getit(obj, 39, 0) - self.color_index = getit(obj, 62, BYLAYER) - width = getit(obj, 43, 0) - self.swidth = width # default start width - self.ewidth = width # default end width - #print 'deb:LWpolyline width=', width #------------------------ - #print 'deb:LWpolyline elevation=', self.elevation #------------------------ - - self.flags = getit(obj, 70, 0) - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - - self.layer = getit(obj, 8, None) - self.extrusion = get_extrusion(obj) - - self.points = self.get_points(obj.data) - - self.pltype = 'poly2d' # LW-polyline is a 2D-polyline - self.spline = False - self.curved = False - - #print 'deb:LWpolyline.obj.data:\n', obj.data #------------------------ - #print 'deb:LWpolyline.ENDinit:----------------' #------------------------ - - - def get_points(self, data): - """Gets points for a polyline type object. - - LW-Polylines have no fixed number of verts, and - each vert can have a number of properties. - Verts should be coded as - 10:xvalue - 20:yvalue - 40:startwidth or 0 - 41:endwidth or 0 - 42:bulge or 0 - for each vert - """ - num = self.num_points - point = None - points = [] - for item in data: - if item[0] == 10: # 10 = x - if point: - points.append(point) - point = Vertex() - point.x = item[1] - point.z = self.elevation - elif item[0] == 20: # 20 = y - point.y = item[1] - elif item[0] == 40: # 40 = start width - point.swidth = item[1] - elif item[0] == 41: # 41 = end width - point.ewidth = item[1] - elif item[0] == 42: # 42 = bulge - point.bulge = item[1] - points.append(point) - return points - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - -class Text: #----------------------------------------------------------------- - """Class for objects representing dxf TEXT. - """ - def __init__(self, obj): - """Expects an entity object of type text as input. - """ - if not obj.type == 'text': - raise TypeError, "Wrong type %s for text object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.height = 1.7 * obj.get_type(40)[0] #text.height - self.value = obj.get_type(1)[0] #The text string value - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.color_index = getit(obj, 62, BYLAYER) - self.thic = getit(obj, 39, 0) - - self.rotation = getit(obj, 50, 0) # radians - self.width_factor = getit(obj, 41, 1) # Scaling factor along local x axis - self.oblique = getit(obj, 51, 0) # oblique angle: skew in degrees -90 <= oblique <= 90 - - #self.style = getit(obj, 7, 'STANDARD') # --todo---- Text style name (optional, default = STANDARD) - - #Text generation flags (optional, default = 0): - #2 = backward (mirrored in X), - #4 = upside down (mirrored in Y) - self.flags = getit(obj, 71, 0) - self.mirrorX, self.mirrorY = 1.0, 1.0 - if self.flags&2: self.mirrorX = - 1.0 - if self.flags&4: self.mirrorY = - 1.0 - - # vertical.alignment: 0=baseline, 1=bottom, 2=middle, 3=top - self.valignment = getit(obj, 73, 0) - #Horizontal text justification type (optional, default = 0) integer codes (not bit-coded) - #0=left, 1=center, 2=right - #3=aligned, 4=middle, 5=fit - self.halignment = getit(obj, 72, 0) - - self.layer = getit(obj, 8, None) - self.loc1, self.loc2 = self.get_loc(obj) - if self.loc2[0] != None and self.halignment != 5: - self.loc = self.loc2 - else: - self.loc = self.loc1 - self.extrusion = get_extrusion(obj) - - - def get_loc(self, data): - """Gets adjusted location for text type objects. - - If group 72 and/or 73 values are nonzero then the first alignment point values - are ignored and AutoCAD calculates new values based on the second alignment - point and the length and height of the text string itself (after applying the - text style). If the 72 and 73 values are zero or missing, then the second - alignment point is meaningless. - I don't know how to calc text size... - """ - # bottom left x, y, z and justification x, y, z = 0 - #x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 - x = getit(data, 10, None) #First alignment point (in OCS). - y = getit(data, 20, None) - z = getit(data, 30, 0.0) - jx = getit(data, 11, None) #Second alignment point (in OCS). - jy = getit(data, 21, None) - jz = getit(data, 31, 0.0) - return [x, y, z],[jx, jy, jz] - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - def draw(self, settings): - """for TEXTs: generate Blender_geometry. - """ - obname = 'tx_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - txt = Text3d.New(obname) - ob = SCENE.objects.new(txt) # create a new text_object - - txt.setText(self.value) - txt.setSize(1.0) #Blender<2.45 accepts only (0.0 - 5.0) - #txt.setSize(self.height) - #txt.setWidth(self.bold) - #setLineSeparation(sep) - txt.setShear(self.oblique/90) - - thic = set_thick(self.thic, settings) - if thic != 0.0: - thic = self.thic * 0.5 - self.loc[2] += thic - txt.setExtrudeDepth(1.0) #Blender<2.45 accepts only (0.1 - 10.0) - if self.halignment == 0: - align = Text3d.LEFT - elif self.halignment == 1: - align = Text3d.MIDDLE - elif self.halignment == 2: - align = Text3d.RIGHT - else: - align = Text3d.LEFT - txt.setAlignment(align) - - if self.valignment == 1: - txt.setYoffset(0.0) - elif self.valignment == 2: - txt.setYoffset(- self.height * 0.5) - elif self.valignment == 3: - txt.setYoffset(- self.height) - - # move the object center to the text location - ob.loc = tuple(self.loc) - transform(self.extrusion, self.rotation, ob) - - # flip it and scale it to the text width - ob.SizeX *= self.height * self.width_factor * self.mirrorX - ob.SizeY *= self.height * self.mirrorY - if thic != 0.0: ob.SizeZ *= abs(thic) - return ob - - - -def set_thick(thickness, settings): - """Set thickness relative to settings variables. - - Set thickness relative to settings variables: - 'thick_on','thick_force','thick_min'. - Accepted also minus values of thickness - python trick: sign(x)=cmp(x,0) - """ - if settings.var['thick_force']: - if settings.var['thick_on']: - if abs(thickness) < settings.var['thick_min']: - thic = settings.var['thick_min'] * cmp(thickness,0) - else: thic = thickness - else: thic = settings.var['thick_min'] - else: - if settings.var['thick_on']: thic = thickness - else: thic = 0.0 - return thic - - - - -class Mtext: #----------------------------------------------------------------- - """Class for objects representing dxf MTEXT. - """ - - def __init__(self, obj): - """Expects an entity object of type mtext as input. - """ - if not obj.type == 'mtext': - raise TypeError, "Wrong type %s for mtext object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.height = obj.get_type(40)[0] - self.width = obj.get_type(41)[0] - self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR - self.value = self.get_text(obj) # The text string value - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.color_index = getit(obj, 62, BYLAYER) - self.rotation = getit(obj, 50, 0) # radians - - self.width_factor = getit(obj, 42, 1) # Scaling factor along local x axis - self.line_space = getit(obj, 44, 1) # percentage of default - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - self.extrusion = get_extrusion(obj) - - - def get_text(self, data): - """Reconstructs mtext data from dxf codes. - """ - primary = '' - secondary = [] - for item in data: - if item[0] == 1: # There should be only one primary... - primary = item[1] - elif item[0] == 3: # There may be any number of extra strings (in order) - secondary.append(item[1]) - if not primary: - #raise ValueError, "Empty Mtext Object!" - string = "Empty Mtext Object!" - if not secondary: - string = primary.replace(r'\P', '\n') - else: - string = ''.join(secondary)+primary - string = string.replace(r'\P', '\n') - return string - - - def get_loc(self, data): - """Gets location for a mtext type objects. - - Mtext objects have only one point indicating - """ - loc = [0, 0, 0] - loc[0] = getit(data, 10, None) - loc[1] = getit(data, 20, None) - loc[2] = getit(data, 30, 0.0) - return loc - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - def draw(self, settings): - """for MTEXTs: generate Blender_geometry. - """ - # Now Create an object - obname = 'tm_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - txt = Text3d.New(obname) - ob = SCENE.objects.new(txt) # create a new text_object - - txt.setSize(1) - # Blender doesn't give access to its text object width currently - # only to the text3d's curve width... - #txt.setWidth(text.width/10) - txt.setLineSeparation(self.line_space) - txt.setExtrudeDepth(0.5) - txt.setText(self.value) - - # scale it to the text size - ob.SizeX = self.height * self.width_factor - ob.SizeY = self.height - ob.SizeZ = self.height - - # move the object center to the text location - ob.loc = tuple(self.loc) - transform(self.extrusion, self.rotation, ob) - - return ob - - -class Circle: #----------------------------------------------------------------- - """Class for objects representing dxf CIRCLEs. - """ - - def __init__(self, obj): - """Expects an entity object of type circle as input. - """ - if not obj.type == 'circle': - raise TypeError, "Wrong type %s for circle object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.radius = obj.get_type(40)[0] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - self.extrusion = get_extrusion(obj) - - - - def get_loc(self, data): - """Gets the center location for circle type objects. - - Circles have a single coord location. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 10, None) - loc[1] = getit(data, 20, None) - loc[2] = getit(data, 30, 0.0) - return loc - - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - def draw(self, settings): - """for CIRCLE: generate Blender_geometry. - """ - obname = 'ci_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - radius = self.radius - - thic = set_thick(self.thic, settings) - width = 0.0 - if settings.var['lines_as'] == 4: # as thin_box - thic = settings.var['thick_min'] - width = settings.var['width_min'] - if settings.var['lines_as'] == 3: # as thin cylinder - cyl_rad = 0.5 * settings.var['width_min'] - - if settings.var['lines_as'] == 5: # draw CIRCLE as curve ------------- - arc_res = settings.var['curve_arc'] - #arc_res = 3 - start, end = 0.0, 360.0 - VectorTriples = calcArc(None, radius, start, end, arc_res, True) - c = Curve.New(obname) # create new curve data - curve = c.appendNurb(BezTriple.New(VectorTriples[0])) - for p in VectorTriples[1:-1]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [FREE, FREE] - point.radius = 1.0 - curve.flagU = 1 # 1 sets the curve cyclic=closed - if settings.var['fill_on']: - c.setFlag(6) # 2+4 set top and button caps - else: - c.setFlag(c.getFlag() & ~6) # dont set top and button caps - - c.setResolu(settings.var['curve_res']) - c.update() - - #--todo-----to check--------------------------- - ob = SCENE.objects.new(c) # create a new curve_object - ob.loc = tuple(self.loc) - if thic != 0.0: #hack: Blender<2.45 curve-extrusion - thic = thic * 0.5 - c.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) - ob.LocZ = thic + self.loc[2] - transform(self.extrusion, 0, ob) - if thic != 0.0: - ob.SizeZ *= abs(thic) - return ob - - else: # draw CIRCLE as mesh ----------------------------------------------- - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - # set a number of segments in entire circle - arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) - start, end = 0.0 , 360.0 - verts = calcArc(None, radius, start, end, arc_res, False) - verts = verts[:-1] #list without last point/edge (cause by circle it is equal to the first point) - #print 'deb:circleDraw: verts:', verts #--------------- - - if thic != 0: - len1 = len(verts) - thic_verts = [] - thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) - if thic < 0.0: - thic_verts.extend(verts) - verts = thic_verts - else: - verts.extend(thic_verts) - faces = [] - f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - #f_band = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1)] - f_band.append([len1 - 1, 0, len1, len1 + len1 -1]) - faces = f_band - smooth_len = len(f_band) - if settings.var['fill_on']: - if thic < 0.0: - verts.append([0,0,thic]) #center of top side - verts.append([0,0,0]) #center of bottom side - else: - verts.append([0,0,0]) #center of bottom side - verts.append([0,0,thic]) #center of top side - center1 = len(verts)-2 - center2 = len(verts)-1 - f_bottom = [[num+1, num, center1] for num in xrange(len1 - 1)] - f_bottom.append([0, len1 - 1, center1]) - f_top = [[num+len1, num+1+len1, center2] for num in xrange(len1 - 1)] - f_top.append([len1-1+len1, 0+len1, center2]) - #print 'deb:circleDraw:verts:', verts #--------------- - faces = f_band + f_bottom + f_top - #print 'deb:circleDraw:faces:', faces #--------------- - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - for i in xrange(smooth_len): - me.faces[i].smooth = True - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - if settings.var['vGroup_on'] and not M_OBJ: - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - replace = Mesh.AssignModes.REPLACE #or .AssignModes.ADD - vg_band, vg_top, vg_bottom = [], [], [] - for v in f_band: vg_band.extend(v) - me.addVertGroup('side.band') ; me.assignVertsToGroup('side.band', vg_band, 1.0, replace) - - if settings.var['fill_on']: - for v in f_top: vg_top.extend(v) - for v in f_bottom: vg_bottom.extend(v) - me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) - me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) - - else: # if thic == 0 - if settings.var['fill_on']: - len1 = len(verts) - verts.append([0,0,0]) #center of circle - center1 = len1 - faces = [] - faces.extend([[num, num+1, center1] for num in xrange(len1)]) - faces.append([len1-1, 0, center1]) - #print 'deb:circleDraw:verts:', verts #--------------- - #print 'deb:circleDraw:faces:', faces #--------------- - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - else: - me.verts.extend(verts) # add vertices to mesh - edges = [[num, num+1] for num in xrange(len(verts))] - edges[-1][1] = 0 # it points the "new" last edge to the first vertex - me.edges.extend(edges) # add edges to the mesh - - ob.loc = tuple(self.loc) - transform(self.extrusion, 0, ob) - return ob - - -class Arc: #----------------------------------------------------------------- - """Class for objects representing dxf ARCs. - """ - - def __init__(self, obj): - """Expects an entity object of type arc as input. - """ - if not obj.type == 'arc': - raise TypeError, "Wrong type %s for arc object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.radius = obj.get_type(40)[0] - self.start_angle = obj.get_type(50)[0] - self.end_angle = obj.get_type(51)[0] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - self.extrusion = get_extrusion(obj) - #print 'deb:Arc__init__: center, radius, start, end:\n', self.loc, self.radius, self.start_angle, self.end_angle #--------- - - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 10, None) - loc[1] = getit(data, 20, None) - loc[2] = getit(data, 30, 0.0) - return loc - - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - def draw(self, settings): - """for ARC: generate Blender_geometry. - """ - obname = 'ar_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - - center = self.loc - radius = self.radius - start = self.start_angle - end = self.end_angle - #print 'deb:calcArcPoints:\n center, radius, start, end:\n', center, radius, start, end #--------- - thic = set_thick(self.thic, settings) - width = 0.0 - if settings.var['lines_as'] == 4: # as thin_box - thic = settings.var['thick_min'] - width = settings.var['width_min'] - if settings.var['lines_as'] == 3: # as thin cylinder - cyl_rad = 0.5 * settings.var['width_min'] - - if settings.var['lines_as'] == 5: # draw ARC as curve ------------- - arc_res = settings.var['curve_arc'] - triples = True - VectorTriples = calcArc(None, radius, start, end, arc_res, triples) - arc = Curve.New(obname) # create new curve data - curve = arc.appendNurb(BezTriple.New(VectorTriples[0])) - for p in VectorTriples[1:]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [FREE, FREE] - point.radius = 1.0 - curve.flagU = 0 # 0 sets the curve not cyclic=open - arc.setResolu(settings.var['curve_res']) - - arc.update() #important for handles calculation - - ob = SCENE.objects.new(arc) # create a new curve_object - ob.loc = tuple(self.loc) - if thic != 0.0: #hack: Blender<2.45 curve-extrusion - thic = thic * 0.5 - arc.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0) - ob.LocZ = thic + self.loc[2] - transform(self.extrusion, 0, ob) - if thic != 0.0: - ob.SizeZ *= abs(thic) - return ob - - else: # draw ARC as mesh -------------------- - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - # set a number of segments in entire circle - arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) - - verts = calcArc(None, radius, start, end, arc_res, False) - #verts = [list(point) for point in verts] - len1 = len(verts) - #print 'deb:len1:', len1 #----------------------- - if width != 0: - radius_out = radius + (0.5 * width) - radius_in = radius - (0.5 * width) - if radius_in <= 0.0: - radius_in = settings.var['dist_min'] - #radius_in = 0.0 - verts_in = [] - verts_out = [] - for point in verts: - pointVec = Mathutils.Vector(point) - pointVec = pointVec.normalize() - verts_in.append(list(radius_in * pointVec)) #vertex inside - verts_out.append(list(radius_out * pointVec)) #vertex outside - verts = verts_in + verts_out - - #print 'deb:verts:', verts #--------------------- - if thic != 0: - thic_verts = [] - thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) - if thic < 0.0: - thic_verts.extend(verts) - verts = thic_verts - else: - verts.extend(thic_verts) - f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] - f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] - f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] - f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] - f_start = [[0, len1, len1+len1+len1, len1+len1]] - f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] - faces = f_left + f_right + f_bottom + f_top + f_start + f_end - - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - smooth_len = len(f_left) + len(f_right) - for i in xrange(smooth_len): - me.faces[i].smooth = True - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - if settings.var['vGroup_on'] and not M_OBJ: - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - replace = Mesh.AssignModes.REPLACE #or .AssignModes.ADD - vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] - for v in f_left: vg_left.extend(v) - for v in f_right: vg_right.extend(v) - for v in f_top: vg_top.extend(v) - for v in f_bottom: vg_bottom.extend(v) - me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) - me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) - me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) - me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) - me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) - me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) - - - else: # if thick=0 - draw only flat ring - faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - elif thic != 0: - thic_verts = [] - thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) - if thic < 0.0: - thic_verts.extend(verts) - verts = thic_verts - else: - verts.extend(thic_verts) - faces = [] - #print 'deb:len1:', len1 #----------------------- - #print 'deb:verts:', verts #--------------------- - faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - for i in xrange(len(faces)): - me.faces[i].smooth = True - - else: - edges = [[num, num+1] for num in xrange(len(verts)-1)] - me.verts.extend(verts) # add vertices to mesh - me.edges.extend(edges) # add edges to the mesh - - #me.update() - #ob = SCENE.objects.new(me) # create a new arc_object - #ob.link(me) - ob.loc = tuple(center) - #ob.loc = Mathutils.Vector(ob.loc) - transform(self.extrusion, 0, ob) - #ob.size = (1,1,1) - return ob - - -class BlockRecord: #----------------------------------------------------------------- - """Class for objects representing dxf block_records. - """ - - def __init__(self, obj): - """Expects an entity object of type block_record as input. - """ - if not obj.type == 'block_record': - raise TypeError, "Wrong type %s for block_record object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.name = getit(obj, 2, None) - - # optional data (with defaults) - self.insertion_units = getit(obj, 70, None) - self.insert_units = getit(obj, 1070, None) - """code 1070 Einfuegeeinheiten: - 0 = Keine Einheiten; 1 = Zoll; 2 = Fuss; 3 = Meilen; 4 = Millimeter; - 5 = Zentimeter; 6 = Meter; 7 = Kilometer; 8 = Mikrozoll; - 9 = Mils; 10 = Yard; 11 = Angstrom; 12 = Nanometer; - 13 = Mikrons; 14 = Dezimeter; 15 = Dekameter; - 16 = Hektometer; 17 = Gigameter; 18 = Astronomische Einheiten; - 19 = Lichtjahre; 20 = Parsecs - """ - - - def __repr__(self): - return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) - - - - -class Block: #----------------------------------------------------------------- - """Class for objects representing dxf BLOCKs. - """ - - def __init__(self, obj): - """Expects an entity object of type block as input. - """ - if not obj.type == 'block': - raise TypeError, "Wrong type %s for block object!" %obj.type - - self.type = obj.type - self.name = obj.name - self.data = obj.data[:] - - # required data - self.flags = getit(obj, 70, 0) - self.anonim = self.flags & 1 #anonymous block generated by hatching, associative dimensioning, other - self.atrib = self.flags & 2 # has attribute definitions - self.xref = self.flags & 4 # is an external reference (xref) - self.xref_lay = self.flags & 8 # is an xref overlay - self.dep_ext = self.flags & 16 # is externally dependent - self.dep_res = self.flags & 32 # resolved external reference - self.xref_ext = self.flags & 64 # is a referenced external reference xref - #--todo--- if self.flag > 4: self.xref = True - - # optional data (with defaults) - self.path = getit(obj, 1, '') # Xref path name - self.discription = getit(obj, 4, '') - - self.entities = dxfObject('block_contents') #creates empty entities_container for this block - self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - - #print 'deb:Block %s data:\n%s' %(self.name, self.data) #------------ - #print 'deb:Block %s self.entities.data:\n%s' %(self.name, self.entities.data) #------------ - - - - def get_loc(self, data): - """Gets the insert point of the block. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 10, 0.0) # 10 = x - loc[1] = getit(data, 20, 0.0) # 20 = y - loc[2] = getit(data, 30, 0.0) # 30 = z - return loc - - - def __repr__(self): - return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) - - - - -class Insert: #----------------------------------------------------------------- - """Class for objects representing dxf INSERTs. - """ - - def __init__(self, obj): - """Expects an entity object of type insert as input. - """ - if not obj.type == 'insert': - raise TypeError, "Wrong type %s for insert object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - #print 'deb:Insert_init_ self.data:\n', self.data #----------- - - # required data - self.name = obj.get_type(2)[0] - - # optional data (with defaults) - self.rotation = getit(obj, 50, 0) - self.space = getit(obj, 67, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - self.scale = self.get_scale(obj) - self.rows, self.columns = self.get_array(obj) - self.extrusion = get_extrusion(obj) - - #self.flags = getit(obj.data, 66, 0) # - #self.attrib = self.flags & 1 - - - def get_loc(self, data): - """Gets the origin location of the insert. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 10, 0.0) - loc[1] = getit(data, 20, 0.0) - loc[2] = getit(data, 30, 0.0) - return loc - - - def get_scale(self, data): - """Gets the x/y/z scale factors of the insert. - """ - scale = [1, 1, 1] - scale[0] = getit(data, 41, 1.0) - scale[1] = getit(data, 42, 1.0) - scale[2] = getit(data, 43, 1.0) - return scale - - - def get_array(self, data): - """Returns the pair (row number, row spacing), (column number, column spacing). - """ - columns = getit(data, 70, 1) - rows = getit(data, 71, 1) - cspace = getit(data, 44, 0.0) - rspace = getit(data, 45, 0.0) - return (rows, rspace), (columns, cspace) - - - def get_target(self, data): - """Gets the origin location of the insert. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 1011, 0.0) - loc[1] = getit(data, 1021, 0.0) - loc[2] = getit(data, 1031, 0.0) - return loc - - - def get_color(self, data): - """Gets the origin location of the insert. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 1010, 0.0) - loc[1] = getit(data, 1020, 0.0) - loc[2] = getit(data, 1030, 0.0) - return loc - - - def get_ave_render(self, data): - """Gets the origin location of the insert. - """ - loc = [0, 0, 0] - loc[0] = getit(data, 1010, 0.0) - loc[1] = getit(data, 1020, 0.0) - loc[2] = getit(data, 1030, 0.0) - return loc - - - def __repr__(self): - return "%s: layer - %s, name - %s" %(self.__class__.__name__, self.layer, self.name) - - - def draw(self, settings, deltaloc): - """for INSERT(block): draw empty-marker for duplicated Blender_Group. - - Blocks are made of three objects: - the block_record in the tables section - the block in the blocks section - the insert object (one or more) in the entities section - block_record gives the insert units, - block provides the objects drawn in the block, - insert object gives the location/scale/rotation of the block instances. - """ - - name = self.name.lower() - if name == 'ave_render': - if settings.var['lights_on']: #if lights support activated - a_data = get_ave_data(self.data) - # AVE_RENDER objects: - # 7:'Pref', 0:'Full Opt', 0:'Quick Opt', 1:'Scanl Opt', 2:'Raytr Opt', 0:'RFile Opt' - # 0:'Fog Opt', 0:'BG Opt', 0:'SCENE1','','','','','','','','','', - # '','','','','','','','','','','','', - - if a_data.key == 'SCENE': # define set of lights as blender group - scene_lights = 1 - return - elif name == 'ave_global': - if settings.var['lights_on']: #if lights support activated - return - elif name == 'sh_spot': - if settings.var['lights_on']: #if lights support activated - obname = settings.blocknamesmap[self.name] - obname = 'sp_%s' %obname # create object name from block name - #obname = obname[:MAX_NAMELENGTH] - # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon' - li = Lamp.New('Spot', obname) - ob = SCENE.objects.new(li) - intensity = 2.0 #--todo-- ----------- - li.setEnergy(intensity) - target = self.get_target(self.data) - color = self.get_color(self.data) - li.R = color[0] - li.G = color[1] - li.B = color[2] - - ob.loc = tuple(self.loc) - transform(self.extrusion, 0, ob) - return ob - - elif name == 'overhead': - if settings.var['lights_on']: #if lights support activated - obname = settings.blocknamesmap[self.name] - obname = 'la_%s' %obname # create object name from block name - #obname = obname[:MAX_NAMELENGTH] - # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon' - li = Lamp.New('Lamp', obname) - ob = SCENE.objects.new(li) - intensity = 2.0 #--todo-- ----------- - li.setEnergy(intensity) - target = self.get_target(self.data) - color = self.get_color(self.data) - li.R = color[0] - li.G = color[1] - li.B = color[2] - - ob.loc = tuple(self.loc) - transform(self.extrusion, 0, ob) - return ob - - elif name == 'direct': - if settings.var['lights_on']: #if lights support activated - obname = settings.blocknamesmap[self.name] - obname = 'su_%s' %obname # create object name from block name - #obname = obname[:MAX_NAMELENGTH] - # blender: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon' - li = Lamp.New('Sun', obname) - ob = SCENE.objects.new(li) - intensity = 2.0 #--todo-- ----------- - li.setEnergy(intensity) - color = self.get_color(self.data) - li.R = color[0] - li.G = color[1] - li.B = color[2] - - ob.loc = tuple(self.loc) - transform(self.extrusion, 0, ob) - return ob - - elif settings.drawTypes['insert']: #if insert_drawType activated - #print 'deb:draw. settings.blocknamesmap:', settings.blocknamesmap #-------------------- - obname = settings.blocknamesmap[self.name] - obname = 'in_%s' %obname # create object name from block name - #obname = obname[:MAX_NAMELENGTH] - - # if material BYBLOCK def needed: use as placeholder a mesh-vertex instead of empty - ob = SCENE.objects.new('Empty', obname) # create a new empty_object - empty_size = 1.0 * settings.var['g_scale'] - if empty_size < 0.01: empty_size = 0.01 #Blender limits (0.01-10.0) - elif empty_size > 10.0: empty_size = 10.0 - ob.drawSize = empty_size - - # get our block_def-group - block = settings.blocks(self.name) - ob.DupGroup = block - ob.enableDupGroup = True - - if block.name.startswith('xr_'): - ob.name = 'xb_' + ob.name[3:] - - #print 'deb:draw.block.deltaloc:', deltaloc #-------------------- - ob.loc = tuple(self.loc) - if deltaloc: - deltaloc = rotXY_Vec(self.rotation, deltaloc) - #print 'deb:draw.block.loc:', deltaloc #-------------------- - ob.loc = [ob.loc[0]+deltaloc[0], ob.loc[1]+deltaloc[1], ob.loc[2]+deltaloc[2]] - transform(self.extrusion, self.rotation, ob) - ob.size = tuple(self.scale) - return ob - - - - -class Ellipse: #----------------------------------------------------------------- - """Class for objects representing dxf ELLIPSEs. - """ - - def __init__(self, obj): - """Expects an entity object of type ellipse as input. - """ - if not obj.type == 'ellipse': - raise TypeError, "Wrong type %s for ellipse object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # required data - self.ratio = obj.get_type(40)[0] # Ratio of minor axis to major axis - self.start_angle = obj.get_type(41)[0] # in radians - self.end_angle = obj.get_type(42)[0] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.thic = getit(obj, 39, 0.0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.loc = self.get_loc(obj) - self.major = self.get_major(obj) - self.extrusion = get_extrusion(obj) - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0.0, 0.0, 0.0] - loc[0] = getit(data, 10, 0.0) - loc[1] = getit(data, 20, 0.0) - loc[2] = getit(data, 30, 0.0) - return loc - - - def get_major(self, data): - """Gets the major axis for ellipse type objects. - - The ellipse major axis defines the rotation of the ellipse and its radius. - """ - loc = [0.0, 0.0, 0.0] - loc[0] = getit(data, 11, 0.0) - loc[1] = getit(data, 21, 0.0) - loc[2] = getit(data, 31, 0.0) - return loc - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - def draw(self, settings): - """for ELLIPSE: generate Blender_geometry. - """ - obname = 'el_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - - center = self.loc - start = degrees(self.start_angle) - end = degrees(self.end_angle) - if abs(end - 360.0) < 0.00001: end = 360.0 - ellipse_closed = False - if end - start == 360.0: ellipse_closed = True - - # rotation = Angle between major and WORLDX - # doesnt work, couse produces always positive value: rotation = Mathutils.AngleBetweenVecs(major, WORLDX) - if self.major[0] == 0: - rotation = 90.0 - if self.major[1] < 0: rotation += 180 - else: - rotation = degrees(atan(self.major[1] / self.major[0])) - if self.major[0] < 0: - rotation += 180.0 - - major = Mathutils.Vector(self.major) - #radius = sqrt(self.major[0]**2 + self.major[1]**2 + self.major[2]**2) - radius = major.length - #print 'deb:calcEllipse:\n center, radius, start, end:\n', center, radius, start, end #--------- - - thic = set_thick(self.thic, settings) - width = 0.0 - if settings.var['lines_as'] == 4: # as thin_box - thic = settings.var['thick_min'] - width = settings.var['width_min'] - elif settings.var['lines_as'] == 3: # as thin cylinder - cyl_rad = 0.5 * settings.var['width_min'] - - elif settings.var['lines_as'] == 5: # draw ELLIPSE as curve ------------- - arc_res = settings.var['curve_arc'] - triples = True - VectorTriples = calcArc(None, radius, start, end, arc_res, triples) - arc = Curve.New(obname) # create new curve data - curve = arc.appendNurb(BezTriple.New(VectorTriples[0])) - if ellipse_closed: - for p in VectorTriples[1:-1]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [FREE, FREE] - point.radius = 1.0 - curve.flagU = 1 # 0 sets the curve not cyclic=open - if settings.var['fill_on']: - arc.setFlag(6) # 2+4 set top and button caps - else: - arc.setFlag(arc.getFlag() & ~6) # dont set top and button caps - else: - for p in VectorTriples[1:]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [FREE, FREE] - point.radius = 1.0 - curve.flagU = 0 # 0 sets the curve not cyclic=open - - arc.setResolu(settings.var['curve_res']) - arc.update() #important for handles calculation - - ob = SCENE.objects.new(arc) # create a new curve_object - ob.loc = tuple(self.loc) - if thic != 0.0: #hack: Blender<2.45 curve-extrusion - thic = thic * 0.5 - arc.setExt1(1.0) # curve-extrusion: Blender2.45 accepts only (0.0 - 5.0) - ob.LocZ = thic + self.loc[2] - transform(self.extrusion, rotation, ob) - ob.SizeY *= self.ratio - if thic != 0.0: - ob.SizeZ *= abs(thic) - return ob - - - else: # draw ELLIPSE as mesh -------------------------------------- - if M_OBJ: obname, me, ob = makeNewObject() - else: - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - # set a number of segments in entire circle - arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) - - verts = calcArc(None, radius, start, end, arc_res, False) - #verts = [list(point) for point in verts] - len1 = len(verts) - #print 'deb:len1:', len1 #----------------------- - if width != 0: - radius_out = radius + (0.5 * width) - radius_in = radius - (0.5 * width) - if radius_in <= 0.0: - radius_in = settings.var['dist_min'] - #radius_in = 0.0 - verts_in = [] - verts_out = [] - for point in verts: - pointVec = Mathutils.Vector(point) - pointVec = pointVec.normalize() - verts_in.append(list(radius_in * pointVec)) #vertex inside - verts_out.append(list(radius_out * pointVec)) #vertex outside - verts = verts_in + verts_out - - #print 'deb:verts:', verts #--------------------- - if thic != 0: - thic_verts = [] - thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) - if thic < 0.0: - thic_verts.extend(verts) - verts = thic_verts - else: - verts.extend(thic_verts) - f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] - f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] - f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] - f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] - f_start = [[0, len1, len1+len1+len1, len1+len1]] - f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] - faces = f_left + f_right + f_bottom + f_top + f_start + f_end - - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - smooth_len = len(f_left) + len(f_right) - for i in xrange(smooth_len): - me.faces[i].smooth = True - if settings.var['vGroup_on'] and not M_OBJ: - # each MeshSide becomes vertexGroup for easier material assignment --------------------- - replace = Mesh.AssignModes.REPLACE #or .AssignModes.ADD - vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] - for v in f_left: vg_left.extend(v) - for v in f_right: vg_right.extend(v) - for v in f_top: vg_top.extend(v) - for v in f_bottom: vg_bottom.extend(v) - me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) - me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) - me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) - me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) - me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) - me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) - - - else: # if thick=0 - draw only flat ring - faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - - elif thic != 0: - thic_verts = [] - thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) - if thic < 0.0: - thic_verts.extend(verts) - verts = thic_verts - else: - verts.extend(thic_verts) - faces = [] - #print 'deb:len1:', len1 #----------------------- - #print 'deb:verts:', verts #--------------------- - faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - - me.verts.extend(verts) # add vertices to mesh - me.faces.extend(faces) # add faces to the mesh - if settings.var['meshSmooth_on']: # left and right side become smooth ---------------------- - for i in xrange(len(faces)): - me.faces[i].smooth = True - - else: - edges = [[num, num+1] for num in xrange(len(verts)-1)] - me.verts.extend(verts) # add vertices to mesh - me.edges.extend(edges) # add edges to the mesh - - #print 'deb:calcEllipse transform rotation: ', rotation #--------- - ob.loc = tuple(center) - #old ob.SizeY = self.ratio - transform(self.extrusion, rotation, ob) - #old transform(self.extrusion, 0, ob) - ob.SizeY *= self.ratio - - return ob - - - -class Face: #----------------------------------------------------------------- - """Class for objects representing dxf 3DFACEs. - """ - - def __init__(self, obj): - """Expects an entity object of type 3dfaceplot as input. - """ - if not obj.type == '3dface': - raise TypeError, "Wrong type %s for 3dface object!" %obj.type - self.type = obj.type -# self.data = obj.data[:] - - # optional data (with defaults) - self.space = getit(obj, 67, 0) - self.color_index = getit(obj, 62, BYLAYER) - - self.layer = getit(obj, 8, None) - self.points = self.get_points(obj) - - - def get_points(self, data): - """Gets 3-4 points for a 3d face type object. - - Faces have three or optionally four verts. - """ - a = [0, 0, 0] - b = [0, 0, 0] - c = [0, 0, 0] - d = [0, 0, 0] - a[0] = getit(data, 10, None) # 10 = x - a[1] = getit(data, 20, None) # 20 = y - a[2] = getit(data, 30, 0.0) # 30 = z - b[0] = getit(data, 11, None) - b[1] = getit(data, 21, None) - b[2] = getit(data, 31, 0.0) - c[0] = getit(data, 12, None) - c[1] = getit(data, 22, None) - c[2] = getit(data, 32, 0.0) - out = [a,b,c] - - d[0] = getit(data, 13, None) - if d[0] != None: - d[1] = getit(data, 23, None) - d[2] = getit(data, 33, 0.0) - out.append(d) - - #if len(out) < 4: print '3dface with only 3 vertices:\n',a,b,c,d #----------------- - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - def draw(self, settings): - """for 3DFACE: generate Blender_geometry. - """ - # Generate the geometery - points = self.points - - global activObjectLayer - global activObjectName - #print 'deb:draw:face.ob IN activObjectName: ', activObjectName #--------------------- - - if M_OBJ: obname, me, ob = makeNewObject() - else: - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:face.draw obname from activObjectName: ', obname #--------------------- - ob = getSceneChild(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - me = ob.getData(name_only=False, mesh=True) - else: - obname = 'fa_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object - activObjectName = ob.name - activObjectLayer = self.layer - #print ('deb:except. new face.ob+mesh:"%s" created!' %ob.name) #--------------------- - - #me = Mesh.Get(ob.name) # open objects mesh data - faces, edges = [], [] - n = len(me.verts) - if len(self.points) == 4: - faces = [[0+n,1+n,2+n,3+n]] - elif len(self.points) == 3: - faces = [[0+n,1+n,2+n]] - elif len(self.points) == 2: - edges = [[0+n,1+n]] - - me.verts.extend(points) # add vertices to mesh - if faces: me.faces.extend(faces) # add faces to the mesh - if edges: me.edges.extend(edges) # add faces to the mesh - if settings.var['vGroup_on'] and not M_OBJ: - # entities with the same color build one vertexGroup for easier material assignment --------------------- - ob.link(me) # link mesh to that object - vG_name = 'color_%s' %self.color_index - if edges: faces = edges - replace = Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD - try: - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: existed vGroup:', vG_name #--------------------- - except: - me.addVertGroup(vG_name) - me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) - #print 'deb: create new vGroup:', vG_name #-------------------- - - #print 'deb:draw:face.ob OUT activObjectName: ', activObjectName #--------------------- - return ob - - -#--------------------------------------------------------------------------------------- -# type to object maping (sorted-dictionary for f_obiectify ONLY!, format={'key':Class} ) -type_map = { - 'vport':Vport, - 'view':View, - 'layer':Layer, - 'block_record':BlockRecord, - 'block':Block, - 'insert':Insert, - 'point':Point, - '3dface':Face, - 'line':Line, -# 'mline':MLine, - 'polyline':Polyline, - 'lwpolyline':LWpolyline, - 'spline':Spline, -# 'region':Region, - 'trace':Solid, - 'solid':Solid, - 'text':Text, - 'mtext':Mtext, - 'circle':Circle, - 'ellipse':Ellipse, - 'arc':Arc -} - - - -def objectify(data): #----------------------------------------------------------------- - """Expects a section type object's data as input. - - Maps object data to the correct object type. - """ - #print 'deb:objectify start %%%%%%%%%%%' #--------------- - objects = [] # colector for finished objects - known_types = type_map.keys() # so we don't have to call foo.keys() every iteration - curves_on = GUI_A['curves_on'].val - index = 0 - while index < len(data): - item = data[index] - #print 'deb:objectify item: \n', item #------------ - if type(item) != list and item.type == 'table': - item.data = objectify(item.data) # tables have sub-objects - objects.append(item) - elif type(item) != list and item.type == 'polyline': #remi --todo----------- - #print 'deb:gosub Polyline\n' #------------- - pline = Polyline(item) - while 1: - index += 1 - item = data[index] - if item.type == 'vertex': - #print 'deb:objectify gosub Vertex--------' #------------- - v = Vertex(item) - if pline.spline: # if NURBSpline-curve - # then for Blender-mesh filter only additional_vertices - # OR - # then for Blender-curve filter only spline_control_vertices - if (v.spline and not curves_on) or (curves_on and v.spline_c): #correct for real NURBS-import - #if (v.spline and not curves_on) or (curves_on and not v.spline_c): #fake for Bezier-emulation of NURBS-import - pline.points.append(v) - elif pline.curved: # if Bezier-curve - # then for Blender-mesh filter only curve_additional_vertices - # OR - # then for Blender-curve filter curve_control_vertices - if not curves_on or (curves_on and not v.curved): - pline.points.append(v) - else: - pline.points.append(v) - elif item.type == 'seqend': - #print 'deb:objectify it is seqEND ---------\n' #------------- - break - else: - print "Error: non-vertex found before seqend!" - index -= 1 #so go back one step - break - objects.append(pline) - elif type(item) != list and item.type in ['block', 'insert']: - if not settings.var['block_nn'] and item.name.startswith('*X'): - #print 'deb:objectify item.type:"%s", item.name:"%s"' %(item.type, item.name) #------------ - pass - elif settings.var['blockFilter_on'] and not settings.accepted_block(item.name): - pass - else: - try: - objects.append(type_map[item.type](item)) - except TypeError: - pass - elif type(item) != list and item.type in known_types: - # proccess the object and append the resulting object - try: - objects.append(type_map[item.type](item)) - except TypeError: - pass - else: - #we will just let the data pass un-harrased - #objects.append(item) - pass - index += 1 - #print 'deb:objectify objects:\n', objects #------------ - #print 'deb:objectify END %%%%%%%%' #------------ - return objects - - - -class MatColors: #----------------------------------------------------------------- - """A smart container for dxf-color based materials. - - This class is a wrapper around a dictionary mapping dxf-color indicies to materials. - When called with a color_index - it returns a material corresponding to that index. - Behind the scenes it checks if that index is in its keys, and if not it creates - a new material. It then adds the new index:material pair to its dict and returns - the material. - """ - - def __init__(self): - """Expects a map - a dictionary mapping layer names to layers. - """ - #self.layersmap = layersmap # a dictionary of layername:layerobject - self.colMaterials = {} # a dictionary of color_index:blender_material - #print 'deb:init_MatColors argument.map: ', map #------------------ - - - def __call__(self, color=None): - """Return the material associated with color. - - If a layer name is provided, the color of that layer is used. - """ - if color == None: color = 256 # color 256=BYLAYER - if type(color) == str: # looking for color of LAYER named "color" - #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"----- - #print 'deb:color is string:--------: ', color - #try: - #color = layersmap[color].color - #print 'deb:color=self.map[color].color:', color #------------------ - #except KeyError: - #layer = Layer(name=color, color=256, frozen=False) - #layersmap[color] = layer - #color = 0 - if color in layersmap.keys(): - color = layersmap[color].color - if color == 256: # color 256 = BYLAYER - #--todo-- should looking for color of LAYER - #if layersmap: color = layersmap[color].color - color = 3 - if color == 0: # color 0 = BYBLOCK - #--todo-- should looking for color of paret-BLOCK - #if layersmap: color = layersmap[color].color - color = 3 - color = abs(color) # cause the value could be nagative = means the layer is turned off - - if color not in self.colMaterials.keys(): - self.add(color) - return self.colMaterials[color] - - - def add(self, color): - """Create a new material 'ColorNr-N' using the provided color index-N. - """ - #global color_map #--todo-- has not to be global? - mat = Material.New('ColorNr-%s' %color) - mat.setRGBCol(color_map[color]) - #mat.mode |= Material.Modes.SHADELESS #--todo-- - #mat.mode |= Material.Modes.WIRE -# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug -# except: pass - self.colMaterials[color] = mat - - - -class MatLayers: #----------------------------------------------------------------- - """A smart container for dxf-layer based materials. - - This class is a wrapper around a dictionary mapping dxf-layer names to materials. - When called with a layer name it returns a material corrisponding to that. - Behind the scenes it checks if that layername is in its keys, and if not it creates - a new material. It then adds the new layername:material pair to its dict and returns - the material. - """ - - def __init__(self): - """Expects a map - a dictionary mapping layer names to layers. - """ - #self.layersmap = layersmap # a dictionary of layername:layer - self.layMaterials = {} # a dictionary of layer_name:blender_material - #print 'deb:init_MatLayers argument.map: ', map #------------------ - - - def __call__(self, layername=None, color=None): - """Return the material associated with dxf-layer. - - If a dxf-layername is not provided, create a new material - """ - #global layernamesmap - layername_short = layername - if layername in layernamesmap.keys(): - layername_short = layernamesmap[layername] - colorlayername = layername_short - if color: colorlayername = str(color) + colorlayername - if colorlayername not in self.layMaterials.keys(): - self.add(layername, color, colorlayername) - return self.layMaterials[colorlayername] - - - def add(self, layername, color, colorlayername): - """Create a new material 'layername'. - """ - try: mat = Material.Get('L-%s' %colorlayername) - except: mat = Material.New('L-%s' %colorlayername) - #print 'deb:MatLayers material: ', mat #---------- - #global settings - #print 'deb:MatLayers material_from: ', settings.var['material_from'] #---------- - if settings.var['material_from'] == 3 and color: - if color == 0 or color == 256: mat_color = 3 - else: mat_color = color - elif layersmap and layername: - mat_color = layersmap[layername].color - else: mat_color = 3 - #print 'deb:MatLayers color: ', color #----------- - #print 'deb:MatLayers mat_color: ', mat_color #----------- - mat.setRGBCol(color_map[abs(mat_color)]) - #mat.mode |= Material.Modes.SHADELESS - #mat.mode |= Material.Modes.WIRE -# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug -# except: pass - self.layMaterials[colorlayername] = mat - - - - -class Blocks: #----------------------------------------------------------------- - """A smart container for blocks. - - This class is a wrapper around a dictionary mapping block names to Blender data blocks. - When called with a name string it returns a block corresponding to that name. - Behind the scenes it checks if that name is in its keys, and if not it creates - a new data block. It then adds the new name:block_data pair to its dict and returns - the block. - """ - - def __init__(self, blocksmap, settings): - """Expects a dictionary mapping block_name:block_data. - """ - self.blocksmap = blocksmap #a dictionary mapping block_name:block_data - self.settings = settings - self.blocks = {} #container for blender groups representing blocks - - - def __call__(self, name=None): - """Return the data block associated with that block_name. - - If that name is not in its keys, it creates a new data block. - If no name is provided return entire self.blocks container. - """ - if name == None: - return self.blocks - if name not in self.blocks.keys(): - self.addBlock(name) - return self.blocks[name] - - - def addBlock(self, name): - """Create a new 'block group' for the block name. - """ - block = self.blocksmap[name] - prefix = 'bl' - if block.xref: prefix = 'xr' - blender_group = Group.New('%s_%s' %(prefix,name)) # Blender groupObject contains definition of BLOCK - block_def = [blender_group, block.loc] - self.settings.write("\nDrawing block:\'%s\' ..." % name) - - if block.xref: - obname = 'xr_%s' %name # create object name from xref block name - #obname = obname[:MAX_NAMELENGTH] - # if material BYBLOCK def needed: use as placeholder a mesh-vertex instead of empty - ob = SCENE.objects.new('Empty', obname) # create a new empty_object - empty_size = 1.0 * settings.var['g_scale'] - if empty_size < 0.01: empty_size = 0.01 #Blender limits (0.01-10.0) - elif empty_size > 10.0: empty_size = 10.0 - ob.drawSize = empty_size - ob.loc = tuple(block.loc) - ob.properties['xref_path'] = block.path - ob.layers = [19] - insertFlag=True; blockFlag=True - global oblist - oblist.append((ob, insertFlag, blockFlag)) - else: - if M_OBJ: - car_end() - car_start() - drawEntities(block.entities, self.settings, block_def) - if M_OBJ: car_end() - self.settings.write("Drawing block:\'%s\' done!" %name) - self.blocks[name] = blender_group - - - - - -class Settings: #----------------------------------------------------------------- - """A container for all the import settings and objects used by the draw functions. - - This is like a collection of globally accessable persistant properties and functions. - """ - # Optimization constants - MIN = 0 - MID = 1 - PRO = 2 - MAX = 3 - - def __init__(self, keywords, drawTypes): - """initialize all the important settings used by the draw functions. - """ - self.obj_number = 1 #global object_number for progress_bar - - self.var = dict(keywords) #a dictionary of (key_variable:Value) control parameter - self.drawTypes = dict(drawTypes) #a dictionary of (entity_type:True/False) = import on/off for this entity_type - - self.var['colorFilter_on'] = False #deb:remi------------ - self.acceptedColors = [0,2,3,4,5,6,7,8,9, - 10 ] - - self.var['layerFilter_on'] = False #deb:remi------------ - self.acceptedLayers = ['3', - '0' - ] - - self.var['groupFilter_on'] = False #deb:remi------------ - self.acceptedLayers = ['3', - '0' - ] - - #self.var['blockFilter_on'] = 0 #deb:remi------------ - self.acceptedBlocks = ['WALL_1871', - 'BOX02' - ] - self.unwantedBlocks = ['BOX05', - 'BOX04' - ] - - - def update(self, keywords, drawTypes): - """update all the important settings used by the draw functions. - mostly used after loading parameters from INI-file - """ - - for k, v in keywords.iteritems(): - self.var[k] = v - #print 'deb:settings_update var %s= %s' %(k, self.var[k]) #-------------- - for t, v in drawTypes.iteritems(): - self.drawTypes[t] = v - #print 'deb:settings_update drawType %s= %s' %(t, self.drawTypes[t]) #-------------- - - self.drawTypes['arc'] = self.drawTypes['line'] - self.drawTypes['circle'] = self.drawTypes['line'] - self.drawTypes['ellipse'] = self.drawTypes['line'] - self.drawTypes['trace'] = self.drawTypes['solid'] - self.drawTypes['insert'] = self.drawTypes['block'] - #self.drawTypes['vport'] = self.drawTypes['view'] - - #print 'deb:self.drawTypes', self.drawTypes #--------------- - - - def validate(self, drawing): - """Given the drawing, build dictionaries of Layers, Colors and Blocks. - """ - - global oblist - #adjust the distance parameter to globalScale - if self.var['g_scale'] != 1.0: - self.var['dist_min'] = self.var['dist_min'] / self.var['g_scale'] - self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale'] - self.var['width_min'] = self.var['width_min'] / self.var['g_scale'] - self.var['arc_rad'] = self.var['arc_rad'] / self.var['g_scale'] - - self.g_origin = Mathutils.Vector(self.var['g_originX'], self.var['g_originY'], self.var['g_originZ']) - - # First sort out all the section_items - sections = dict([(item.name, item) for item in drawing.data]) - - # The section:header may be omited - if 'header' in sections.keys(): - self.write("found section:header") - else: - self.write("File contains no section:header!") - - if self.var['optimization'] == 0: self.var['one_mesh_on'] = 0 - # The section:tables may be partialy or completely missing. - self.layersTable = False - self.colMaterials = MatColors() #A container for dxf-color based materials - self.layMaterials = MatLayers() #A container for dxf-layer based materials - #self.collayMaterials = MatColLayers({}) #A container for dxf-color+layer based materials - global layersmap, layernamesmap - layersmap, layernamesmap = {}, {} - if 'tables' in sections.keys(): - self.write("found section:tables") - views, vports, layers = False, False, False - for table in drawing.tables.data: - if table.name == 'layer': - self.write("found table:layers") - layers = table - elif table.name == 'view': - print "found table:view" - views = table - elif table.name == 'vport': - print "found table:vport" - vports = table - if layers: #---------------------------------- - # Read the layers table and get the layer colors - layersmap, layernamesmap = getLayersmap(layers) - #self.colMaterials = MatColors() - #self.layMaterials = MatLayers() - else: - self.write("File contains no table:layers!") - - - if views: #---------------------------------- - if self.var['views_on']: - for item in views.data: - if type(item) != list and item.type == 'view': - #print 'deb:settings_valid views dir(item)=', dir(item) #------------- - #print 'deb:settings_valid views item=', item #------------- - ob = item.draw(self) - #viewsmap[item.name] = [item.length] - #--todo-- add to obj_list for global.Scaling - insertFlag, blockFlag = False, False - oblist.append((ob, insertFlag, blockFlag)) - - else: - self.write("File contains no table:views!") - - - if vports: #---------------------------------- - if self.var['views_on']: - for item in vports.data: - if type(item) != list and item.type == 'vport': - #print 'deb:settings_valid views dir(item)=', dir(item) #------------- - #print 'deb:settings_valid views item=', item #------------- - ob = item.draw(self) - #viewsmap[item.name] = [item.length] - #--todo-- add to obj_list for global.Scaling - insertFlag, blockFlag = False, False - oblist.append((ob, insertFlag, blockFlag)) - else: - self.write("File contains no table:vports!") - - - else: - self.write("File contains no section:tables!") - self.write("File contains no table:layers!") - - - # The section:blocks may be omited - if 'blocks' in sections.keys(): - self.write("found section:blocks") - # Read the block definitions and build our block object - if self.drawTypes['insert']: #if support for entity type 'Insert' is activated - #Build a dictionary of blockname:block_data pairs - blocksmap, obj_number = getBlocksmap(drawing, layersmap, self.var['layFrozen_on']) - self.obj_number += obj_number - self.blocknamesmap = getBlocknamesmap(blocksmap) - self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data - self.usedBlocks = blocksmap.keys() - #print 'deb:settings_valid self.usedBlocks', self.usedBlocks #---------- - else: - self.write("ignored, because support for BLOCKs is turn off!") - #print 'deb:settings_valid self.obj_number', self.obj_number #---------- - else: - self.write("File contains no section:blocks!") - self.drawTypes['insert'] = False - - # The section:entities - if 'entities' in sections.keys(): - self.write("found section:entities") - self.obj_number += len(drawing.entities.data) - self.obj_number = 1.0 / self.obj_number - - - def accepted_block(self, name): - if name not in self.usedBlocks: return False - if name in self.unwantedBlocks: return False - elif name in self.acceptedBlocks: return True - #elif (name.find('*X')+1): return False - #elif name.startswith('3'): return True - #elif name.endswith('H'): return False - return True - - - def write(self, text, newline=True): - """Wraps the built-in print command in a optimization check. - """ - if self.var['optimization'] <= self.MID: - if newline: print text - else: print text, - - - def redraw(self): - """Update Blender if optimization level is low enough. - """ - if self.var['optimization'] <= self.MIN: - Blender.Redraw() - - - def progress(self, done, text): - """Wrapper for Blender.Window.DrawProgressBar. - """ - if self.var['optimization'] <= self.PRO: - progressbar = done * self.obj_number - Window.DrawProgressBar(progressbar, text) - #print 'deb:drawer done, progressbar: ', done, progressbar #----------------------- - - def layer_isOff(self, layername): # no more used ------- - """Given a layer name, and return its visible status. - """ - # if layer is off then color_index is negative - if layersmap and layersmap[layername].color < 0: return True - #print 'deb:layer_isOff: layer is ON' #--------------- - return False - - - def layer_isFrozen(self, layername): # no more used ------- - """Given a layer name, and return its frozen status. - """ - if layersmap and layersmap[layername].frozen: return True - #print 'deb:layer_isFrozen: layer is not FROZEN' #--------------- - return False - - - -def analyzeDXF(dxfFile): #--------------------------------------- - """list statistics about LAYER and BLOCK dependences into textfile.INF - - """ - Window.WaitCursor(True) # Let the user know we are thinking - print 'reading DXF file: %s.' % dxfFile - time1 = sys.time() #time marker1 - drawing = readDXF(dxfFile, objectify) - print 'finish reading in %.4f sec.' % (sys.time()-time1) - - # First sort out all the section_items - sections = dict([(item.name, item) for item in drawing.data]) - - # The section:header may be omited - if 'header' in sections.keys(): print "found section:header" - else: print "File contains no section:header!" - - # The section:tables may be partialy or completely missing. - layersTable = False - global layersmap - layersmap = {} - viewsmap = {} - vportsmap = {} - layersmap_str = '#File contains no table:layers!' - viewsmap_str = '#File contains no table:views!' - vportsmap_str = '#File contains no table:vports!' - if 'tables' in sections.keys(): - print "found section:tables" - views, vports, layers = False, False, False - for table in drawing.tables.data: - if table.name == 'layer': - print "found table:layers" - layers = table - elif table.name == 'view': - print "found table:view" - views = table - elif table.name == 'vport': - print "found table:vport" - vports = table - if layers: #---------------------------------- - for item in layers.data: - if type(item) != list and item.type == 'layer': - #print dir(item) - layersmap[item.name] = [item.color, item.frozen] - #print 'deb:analyzeDXF: layersmap=' , layersmap #------------- - layersmap_str = '#list of LAYERs: name, color, frozen_status ---------------------------\n' - key_list = layersmap.keys() - key_list.sort() - for key in key_list: - #for layer_name, layer_data in layersmap.iteritems(): - layer_name, layer_data = key, layersmap[key] - layer_str = '\'%s\': col=%s' %(layer_name,layer_data[0])#------------- - if layer_data[1]: layer_str += ', frozen' - layersmap_str += layer_str + '\n' - #print 'deb:analyzeDXF: layersmap_str=\n' , layersmap_str #------------- - else: - print "File contains no table:layers!" - - if views: #---------------------------------- - for item in views.data: - if type(item) != list and item.type == 'view': - #print dir(item) - viewsmap[item.name] = [item.length] - #print 'deb:analyzeDXF: viewsmap=' , viewsmap #------------- - viewsmap_str = '#list of VIEWs: name, focus_length ------------------------------------\n' - key_list = viewsmap.keys() - key_list.sort() - for key in key_list: - #for view_name, view_data in viewsmap.iteritems(): - view_name, view_data = key, viewsmap[key] - view_str = '\'%s\': length=%s' %(view_name,view_data[0])#------------- - #if view_data[1]: view_str += ', something' - viewsmap_str += view_str + '\n' - #print 'deb:analyzeDXF: layersmap_str=\n' , layersmap_str #------------- - else: - print "File contains no table:views!" - - if vports: #---------------------------------- - for item in vports.data: - if type(item) != list and item.type == 'vport': - #print dir(item) - vportsmap[item.name] = [item.length] - #print 'deb:analyzeDXF: vportsmap=' , vportsmap #------------- - vportsmap_str = '#list of VPORTs: name, focus_length -----------------------------------\n' - key_list = vportsmap.keys() - key_list.sort() - for key in key_list: - #for vport_name, vport_data in vportsmap.iteritems(): - vport_name, vport_data = key, vportsmap[key] - vport_str = '\'%s\': length=%s' %(vport_name,vport_data[0])#------------- - #if vport_data[1]: vport_str += ', something' - vportsmap_str += vport_str + '\n' - #print 'deb:analyzeDXF: vportsmap_str=\n' , vportsmap_str #------------- - else: - print "File contains no table:vports!" - - else: - print "File contains no section:tables!" - print "File contains no tables:layers,views,vports!" - - # The section:blocks may be omited - if 'blocks' in sections.keys(): - print "found section:blocks" - blocksmap = {} - for item in drawing.blocks.data: - #print 'deb:getBlocksmap item=' ,item #-------- - #print 'deb:getBlocksmap item.entities=' ,item.entities #-------- - #print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #-------- - if type(item) != list and item.type == 'block': - xref = False - if item.xref: xref = True - childList = [] - used = False - for item2 in item.entities.data: - if type(item2) != list and item2.type == 'insert': - #print 'deb:getBlocksmap dir(item2)=', dir(item2) #---------- - item2str = [item2.name, item2.layer, item2.color_index, item2.scale, item2.space] - childList.append(item2str) - try: blocksmap[item.name] = [used, childList, xref] - except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) - #print 'deb:analyzeDXF: blocksmap=' , blocksmap #------------- - - for item2 in drawing.entities.data: - if type(item2) != list and item2.type == 'insert': - if item2.name in blocksmap.keys(): - if not layersmap or (layersmap and not layersmap[item2.layer][1]): #if insert_layer is not frozen - blocksmap[item2.name][0] = True # marked as world used BLOCK - - key_list = blocksmap.keys() - key_list.reverse() - for key in key_list: - if blocksmap[key][0]: #if used - for child in blocksmap[key][1]: - if not layersmap or (layersmap and not layersmap[child[1]][1]): #if insert_layer is not frozen - blocksmap[child[0]][0] = True # marked as used BLOCK - - blocksmap_str = '#list of BLOCKs: name:(unused)(xref) -[child_name, layer, color, scale, space]-------\n' - key_list = blocksmap.keys() - key_list.sort() - for key in key_list: - #for block_name, block_data in blocksmap.iteritems(): - block_name, block_data = key, blocksmap[key] - block_str = '\'%s\': ' %(block_name) #------------- - used = '(unused)' - if block_data[0]: used = '' -# else: used = '(unused)' - xref = '' - if block_data[2]: xref = '(xref)' - blocksmap_str += block_str + used + xref +'\n' - if block_data: - for block_item in block_data[1]: - block_data_str = ' - %s\n' %block_item - blocksmap_str += block_data_str - #print 'deb:analyzeDXF: blocksmap_str=\n' , blocksmap_str #------------- - else: - blocksmap_str = '#File contains no section:blocks!' - print "File contains no section:blocks!" - - Window.WaitCursor(False) - output_str = '%s\n%s\n%s\n%s' %(viewsmap_str, vportsmap_str, layersmap_str, blocksmap_str) - infFile = dxfFile[:-4] + '_DXF.INF' # replace last char:'.dxf' with '_DXF.inf' - try: - f = file(infFile, 'w') - f.write(INFFILE_HEADER + '\n# this is a comment line\n\n') - f.write(output_str) - f.close() - Draw.PupMenu('DXF importer: report saved in INF-file:%t|' + '\'%s\'' %infFile) - except: - Draw.PupMenu('DXF importer: ERROR by writing report in INF-file:%t|' + '\'%s\'' %infFile) - #finally: f.close() - - - - -def main(dxfFile): #---------------#############################----------- - #print 'deb:filename:', filename #-------------- - global SCENE - global oblist - editmode = Window.EditMode() # are we in edit mode? If so ... - if editmode: - Window.EditMode(0) # leave edit mode before - - #SCENE = bpy.data.scenes.active - #SCENE.objects.selected = [] # deselect all - - global cur_COUNTER #counter for progress_bar - cur_COUNTER = 0 - - #try: - if 1: - #print "Getting settings..." - global GUI_A, GUI_B, g_scale_as - if not GUI_A['g_scale_on'].val: - GUI_A['g_scale'].val = 1.0 - - keywords = {} - drawTypes = {} - for k, v in GUI_A.iteritems(): - keywords[k] = v.val - for k, v in GUI_B.iteritems(): - drawTypes[k] = v.val - #print 'deb:startUInew keywords: ', keywords #-------------- - #print 'deb:startUInew drawTypes: ', drawTypes #-------------- - - # The settings object controls how dxf entities are drawn - settings.update(keywords, drawTypes) - #print 'deb:settings.var:\n', settings.var #----------------------- - - if not settings: - #Draw.PupMenu('DXF importer: EXIT!%t') - #print '\nDXF Import: terminated by user!' - print '\nDXF Import: terminated, cause settings failure!' - Window.WaitCursor(False) - if editmode: Window.EditMode(1) # and put things back how we fond them - return None - - #no more used dxfFile = dxfFileName.val - #print 'deb: dxfFile file: ', dxfFile #---------------------- - if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): - Window.WaitCursor(True) # Let the user know we are thinking - print 'reading file: %s.' % dxfFile - time1 = sys.time() #time marker1 - drawing = readDXF(dxfFile, objectify) - print 'reading finished in %.4f sec.' % (sys.time()-time1) - Window.WaitCursor(False) - elif dxfFile.lower().endswith('.dwg') and sys.exists(dxfFile): - if not extCONV_OK: - Draw.PupMenu(extCONV_TEXT) - Window.WaitCursor(False) - if editmode: Window.EditMode(1) # and put things back how we fond them - return None - else: - Window.WaitCursor(True) # Let the user know we are thinking - #todo: issue: in DConvertCon.exe the output filename is fixed to dwg_name.dxf - - if 0: # works only for Windows - dwgTemp = 'temp_01.dwg' - dxfTemp = 'temp_01.dxf' - os.system('copy %s %s' %(dxfFile,dwgTemp)) - else: - dwgTemp = dxfFile - dxfTemp = dxfFile[:-3]+'dxf' - #print 'temp. converting: %s\n to: %s' %(dxfFile, dxfTemp) - #os.system('%s %s -acad11 -dxf' %(extCONV_PATH, dxfFile)) - os.system('%s %s -dxf' %(extCONV_PATH, dwgTemp)) - #os.system('%s %s -dxf' %(extCONV_PATH, dxfFile_temp)) - if sys.exists(dxfTemp): - print 'reading file: %s.' % dxfTemp - time1 = sys.time() #time marker1 - drawing = readDXF(dxfTemp, objectify) - #os.remove(dwgTemp) - os.remove(dxfTemp) # clean up - print 'reading finished in %.4f sec.' % (sys.time()-time1) - Window.WaitCursor(False) - else: - if UI_MODE: Draw.PupMenu('DWG importer: nothing imported!%t|No valid DXF-representation found!') - print 'DWG importer: nothing imported. No valid DXF-representation found.' - Window.WaitCursor(False) - if editmode: Window.EditMode(1) # and put things back how we fond them - return None - else: - if UI_MODE: Draw.PupMenu('DXF importer: Alert!%t| no valid DXF-file selected!') - print "DXF importer: Alert! - no valid DXF-file selected." - Window.WaitCursor(False) - if editmode: Window.EditMode(1) # and put things back how we fond them - return None - - # Draw all the know entity types in the current scene - oblist = [] # a list of all created AND linked objects for final f_globalScale - time2 = sys.time() #time marker2 - - Window.WaitCursor(True) # Let the user know we are thinking - settings.write("\n\nDrawing entities...") - - settings.validate(drawing) - - global activObjectLayer, activObjectName - activObjectLayer, activObjectName = None, None - - if M_OBJ: car_init() - - drawEntities(drawing.entities, settings) - - #print 'deb:drawEntities after: oblist:', oblist #----------------------- - if M_OBJ: car_end() - if oblist: # and settings.var['g_scale'] != 1: - globalScale(oblist, settings.var['g_scale']) - - # Set visibility for all layers on all View3d - #Window.ViewLayers([i+1 for i in range(18)]) # for 2.45 - SCENE.setLayers([i+1 for i in range(18)]) - SCENE.update(1) - SCENE.objects.selected = [i[0] for i in oblist] #select only the imported objects - #SCENE.objects.selected = SCENE.objects #select all objects in current scene - Blender.Redraw() - - time_text = sys.time() - time2 - Window.WaitCursor(False) - if settings.var['paper_space_on']: space = 'from paper space' - else: space = 'from model space' - ob_len = len(oblist) - message = ' %s objects imported %s in %.4f sec. -----DONE-----' % (ob_len, space, time_text) - settings.progress(1.0/settings.obj_number, 'DXF import done!') - print message - #settings.write(message) - if UI_MODE: Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % time_text) - - #finally: - # restore state even if things didn't work - #print 'deb:drawEntities finally!' #----------------------- - Window.WaitCursor(False) - if editmode: Window.EditMode(1) # and put things back how we fond them - - - -def getOCS(az): #----------------------------------------------------------------- - """An implimentation of the Arbitrary Axis Algorithm. - """ - #decide if we need to transform our coords - #if az[0] == 0 and az[1] == 0: - if abs(az[0]) < 0.00001 and abs(az[1]) < 0.00001: - if az[2] > 0.0: - return False - elif az[2] < 0.0: - ax = Mathutils.Vector(-1.0, 0, 0) - ay = Mathutils.Vector(0, 1.0, 0) - az = Mathutils.Vector(0, 0, -1.0) - return ax, ay, az - - az = Mathutils.Vector(az) - - cap = 0.015625 # square polar cap value (1/64.0) - if abs(az.x) < cap and abs(az.y) < cap: - ax = M_CrossVecs(WORLDY,az) - else: - ax = M_CrossVecs(WORLDZ,az) - ax = ax.normalize() - ay = M_CrossVecs(az, ax) - ay = ay.normalize() - return ax, ay, az - - - -def transform(normal, rotation, obj): #-------------------------------------------- - """Use the calculated ocs to determine the objects location/orientation in space. - - Quote from dxf docs: - The elevation value stored with an entity and output in DXF files is a sum - of the Z-coordinate difference between the UCS XY plane and the OCS XY - plane, and the elevation value that the user specified at the time the entity - was drawn. - """ - ma = Mathutils.Matrix([1,0,0],[0,1,0],[0,0,1]) - o = Mathutils.Vector(obj.loc) - ocs = getOCS(normal) - if ocs: - ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) - o = ma.invert() * o - ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) - - if rotation != 0: - g = radians(-rotation) - rmat = Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) - ma = rmat * ma - - obj.setMatrix(ma) - obj.loc = o - #print 'deb:new obj.matrix:\n', obj.getMatrix() #-------------------- - - - -def rotXY_Vec(rotation, vec): #---------------------------------------------------- - """Rotate vector vec in XY-plane. vec must be in radians - """ - if rotation != 0: - o = Mathutils.Vector(vec) - g = radians(-rotation) - vec = o * Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) - return vec - - - -def getLayersmap(dxflayers): #------------------------------------------------------ - """Build two dictionaries: 1.layername:layer object, and 2.layername:layername_short - gets set of layers from TABLES SECTION LAYERS - """ - layersmap = {} - layernamesmap = {} - for item in dxflayers.data: - if type(item) != list and item.type == 'layer': - layersmap[item.name] = item - layername_short = item.name[:MAX_NAMELENGTH-1] - i = 0 #sufix for layernames cause Blender-objectnames-limits - while layername_short in layernamesmap.keys(): - i += 1 - suffix = str(i) #--todo--set zero-leading number format - layername_short = layername_short[:-2] + suffix - layernamesmap[item.name] = layername_short - - #print 'deb:getLayersmap layersmap:\n', layersmap #------------ - #print 'deb:getLayersmap layernamesmap:\n', layernamesmap #------------ - return layersmap, layernamesmap - - - -def getBlocksmap(drawing, layersmap, layFrozen_on=False): #-------------------------------------------------------- - """Build a dictionary of blockname:block_data pairs - """ - usedblocks = {} - for item in drawing.blocks.data: - #print 'deb:getBlocksmap item=%s\n i.entities=%s\n i.data=%s' %(item,item.entities,item.entities.data) - if type(item) != list and item.type == 'block': - childList = [] - used = False - for item2 in item.entities.data: - if type(item2) != list and item2.type == 'insert': - #print 'deb:getBlocksmap dir(item2)=', dir(item2) #---------- - item2str = [item2.name, item2.layer] - childList.append(item2str) - try: usedblocks[item.name] = [used, childList] - except KeyError: print 'Cannot find "%s" Block!' %(item.name) - #print 'deb:getBlocksmap: usedblocks=' , usedblocks #------------- - #print 'deb:getBlocksmap: layersmap=' , layersmap #------------- - - for item in drawing.entities.data: - if type(item) != list and item.type == 'insert': - if not layersmap or (not layersmap[item.layer].frozen or layFrozen_on): #if insert_layer is not frozen - try: usedblocks[item.name][0] = True - except KeyError: print 'Cannot find "%s" Block!' %(item.name) - - key_list = usedblocks.keys() - key_list.reverse() - for key in key_list: - if usedblocks[key][0]: #if parent used, then set used also all child blocks - for child in usedblocks[key][1]: - if not layersmap or (layersmap and not layersmap[child[1]].frozen): #if insert_layer is not frozen - try: usedblocks[child[0]][0] = True # marked as used BLOCK - except KeyError: print 'Cannot find "%s" Block!' %(child[0]) - - usedblocks = [i for i in usedblocks.keys() if usedblocks[i][0]] - #print 'deb:getBlocksmap: usedblocks=' , usedblocks #------------- - obj_number = 0 - blocksmap = {} - for item in drawing.blocks.data: - if type(item) != list and item.type == 'block' and item.name in usedblocks: - #if item.name.startswith('*X'): #--todo-- - obj_number += len(item.entities.data) - try: blocksmap[item.name] = item - except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) - - - #print 'deb:getBlocksmap: blocksmap:\n', blocksmap #------------ - return blocksmap, obj_number - - -def getBlocknamesmap(blocksmap): #-------------------------------------------------------- - """Build a dictionary of blockname:blockname_short pairs - """ - #print 'deb:getBlocknamesmap blocksmap:\n', blocksmap #------------ - blocknamesmap = {} - for n in blocksmap.keys(): - blockname_short = n[:MAX_NAMELENGTH-1] - i = 0 #sufix for blockname cause Blender-objectnamelength-limit - while blockname_short in blocknamesmap.keys(): - i += 1 - suffix = str(i) - blockname_short = blockname_short[:-2] + suffix - blocknamesmap[n] = blockname_short - #print 'deb:getBlocknamesmap blocknamesmap:\n', blocknamesmap #------------ - return blocknamesmap - - -def drawEntities(entities, settings, block_def=None): #---------------------------------------- - """Draw every kind of thing in the entity list. - - If provided 'block_def': the entities are to be added to the Blender 'group'. - """ - for _type in type_map.keys(): - #print 'deb:drawEntities_type:', _type #------------------ - # for each known type get a list of that type and call the associated draw function - entities_type = entities.get_type(_type) - if entities_type: drawer(_type, entities_type, settings, block_def) - - -def drawer(_type, entities, settings, block_def): #------------------------------------------ - """Call with a list of entities and a settings object to generate Blender geometry. - - If 'block_def': the entities are to be added to the Blender 'group'. - """ - global layersmap, layersmapshort - #print 'deb:drawer _type, entities:\n ', _type, entities #----------------------- - - if entities: - # Break out early if settings says we aren't drawing the current dxf-type - global cur_COUNTER #counter for progress_bar - group = None - #print 'deb:drawer.check:_type: ', _type #-------------------- - if _type == '3dface':_type = 'face' # hack, while python_variable_name can not beginn with a nummber - if not settings.drawTypes[_type] or _type == 'block_record': - message = 'Skipping dxf\'%ss\' entities' %_type - settings.write(message, True) - cur_COUNTER += len(entities) - settings.progress(cur_COUNTER, message) - return - #print 'deb:drawer.todo:_type:', _type #----------------------- - #print 'deb:drawer entities:\n ', entities #----------------------- - - len_temp = len(entities) - # filtering only model-space enitities (no paper-space enitities) - if settings.var['paper_space_on']: - entities = [entity for entity in entities if entity.space != 0] - else: - entities = [entity for entity in entities if entity.space == 0] - - # filtering only objects with color from acceptedColorsList - if settings.var['colorFilter_on']: - entities = [entity for entity in entities if entity.color in settings.acceptedColors] - - # filtering only objects on layers from acceptedLayersList - if settings.var['layerFilter_on']: - #entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')] - entities = [entity for entity in entities if entity.layer in settings.acceptedLayers] - - # patch for incomplete layer table in HL2-DXF-files - if layersmap: - for entity in entities: - oblayer = entity.layer - if oblayer not in layersmap.keys(): - layer_obj = Layer(None, name=oblayer) - layersmap[oblayer] = layer_obj - layername_short = oblayer[:MAX_NAMELENGTH-1] - i = 0 #sufix for layernames cause Blender-objectnames-limits - while layername_short in layernamesmap.keys(): - i += 1 - suffix = str(i) #--todo--set zero-leading number format - layername_short = layername_short[:-2] + suffix - layernamesmap[oblayer] = layername_short - - # filtering only objects on not-frozen layers - if layersmap and not settings.var['layFrozen_on']: - entities = [entity for entity in entities if not layersmap[entity.layer].frozen] - - global activObjectLayer, activObjectName - activObjectLayer = '' - activObjectName = '' - - message = "Drawing dxf \'%ss\'..." %_type - cur_COUNTER += len_temp - len(entities) - settings.write(message, False) - settings.progress(cur_COUNTER, message) - if len(entities) > 0.1 / settings.obj_number: - show_progress = int(0.03 / settings.obj_number) - else: show_progress = 0 - cur_temp = 0 - - #print 'deb:drawer cur_COUNTER: ', cur_COUNTER #----------------------- - - for entity in entities: #----loop------------------------------------- - settings.write('\b.', False) - cur_COUNTER += 1 - if show_progress: - cur_temp += 1 - if cur_temp == show_progress: - settings.progress(cur_COUNTER, message) - cur_temp = 0 - #print 'deb:drawer show_progress=',show_progress #---------------- - - # get the layer group (just to make things a little cleaner) - if settings.var['group_bylayer_on'] and not block_def: - group = getGroup('l:%s' % layernamesmap[entity.layer]) - - if _type == 'insert': #---- INSERT and MINSERT=array -------------------- - if not settings.var['block_nn']: #----turn off support for noname BLOCKs - prefix = entity.name[:2] - if prefix in ('*X', '*U', '*D'): - #print 'deb:drawer entity.name:', entity.name #------------ - continue - if settings.var['blockFilter_on'] and not settings.accepted_block(entity.name): - continue - - #print 'deb:insert entity.loc:', entity.loc #---------------- - insertFlag = True - columns = entity.columns[0] - coldist = entity.columns[1] - rows = entity.rows[0] - rowdist = entity.rows[1] - deltaloc = [0,0,0] - #print 'deb:insert columns, rows:', columns, rows #----------- - for col in xrange(columns): - deltaloc[0] = col * coldist - for row in xrange(rows): - deltaloc[1] = row * rowdist - #print 'deb:insert col=%s, row=%s,deltaloc=%s' %(col, row, deltaloc) #------ - ob = entity.draw(settings, deltaloc) #-----draw BLOCK---------- - if block_def: - blockFlag = True - bl_loc = block_def[1] - ob.loc = [ob.loc[0]-bl_loc[0],ob.loc[1]-bl_loc[1],ob.loc[2]-bl_loc[2]] - else: blockFlag = False - setObjectProperties(ob, group, entity, settings, block_def) - if ob: - if settings.var['optimization'] <= settings.MIN: - #if settings.var['g_origin_on'] and not block_def: ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin - if settings.var['g_scale_on']: globalScaleOne(ob, insertFlag, blockFlag, settings.var['g_scale']) - settings.redraw() - else: oblist.append((ob, insertFlag, blockFlag)) - - else: #---draw entities except BLOCKs/INSERTs--------------------- - insertFlag = False - alt_obname = activObjectName - ob = entity.draw(settings) - if ob: - if M_OBJ and ob.type=='Mesh': #'Curve', 'Text' - if block_def: - blockFlag = True - bl_loc = block_def[1] - ob.loc = [ob.loc[0]-bl_loc[0],ob.loc[1]-bl_loc[1],ob.loc[2]-bl_loc[2]] - car_nr() - - elif ob.name != alt_obname: - if block_def: - blockFlag = True - bl_loc = block_def[1] - ob.loc = [ob.loc[0]-bl_loc[0],ob.loc[1]-bl_loc[1],ob.loc[2]-bl_loc[2]] - else: blockFlag = False - setObjectProperties(ob, group, entity, settings, block_def) - if settings.var['optimization'] <= settings.MIN: - #if settings.var['g_origin_on'] and not block_def: ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin - if settings.var['g_scale_on']: globalScaleOne(ob, insertFlag, blockFlag, settings.var['g_scale']) - settings.redraw() - else: oblist.append((ob, insertFlag, blockFlag)) - - #print 'deb:Finished drawing:', entities[0].type #------------------------ - message = "\nDrawing dxf\'%ss\' done!" % _type - settings.write(message, True) - - - -def globalScale(oblist, SCALE): #--------------------------------------------------------- - """Global_scale for list of all imported objects. - - oblist is a list of pairs (ob, insertFlag), where insertFlag=True/False - """ - #print 'deb:globalScale.oblist: ---------%\n', oblist #--------------------- - for l in oblist: - ob, insertFlag, blockFlag = l[0], l[1], l[2] - globalScaleOne(ob, insertFlag, blockFlag, SCALE) - - -def globalScaleOne(ob, insertFlag, blockFlag, SCALE): #--------------------------------------------------------- - """Global_scale imported object. - """ - #print 'deb:globalScaleOne ob: ', ob #--------------------- - if settings.var['g_origin_on'] and not blockFlag: - ob.loc = Mathutils.Vector(ob.loc) + settings.g_origin - - SCALE_MAT= Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) - if insertFlag: # by BLOCKs/INSERTs only insert-point coords must be scaled------------ - ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT - else: # entire scaling for all other imported objects ------------ - if ob.type == 'Mesh': - me = ob.getData(name_only=False, mesh=True) - #me = Mesh.Get(ob.name) - # set centers of all objects in (0,0,0) - #me.transform(ob.matrixWorld*SCALE_MAT) - #ob.loc = Mathutils.Vector([0,0,0]) - # preseve centers of all objects - me.transform(SCALE_MAT) - ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT - else: #--todo-- also for curves: neutral scale factor after import - ob.setMatrix(ob.matrixWorld*SCALE_MAT) - - -def setObjectProperties(ob, group, entity, settings, block_def): #----------------------- - """Link object to scene. - """ - - if not ob: #remi--todo----------------------- - message = "\nObject \'%s\' not found!" %entity - settings.write(message) - return - - if group: - setGroup(group, ob) # if object belongs to group - - if block_def: # if object belongs to BLOCK_def - Move it to layer nr19 - setGroup(block_def[0], ob) - #print 'deb:setObjectProperties \'%s\' set to block_def_group!' %ob.name #--------- - ob.layers = [19] - else: - #ob.layers = [i+1 for i in xrange(20)] #remi--todo------------ - ob.layers = [settings.var['target_layer']] - - # Set material for any objects except empties - if ob.type != 'Empty' and settings.var['material_on']: - setMaterial_from(entity, ob, settings, block_def) - - # Set the visibility - #if settings.layer_isOff(entity.layer): - if layersmap and layersmap[entity.layer].color < 0: # color is negative if layer is off - #ob.layers = [20] #remi--todo------------- - ob.restrictDisplay = True - ob.restrictRender = True - - #print 'deb:\n---------linking Object %s!' %ob.name #---------- - - - -def getGroup(name): #----------------------------------------------------------------- - """Returns a Blender group-object. - """ - try: - group = Group.Get(name) - except: # What is the exception? - group = Group.New(name) - return group - - -def setGroup(group, ob): #------------------------------------------------------------ - """Assigns object to Blender group. - """ - try: - group.objects.link(ob) - except: - group.objects.append(ob) #remi?--------------- - - - -def setMaterial_from(entity, ob, settings, block_def): #------------------------------------------------ - """ Set Blender-material for the object controled by item. - - Set Blender-material for the object - - controlled by settings.var['material_from'] - """ - if settings.var['material_from'] == 1: # 1= material from color - if entity.color_index == BYLAYER or entity.color_index == 256: - mat = settings.colMaterials(entity.layer) - elif entity.color_index == BYBLOCK or entity.color_index == 0: - #--todo-- looking for block.color_index - #mat = settings.colMaterials(block.color_index) - #if block_def: mat = settings.colMaterials(block_def[2]) - mat = settings.colMaterials(3) - else: - mat = settings.colMaterials(entity.color_index) - - elif settings.var['material_from'] == 2: # 2= material from layer_name - mat = settings.layMaterials(layername=entity.layer) - - elif settings.var['material_from'] == 3: # 3= material from layer+color - mat = settings.layMaterials(layername=entity.layer, color=entity.color_index) - -# elif settings.var['material_from'] == 4: # 4= material from block_name - -# elif settings.var['material_from'] == 5: # 5= material from XDATA - -# elif settings.var['material_from'] == 6: # 6= material from INI-file - - else: # set neutral material - try: - mat = Material.Get('dxf-neutral') - except: - mat = Material.New('dxf-neutral') - mat.setRGBCol(color_map[3]) - try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug - except: - mat.mode |= Material.Modes.SHADELESS # - mat.mode |= Material.Modes.WIRE - try: - #print 'deb:material mat:', mat #----------- - ob.setMaterials([mat]) #assigns Blender-material to object - except ValueError: - settings.write("material error - \'%s\'!" %mat) - ob.colbits = 0x01 # Set OB materials. - - - -def calcBulge(p1, p2, arc_res, triples=False): #------------------------------------------------- - """given startpoint, endpoint and bulge of arc, returns points/segments of its representation. - - Needs to take into account bulge sign. - negative = clockwise - positive = counter-clockwise - - to find center given two points, and arc angle - calculate radius - Cord = sqrt(start^2 + end^2) - S = (bulge*Cord)/2 - radius = ((Cord/2)^2+S^2)/2*S - angle of arc = 4*atan( bulge ) - angle from p1 to center is (180-angle)/2 - get vector pointing from p1 to p2 (p2 - p1) - normalize it and multiply by radius - rotate around p1 by angle to center, point to center. - start angle = angle between (center - p1) and worldX - end angle = angle between (center - p2) and worldX - - calculate the center, radius, start angle, and end angle - returns points/segments of its mesh representation - incl.startpoint, without endpoint - """ - - bulge = p1.bulge - p1 = Mathutils.Vector(p1.loc) - p2 = Mathutils.Vector(p2.loc) - cord = p2 - p1 # vector from p1 to p2 - clength = cord.length - s = (bulge * clength)/2.0 # sagitta (height) - radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula - angle = (degrees(4.0*atan(bulge))) # theta (included angle) - radial = cord.normalize() * radius # a radius length vector aligned with cord - delta = (180.0 - abs(angle))/2.0 # the angle from cord to center - if bulge < 0: delta = -delta - rmat = Mathutils.RotationMatrix(-delta, 3, 'Z') - center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center - #length = radians(abs(angle)) * radius - #print 'deb:calcBulge:\n angle, delta: ', angle, delta #---------------- - #print 'deb:center, radius: ', center, radius #---------------------- - startpoint = p1 - center - endpoint = p2 - center - #print 'deb:calcBulg: startpoint:', startpoint #--------- - #print 'deb:calcBulg: endpoint:', endpoint #--------- - - if not triples: #IF mesh-representation ----------- - if arc_res > 1024: arc_res = 1024 - elif arc_res < 4: arc_res = 4 - pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION - if pieces < 3: pieces = 3 - else: #IF curve-representation ------------------------------- - if arc_res > 32: arc_res = 32 - elif arc_res < 3: arc_res = 3 - pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION - if pieces < 2: pieces = 2 - - step = angle/pieces # set step so pieces * step = degrees in arc - stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - - if not triples: #IF mesh-representation ----------- - points = [startpoint] - point = startpoint - for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(-step*i,3,"Z") - point = stepmatrix * point - points.append(point) - points = [ point+center for point in points] - # vector to point convertion: - points = [list(point) for point in points] - return points, list(center) - - else: #IF curve-representation ------------------------------- - # correct Bezier curves representation for free segmented circles/arcs - step2 = radians(step * 0.5) - bulg = radius * (1 - cos(step2)) - deltaY = 4.0 * bulg / (3.0 * sin(step2) ) - #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #--------- - #print 'deb:calcArcCurve: step:\n', step #--------- - - #org handler0 = Mathutils.Vector(0.0, -deltaY, 0.0) - #handler = startmatrix * handler0 - #endhandler = endmatrix * handler0 - rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) - handler = rotMatr90 * startpoint - handler = - deltaY * handler.normalize() - endhandler = rotMatr90 * endpoint - endhandler = - deltaY * endhandler.normalize() - - points = [startpoint] - handlers1 = [startpoint + handler] - handlers2 = [startpoint - handler] - point = Mathutils.Vector(startpoint) - for i in xrange(int(pieces)-1): - point = stepmatrix * point - handler = stepmatrix * handler - handler1 = point + handler - handler2 = point - handler - points.append(point) - handlers1.append(handler1) - handlers2.append(handler2) - points.append(endpoint) - handlers1.append(endpoint + endhandler) - handlers2.append(endpoint - endhandler) - - points = [point + center for point in points] - handlers1 = [point + center for point in handlers1] - handlers2 = [point + center for point in handlers2] - - VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)] - #print 'deb:calcBulgCurve: handlers1:\n', handlers1 #--------- - #print 'deb:calcBulgCurve: points:\n', points #--------- - #print 'deb:calcBulgCurve: handlers2:\n', handlers2 #--------- - #print 'deb:calcBulgCurve: VectorTriples:\n', VectorTriples #--------- - return VectorTriples - - - - -def calcArc(center, radius, start, end, arc_res, triples): #----------------------------------------- - """calculate Points (or BezierTriples) for ARC/CIRCLEs representation. - - Given parameters of the ARC/CIRCLE, - returns points/segments (or BezierTriples) and centerPoint - """ - # center is currently set by object - # if start > end: start = start - 360 - if end > 360: end = end % 360.0 - - startmatrix = Mathutils.RotationMatrix(-start, 3, "Z") - startpoint = startmatrix * Mathutils.Vector(radius, 0, 0) - endmatrix = Mathutils.RotationMatrix(-end, 3, "Z") - endpoint = endmatrix * Mathutils.Vector(radius, 0, 0) - - if end < start: end +=360.0 - angle = end - start - #length = radians(angle) * radius - - if not triples: #IF mesh-representation ----------- - if arc_res > 1024: arc_res = 1024 - elif arc_res < 4: arc_res = 4 - pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION - if pieces < 3: pieces = 3 - step = angle/pieces # set step so pieces * step = degrees in arc - stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - - points = [startpoint] - point = startpoint - for i in xrange(int(pieces)-1): - point = stepmatrix * point - points.append(point) - points.append(endpoint) - - if center: - centerVec = Mathutils.Vector(center) - #points = [point + centerVec for point in points()] - points = [point + centerVec for point in points] - # vector to point convertion: - points = [list(point) for point in points] - return points - - else: #IF curve-representation --------------- - if arc_res > 32: arc_res = 32 - elif arc_res < 3: arc_res = 3 - pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION - if pieces < 2: pieces = 2 - step = angle/pieces # set step so pieces * step = degrees in arc - stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") - - # correct Bezier curves representation for free segmented circles/arcs - step2 = radians(step * 0.5) - bulg = radius * (1 - cos(step2)) - deltaY = 4.0 * bulg / (3.0 * sin(step2) ) - #print 'deb:calcArcCurve: bulg, deltaY:\n', bulg, deltaY #--------- - #print 'deb:calcArcCurve: step:\n', step #--------- - handler0 = Mathutils.Vector(0.0, -deltaY, 0.0) - - points = [startpoint] - handler = startmatrix * handler0 - endhandler = endmatrix * handler0 - handlers1 = [startpoint + handler] - handlers2 = [startpoint - handler] - point = Mathutils.Vector(startpoint) - for i in xrange(int(pieces)-1): - point = stepmatrix * point - handler = stepmatrix * handler - handler1 = point + handler - handler2 = point - handler - points.append(point) - handlers1.append(handler1) - handlers2.append(handler2) - points.append(endpoint) - handlers1.append(endpoint + endhandler) - handlers2.append(endpoint - endhandler) - VectorTriples = [list(h1)+list(p)+list(h2) for h1,p,h2 in zip(handlers1, points, handlers2)] - #print 'deb:calcArcCurve: handlers1:\n', handlers1 #--------- - #print 'deb:calcArcCurve: points:\n', points #--------- - #print 'deb:calcArcCurve: handlers2:\n', handlers2 #--------- - #print 'deb:calcArcCurve: VectorTriples:\n', VectorTriples #--------- - return VectorTriples - - -def drawCurveCircle(circle): #--- no more used -------------------------------------------- - """Given a dxf circle object return a blender circle object using curves. - """ - c = Curve.New('circle') # create new curve data - center = circle.loc - radius = circle.radius - - p1 = (0, -radius, 0) - p2 = (radius, 0, 0) - p3 = (0, radius, 0) - p4 = (-radius, 0, 0) - - p1 = BezTriple.New(p1) - p2 = BezTriple.New(p2) - p3 = BezTriple.New(p3) - p4 = BezTriple.New(p4) - - curve = c.appendNurb(p1) - curve.append(p2) - curve.append(p3) - curve.append(p4) - for point in curve: - point.handleTypes = [AUTO, AUTO] - point.radius = 1.0 - curve.flagU = 1 # Set curve cyclic - c.update() - - ob = Object.New('Curve', 'circle') # make curve object - return ob - - -def drawCurveArc(self): #---- only for ELLIPSE ------------------------------------------------------------- - """Given a dxf ELLIPSE object return a blender_curve. - """ - center = self.loc - radius = self.radius - start = self.start_angle - end = self.end_angle - - if start > end: - start = start - 360.0 - startmatrix = Mathutils.RotationMatrix(start, 3, "Z") - startpoint = startmatrix * Mathutils.Vector((radius, 0, 0)) - endmatrix = Mathutils.RotationMatrix(end, 3, "Z") - endpoint = endmatrix * Mathutils.Vector((radius, 0, 0)) - # Note: handles must be tangent to arc and of correct length... - - a = Curve.New('arc') # create new curve data - - p1 = (0, -radius, 0) - p2 = (radius, 0, 0) - p3 = (0, radius, 0) - p4 = (-radius, 0, 0) - - p1 = BezTriple.New(p1) - p2 = BezTriple.New(p2) - p3 = BezTriple.New(p3) - p4 = BezTriple.New(p4) - - curve = a.appendNurb(p1) - curve.append(p2) - curve.append(p3) - curve.append(p4) - for point in curve: - point.handleTypes = [AUTO, AUTO] - point.radius = 1.0 - curve.flagU = 1 # Set curve cyclic - a.update() - - ob = Object.New('Curve', 'arc') # make curve object - return ob - - - - -# GUI STUFF -----#################################################----------------- -from Blender.BGL import glColor3f, glRecti, glClear, glRasterPos2d - -EVENT_NONE = 1 -EVENT_START = 2 -EVENT_REDRAW = 3 -EVENT_LOAD_INI = 4 -EVENT_SAVE_INI = 5 -EVENT_RESET = 6 -EVENT_CHOOSE_INI = 7 -EVENT_CHOOSE_DXF = 8 -EVENT_HELP = 9 -EVENT_PRESETCURV = 10 -EVENT_PRESETS = 11 -EVENT_DXF_DIR = 12 -# = 13 -EVENT_LIST = 14 -EVENT_ORIGIN = 15 -EVENT_SCALE = 16 -EVENT_PRESET2D = 20 -EVENT_PRESET3D = 21 -EVENT_EXIT = 100 -GUI_EVENT = EVENT_NONE - -GUI_A = {} # GUI-buttons dictionary for parameter -GUI_B = {} # GUI-buttons dictionary for drawingTypes - -# settings default, initialize ------------------------ - -points_as_menu = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4|..curve.vertex %x5" -lines_as_menu = "convert to: %t|..edge %x1|mesh %x2|..thin cylinder %x3|thin box %x4|Bezier-curve %x5|..NURBS-curve %x6" -mlines_as_menu = "convert to: %t|..edge %x1|..mesh %x2|..thin cylinder %x3|..thin box %x|..curve %x5" -plines_as_menu = "convert to: %t|..edge %x1|mesh %x2|..thin cylinder %x3|..thin box %x4|Bezier-curve %x5|NURBS-curve %x6" -splines_as_menu = "convert to: %t|mesh %x2|..thin cylinder %x3|..thin box %x4|Bezier-curve %x5|NURBS-curve %x6" -plines3_as_menu = "convert to: %t|..edge %x1|mesh %x2|..thin cylinder %x3|..thin box %x4|Bezier-curve %x5|NURBS-curve %x6" -plmesh_as_menu = "convert to: %t|..edge %x1|mesh %x2|..NURBS-surface %x6" -solids_as_menu = "convert to: %t|..edge %x1|mesh %x2" -blocks_as_menu = "convert to: %t|dupliGroup %x1|..real.Group %x2|..exploded %x3" -texts_as_menu = "convert to: %t|text %x1|..mesh %x2|..curve %x5" -material_from_menu= "material from: %t|..LINESTYLE %x7|COLOR %x1|LAYER %x2|..LAYER+COLOR %x3|..BLOCK %x4|..XDATA %x5|..INI-File %x6" -g_scale_list = ''.join(( - 'scale factor: %t', - '|user def. %x12', - '|yard to m %x8', - '|feet to m %x7', - '|inch to m %x6', - '| x 1000 %x3', - '| x 100 %x2', - '| x 10 %x1', - '| x 1 %x0', - '| x 0.1 %x-1', - '| x 0.01 %x-2', - '| x 0.001 %x-3', - '| x 0.0001 %x-4', - '| x 0.00001 %x-5')) - -#print 'deb: g_scale_list', g_scale_list #----------- - -dxfFileName = Draw.Create("") -iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION) -user_preset = 0 -config_UI = Draw.Create(0) #switch_on/off extended config_UI -g_scale_as = Draw.Create(int(log10(G_SCALE))) - - -keywords_org = { - 'curves_on' : 0, - 'optimization': 2, - 'one_mesh_on': 1, - 'vGroup_on' : 1, - 'dummy_on' : 0, - 'views_on' : 0, - 'cams_on' : 0, - 'lights_on' : 0, - 'xref_on' : 1, - 'block_nn': 0, - 'blockFilter_on': 0, - 'layerFilter_on': 0, - 'colorFilter_on': 0, - 'groupFilter_on': 0, - 'newScene_on' : 1, - 'target_layer' : TARGET_LAYER, - 'group_bylayer_on' : GROUP_BYLAYER, - 'g_originX' : G_ORIGIN_X, - 'g_originY' : G_ORIGIN_Y, - 'g_originZ' : G_ORIGIN_Z, - 'g_origin_on': 0, - 'g_scale' : float(G_SCALE), -# 'g_scale_as': int(log10(G_SCALE)), # 0, - 'g_scale_on': 0, - 'thick_on' : 1, - 'thick_min' : float(MIN_THICK), - 'thick_force': 0, - 'width_on' : 1, - 'width_min' : float(MIN_WIDTH), - 'width_force': 0, - 'dist_on' : 1, - 'dist_min' : float(MIN_DIST), - 'dist_force': 0, - 'material_on': 1, - 'material_from': 2, - 'fill_on' : 1, - 'meshSmooth_on': 1, - 'curve_res' : CURV_RESOLUTION, - 'curve_arc' : CURVARC_RESOLUTION, - 'arc_res' : ARC_RESOLUTION, - 'arc_rad' : ARC_RADIUS, - 'thin_res' : THIN_RESOLUTION, - 'pl_trim_max' : TRIM_LIMIT, - 'pl_trim_on': 1, - 'plmesh_flip': 0, - 'normals_out': 0, - 'paper_space_on': 0, - 'layFrozen_on': 0, - 'Z_force_on': 0, - 'Z_elev': float(ELEVATION), - 'points_as' : 2, - 'lines_as' : 2, - 'mlines_as' : 2, - 'plines_as' : 2, - 'splines_as' : 5, - 'plines3_as': 2, - 'plmesh_as' : 2, - 'solids_as' : 2, - 'blocks_as' : 1, - 'texts_as' : 1 - } - -drawTypes_org = { - 'point' : 1, - 'line' : 1, - 'arc' : 1, - 'circle': 1, - 'ellipse': 1, - 'mline' : 0, - 'polyline': 1, - 'spline': 1, - 'plmesh': 1, - 'pline3': 1, - 'lwpolyline': 1, - 'text' : 1, - 'mtext' : 0, - 'block' : 1, - 'insert': 1, - 'solid' : 1, - 'trace' : 1, - 'face' : 1, -# 'view' : 0, - } - -# creating of GUI-buttons -# GUI_A - GUI-buttons dictionary for parameter -# GUI_B - GUI-buttons dictionary for drawingTypes -for k, v in keywords_org.iteritems(): - GUI_A[k] = Draw.Create(v) -for k, v in drawTypes_org.iteritems(): - GUI_B[k] = Draw.Create(v) -#print 'deb:init GUI_A: ', GUI_A #--------------- -#print 'deb:init GUI_B: ', GUI_B #--------------- - -model_space_on = Draw.Create(1) - -# initialize settings-object controls how dxf entities are drawn -settings = Settings(keywords_org, drawTypes_org) - - -def update_RegistryKey(key, item): # - """updates key in Blender.Registry - """ - cache = True # data is also saved to a file - rdict = Registry.GetKey('DXF_Importer', cache) - if not rdict: rdict = {} - if item: - rdict[key] = item - Registry.SetKey('DXF_Importer', rdict, cache) - #print 'deb:update_RegistryKey rdict', rdict #--------------- - - -def check_RegistryKey(key): - """ check if the key is already there (saved on a previous execution of this script) - """ - cache = True # data is also saved to a file - rdict = Registry.GetKey('DXF_Importer', cache) - #print 'deb:check_RegistryKey rdict:', rdict #---------------- - if rdict: # if found, get the values saved there - try: - item = rdict[key] - return item - except: - #update_RegistryKey() # if data isn't valid rewrite it - pass - -def saveConfig(): #--todo----------------------------------------------- - """Save settings/config/materials from GUI to INI-file. - - Write all config data to INI-file. - """ - global iniFileName - - iniFile = iniFileName.val - #print 'deb:saveConfig inifFile: ', inifFile #---------------------- - if iniFile.lower().endswith(INIFILE_EXTENSION): - - #--todo-- sort key.list for output - #key_list = GUI_A.keys().val - #key_list.sort() - #for key in key_list: - # l_name, l_data = key, GUI_A[key].val - # list_A - - output_str = '[%s,%s]' %(GUI_A, GUI_B) - if output_str =='None': - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no config-data present to save!') - else: - #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct - if sys.exists(iniFile): - f = file(iniFile, 'r') - header_str = f.readline() - f.close() - if header_str.startswith(INIFILE_HEADER[0:13]): - if Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1: - save_ok = True - else: save_ok = False - elif Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile + - '|Alert: this file has no valid ImportDXF-header| ! it may belong to another aplication !') == 1: - save_ok = True - else: save_ok = False - else: save_ok = True - - if save_ok: - # replace: ',' -> ',\n' - # replace: '{' -> '\n{\n' - # replace: '}' -> '\n}\n' - output_str = ',\n'.join(output_str.split(',')) - output_str = '\n}'.join(output_str.split('}')) - output_str = '{\n'.join(output_str.split('{')) - try: - f = file(iniFile, 'w') - f.write(INIFILE_HEADER + '\n# this is a comment line\n') - f.write(output_str) - f.close() - #Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) - except: - Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile) - - else: - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid name/extension for INI-file selected!') - print "DXF importer: Alert!: no valid INI-file selected." - if not iniFile: - if dxfFileName.val.lower().endswith('.dxf'): - iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION - - -def loadConfig(): #remi--todo----------------------------------------------- - """Load settings/config/materials from INI-file. - - Read material-assignements from config-file. - """ - #070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename) - global iniFileName, GUI_A, GUI_B - - iniFile = iniFileName.val - update_RegistryKey('iniFileName', iniFile) - #print 'deb:loadConfig iniFile: ', iniFile #---------------------- - if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile): - f = file(iniFile, 'r') - header_str = f.readline() - if header_str.startswith(INIFILE_HEADER): - data_str = f.read() - f.close() - #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #----------------- - data = eval(data_str) - for k, v in data[0].iteritems(): - try: GUI_A[k].val = v - except: GUI_A[k] = Draw.Create(v) - for k, v in data[1].iteritems(): - try: GUI_B[k].val = v - except: GUI_B[k] = Draw.Create(v) - else: - f.close() - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) - else: - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!') - print "DXF importer: Alert!: no valid INI-file selected." - if not iniFileName: - if dxfFileName.val.lower().endswith('.dxf'): - iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION - - - -def updateConfig(keywords, drawTypes): #----------------------------------------------- - """updates GUI_settings with given dictionaries - - """ - global GUI_A, GUI_B - #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- - for k, v in keywords.iteritems(): - GUI_A[k].val = v - for k, v in drawTypes.iteritems(): - GUI_B[k].val = v - -def resetDefaultConfig(): #----------------------------------------------- - """Resets settings/config/materials to defaults. - - """ - #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- - updateConfig(keywords_org, drawTypes_org) - - -def presetConfig_curv(activate): #----------------------------------------------- - """Sets settings/config/materials for curve representation. - - """ - global GUI_A - if activate: - GUI_A['curves_on'].val = 1 - GUI_A['points_as'].val = 5 - GUI_A['lines_as'].val = 5 - GUI_A['mlines_as'].val = 5 - GUI_A['plines_as'].val = 5 - GUI_A['splines_as'].val = 5 - GUI_A['plines3_as'].val = 5 - else: - GUI_A['curves_on'].val = 0 - GUI_A['points_as'].val = 2 - GUI_A['lines_as'].val = 2 - GUI_A['mlines_as'].val = 2 - GUI_A['plines_as'].val = 2 - GUI_A['splines_as'].val = 6 - GUI_A['plines3_as'].val = 2 - - -def resetDefaultConfig_2D(): #----------------------------------------------- - """Sets settings/config/materials to defaults 2D. - - """ - presetConfig_curv(1) - keywords2d = { - 'views_on' : 0, - 'cams_on' : 0, - 'lights_on' : 0, - 'vGroup_on' : 1, - 'thick_on' : 0, - 'thick_force': 0, - 'width_on' : 1, - 'width_force': 0, - 'dist_on' : 1, - 'dist_force': 0, - 'fill_on' : 0, - 'pl_trim_on': 1, - 'Z_force_on': 0, - 'meshSmooth_on': 0, - 'solids_as' : 2, - 'blocks_as' : 1, - 'texts_as' : 1 - } - - drawTypes2d = { - 'point' : 1, - 'line' : 1, - 'arc' : 1, - 'circle': 1, - 'ellipse': 1, - 'mline' : 0, - 'polyline': 1, - 'spline': 1, - 'plmesh': 0, - 'pline3': 1, - 'lwpolyline': 1, - 'text' : 1, - 'mtext' : 0, - 'block' : 1, - 'insert': 1, - 'solid' : 1, - 'trace' : 1, - 'face' : 0, -# 'view' : 0, - } - - updateConfig(keywords2d, drawTypes2d) - -def resetDefaultConfig_3D(): #----------------------------------------------- - """Sets settings/config/materials to defaults 3D. - - """ - presetConfig_curv(0) - keywords3d = { -# 'views_on' : 1, -# 'cams_on' : 1, -# 'lights_on' : 1, - 'vGroup_on' : 1, - 'thick_on' : 1, - 'thick_force': 0, - 'width_on' : 1, - 'width_force': 0, - 'dist_on' : 1, - 'dist_force': 0, - 'fill_on' : 1, - 'pl_trim_on': 1, - 'Z_force_on': 0, - 'meshSmooth_on': 1, - 'solids_as' : 2, - 'blocks_as' : 1, - 'texts_as' : 1 - } - - drawTypes3d = { - 'point' : 1, - 'line' : 1, - 'arc' : 1, - 'circle': 1, - 'ellipse': 1, - 'mline' : 0, - 'polyline': 1, - 'spline': 1, - 'plmesh': 1, - 'pline3': 1, - 'lwpolyline': 1, - 'text' : 0, - 'mtext' : 0, - 'block' : 1, - 'insert': 1, - 'solid' : 1, - 'trace' : 1, - 'face' : 1, -# 'view' : 0, - } - - updateConfig(keywords3d, drawTypes3d) - - -def inputGlobalScale(): - """Pop-up UI-Block for global scale factor - """ - global GUI_A - #print 'deb:inputGlobalScale ##########' #------------ - x_scale = Draw.Create(GUI_A['g_scale'].val) - block = [] - #block.append("global translation vector:") - block.append(("", x_scale, 0.0, 10000000.0)) - - retval = Draw.PupBlock("set global scale factor:", block) - - GUI_A['g_scale'].val = float(x_scale.val) - - -def inputOriginVector(): - """Pop-up UI-Block for global translation vector - """ - global GUI_A - #print 'deb:inputOriginVector ##########' #------------ - x_origin = Draw.Create(GUI_A['g_originX'].val) - y_origin = Draw.Create(GUI_A['g_originY'].val) - z_origin = Draw.Create(GUI_A['g_originZ'].val) - block = [] - #block.append("global translation vector:") - block.append(("X: ", x_origin, -100000000.0, 100000000.0)) - block.append(("Y: ", y_origin, -100000000.0, 100000000.0)) - block.append(("Z: ", z_origin, -100000000.0, 100000000.0)) - - retval = Draw.PupBlock("set global translation vector:", block) - - GUI_A['g_originX'].val = x_origin.val - GUI_A['g_originY'].val = y_origin.val - GUI_A['g_originZ'].val = z_origin.val - - -def draw_UI(): #----------------------------------------------------------------- - """ Draw startUI and setup Settings. - """ - global GUI_A, GUI_B #__version__ - global user_preset, iniFileName, dxfFileName, config_UI, g_scale_as - global model_space_on - - # This is for easy layout changes - but_0c = 70 #button 1.column width - but_1c = 70 #button 1.column width - but_2c = 70 #button 2.column - but_3c = 70 #button 3.column - menu_margin = 10 - butt_margin = 10 - menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width - - simple_menu_h = 100 - extend_menu_h = 350 - y = simple_menu_h # y is menu upper.y - if config_UI.val: y += extend_menu_h - x = 20 #menu left.x - but0c = x + menu_margin #buttons 0.column position.x - but1c = but0c + but_0c + butt_margin - but2c = but1c + but_1c + butt_margin - but3c = but2c + but_2c + butt_margin - but4c = but3c + but_3c - - # Here starts menu ----------------------------------------------------- - #glClear(GL_COLOR_BUFFER_BIT) - #glRasterPos2d(8, 125) - - y += 30 - colorbox(x, y+20, x+menu_w+menu_margin*2, menu_margin) - Draw.Label("DXF/DWG-Importer v" + __version__, but0c, y, menu_w, 20) - - if config_UI.val: - b0, b0_ = but0c, but_0c + butt_margin - b1, b1_ = but1c, but_1c - y_top = y - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_B['point'] = Draw.Toggle('POINT', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['point'].val, "support dxf-POINT on/off") - if GUI_B['point'].val: - GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, b1, y, b1_, 20, GUI_A['points_as'].val, "select target Blender-object") -# Draw.Label('-->', but2c, y, but_2c, 20) - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['line'] = Draw.Toggle('LINE...etc', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off") - if GUI_B['line'].val: - GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['lines_as'].val, "select target Blender-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['mline'] = Draw.Toggle('..MLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['mline'].val, "(*todo)support dxf-MLINE on/off") - if GUI_B['mline'].val: - GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['mlines_as'].val, "select target Blender-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['spline'] = Draw.Toggle('SPLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['spline'].val, "support dxf-SPLINE on/off") - if GUI_B['spline'].val: - GUI_A['splines_as'] = Draw.Menu(splines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['splines_as'].val, "select target Blender-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['polyline'] = Draw.Toggle('2D/LWPLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off") - if GUI_B['polyline'].val: - GUI_A['plines_as'] = Draw.Menu(plines_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plines_as'].val, "select target Blender-object") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_B['pline3'] = Draw.Toggle('3D-PLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off") - if GUI_B['pline3'].val: - GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plines3_as'].val, "select target Blender-object") - Draw.EndAlign() - - y_down = y - # ----------------------------------------------- - - y = y_top - b0, b0_ = but2c, but_2c + butt_margin - b1, b1_ = but3c, but_3c - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_B['plmesh'] = Draw.Toggle('PL-MESH/FACE', EVENT_NONE, b0, y, b0_+b1_-40, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off") -# GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu, EVENT_NONE, but1c, y, but_1c, 20, GUI_A['plmesh_as'].val, "select target Blender-object") - GUI_A['plmesh_flip'] = Draw.Toggle('N', EVENT_NONE, b1+b1_-40, y, 20, 20, GUI_A['plmesh_flip'].val, "flip DXF normals on/off") - GUI_A['normals_out'] = Draw.Toggle('N', EVENT_NONE, b1+b1_-20, y, 20, 20, GUI_A['normals_out'].val, "force Blender normals to outside on/off") - Draw.EndAlign() - - y -= 20 - GUI_B['solid'] = Draw.Toggle('SOLID', EVENT_NONE, b0, y, b0_, 20, GUI_B['solid'].val, "support dxf-SOLID and TRACE on/off") - GUI_B['face'] = Draw.Toggle('3DFACE', EVENT_NONE, b1, y, b1_, 20, GUI_B['face'].val, "support dxf-3DFACE on/off") -# GUI_A['solids_as'] = Draw.Menu(solids_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['solids_as'].val, "select target Blender-object") - #print 'deb:support solid, trace', GUI_B['trace'].val, GUI_B['solid'].val # ------------ - - - y -= 20 - GUI_B['text'] = Draw.Toggle('TEXT', EVENT_NONE, b0, y, b0_, 20, GUI_B['text'].val, "support dxf-TEXT on/off") - GUI_B['mtext'] = Draw.Toggle('..MTEXT', EVENT_NONE, b1, y, b1_, 20, GUI_B['mtext'].val, "(*todo)support dxf-MTEXT on/off") -# GUI_A['texts_as'] = Draw.Menu(texts_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['texts_as'].val, "select target Blender-object") - - y -= 20 - Draw.BeginAlign() - GUI_B['block'] = Draw.Toggle('BLOCK', EVENT_REDRAW, b0, y, b0_-30, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") - GUI_B['insert'].val = GUI_B['block'].val - if GUI_B['block'].val: - GUI_A['block_nn'] = Draw.Toggle('n', EVENT_NONE, b1-30, y, 15, 20, GUI_A['block_nn'].val, "support hatch/noname BLOCKs *X... on/off") - GUI_A['xref_on'] = Draw.Toggle('Xref', EVENT_NONE, b1-15, y, 35, 20, GUI_A['xref_on'].val, "support for XREF-BLOCKs (place holders) on/off") - GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, b1+20, y, b1_-20, 20, GUI_A['blocks_as'].val, "select target representation for imported BLOCKs") - Draw.EndAlign() - - - y -= 20 - y -= 20 - - Draw.BeginAlign() - GUI_A['views_on'] = Draw.Toggle('views', EVENT_NONE, b0, y, b0_-25, 20, GUI_A['views_on'].val, "imports VIEWs and VIEWPORTs as cameras on/off") - GUI_A['cams_on'] = Draw.Toggle('..cams', EVENT_NONE, b1-25, y, b1_-25, 20, GUI_A['cams_on'].val, "(*todo) support ASHADE cameras on/off") - GUI_A['lights_on'] = Draw.Toggle('..lights', EVENT_NONE, b1+25, y, b1_-25, 20, GUI_A['lights_on'].val, "(*todo) support AVE_RENDER lights on/off") - Draw.EndAlign() - - - if y < y_down: y_down = y - # -----end supported objects-------------------------------------- - - y_top = y_down - y = y_top - y -= 10 - y -= 20 - but_ = menu_w / 6 - b0 = but0c + (menu_w - but_*6)/2 - Draw.BeginAlign() - GUI_A['paper_space_on'] = Draw.Toggle('paper', EVENT_NONE, b0+but_*0, y, but_, 20, GUI_A['paper_space_on'].val, "import only from Paper-Space on/off") - GUI_A['layFrozen_on'] = Draw.Toggle ('frozen', EVENT_NONE, b0+but_*1, y, but_, 20, GUI_A['layFrozen_on'].val, "import also from frozen LAYERs on/off") - GUI_A['layerFilter_on'] = Draw.Toggle('..layer', EVENT_NONE, b0+but_*2, y, but_, 20, GUI_A['layerFilter_on'].val, "(*todo) LAYER filtering on/off") - GUI_A['colorFilter_on'] = Draw.Toggle('..color', EVENT_NONE, b0+but_*3, y, but_, 20, GUI_A['colorFilter_on'].val, "(*todo) COLOR filtering on/off") - GUI_A['groupFilter_on'] = Draw.Toggle('..group', EVENT_NONE, b0+but_*4, y, but_, 20, GUI_A['groupFilter_on'].val, "(*todo) GROUP filtering on/off") - GUI_A['blockFilter_on'] = Draw.Toggle('..block', EVENT_NONE, b0+but_*5, y, but_, 20, GUI_A['blockFilter_on'].val, "(*todo) BLOCK filtering on/off") - #GUI_A['dummy_on'] = Draw.Toggle('-', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dummy_on'].val, "dummy on/off") - Draw.EndAlign() - - # -----end filters-------------------------------------- - - b0, b0_ = but0c, but_0c + butt_margin - b1, b1_ = but1c, but_1c - - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_A['g_origin_on'] = Draw.Toggle('glob.reLoc', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_origin_on'].val, "global relocate all DXF objects on/off") - if GUI_A['g_origin_on'].val: - tmp = Draw.PushButton('=', EVENT_ORIGIN, b1, y, 20, 20, "edit relocation-vector (x,y,z in DXF units)") - origin_str = '(%.4f, %.4f, %.4f)' % ( - GUI_A['g_originX'].val, - GUI_A['g_originY'].val, - GUI_A['g_originZ'].val - ) - tmp = Draw.Label(origin_str, b1+20, y, 300, 20) - #GUI_A['g_origin'] = Draw.String('', EVENT_ORIGIN, b1, y, b1_, 20, GUI_A['g_origin'].val, "global translation-vector (x,y,z) in DXF units") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['g_scale_on'].val, "global scale all DXF objects on/off") - if GUI_A['g_scale_on'].val: - g_scale_as = Draw.Menu(g_scale_list, EVENT_SCALE, b1, y, 45, 20, g_scale_as.val, "factor for scaling the DXFdata") - if g_scale_as.val == 12: - pass - else: - if g_scale_as.val == 6: #scale inches to meters - GUI_A['g_scale'].val = 0.0254000 - elif g_scale_as.val == 7: #scale feets to meters - GUI_A['g_scale'].val = 0.3048000 - elif g_scale_as.val == 8: #scale yards to meters - GUI_A['g_scale'].val = 0.9144000 - else: - GUI_A['g_scale'].val = 10.0 ** int(g_scale_as.val) - scale_float = GUI_A['g_scale'].val - if scale_float < 0.000001 or scale_float > 1000000: - scale_str = ' = %s' % GUI_A['g_scale'].val - else: - scale_str = ' = %.6f' % GUI_A['g_scale'].val - Draw.Label(scale_str, b1+45, y, 200, 20) - Draw.EndAlign() - - y_down = y - # -----end material,translate,scale------------------------------------------ - - b0, b0_ = but0c, but_0c + butt_margin - b1, b1_ = but1c, but_1c - - y_top = y_down - y = y_top - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_A['meshSmooth_on'] = Draw.Toggle('smooth', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['meshSmooth_on'].val, "mesh smooth for circles/arc-segments on/off") - GUI_A['pl_trim_on'] = Draw.Toggle('trim', EVENT_NONE, b1-20, y, 32, 20, GUI_A['pl_trim_on'].val, "clean intersection of POLYLINE-wide-segments on/off") - GUI_A['pl_trim_max'] = Draw.Number('', EVENT_NONE, b1+12, y, b1_-12, 20, GUI_A['pl_trim_max'].val, 0, 5, "threshold intersection of POLYLINE-wide-segments: 0.0-5.0") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() -# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 64, "thin cylinder resolution - number of segments (4-64)") - GUI_A['arc_rad'] = Draw.Number('bR:', EVENT_NONE, b0, y, b0_, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution (0.01-100)") - GUI_A['arc_res'] = Draw.Number('', EVENT_NONE, b1, y, b1_/2, 20, GUI_A['arc_res'].val, 3, 500, "arc/circle resolution - number of segments (3-500)") - GUI_A['fill_on'] = Draw.Toggle('caps', EVENT_NONE, b1+b1_/2, y, b1_/2, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs/closed curves on/off") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['curve_arc'] = Draw.Number('', EVENT_NONE, b0, y, b0_/2, 20, GUI_A['curve_arc'].val, 3, 32, "Bezier circle: amount of segments: 3-32") - GUI_A['curve_res'] = Draw.Number('', EVENT_NONE, b0+b0_/2, y, b0_/2, 20, GUI_A['curve_res'].val, 1, 128, "Set the Curve's U-resolution value: 1-128") - GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_PRESETCURV, b1, y, b1_, 20, GUI_A['curves_on'].val, "set Curve as target object type on/off") - Draw.EndAlign() - - y -= 20 - GUI_A['group_bylayer_on'] = Draw.Toggle('Layer', EVENT_NONE, b0, y, 30, 20, GUI_A['group_bylayer_on'].val, "DXF-entities group by layer on/off") - GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, b0+30, y, b1_-10, 20, GUI_A['vGroup_on'].val, "sort faces into VertexGroups on/off") - GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, b1+10, y, b1_-10, 20, GUI_A['one_mesh_on'].val, "draw DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") - - y -= 30 - Draw.BeginAlign() - GUI_A['material_on'] = Draw.Toggle('material', EVENT_REDRAW, b0, y, b0_-20, 20, GUI_A['material_on'].val, "support for material assignment on/off") - if GUI_A['material_on'].val: - GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, b1-20, y, b1_+20, 20, GUI_A['material_from'].val, "material assignment from?") - Draw.EndAlign() - - y_down = y - # ----------------------------------------------- - - b0, b0_ = but2c, but_2c + butt_margin - b1, b1_ = but3c, but_3c - - y = y_top - y -= 10 - y -= 20 - Draw.BeginAlign() - GUI_A['Z_force_on'] = Draw.Toggle('.elevation', EVENT_REDRAW, b0, y, b0_, 20, GUI_A['Z_force_on'].val, ".set objects Z-coordinates to elevation on/off") - if GUI_A['Z_force_on'].val: - GUI_A['Z_elev'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['Z_elev'].val, -1000, 1000, "set default elevation(Z-coordinate)") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['dist_on'].val, "support distance on/off") - GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, b0+b0_-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off") - GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['dist_min'].val, 0, 10, "minimal length/distance (double.vertex removing)") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['thick_on'].val, "support thickness on/off") - GUI_A['thick_force'] = Draw.Toggle('F', EVENT_REDRAW, b0+b0_-20, y, 20, 20, GUI_A['thick_force'].val, "force for thickness at least limiter value on/off") - if GUI_A['thick_force'].val: - GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['thick_min'].val, 0, 10, "minimal value for thickness") - Draw.EndAlign() - - y -= 20 - Draw.BeginAlign() - GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, b0, y, b0_-20, 20, GUI_A['width_on'].val, "support width on/off") - GUI_A['width_force'] = Draw.Toggle('F', EVENT_REDRAW, b0+b0_-20, y, 20, 20, GUI_A['width_force'].val, "force for width at least limiter value on/off") - if GUI_A['width_force'].val: - GUI_A['width_min'] = Draw.Number('', EVENT_NONE, b1, y, b1_, 20, GUI_A['width_min'].val, 0, 10, "minimal value for width") - Draw.EndAlign() - - y -= 30 - but, but_ = but2c, 25 - Draw.BeginAlign() - Draw.EndAlign() - - if y < y_down: y_down = y - # -----end options -------------------------------------- - - - #-------------------------------------- - y_top = y_down - y = y_top - #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved") - y -= 30 - Draw.BeginAlign() - Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file from project directory') - iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_1c-60, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file") - but = but4c-60 - Draw.PushButton('#', EVENT_PRESETS, but, y, 20, 20, "toggle Preset-INI-files") - Draw.PushButton('L', EVENT_LOAD_INI, but+20, y, 20, 20, 'Loads configuration from ini-file: %s' % iniFileName.val) - Draw.PushButton('S', EVENT_SAVE_INI, but+40, y, 20, 20, 'Saves configuration to ini-file: %s' % iniFileName.val) - Draw.EndAlign() - - - b0, b0_ = but2c, but_2c + butt_margin - b1, b1_ = but3c, but_3c - - y = simple_menu_h - bm = butt_margin/2 - - #y -= 10 - Draw.BeginAlign() - Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF/DWG-file for import') - dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF/DWG-file or type *.dxf/*.dwg for multiple files") - Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'set filter for import all files from this directory') - Draw.EndAlign() - - y -= 30 - config_UI = Draw.Toggle('CONFIG', EVENT_REDRAW, but0c, y, but_0c+bm, 20, config_UI.val, 'Advanced configuration on/off' ) - Draw.BeginAlign() - but, but_ = but1c, but_1c+bm - but_ /= 3 - Draw.PushButton('X', EVENT_RESET, but, y, 15, 20, "reset configuration to defaults") - Draw.PushButton('2D', EVENT_PRESET2D, but+but_, y, but_, 20, 'set configuration for 2D import') - Draw.PushButton('3D', EVENT_PRESET3D, but+(but_*2), y, but_, 20, 'set configuration for 3D import') - Draw.EndAlign() - - Draw.BeginAlign() - GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['newScene_on'].val, "create new Scene for each imported dxf file on/off") - GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['target_layer'].val, 1, 18, "target Blender-layer (<19> reserved for block_definitions)") - Draw.EndAlign() - - y -= 40 - Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c+bm, 20, '' ) - Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c+bm, 20, 'calls DXF-Importer Manual Page on Wiki.Blender.org') - Draw.BeginAlign() - GUI_A['optimization'] = Draw.Number('', EVENT_NONE, but2c, y+20, 40, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=SilentMode") - Draw.EndAlign() - Draw.BeginAlign() - Draw.PushButton('TEST', EVENT_LIST, but2c, y, 40, 20, 'DXF-Analyze-Tool: reads data from selected dxf file and writes report in project_directory/dxf_blendname.INF') - Draw.PushButton('START IMPORT', EVENT_START, but2c+40, y, but_2c-40+but_3c+butt_margin, 40, 'Start the import process. For Cancel go to console and hit Ctrl-C') - Draw.EndAlign() - - - - - y -= 20 - Draw.BeginAlign() - Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20) - Draw.Label(LAB, but0c, y, menu_w, 20) - Draw.Label(' ', but0c+menu_w, y, menu_margin, 20) - Draw.EndAlign() - -#-- END GUI Stuf----------------------------------------------------- - -def colorbox(x,y,xright,bottom): - glColor3f(0.75, 0.75, 0.75) - glRecti(x + 1, y + 1, xright - 1, bottom - 1) - -def dxf_callback(input_filename): - global dxfFileName - if input_filename.lower()[-3:] in ('dwg','dxf'): - dxfFileName.val=input_filename -# dirname == sys.dirname(Blender.Get('filename')) -# update_RegistryKey('DirName', dirname) -# update_RegistryKey('dxfFileName', input_filename) - -def ini_callback(input_filename): - global iniFileName - iniFileName.val=input_filename - -def event(evt, val): - if evt in (Draw.QKEY, Draw.ESCKEY) and not val: - Draw.Exit() - -def bevent(evt): -# global EVENT_NONE,EVENT_LOAD_DXF,EVENT_LOAD_INI,EVENT_SAVE_INI,EVENT_EXIT - global config_UI, user_preset - global GUI_A, UI_MODE - - ######### Manages GUI events - if (evt==EVENT_EXIT): - Draw.Exit() - print 'DXF/DWG-Importer *** exit ***' #--------------------- - elif (evt==EVENT_CHOOSE_INI): - Window.FileSelector(ini_callback, "INI-file Selection", '*.ini') - elif (evt==EVENT_REDRAW): - Draw.Redraw() - elif (evt==EVENT_RESET): - resetDefaultConfig() - Draw.Redraw() - elif (evt==EVENT_PRESET2D): - resetDefaultConfig_2D() - Draw.Redraw() - elif (evt==EVENT_SCALE): - if g_scale_as.val == 12: - inputGlobalScale() - if GUI_A['g_scale'].val < 0.00000001: - GUI_A['g_scale'].val = 0.00000001 - Draw.Redraw() - elif (evt==EVENT_ORIGIN): - inputOriginVector() - Draw.Redraw() - elif (evt==EVENT_PRESET3D): - resetDefaultConfig_3D() - Draw.Redraw() - elif (evt==EVENT_PRESETCURV): - presetConfig_curv(GUI_A['curves_on'].val) - Draw.Redraw() - elif (evt==EVENT_PRESETS): - user_preset += 1 - index = str(user_preset) - if user_preset > 5: user_preset = 0; index = '' - iniFileName.val = INIFILE_DEFAULT_NAME + index + INIFILE_EXTENSION - Draw.Redraw() - elif (evt==EVENT_LIST): - dxfFile = dxfFileName.val - update_RegistryKey('dxfFileName', dxfFileName.val) - if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): - analyzeDXF(dxfFile) - else: - Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!') - print "DXF importer: error, no valid DXF-file selected! try again" - Draw.Redraw() - elif (evt==EVENT_HELP): - try: - import webbrowser - webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') - except: - Draw.PupMenu('DXF importer: HELP Alert!%t|no connection to manual-page on Blender-Wiki! try:|\ -http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') - Draw.Redraw() - elif (evt==EVENT_LOAD_INI): - loadConfig() - Draw.Redraw() - elif (evt==EVENT_SAVE_INI): - saveConfig() - Draw.Redraw() - elif (evt==EVENT_DXF_DIR): - dxfFile = dxfFileName.val - dxfFileExt = '*'+dxfFile.lower()[-4:] #can be .dxf or .dwg - dxfPathName = '' - if '/' in dxfFile: - dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/' - elif '\\' in dxfFile: - dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\' - dxfFileName.val = dxfPathName + dxfFileExt -# dirname == sys.dirname(Blender.Get('filename')) -# update_RegistryKey('DirName', dirname) -# update_RegistryKey('dxfFileName', dxfFileName.val) - GUI_A['newScene_on'].val = 1 - Draw.Redraw() - elif (evt==EVENT_CHOOSE_DXF): - filename = '' # '*.dxf' - if dxfFileName.val: filename = dxfFileName.val - Window.FileSelector(dxf_callback, "DXF/DWG-file Selection", filename) - elif (evt==EVENT_START): - dxfFile = dxfFileName.val - #print 'deb: dxfFile file: ', dxfFile #---------------------- - if E_M: dxfFileName.val, dxfFile = e_mode(dxfFile) #evaluation mode - update_RegistryKey('dxfFileName', dxfFileName.val) - if dxfFile.lower().endswith('*.dxf'): - if Draw.PupMenu('DXF importer will import all DXF-files from:|%s|OK?' % dxfFile) != -1: - UI_MODE = False - multi_import(dxfFile) - UI_MODE = True - Draw.Redraw() - - elif dxfFile.lower().endswith('*.dwg'): - if not extCONV_OK: Draw.PupMenu(extCONV_TEXT) - elif Draw.PupMenu('DWG importer will import all DWG-files from:|%s|OK?' % dxfFile) != -1: - #elif Draw.PupMenu('DWG importer will import all DWG-files from:|%s|Caution! overwrites existing DXF-files!| OK?' % dxfFile) != -1: - UI_MODE = False - multi_import(dxfFile) - UI_MODE = True - Draw.Redraw() - - elif sys.exists(dxfFile) and dxfFile.lower()[-4:] in ('.dxf','.dwg'): - if dxfFile.lower().endswith('.dwg') and (not extCONV_OK): - Draw.PupMenu(extCONV_TEXT) - else: - #print '\nStandard Mode: active' - if GUI_A['newScene_on'].val: - _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] - _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' - _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) - global SCENE - SCENE = Blender.Scene.New(_dxf_file) - SCENE.makeCurrent() - Blender.Redraw() - #or so? Blender.Scene.makeCurrent(_dxf_file) - #sce = bpy.data.scenes.new(_dxf_file) - #bpy.data.scenes.active = sce - else: - SCENE = Blender.Scene.GetCurrent() - SCENE.objects.selected = [] # deselect all - main(dxfFile) - #SCENE.objects.selected = SCENE.objects - #Window.RedrawAll() - #Blender.Redraw() - #Draw.Redraw() - else: - Draw.PupMenu('DXF importer: nothing imported!%t|no valid DXF-file selected!') - print "DXF importer: nothing imported, no valid DXF-file selected! try again" - Draw.Redraw() - - - - -def multi_import(DIR): - """Imports all DXF-files from directory DIR. - - """ - global SCENE - batchTIME = sys.time() - #if #DIR == "": DIR = os.path.curdir - if DIR == "": - DIR = sys.dirname(Blender.Get('filename')) - EXT = '.dxf' - else: - EXT = DIR[-4:] # get last 4 characters '.dxf' - DIR = DIR[:-5] # cut last 5 characters '*.dxf' - print 'importing multiple %s files from %s' %(EXT,DIR) - files = \ - [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith(EXT)] - if not files: - print '...None %s-files found. Abort!' %EXT - return - - i = 0 - for dxfFile in files: - i += 1 - print '\n%s-file' %EXT, i, 'of', len(files) #,'\nImporting', dxfFile - if GUI_A['newScene_on'].val: - _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] - _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' - _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) - SCENE = Blender.Scene.New(_dxf_file) - SCENE.makeCurrent() - #or so? Blender.Scene.makeCurrent(_dxf_file) - #sce = bpy.data.scenes.new(_dxf_file) - #bpy.data.scenes.active = sce - else: - SCENE = Blender.Scene.GetCurrent() - SCENE.objects.selected = [] # deselect all - main(dxfFile) - #Blender.Redraw() - - print 'TOTAL TIME: %.6f' % (sys.time() - batchTIME) - print '\a\r', # beep when done - Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % (sys.time() - batchTIME)) - - -if __name__ == "__main__": - #Draw.PupMenu('DXF importer: Abort%t|This script version works for Blender up 2.49 only!') - UI_MODE = True - # recall last used DXF-file and INI-file names - dxffilename = check_RegistryKey('dxfFileName') - #print 'deb:start dxffilename:', dxffilename #---------------- - if dxffilename: dxfFileName.val = dxffilename - else: - dirname = sys.dirname(Blender.Get('filename')) - #print 'deb:start dirname:', dirname #---------------- - dxfFileName.val = sys.join(dirname, '') - inifilename = check_RegistryKey('iniFileName') - if inifilename: iniFileName.val = inifilename - - Draw.Register(draw_UI, event, bevent) - - -""" -if 1: - # DEBUG ONLY - UI_MODE = False - TIME= sys.time() - #DIR = '/dxf_r12_testfiles/' - DIR = '/metavr/' - import os - print 'Searching for files' - os.system('find %s -iname "*.dxf" > /tmp/tempdxf_list' % DIR) - # os.system('find /storage/ -iname "*.dxf" > /tmp/tempdxf_list') - print '...Done' - file= open('/tmp/tempdxf_list', 'r') - lines= file.readlines() - file.close() - # sort by filesize for faster testing - lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] - lines_size.sort() - lines = [f[1] for f in lines_size] - - for i, _dxf in enumerate(lines): - if i >= 70: - #if 1: - print 'Importing', _dxf, '\nNUMBER', i, 'of', len(lines) - if True: - _dxf_file= _dxf.split('/')[-1].split('\\')[-1] - _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' - _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) - sce = bpy.data.scenes.new(_dxf_file) - bpy.data.scenes.active = sce - dxfFileName.val = _dxf - main(_dxf) - - print 'TOTAL TIME: %.6f' % (sys.time() - TIME) -""" \ No newline at end of file diff --git a/release/scripts/import_edl.py b/release/scripts/import_edl.py deleted file mode 100644 index 8c5d041b34c..00000000000 --- a/release/scripts/import_edl.py +++ /dev/null @@ -1,961 +0,0 @@ -#!BPY - -""" -Name: 'Video Sequence (.edl)...' -Blender: 248 -Group: 'Import' -Tooltip: 'Load a CMX formatted EDL into the sequencer' -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2009: Campbell Barton, ideasman42@gmail.com -# -# 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, -# -------------------------------------------------------------------------- - -class TimeCode(object): - ''' - Simple timecode class - also supports conversion from other time strings used by EDL - ''' - def __init__(self, data, fps): - self.fps= fps - if type(data)==str: - self.fromString(data) - frame = self.asFrame() - self.fromFrame(frame) - else: - self.fromFrame(data) - - def fromString(self, text): - # hh:mm:ss:ff - # No dropframe support yet - - if text.lower().endswith('mps'): # 5.2mps - return self.fromFrame( int( float(text[:-3]) * self.fps ) ) - elif text.lower().endswith('s'): # 5.2s - return self.fromFrame( int( float(text[:-1]) * self.fps ) ) - elif text.isdigit(): # 1234 - return self.fromFrame( int(text) ) - elif ':' in text: # hh:mm:ss:ff - text= text.replace(';', ':').replace(',', ':').replace('.', ':') - text= text.split(':') - - self.hours= int(text[0]) - self.minutes= int(text[1]) - self.seconds= int(text[2]) - self.frame= int(text[3]) - return self - else: - print 'ERROR: could not convert this into timecode "%s"' % test - return self - - - def fromFrame(self, frame): - - if frame < 0: - frame = -frame; - neg=True - else: - neg=False - - fpm = 60 * self.fps - fph = 60 * fpm - - if frame < fph: - self.hours= 0 - else: - self.hours= int(frame/fph) - frame = frame % fph - - if frame < fpm: - self.minutes= 0 - else: - self.minutes= int(frame/fpm) - frame = frame % fpm - - if frame < self.fps: - self.seconds= 0 - else: - self.seconds= int(frame/self.fps) - frame = frame % self.fps - - self.frame= frame - - if neg: - self.frame = -self.frame - self.seconds = -self.seconds - self.minutes = -self.minutes - self.hours = -self.hours - - return self - - def asFrame(self): - abs_frame= self.frame - abs_frame += self.seconds * self.fps - abs_frame += self.minutes * 60 * self.fps - abs_frame += self.hours * 60 * 60 * self.fps - - return abs_frame - - def asString(self): - self.fromFrame(int(self)) - return '%.2d:%.2d:%.2d:%.2d' % (self.hours, self.minutes, self.seconds, self.frame) - - def __repr__(self): - return self.asString() - - # Numeric stuff, may as well have this - def __neg__(self): return TimeCode(-int(self), self.fps) - def __int__(self): return self.asFrame() - def __sub__(self, other): return TimeCode(int(self)-int(other), self.fps) - def __add__(self, other): return TimeCode(int(self)+int(other), self.fps) - def __mul__(self, other): return TimeCode(int(self)*int(other), self.fps) - def __div__(self, other): return TimeCode(int(self)/int(other), self.fps) - def __abs__(self): return TimeCode(abs(int(self)), self.fps) - def __iadd__(self, other): return self.fromFrame(int(self)+int(other)) - def __imul__(self, other): return self.fromFrame(int(self)*int(other)) - def __idiv__(self, other): return self.fromFrame(int(self)/int(other)) -# end timecode - - -'''Comments -Comments can appear at the beginning of the EDL file (header) or between the edit lines in the EDL. The first block of comments in the file is defined to be the header comments and they are associated with the EDL as a whole. Subsequent comments in the EDL file are associated with the first edit line that appears after them. -Edit Entries - [num] [duration] [srcIn] [srcOut] [recIn] [recOut] - - * : Filename or tag value. Filename can be for an MPEG file, Image file, or Image file template. Image file templates use the same pattern matching as for command line glob, and can be used to specify images to encode into MPEG. i.e. /usr/data/images/image*.jpg - * : 'V' | 'A' | 'VA' | 'B' | 'v' | 'a' | 'va' | 'b' which equals Video, Audio, Video_Audio edits (note B or b can be used in place of VA or va). - * : 'C' | 'D' | 'E' | 'FI' | 'FO' | 'W' | 'c' | 'd' | 'e' | 'fi' | 'fo' | 'w'. which equals Cut, Dissolve, Effect, FadeIn, FadeOut, Wipe. - * [num]: if TransitionType = Wipe, then a wipe number must be given. At the moment only wipe 'W0' and 'W1' are supported. - * [duration]: if the TransitionType is not equal to Cut, then an effect duration must be given. Duration is in frames. - * [srcIn]: Src in. If no srcIn is given, then it defaults to the first frame of the video or the first frame in the image pattern. If srcIn isn't specified, then srcOut, recIn, recOut can't be specified. - * [srcOut]: Src out. If no srcOut is given, then it defaults to the last frame of the video - or last image in the image pattern. if srcOut isn't given, then recIn and recOut can't be specified. - * [recIn]: Rec in. If no recIn is given, then it is calculated based on its position in the EDL and the length of its input. - [recOut]: Rec out. If no recOut is given, then it is calculated based on its position in the EDL and the length of its input. first frame of the video. - -For srcIn, srcOut, recIn, recOut, the values can be specified as either timecode, frame number, seconds, or mps seconds. i.e. -[tcode | fnum | sec | mps], where: - - * tcode : SMPTE timecode in hh:mm:ss:ff - * fnum : frame number (the first decodable frame in the video is taken to be frame 0). - * sec : seconds with 's' suffix (e.g. 5.2s) - * mps : seconds with 'mps' suffix (e.g. 5.2mps). This corresponds to the 'seconds' value displayed by Windows MediaPlayer. - -More notes, -Key - -''' - -enum= 0 -TRANSITION_UNKNOWN= enum -TRANSITION_CUT= enum; enum+=1 -TRANSITION_DISSOLVE= enum; enum+=1 -TRANSITION_EFFECT= enum; enum+=1 -TRANSITION_FADEIN= enum; enum+=1 -TRANSITION_FADEOUT= enum; enum+=1 -TRANSITION_WIPE= enum; enum+=1 -TRANSITION_KEY= enum; enum+=1 - -TRANSITION_DICT={ \ - 'c':TRANSITION_CUT, - 'd':TRANSITION_DISSOLVE, - 'e':TRANSITION_EFFECT, - 'fi':TRANSITION_FADEIN, - 'fo':TRANSITION_FADEOUT, - 'w':TRANSITION_WIPE, - 'k':TRANSITION_KEY, - } - -enum= 0 -EDIT_UNKNOWN= 1<= 1.0: - mov.endStill = int(mov.length * (scale - 1.0)) - else: - speed.speedEffectGlobalSpeed = 1.0/scale - meta.endOffset = mov.length - int(mov.length*scale) - - speed.update() - meta.update() - return meta - -def apply_dissolve_ipo(mov, blendin): - len_disp = float(mov.endDisp - mov.startDisp) - - if len_disp <= 0.0: - print 'Error, strip is zero length' - return - - mov.ipo= ipo= bpy.data.ipos.new("fade", "Sequence") - icu= ipo.addCurve('Fac') - - icu.interpolation= Blender.IpoCurve.InterpTypes.LINEAR - icu.append((0, 0)) - icu.append(((int(blendin)/len_disp) * 100, 1)) - - if mov.type not in (SEQ_HD_SOUND, SEQ_RAM_SOUND): - mov.blendMode = Blender.Scene.Sequence.BlendModes.ALPHAOVER - - -def replace_ext(path, ext): - return path[:path.rfind('.')+1] + ext - -def load_edl(filename, reel_files, reel_offsets): - ''' - reel_files - key:reel <--> reel:filename - ''' - - # For test file - # frame_offset = -769 - - - sce= bpy.data.scenes.active - fps= sce.render.fps - - elist= EditList() - if not elist.parse(filename, fps): - return 'Unable to parse "%s"' % filename - # elist.clean() - - - seq= sce.sequence - - track= 0 - - edits = elist.edits[:] - # edits.sort(key = lambda edit: int(edit.recIn)) - - prev_edit = None - for edit in edits: - print edit - frame_offset = reel_offsets[edit.reel] - - - src_start= int(edit.srcIn) + frame_offset - src_end= int(edit.srcOut) + frame_offset - src_length= src_end-src_start - - rec_start= int(edit.recIn) + 1 - rec_end= int(edit.recOut) + 1 - rec_length= rec_end-rec_start - - # print src_length, rec_length, src_start - - if edit.m2 != None: scale = fps/float(edit.m2.fps) - else: scale = 1.0 - - unedited_start= rec_start - src_start - offset_start = src_start - int(src_start*scale) # works for scaling up AND down - - if edit.transition_type == TRANSITION_CUT and (not elist.testOverlap(edit)): - track = 1 - - strip= None - final_strips = [] - if edit.reel.lower()=='bw': - strip= seq.new((0,0,0), rec_start, track+1) - strip.length= rec_length # for color its simple - final_strips.append(strip) - else: - - path_full = reel_files[edit.reel] - path_fileonly= path_full.split('/')[-1].split('\\')[-1] # os.path.basename(full) - path_dironly= path_full[:-len(path_fileonly)] # os.path.dirname(full) - - if edit.edit_type & EDIT_VIDEO: #and edit.transition_type == TRANSITION_CUT: - - try: - strip= seq.new((path_fileonly, path_dironly, path_full, 'movie'), unedited_start + offset_start, track+1) - except: - return 'Invalid input for movie' - - # Apply scaled rec in bounds - if scale != 1.0: - meta = scale_meta_speed(seq, strip, scale) - final_strip = meta - else: - final_strip = strip - - - final_strip.update() - final_strip.startOffset= rec_start - final_strip.startDisp - final_strip.endOffset= rec_end- final_strip.endDisp - final_strip.update() - final_strip.endOffset += (final_strip.endDisp - rec_end) - final_strip.update() - - - if edit.transition_duration: - if not prev_edit: - print "Error no previous strip" - else: - new_end = rec_start + int(edit.transition_duration) - for other in prev_edit.custom_data: - if other.type != SEQ_HD_SOUND and other.type != SEQ_RAM_SOUND: - other.endOffset += (other.endDisp - new_end) - other.update() - - # Apply disolve - if edit.transition_type == TRANSITION_DISSOLVE: - apply_dissolve_ipo(final_strip, edit.transition_duration) - - if edit.transition_type == TRANSITION_WIPE: - other_track = track + 2 - for other in prev_edit.custom_data: - if other.type != SEQ_HD_SOUND and other.type != SEQ_RAM_SOUND: - - strip_wipe= seq.new((SEQ_WIPE, other, final_strip), 1, other_track) - - if edit.wipe_type == WIPE_0: - strip_wipe.wipeEffectAngle = 90 - else: - strip_wipe.wipeEffectAngle = -90 - - other_track += 1 - - - - # strip.endOffset= strip.length - int(edit.srcOut) - #end_offset= (unedited_start+strip.length) - end - # print start, end, end_offset - #strip.endOffset = end_offset - - # break - # print strip - - final_strips.append(final_strip) - - - if edit.edit_type & (EDIT_AUDIO | EDIT_AUDIO_STEREO | EDIT_VIDEO_AUDIO): - - if scale == 1.0: # TODO - scaled audio - - try: - strip= seq.new((path_fileonly, path_dironly, path_full, 'audio_hd'), unedited_start + offset_start, track+6) - except: - - # See if there is a wave file there - path_full_wav = replace_ext(path_full, 'wav') - path_fileonly_wav = replace_ext(path_fileonly, 'wav') - - #try: - strip= seq.new((path_fileonly_wav, path_dironly, path_full_wav, 'audio_hd'), unedited_start + offset_start, track+6) - #except: - # return 'Invalid input for audio' - - final_strip = strip - - # Copied from above - final_strip.update() - final_strip.startOffset= rec_start - final_strip.startDisp - final_strip.endOffset= rec_end- final_strip.endDisp - final_strip.update() - final_strip.endOffset += (final_strip.endDisp - rec_end) - final_strip.update() - - if edit.transition_type == TRANSITION_DISSOLVE: - apply_dissolve_ipo(final_strip, edit.transition_duration) - - final_strips.append(final_strip) - - # strip= seq.new((0.6, 0.6, 0.6), start, track+1) - - if final_strips: - for strip in final_strips: - # strip.length= length - final_strip.name = edit.asName() - edit.custom_data[:]= final_strips - # track = not track - prev_edit = edit - track += 1 - - #break - - - def recursive_update(s): - s.update(1) - for s_kid in s: - recursive_update(s_kid) - - - for s in seq: - recursive_update(s) - - return '' - - - -#load_edl('/fe/edl/EP30CMXtrk1.edl') # /tmp/test.edl -#load_edl('/fe/edl/EP30CMXtrk2.edl') # /tmp/test.edl -#load_edl('/fe/edl/EP30CMXtrk3.edl') # /tmp/test.edl -#load_edl('/root/vid/rush/blender_edl.edl', ['/root/vid/rush/rushes3.avi',]) # /tmp/test.edl - - - - -# ---------------------- Blender UI part -from Blender import Draw, Window -import BPyWindow - -if 0: - DEFAULT_FILE_EDL = '/root/vid/rush/blender_edl.edl' - DEFAULT_FILE_MEDIA = '/root/vid/rush/rushes3_wav.avi' - DEFAULT_FRAME_OFFSET = -769 -else: - DEFAULT_FILE_EDL = '' - DEFAULT_FILE_MEDIA = '' - DEFAULT_FRAME_OFFSET = 0 - -B_EVENT_IMPORT = 1 -B_EVENT_RELOAD = 2 -B_EVENT_FILESEL_EDL = 3 -B_EVENT_NOP = 4 - -B_EVENT_FILESEL = 100 # or greater - -class ReelItemUI(object): - __slots__ = 'filename_but', 'offset_but', 'ui_text' - def __init__(self): - self.filename_but = Draw.Create(DEFAULT_FILE_MEDIA) - self.offset_but = Draw.Create(DEFAULT_FRAME_OFFSET) - self.ui_text = '' - - - -REEL_UI = {} # reel:ui_string - - -#REEL_FILENAMES = {} # reel:filename -#REEL_OFFSETS = {} # reel:filename - -PREF = {} - -PREF['filename'] = Draw.Create(DEFAULT_FILE_EDL) -PREF['reel_act'] = '' - -def edl_reload(): - Window.WaitCursor(1) - filename = PREF['filename'].val - sce= bpy.data.scenes.active - fps= sce.render.fps - - elist= EditList() - - if filename: - if not elist.parse(filename, fps): - Draw.PupMenu('Error%t|Could not open the file "' + filename + '"') - reels = elist.getReels() - else: - reels = {} - - REEL_UI.clear() - for reel_key, edits in reels.iteritems(): - - if reel_key == 'bw': - continue - - flag = 0 - for edit in edits: - flag |= edit.edit_type - - reel_item = REEL_UI[reel_key] = ReelItemUI() - - reel_item.ui_text = '%s (%s): ' % (reel_key, editFlagsToText(flag)) - - Window.WaitCursor(0) - -def edl_set_path(filename): - PREF['filename'].val = filename - edl_reload() - Draw.Redraw() - -def edl_set_path_reel(filename): - REEL_UI[PREF['reel_act']].filename_but.val = filename - Draw.Redraw() - -def edl_reel_keys(): - reel_keys = REEL_UI.keys() - - if 'bw' in reel_keys: - reel_keys.remove('bw') - - reel_keys.sort() - return reel_keys - -def edl_draw(): - - MARGIN = 4 - rect = BPyWindow.spaceRect() - but_width = int((rect[2]-MARGIN*2)/4.0) # 72 - # Clamp - if but_width>100: but_width = 100 - but_height = 17 - - x=MARGIN - y=rect[3]-but_height-MARGIN - xtmp = x - - - - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREF['filename'] = Draw.String('edl path: ', B_EVENT_RELOAD, xtmp, y, (but_width*3)-20, but_height, PREF['filename'].val, 256, 'EDL Path'); xtmp += (but_width*3)-20; - Draw.PushButton('..', B_EVENT_FILESEL_EDL, xtmp, y, 20, but_height, 'Select an EDL file'); xtmp += 20; - Blender.Draw.EndAlign() - - Draw.PushButton('Reload', B_EVENT_RELOAD, xtmp + MARGIN, y, but_width - MARGIN, but_height, 'Read the ID Property settings from the active curve object'); xtmp += but_width; - y-=but_height + MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - reel_keys = edl_reel_keys() - - - - if reel_keys: text = 'Reel file list...' - elif PREF['filename'].val == '': text = 'No EDL loaded.' - else: text = 'No reels found!' - - Draw.Label(text, xtmp + MARGIN, y, but_width*4, but_height); xtmp += but_width*4; - - y-=but_height + MARGIN - xtmp = x - - # ---------- ---------- ---------- ---------- - - - for i, reel_key in enumerate(reel_keys): - reel_item = REEL_UI[reel_key] - - Blender.Draw.BeginAlign() - REEL_UI[reel_key].filename_but = Draw.String(reel_item.ui_text, B_EVENT_NOP, xtmp, y, (but_width*3)-20, but_height, REEL_UI[reel_key].filename_but.val, 256, 'Select the reel path'); xtmp += (but_width*3)-20; - Draw.PushButton('..', B_EVENT_FILESEL + i, xtmp, y, 20, but_height, 'Media path to use for this reel'); xtmp += 20; - Blender.Draw.EndAlign() - - reel_item.offset_but= Draw.Number('ofs:', B_EVENT_NOP, xtmp + MARGIN, y, but_width - MARGIN, but_height, reel_item.offset_but.val, -100000, 100000, 'Start offset in frames when applying timecode'); xtmp += but_width - MARGIN; - - y-=but_height + MARGIN - xtmp = x - - # ---------- ---------- ---------- ---------- - - Draw.PushButton('Import CMX-EDL Sequencer Strips', B_EVENT_IMPORT, xtmp + MARGIN, MARGIN, but_width*4 - MARGIN, but_height, 'Load the EDL file into the sequencer'); xtmp += but_width*4; - y-=but_height + MARGIN - xtmp = x - - -def edl_event(evt, val): - pass - -def edl_bevent(evt): - - if evt == B_EVENT_NOP: - pass - elif evt == B_EVENT_IMPORT: - ''' - Load the file into blender with UI settings - ''' - filename = PREF['filename'].val - - reel_files = {} - reel_offsets = {} - - for reel_key, reel_item in REEL_UI.iteritems(): - reel_files[reel_key] = reel_item.filename_but.val - reel_offsets[reel_key] = reel_item.offset_but.val - - error = load_edl(filename, reel_files, reel_offsets) - if error != '': - Draw.PupMenu('Error%t|' + error) - else: - Window.RedrawAll() - - elif evt == B_EVENT_RELOAD: - edl_reload() - Draw.Redraw() - - elif evt == B_EVENT_FILESEL_EDL: - filename = PREF['filename'].val - if not filename: filename = Blender.sys.join(Blender.sys.expandpath('//'), '*.edl') - - Window.FileSelector(edl_set_path, 'Select EDL', filename) - - elif evt >= B_EVENT_FILESEL: - reel_keys = edl_reel_keys() - reel_key = reel_keys[evt - B_EVENT_FILESEL] - - filename = REEL_UI[reel_key].filename_but.val - if not filename: filename = Blender.sys.expandpath('//') - - PREF['reel_act'] = reel_key # so file set path knows which one to set - Window.FileSelector(edl_set_path_reel, 'Reel Media', filename) - - - -if __name__ == '__main__': - Draw.Register(edl_draw, edl_event, edl_bevent) - edl_reload() - diff --git a/release/scripts/import_lightwave_motion.py b/release/scripts/import_lightwave_motion.py deleted file mode 100644 index 20c87dfd5c6..00000000000 --- a/release/scripts/import_lightwave_motion.py +++ /dev/null @@ -1,244 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: <- these words are ignored -Name: 'Lightwave Motion (.mot)...' -Blender: 245 -Group: 'Import' -Tip: 'Import Loc Rot Size chanels from a Lightwave .mot file' -""" - -__author__ = "Daniel Salazar (ZanQdo)" -__url__ = ("blender", "blenderartists.org", -"e-mail: zanqdo@gmail.com") -__version__ = "16/04/08" - -__bpydoc__ = """\ -This script loads Lightwave motion files (.mot) -into the selected objects - -Usage: -Run the script with one or more objects selected (any kind) -Be sure to set the framerate correctly - -""" - -# $Id$ -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2003, 2004: A Vanpoucke -# -# 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 math as M -import Blender as B -import bpy - - -def FuncionPrincipal (Dir): - B.Window.WaitCursor(1) - ObjSelect = B.Object.GetSelected() - - if not ObjSelect: - B.Draw.PupMenu('Select one or more objects, aborting.') - return - - - SC = B.Scene.GetCurrent() - SCR = SC.getRenderingContext() - FrameRate = float(SCR.framesPerSec()) - - - # Creating new IPO - - IPO = B.Ipo.New('Object', 'LW_Motion') - - - # Creating Curves in the IPO - - LocX = IPO.addCurve("LocX") - LocX.setInterpolation("Bezier") - - LocY = IPO.addCurve("LocY") - LocX.setInterpolation("Bezier") - - LocZ = IPO.addCurve("LocZ") - LocX.setInterpolation("Bezier") - - RotX = IPO.addCurve("RotX") - LocX.setInterpolation("Bezier") - - RotY = IPO.addCurve("RotY") - LocX.setInterpolation("Bezier") - - RotZ = IPO.addCurve("RotZ") - LocX.setInterpolation("Bezier") - - ScaleX = IPO.addCurve("ScaleX") - LocX.setInterpolation("Bezier") - - ScaleY = IPO.addCurve("ScaleY") - LocX.setInterpolation("Bezier") - - ScaleZ = IPO.addCurve("ScaleZ") - LocX.setInterpolation("Bezier") - - - # Opening the mot file - - File = open (Dir, 'rU') - - - # Init flags - - CurChannel = -1 - ScaleFlag = 0 - - # Main file reading cycle - - for Line in File: - - ''' - # Number of channels in the file - - if "NumChannels" in Line: - Line = Line.split (' ') - NumChannels = int(Line[1]) - ''' - - # Current Channel Flag - - if "Channel 0" in Line: - CurChannel = 0 - - elif "Channel 1" in Line: - CurChannel = 1 - - elif "Channel 2" in Line: - CurChannel = 2 - - elif "Channel 3" in Line: - CurChannel = 3 - - elif "Channel 4" in Line: - CurChannel = 4 - - elif "Channel 5" in Line: - CurChannel = 5 - - elif "Channel 6" in Line: - CurChannel = 6 - - elif "Channel 7" in Line: - CurChannel = 7 - - elif "Channel 8" in Line: - CurChannel = 8 - - - # Getting the data and writing to IPOs - - if CurChannel == 0: - if "Key" in Line: - Line = Line.split (' ') - ValCh_0 = float (Line [3]) - TimeCh_0 = float (Line [4]) * FrameRate - LocX.addBezier ((TimeCh_0, ValCh_0)) - - if CurChannel == 1: - if "Key" in Line: - Line = Line.split (' ') - ValCh_1 = float (Line [3]) - TimeCh_1 = float (Line [4]) * FrameRate - LocZ.addBezier ((TimeCh_1, ValCh_1)) - - if CurChannel == 2: - if "Key" in Line: - Line = Line.split (' ') - ValCh_2 = float (Line [3]) - TimeCh_2 = float (Line [4]) * FrameRate - LocY.addBezier ((TimeCh_2, ValCh_2)) - - if CurChannel == 3: - if "Key" in Line: - Line = Line.split (' ') - ValCh_3 = M.degrees ( - float (Line [3]) ) / 10 - TimeCh_3 = float (Line [4]) * FrameRate - RotZ.addBezier ((TimeCh_3, ValCh_3)) - - if CurChannel == 4: - if "Key" in Line: - Line = Line.split (' ') - ValCh_4 = M.degrees ( - float (Line [3]) ) / 10 - TimeCh_4 = float (Line [4]) * FrameRate - RotX.addBezier ((TimeCh_4, ValCh_4)) - - if CurChannel == 5: - if "Key" in Line: - Line = Line.split (' ') - ValCh_5 = M.degrees ( - float (Line [3]) ) / 10 - TimeCh_5 = float (Line [4]) * FrameRate - RotY.addBezier ((TimeCh_5, ValCh_5)) - - if CurChannel == 6: - if "Key" in Line: - Line = Line.split (' ') - ValCh_6 = float (Line [3]) - TimeCh_6 = float (Line [4]) * FrameRate - ScaleX.addBezier ((TimeCh_6, ValCh_6)) - elif ScaleFlag < 3: - ScaleFlag += 1 - ScaleX.addBezier ((0, 1)) - - if CurChannel == 7: - if "Key" in Line: - Line = Line.split (' ') - ValCh_7 = float (Line [3]) - TimeCh_7 = float (Line [4]) * FrameRate - ScaleZ.addBezier ((TimeCh_7, ValCh_7)) - elif ScaleFlag < 3: - ScaleFlag += 1 - ScaleZ.addBezier ((0, 1)) - - if CurChannel == 8: - if "Key" in Line: - Line = Line.split (' ') - ValCh_8 = float (Line [3]) - TimeCh_8 = float (Line [4]) * FrameRate - ScaleY.addBezier ((TimeCh_8, ValCh_8)) - elif ScaleFlag < 3: - ScaleFlag += 1 - ScaleY.addBezier ((0, 1)) - - - # Link the IPO to all selected objects - - for ob in ObjSelect: - ob.setIpo(IPO) - - File.close() - - print '\nDone, the following motion file has been loaded:\n\n%s' % Dir - B.Window.WaitCursor(0) - -def main(): - B.Window.FileSelector(FuncionPrincipal, "Load IPO from .mot File", B.sys.makename(ext='.mot')) - -if __name__=='__main__': - main() - diff --git a/release/scripts/import_mdd.py b/release/scripts/import_mdd.py deleted file mode 100644 index 1ee196ab67f..00000000000 --- a/release/scripts/import_mdd.py +++ /dev/null @@ -1,158 +0,0 @@ -#!BPY - -""" - Name: 'Load MDD to Mesh RVKs' - Blender: 242 - Group: 'Import' - Tooltip: 'baked vertex animation to active mesh object.' -""" -__author__ = "Bill L.Nieuwendorp" -__bpydoc__ = """\ -This script Imports Lightwaves MotionDesigner format. - -The .mdd format has become quite a popular Pipeline format
-for moving animations from package to package. -""" -# mdd importer -# -# Warning if the vertex order or vertex count differs from the -# origonal model the mdd was Baked out from their will be Strange -# behavior -# -# -#vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0 -#A modifier to read mdd files would be Ideal but thats for another day :) -# -#Please send any fixes,updates,bugs to Slow67_at_Gmail.com -#Bill Niewuendorp - -# ***** 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 ***** - - - - -try: - from struct import unpack -except: - unpack = None - -import Blender -from Blender import Mesh, Object, Scene -import BPyMessages - -def mdd_import(filepath, ob, PREF_IPONAME, PREF_START_FRAME, PREF_JUMP): - - print '\n\nimporting mdd "%s"' % filepath - - Blender.Window.DrawProgressBar (0.0, "Importing mdd ...") - Blender.Window.EditMode(0) - Blender.Window.WaitCursor(1) - - file = open(filepath, 'rb') - frames, points = unpack(">2i", file.read(8)) - time = unpack((">%df" % frames), file.read(frames * 4)) - - print '\tpoints:%d frames:%d' % (points,frames) - - scn = Scene.GetCurrent() - ctx = scn.getRenderingContext() - Blender.Set("curframe", PREF_START_FRAME) - me = ob.getData(mesh=1) - - def UpdateMesh(me,fr): - for v in me.verts: - # 12 is the size of 3 floats - x,y,z= unpack('>3f', file.read(12)) - v.co[:] = x,z,y - me.update() - - Blender.Window.DrawProgressBar (0.4, "4 Importing mdd ...") - - - curfr = ctx.currentFrame() - print'\twriting mdd data...' - for i in xrange(frames): - Blender.Set("curframe", i+PREF_START_FRAME) - if len(me.verts) > 1 and (curfr >= PREF_START_FRAME) and (curfr <= PREF_START_FRAME+frames): - UpdateMesh(me, i) - ob.insertShapeKey() - - Blender.Window.DrawProgressBar (0.5, "5 Importing mdd ...") - - key= me.key - - # Add the key of its not there - if not key: - me.insertKey(1, 'relative') - key= me.key - - key.ipo = Blender.Ipo.New('Key', PREF_IPONAME) - ipo = key.ipo - # block = key.getBlocks() # not used. - all_keys = ipo.curveConsts - - for i in xrange(PREF_JUMP+1, len(all_keys), PREF_JUMP): - curve = ipo.getCurve(i) - if curve == None: - curve = ipo.addCurve(all_keys[i]) - - curve.append((PREF_START_FRAME+i-1,1)) - curve.append((PREF_START_FRAME+i- PREF_JUMP -1,0)) - curve.append((PREF_START_FRAME+i+ PREF_JUMP-1,0)) - curve.setInterpolation('Linear') - curve.recalc() - - print 'done' - Blender.Window.WaitCursor(0) - Blender.Window.DrawProgressBar (1.0, '') - - -def mdd_import_ui(filepath): - - if BPyMessages.Error_NoFile(filepath): - return - - scn= Scene.GetCurrent() - ob_act= scn.objects.active - - if ob_act == None or ob_act.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - PREF_IPONAME = Blender.Draw.Create(filepath.split('/')[-1].split('\\')[-1].split('.')[0]) - PREF_START_FRAME = Blender.Draw.Create(1) - PREF_JUMP = Blender.Draw.Create(1) - - block = [\ - ("Ipo Name: ", PREF_IPONAME, 0, 30, "Ipo name for the new shape key"),\ - ("Start Frame: ", PREF_START_FRAME, 1, 3000, "Start frame for the animation"),\ - ("Key Skip: ", PREF_JUMP, 1, 100, "KeyReduction, Skip every Nth Frame")\ - ] - - if not Blender.Draw.PupBlock("Import MDD", block): - return - orig_frame = Blender.Get('curframe') - mdd_import(filepath, ob_act, PREF_IPONAME.val, PREF_START_FRAME.val, PREF_JUMP.val) - Blender.Set('curframe', orig_frame) - -if __name__ == '__main__': - if not unpack: - Draw.PupMenu('Error%t|This script requires a full python install') - - Blender.Window.FileSelector(mdd_import_ui, 'IMPORT MDD', '*.mdd') diff --git a/release/scripts/import_obj.py b/release/scripts/import_obj.py deleted file mode 100644 index 81230bfcf03..00000000000 --- a/release/scripts/import_obj.py +++ /dev/null @@ -1,1234 +0,0 @@ -#!BPY - -""" -Name: 'Wavefront (.obj)...' -Blender: 249 -Group: 'Import' -Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' -""" - -__author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone" -__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org'] -__version__= "2.13" - -__bpydoc__= """\ -This script imports a Wavefront OBJ files to Blender. - -Usage: -Run this script from "File->Import" menu and then load the desired OBJ file. -Note, This loads mesh objects and materials only, nurbs and curves are not supported. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton 2007-2009 -# - V2.12- bspline import/export added (funded by PolyDimensions GmbH) -# -# 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 ***** -# -------------------------------------------------------------------------- - -from Blender import Mesh, Draw, Window, Texture, Material, sys -import bpy -import BPyMesh -import BPyImage -import BPyMessages - -try: import os -except: os= False - -# Generic path functions -def stripFile(path): - '''Return directory, where the file is''' - lastSlash= max(path.rfind('\\'), path.rfind('/')) - if lastSlash != -1: - path= path[:lastSlash] - return '%s%s' % (path, sys.sep) - -def stripPath(path): - '''Strips the slashes from the back of a string''' - return path.split('/')[-1].split('\\')[-1] - -def stripExt(name): # name is a string - '''Strips the prefix off the name before writing''' - index= name.rfind('.') - if index != -1: - return name[ : index ] - else: - return name -# end path funcs - - - -def line_value(line_split): - ''' - Returns 1 string represneting the value for this line - None will be returned if theres only 1 word - ''' - length= len(line_split) - if length == 1: - return None - - elif length == 2: - return line_split[1] - - elif length > 2: - return ' '.join( line_split[1:] ) - -def obj_image_load(imagepath, DIR, IMAGE_SEARCH): - ''' - Mainly uses comprehensiveImageLoad - but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. - ''' - - if '_' in imagepath: - image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) - if image: return image - # Did the exporter rename the image? - image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) - if image: return image - - # Return an image, placeholder if it dosnt exist - image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) - return image - - -def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): - ''' - Create all the used materials in this obj, - assign colors and images to the materials from all referenced material libs - ''' - DIR= stripFile(filepath) - - #==================================================================================# - # This function sets textures defined in .mtl file # - #==================================================================================# - def load_material_image(blender_material, context_material_name, imagepath, type): - - texture= bpy.data.textures.new(type) - texture.setType('Image') - - # Absolute path - c:\.. etc would work here - image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) - has_data = image.has_data - texture.image = image - - if not has_data: - try: - # first time using this image. We need to load it first - image.glLoad() - except: - # probably the image is crashed - pass - else: - has_data = image.has_data - - # Adds textures for materials (rendering) - if type == 'Kd': - if has_data and image.depth == 32: - # Image has alpha - blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) - texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') - blender_material.mode |= Material.Modes.ZTRANSP - blender_material.alpha = 0.0 - else: - blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - - # adds textures to faces (Textured/Alt-Z mode) - # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. - unique_material_images[context_material_name]= image, has_data # set the texface image - - elif type == 'Ka': - blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API - - elif type == 'Ks': - blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) - - elif type == 'Bump': - blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) - elif type == 'D': - blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) - blender_material.mode |= Material.Modes.ZTRANSP - blender_material.alpha = 0.0 - # Todo, unset deffuse material alpha if it has an alpha channel - - elif type == 'refl': - blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) - - - # Add an MTL with the same name as the obj if no MTLs are spesified. - temp_mtl= stripExt(stripPath(filepath))+ '.mtl' - - if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: - material_libs.append( temp_mtl ) - del temp_mtl - - #Create new materials - for name in unique_materials: # .keys() - if name != None: - unique_materials[name]= bpy.data.materials.new(name) - unique_material_images[name]= None, False # assign None to all material images to start with, add to later. - - unique_materials[None]= None - unique_material_images[None]= None, False - - for libname in material_libs: - mtlpath= DIR + libname - if not sys.exists(mtlpath): - #print '\tError Missing MTL: "%s"' % mtlpath - pass - else: - #print '\t\tloading mtl: "%s"' % mtlpath - context_material= None - mtl= open(mtlpath, 'rU') - for line in mtl: #.xreadlines(): - if line.startswith('newmtl'): - context_material_name= line_value(line.split()) - if unique_materials.has_key(context_material_name): - context_material = unique_materials[ context_material_name ] - else: - context_material = None - - elif context_material: - # we need to make a material to assign properties to it. - line_split= line.split() - line_lower= line.lower().lstrip() - if line_lower.startswith('ka'): - context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('kd'): - context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('ks'): - context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) - elif line_lower.startswith('ns'): - context_material.setHardness( int((float(line_split[1])*0.51)) ) - elif line_lower.startswith('ni'): # Refraction index - context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 - elif line_lower.startswith('d') or line_lower.startswith('tr'): - context_material.setAlpha(float(line_split[1])) - context_material.mode |= Material.Modes.ZTRANSP - elif line_lower.startswith('map_ka'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Ka') - elif line_lower.startswith('map_ks'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Ks') - elif line_lower.startswith('map_kd'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Kd') - elif line_lower.startswith('map_bump'): - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'Bump') - elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'D') - - elif line_lower.startswith('refl'): # Reflectionmap - img_filepath= line_value(line.split()) - if img_filepath: - load_material_image(context_material, context_material_name, img_filepath, 'refl') - mtl.close() - - - - -def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): - ''' - Takes vert_loc and faces, and seperates into multiple sets of - (verts_loc, faces, unique_materials, dataname) - This is done so objects do not overload the 16 material limit. - ''' - - filename = stripExt(stripPath(filepath)) - - if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: - # use the filename for the object name since we arnt chopping up the mesh. - return [(verts_loc, faces, unique_materials, filename)] - - - def key_to_name(key): - # if the key is a tuple, join it to make a string - if type(key) == tuple: - return '%s_%s' % key - elif not key: - return filename # assume its a string. make sure this is true if the splitting code is changed - else: - return key - - # Return a key that makes the faces unique. - if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: - def face_key(face): - return face[4] # object - - elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: - def face_key(face): - return face[2] # material - - else: # Both - def face_key(face): - return face[4], face[2] # object,material - - - face_split_dict= {} - - oldkey= -1 # initialize to a value that will never match the key - - for face in faces: - - key= face_key(face) - - if oldkey != key: - # Check the key has changed. - try: - verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] - except KeyError: - faces_split= [] - verts_split= [] - unique_materials_split= {} - vert_remap= [-1]*len(verts_loc) - - face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) - - oldkey= key - - face_vert_loc_indicies= face[0] - - # Remap verts to new vert list and add where needed - for enum, i in enumerate(face_vert_loc_indicies): - if vert_remap[i] == -1: - new_index= len(verts_split) - vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. - face_vert_loc_indicies[enum] = new_index # remap to the local index - verts_split.append( verts_loc[i] ) # add the vert to the local verts - - else: - face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index - - matname= face[2] - if matname and not unique_materials_split.has_key(matname): - unique_materials_split[matname] = unique_materials[matname] - - faces_split.append(face) - - - # remove one of the itemas and reorder - return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()] - - -def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): - ''' - Takes all the data gathered and generates a mesh, adding the new object to new_objects - deals with fgons, sharp edges and assigning materials - ''' - if not has_ngons: - CREATE_FGONS= False - - if unique_smooth_groups: - sharp_edges= {} - smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ]) - context_smooth_group_old= -1 - - # Split fgons into tri's - fgon_edges= {} # Used for storing fgon keys - if CREATE_EDGES: - edges= [] - - context_object= None - - # reverse loop through face indicies - for f_idx in xrange(len(faces)-1, -1, -1): - - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object= faces[f_idx] - - len_face_vert_loc_indicies = len(face_vert_loc_indicies) - - if len_face_vert_loc_indicies==1: - faces.pop(f_idx)# cant add single vert faces - - elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines - if CREATE_EDGES: - # generators are better in python 2.4+ but can't be used in 2.3 - # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) - edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] ) - - faces.pop(f_idx) - else: - - # Smooth Group - if unique_smooth_groups and context_smooth_group: - # Is a part of of a smooth group and is a face - if context_smooth_group_old is not context_smooth_group: - edge_dict= smooth_group_users[context_smooth_group] - context_smooth_group_old= context_smooth_group - - for i in xrange(len_face_vert_loc_indicies): - i1= face_vert_loc_indicies[i] - i2= face_vert_loc_indicies[i-1] - if i1>i2: i1,i2= i2,i1 - - try: - edge_dict[i1,i2]+= 1 - except KeyError: - edge_dict[i1,i2]= 1 - - # FGons into triangles - if has_ngons and len_face_vert_loc_indicies > 4: - - ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) - faces.extend(\ - [(\ - [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ - [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ - context_material,\ - context_smooth_group,\ - context_object)\ - for ngon in ngon_face_indices]\ - ) - - # edges to make fgons - if CREATE_FGONS: - edge_users= {} - for ngon in ngon_face_indices: - for i in (0,1,2): - i1= face_vert_loc_indicies[ngon[i ]] - i2= face_vert_loc_indicies[ngon[i-1]] - if i1>i2: i1,i2= i2,i1 - - try: - edge_users[i1,i2]+=1 - except KeyError: - edge_users[i1,i2]= 1 - - for key, users in edge_users.iteritems(): - if users>1: - fgon_edges[key]= None - - # remove all after 3, means we dont have to pop this one. - faces.pop(f_idx) - - - # Build sharp edges - if unique_smooth_groups: - for edge_dict in smooth_group_users.itervalues(): - for key, users in edge_dict.iteritems(): - if users==1: # This edge is on the boundry of a group - sharp_edges[key]= None - - - # map the material names to an index - material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys() - - materials= [None] * len(unique_materials) - - for name, index in material_mapping.iteritems(): - materials[index]= unique_materials[name] - - me= bpy.data.meshes.new(dataname) - - me.materials= materials[0:16] # make sure the list isnt too big. - #me.verts.extend([(0,0,0)]) # dummy vert - me.verts.extend(verts_loc) - - face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) - - if verts_tex and me.faces: - me.faceUV= 1 - # TEXMODE= Mesh.FaceModes['TEX'] - - context_material_old= -1 # avoid a dict lookup - mat= 0 # rare case it may be un-initialized. - me_faces= me.faces - ALPHA= Mesh.FaceTranspModes.ALPHA - - for i, face in enumerate(faces): - if len(face[0]) < 2: - pass #raise "bad face" - elif len(face[0])==2: - if CREATE_EDGES: - edges.append(face[0]) - else: - face_index_map= face_mapping[i] - if face_index_map!=None: # None means the face wasnt added - blender_face= me_faces[face_index_map] - - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object= face - - - - if context_smooth_group: - blender_face.smooth= True - - if context_material: - if context_material_old is not context_material: - mat= material_mapping[context_material] - if mat>15: - mat= 15 - context_material_old= context_material - - blender_face.mat= mat - - - if verts_tex: - if context_material: - image, has_data= unique_material_images[context_material] - if image: # Can be none if the material dosnt have an image. - blender_face.image= image - if has_data and image.depth == 32: - blender_face.transp |= ALPHA - - # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. - if len(face_vert_loc_indicies)==4: - if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: - face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] - else: # length of 3 - if face_vert_loc_indicies[2]==0: - face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] - # END EEEKADOODLE FIX - - # assign material, uv's and image - for ii, uv in enumerate(blender_face.uv): - uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] - del me_faces - del ALPHA - - # Add edge faces. - me_edges= me.edges - if CREATE_FGONS and fgon_edges: - FGON= Mesh.EdgeFlags.FGON - for ed in me.findEdges( fgon_edges.keys() ): - if ed!=None: - me_edges[ed].flag |= FGON - del FGON - - if unique_smooth_groups and sharp_edges: - SHARP= Mesh.EdgeFlags.SHARP - for ed in me.findEdges( sharp_edges.keys() ): - if ed!=None: - me_edges[ed].flag |= SHARP - del SHARP - - if CREATE_EDGES: - me_edges.extend( edges ) - - del me_edges - - me.calcNormals() - - ob= scn.objects.new(me) - new_objects.append(ob) - - # Create the vertex groups. No need to have the flag passed here since we test for the - # content of the vertex_groups. If the user selects to NOT have vertex groups saved then - # the following test will never run - for group_name, group_indicies in vertex_groups.iteritems(): - me.addVertGroup(group_name) - me.assignVertsToGroup(group_name, group_indicies,1.00, Mesh.AssignModes.REPLACE) - - -def create_nurbs(scn, context_nurbs, vert_loc, new_objects): - ''' - Add nurbs object to blender, only support one type at the moment - ''' - deg = context_nurbs.get('deg', (3,)) - curv_range = context_nurbs.get('curv_range', None) - curv_idx = context_nurbs.get('curv_idx', []) - parm_u = context_nurbs.get('parm_u', []) - parm_v = context_nurbs.get('parm_v', []) - name = context_nurbs.get('name', 'ObjNurb') - cstype = context_nurbs.get('cstype', None) - - if cstype == None: - print '\tWarning, cstype not found' - return - if cstype != 'bspline': - print '\tWarning, cstype is not supported (only bspline)' - return - if not curv_idx: - print '\tWarning, curv argument empty or not set' - return - if len(deg) > 1 or parm_v: - print '\tWarning, surfaces not supported' - return - - cu = bpy.data.curves.new(name, 'Curve') - cu.flag |= 1 # 3D curve - - nu = None - for pt in curv_idx: - - pt = vert_loc[pt] - pt = (pt[0], pt[1], pt[2], 1.0) - - if nu == None: - nu = cu.appendNurb(pt) - else: - nu.append(pt) - - nu.orderU = deg[0]+1 - - # get for endpoint flag from the weighting - if curv_range and len(parm_u) > deg[0]+1: - do_endpoints = True - for i in xrange(deg[0]+1): - - if abs(parm_u[i]-curv_range[0]) > 0.0001: - do_endpoints = False - break - - if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001: - do_endpoints = False - break - - else: - do_endpoints = False - - if do_endpoints: - nu.flagU |= 2 - - - # close - ''' - do_closed = False - if len(parm_u) > deg[0]+1: - for i in xrange(deg[0]+1): - #print curv_idx[i], curv_idx[-(i+1)] - - if curv_idx[i]==curv_idx[-(i+1)]: - do_closed = True - break - - if do_closed: - nu.flagU |= 1 - ''' - - ob = scn.objects.new(cu) - new_objects.append(ob) - - -def strip_slash(line_split): - if line_split[-1][-1]== '\\': - if len(line_split[-1])==1: - line_split.pop() # remove the \ item - else: - line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number - return True - return False - - - -def get_float_func(filepath): - ''' - find the float function for this obj file - - weather to replace commas or not - ''' - file= open(filepath, 'rU') - for line in file: #.xreadlines(): - line = line.lstrip() - if line.startswith('v'): # vn vt v - if ',' in line: - return lambda f: float(f.replace(',', '.')) - elif '.' in line: - return float - - # incase all vert values were ints - return float - -def load_obj(filepath, - CLAMP_SIZE= 0.0, - CREATE_FGONS= True, - CREATE_SMOOTH_GROUPS= True, - CREATE_EDGES= True, - SPLIT_OBJECTS= True, - SPLIT_GROUPS= True, - SPLIT_MATERIALS= True, - ROTATE_X90= True, - IMAGE_SEARCH=True, - POLYGROUPS=False): - ''' - Called by the user interface or another script. - load_obj(path) - should give acceptable results. - This function passes the file and sends the data off - to be split into objects and then converted into mesh objects - ''' - print '\nimporting obj "%s"' % filepath - - if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: - POLYGROUPS = False - - time_main= sys.time() - - verts_loc= [] - verts_tex= [] - faces= [] # tuples of the faces - material_libs= [] # filanems to material libs this uses - vertex_groups = {} # when POLYGROUPS is true - - # Get the string to float conversion func for this file- is 'float' for almost all files. - float_func= get_float_func(filepath) - - # Context variables - context_material= None - context_smooth_group= None - context_object= None - context_vgroup = None - - # Nurbs - context_nurbs = {} - nurbs = [] - context_parm = '' # used by nurbs too but could be used elsewhere - - has_ngons= False - # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 - - # Until we can use sets - unique_materials= {} - unique_material_images= {} - unique_smooth_groups= {} - # unique_obects= {} - no use for this variable since the objects are stored in the face. - - # when there are faces that end with \ - # it means they are multiline- - # since we use xreadline we cant skip to the next line - # so we need to know weather - context_multi_line= '' - - print '\tparsing obj file "%s"...' % filepath, - time_sub= sys.time() - - file= open(filepath, 'rU') - for line in file: #.xreadlines(): - line = line.lstrip() # rare cases there is white space at the start of the line - - if line.startswith('v '): - line_split= line.split() - # rotate X90: (x,-z,y) - verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) - - elif line.startswith('vn '): - pass - - elif line.startswith('vt '): - line_split= line.split() - verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) - - # Handel faces lines (as faces) and the second+ lines of fa multiline face here - # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) - elif line.startswith('f') or context_multi_line == 'f': - - if context_multi_line: - # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face - line_split= line.split() - - else: - line_split= line[2:].split() - face_vert_loc_indicies= [] - face_vert_tex_indicies= [] - - # Instance a face - faces.append((\ - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object\ - )) - - if strip_slash(line_split): - context_multi_line = 'f' - else: - context_multi_line = '' - - for v in line_split: - obj_vert= v.split('/') - - vert_loc_index= int(obj_vert[0])-1 - # Add the vertex to the current group - # *warning*, this wont work for files that have groups defined around verts - if POLYGROUPS and context_vgroup: - vertex_groups[context_vgroup].append(vert_loc_index) - - # Make relative negative vert indicies absolute - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - face_vert_loc_indicies.append(vert_loc_index) - - if len(obj_vert)>1 and obj_vert[1]: - # formatting for faces with normals and textures us - # loc_index/tex_index/nor_index - - vert_tex_index= int(obj_vert[1])-1 - # Make relative negative vert indicies absolute - if vert_tex_index < 0: - vert_tex_index= len(verts_tex) + vert_tex_index + 1 - - face_vert_tex_indicies.append(vert_tex_index) - else: - # dummy - face_vert_tex_indicies.append(0) - - if len(face_vert_loc_indicies) > 4: - has_ngons= True - - elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'): - # very similar to the face load function above with some parts removed - - if context_multi_line: - # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face - line_split= line.split() - - else: - line_split= line[2:].split() - face_vert_loc_indicies= [] - face_vert_tex_indicies= [] - - # Instance a face - faces.append((\ - face_vert_loc_indicies,\ - face_vert_tex_indicies,\ - context_material,\ - context_smooth_group,\ - context_object\ - )) - - if strip_slash(line_split): - context_multi_line = 'l' - else: - context_multi_line = '' - - isline= line.startswith('l') - - for v in line_split: - vert_loc_index= int(v)-1 - - # Make relative negative vert indicies absolute - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - face_vert_loc_indicies.append(vert_loc_index) - - elif line.startswith('s'): - if CREATE_SMOOTH_GROUPS: - context_smooth_group= line_value(line.split()) - if context_smooth_group=='off': - context_smooth_group= None - elif context_smooth_group: # is not None - unique_smooth_groups[context_smooth_group]= None - - elif line.startswith('o'): - if SPLIT_OBJECTS: - context_object= line_value(line.split()) - # unique_obects[context_object]= None - - elif line.startswith('g'): - if SPLIT_GROUPS: - context_object= line_value(line.split()) - # print 'context_object', context_object - # unique_obects[context_object]= None - elif POLYGROUPS: - context_vgroup = line_value(line.split()) - if context_vgroup and context_vgroup != '(null)': - vertex_groups.setdefault(context_vgroup, []) - else: - context_vgroup = None # dont assign a vgroup - - elif line.startswith('usemtl'): - context_material= line_value(line.split()) - unique_materials[context_material]= None - elif line.startswith('mtllib'): # usemap or usemat - material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line - - - # Nurbs support - elif line.startswith('cstype '): - context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline' - elif line.startswith('curv ') or context_multi_line == 'curv': - line_split= line.split() - - curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline - - if not context_multi_line: - context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2]) - line_split[0:3] = [] # remove first 3 items - - if strip_slash(line_split): - context_multi_line = 'curv' - else: - context_multi_line = '' - - - for i in line_split: - vert_loc_index = int(i)-1 - - if vert_loc_index < 0: - vert_loc_index= len(verts_loc) + vert_loc_index + 1 - - curv_idx.append(vert_loc_index) - - elif line.startswith('parm') or context_multi_line == 'parm': - line_split= line.split() - - if context_multi_line: - context_multi_line = '' - else: - context_parm = line_split[1] - line_split[0:2] = [] # remove first 2 - - if strip_slash(line_split): - context_multi_line = 'parm' - else: - context_multi_line = '' - - if context_parm.lower() == 'u': - context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] ) - elif context_parm.lower() == 'v': # surfaces not suported yet - context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] ) - # else: # may want to support other parm's ? - - elif line.startswith('deg '): - context_nurbs['deg']= [int(i) for i in line.split()[1:]] - elif line.startswith('end'): - # Add the nurbs curve - if context_object: - context_nurbs['name'] = context_object - nurbs.append(context_nurbs) - context_nurbs = {} - context_parm = '' - - ''' # How to use usemap? depricated? - elif line.startswith('usema'): # usemap or usemat - context_image= line_value(line.split()) - ''' - - file.close() - time_new= sys.time() - print '%.4f sec' % (time_new-time_sub) - time_sub= time_new - - - print '\tloading materials and images...', - create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) - - time_new= sys.time() - print '%.4f sec' % (time_new-time_sub) - time_sub= time_new - - if not ROTATE_X90: - verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] - - # deselect all - scn = bpy.data.scenes.active - scn.objects.selected = [] - new_objects= [] # put new objects here - - print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), - # Split the mesh by objects/materials, may - if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True - else: SPLIT_OB_OR_GROUP = False - - for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): - # Create meshes from the data, warning 'vertex_groups' wont support splitting - create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) - - # nurbs support - for context_nurbs in nurbs: - create_nurbs(scn, context_nurbs, verts_loc, new_objects) - - - axis_min= [ 1000000000]*3 - axis_max= [-1000000000]*3 - - if CLAMP_SIZE: - # Get all object bounds - for ob in new_objects: - for v in ob.getBoundBox(): - for axis, value in enumerate(v): - if axis_min[axis] > value: axis_min[axis]= value - if axis_max[axis] < value: axis_max[axis]= value - - # Scale objects - max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) - scale= 1.0 - - while CLAMP_SIZE < max_axis * scale: - scale= scale/10.0 - - for ob in new_objects: - ob.setSize(scale, scale, scale) - - # Better rotate the vert locations - #if not ROTATE_X90: - # for ob in new_objects: - # ob.RotX = -1.570796326794896558 - - time_new= sys.time() - - print '%.4f sec' % (time_new-time_sub) - print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) - - -DEBUG= True - - -def load_obj_ui(filepath, BATCH_LOAD= False): - if BPyMessages.Error_NoFile(filepath): - return - - global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 - - CREATE_SMOOTH_GROUPS= Draw.Create(0) - CREATE_FGONS= Draw.Create(1) - CREATE_EDGES= Draw.Create(1) - SPLIT_OBJECTS= Draw.Create(0) - SPLIT_GROUPS= Draw.Create(0) - SPLIT_MATERIALS= Draw.Create(0) - CLAMP_SIZE= Draw.Create(10.0) - IMAGE_SEARCH= Draw.Create(1) - POLYGROUPS= Draw.Create(0) - KEEP_VERT_ORDER= Draw.Create(1) - ROTATE_X90= Draw.Create(1) - - - # Get USER Options - # Note, Works but not pretty, instead use a more complicated GUI - ''' - pup_block= [\ - 'Import...',\ - ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ - ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ - ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ - 'Separate objects from obj...',\ - ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ - ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ - ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ - 'Options...',\ - ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ - ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ - ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ - ] - - if not Draw.PupBlock('Import OBJ...', pup_block): - return - - if KEEP_VERT_ORDER.val: - SPLIT_OBJECTS.val = False - SPLIT_GROUPS.val = False - SPLIT_MATERIALS.val = False - ''' - - - - # BEGIN ALTERNATIVE UI ******************* - if True: - - EVENT_NONE = 0 - EVENT_EXIT = 1 - EVENT_REDRAW = 2 - EVENT_IMPORT = 3 - - GLOBALS = {} - GLOBALS['EVENT'] = EVENT_REDRAW - #GLOBALS['MOUSE'] = Window.GetMouseCoords() - GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] - - def obj_ui_set_event(e,v): - GLOBALS['EVENT'] = e - - def do_split(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS - if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val: - KEEP_VERT_ORDER.val = 0 - POLYGROUPS.val = 0 - else: - KEEP_VERT_ORDER.val = 1 - - def do_vertorder(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER - if KEEP_VERT_ORDER.val: - SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 - else: - if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val): - KEEP_VERT_ORDER.val = 1 - - def do_polygroups(e,v): - global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS - if POLYGROUPS.val: - SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 - - def do_help(e,v): - url = __url__[0] - print 'Trying to open web browser with documentation at this address...' - print '\t' + url - - try: - import webbrowser - webbrowser.open(url) - except: - print '...could not open a browser window.' - - def obj_ui(): - ui_x, ui_y = GLOBALS['MOUSE'] - - # Center based on overall pup size - ui_x -= 165 - ui_y -= 90 - - global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 - - Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21) - Draw.BeginAlign() - CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges') - CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons') - CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges') - Draw.EndAlign() - - Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20) - Draw.BeginAlign() - SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split) - SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split) - SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split) - Draw.EndAlign() - - # Only used for user feedback - KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder) - - ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.') - - Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20) - CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)') - POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups) - IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)') - Draw.BeginAlign() - Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help) - Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event) - Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event) - Draw.EndAlign() - - - # hack so the toggle buttons redraw. this is not nice at all - while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT): - Draw.UIBlock(obj_ui, 0) - - if GLOBALS['EVENT'] != EVENT_IMPORT: - return - - # END ALTERNATIVE UI ********************* - - - - - - - - Window.WaitCursor(1) - - if BATCH_LOAD: # load the dir - try: - files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] - except: - Window.WaitCursor(0) - Draw.PupMenu('Error%t|Could not open path ' + filepath) - return - - if not files: - Window.WaitCursor(0) - Draw.PupMenu('Error%t|No files at path ' + filepath) - return - - for f in files: - scn= bpy.data.scenes.new( stripExt(f) ) - scn.makeCurrent() - - load_obj(sys.join(filepath, f),\ - CLAMP_SIZE.val,\ - CREATE_FGONS.val,\ - CREATE_SMOOTH_GROUPS.val,\ - CREATE_EDGES.val,\ - SPLIT_OBJECTS.val,\ - SPLIT_GROUPS.val,\ - SPLIT_MATERIALS.val,\ - ROTATE_X90.val,\ - IMAGE_SEARCH.val,\ - POLYGROUPS.val - ) - - else: # Normal load - load_obj(filepath,\ - CLAMP_SIZE.val,\ - CREATE_FGONS.val,\ - CREATE_SMOOTH_GROUPS.val,\ - CREATE_EDGES.val,\ - SPLIT_OBJECTS.val,\ - SPLIT_GROUPS.val,\ - SPLIT_MATERIALS.val,\ - ROTATE_X90.val,\ - IMAGE_SEARCH.val,\ - POLYGROUPS.val - ) - - Window.WaitCursor(0) - - -def load_obj_ui_batch(file): - load_obj_ui(file, True) - -DEBUG= False - -if __name__=='__main__' and not DEBUG: - if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: - Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') - else: - Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') - - # For testing compatibility -''' -else: - # DEBUG ONLY - TIME= sys.time() - DIR = '/fe/obj' - import os - print 'Searching for files' - def fileList(path): - for dirpath, dirnames, filenames in os.walk(path): - for filename in filenames: - yield os.path.join(dirpath, filename) - - files = [f for f in fileList(DIR) if f.lower().endswith('.obj')] - files.sort() - - for i, obj_file in enumerate(files): - if 0 < i < 20: - print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files) - newScn= bpy.data.scenes.new(os.path.basename(obj_file)) - newScn.makeCurrent() - load_obj(obj_file, False, IMAGE_SEARCH=0) - - print 'TOTAL TIME: %.6f' % (sys.time() - TIME) -''' -#load_obj('/test.obj') -#load_obj('/fe/obj/mba1.obj') diff --git a/release/scripts/import_web3d.py b/release/scripts/import_web3d.py deleted file mode 100644 index a5547506dc7..00000000000 --- a/release/scripts/import_web3d.py +++ /dev/null @@ -1,2594 +0,0 @@ -#!BPY -""" -Name: 'X3D & VRML97 (.x3d / wrl)...' -Blender: 248 -Group: 'Import' -Tooltip: 'Load an X3D or VRML97 file' -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# (C) Copyright 2008 Paravizion -# Written by Campbell Barton aka Ideasman42 -# -# 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 ***** -# -------------------------------------------------------------------------- - -__author__ = "Campbell Barton" -__url__ = ['www.blender.org', 'blenderartists.org', 'http://wiki.blender.org/index.php/Scripts/Manual/Import/X3D_VRML97'] -__version__ = "0.1" - -__bpydoc__ = """\ -This script is an importer for the X3D and VRML97 file formats. -""" - -DEBUG = False - -# This should work without a blender at all -try: - from Blender.sys import exists -except: - from os.path import exists - -def baseName(path): - return path.split('/')[-1].split('\\')[-1] - -def dirName(path): - return path[:-len(baseName(path))] - -def imageConvertCompat(path): - - try: import os - except: return path - if os.sep=='\\': return path # assime win32 has quicktime, dont convert - - if path.lower().endswith('.gif'): - path_to = path[:-3] + 'png' - - ''' - if exists(path_to): - return path_to - ''' - # print '\n'+path+'\n'+path_to+'\n' - os.system('convert "%s" "%s"' % (path, path_to)) # for now just hope we have image magick - - if exists(path_to): - return path_to - - return path - -# notes -# transform are relative -# order dosnt matter for loc/size/rot -# right handed rotation -# angles are in radians -# rotation first defines axis then ammount in radians - - - -# =============================== VRML Spesific - - -def vrmlFormat(data): - ''' - Keep this as a valid vrml file, but format in a way we can predict. - ''' - # Strip all commends - # not in strings - warning multiline strings are ignored. - def strip_comment(l): - #l = ' '.join(l.split()) - l = l.strip() - - if l.startswith('#'): - return '' - - i = l.find('#') - - if i==-1: - return l - - # Most cases accounted for! if we have a comment at the end of the line do this... - #j = l.find('url "') - j = l.find('"') - - if j == -1: # simple no strings - return l[:i].strip() - - q = False - for i,c in enumerate(l): - if c == '"': - q = not q # invert - - elif c == '#': - if q==False: - return l[:i-1] - - return l - - data = '\n'.join([strip_comment(l) for l in data.split('\n') ]) # remove all whitespace - - EXTRACT_STRINGS = True # only needed when strings or filesnames containe ,[]{} chars :/ - - if EXTRACT_STRINGS: - - # We need this so we can detect URL's - data = '\n'.join([' '.join(l.split()) for l in data.split('\n')]) # remove all whitespace - - string_ls = [] - - #search = 'url "' - search = '"' - - ok = True - last_i = 0 - while ok: - ok = False - i = data.find(search, last_i) - if i != -1: - - start = i + len(search) # first char after end of search - end = data.find('"', start) - if end != -1: - item = data[start:end] - string_ls.append( item ) - data = data[:start] + data[end:] - ok = True # keep looking - - last_i = (end - len(item)) + 1 - # print last_i, item, '|' + data[last_i] + '|' - - # done with messy extracting strings part - - - # Bad, dont take strings into account - ''' - data = data.replace('#', '\n#') - data = '\n'.join([ll for l in data.split('\n') for ll in (l.strip(),) if not ll.startswith('#')]) # remove all whitespace - ''' - data = data.replace('{', '\n{\n') - data = data.replace('}', '\n}\n') - data = data.replace('[', '\n[\n') - data = data.replace(']', '\n]\n') - data = data.replace(',', ' , ') # make sure comma's seperate - - if EXTRACT_STRINGS: - # add strings back in - - search = '"' # fill in these empty strings - - ok = True - last_i = 0 - while ok: - ok = False - i = data.find(search + '"', last_i) - # print i - if i != -1: - start = i + len(search) # first char after end of search - item = string_ls.pop(0) - # print item - data = data[:start] + item + data[start:] - - last_i = start + len(item) + 1 - - ok = True - - - # More annoying obscure cases where USE or DEF are placed on a newline - # data = data.replace('\nDEF ', ' DEF ') - # data = data.replace('\nUSE ', ' USE ') - - data = '\n'.join([' '.join(l.split()) for l in data.split('\n')]) # remove all whitespace - - # Better to parse the file accounting for multiline arrays - ''' - data = data.replace(',\n', ' , ') # remove line endings with commas - data = data.replace(']', '\n]\n') # very very annoying - but some comma's are at the end of the list, must run this again. - ''' - - return [l for l in data.split('\n') if l] - -NODE_NORMAL = 1 # {} -NODE_ARRAY = 2 # [] -NODE_REFERENCE = 3 # USE foobar -# NODE_PROTO = 4 # - -lines = [] - -def getNodePreText(i, words): - # print lines[i] - use_node = False - while len(words) < 5: - - if i>=len(lines): - break - ''' - elif lines[i].startswith('PROTO'): - return NODE_PROTO, i+1 - ''' - elif lines[i]=='{': - # words.append(lines[i]) # no need - # print "OK" - return NODE_NORMAL, i+1 - elif lines[i].count('"') % 2 != 0: # odd number of quotes? - part of a string. - # print 'ISSTRING' - break - else: - new_words = lines[i].split() - if 'USE' in new_words: - use_node = True - - words.extend(new_words) - i += 1 - - # Check for USE node - no { - # USE #id - should always be on the same line. - if use_node: - # print 'LINE', i, words[:words.index('USE')+2] - words[:] = words[:words.index('USE')+2] - if lines[i] == '{' and lines[i+1] == '}': - # USE sometimes has {} after it anyway - i+=2 - return NODE_REFERENCE, i - - # print "error value!!!", words - return 0, -1 - -def is_nodeline(i, words): - - if not lines[i][0].isalpha(): - return 0, 0 - - #if lines[i].startswith('field'): - # return 0, 0 - - # Is this a prototype?? - if lines[i].startswith('PROTO'): - words[:] = lines[i].split() - return NODE_NORMAL, i+1 # TODO - assumes the next line is a '[\n', skip that - if lines[i].startswith('EXTERNPROTO'): - words[:] = lines[i].split() - return NODE_ARRAY, i+1 # TODO - assumes the next line is a '[\n', skip that - - ''' - proto_type, new_i = is_protoline(i, words, proto_field_defs) - if new_i != -1: - return proto_type, new_i - ''' - - # Simple "var [" type - if lines[i+1] == '[': - if lines[i].count('"') % 2 == 0: - words[:] = lines[i].split() - return NODE_ARRAY, i+2 - - node_type, new_i = getNodePreText(i, words) - - if not node_type: - if DEBUG: print "not node_type", lines[i] - return 0, 0 - - # Ok, we have a { after some values - # Check the values are not fields - for i, val in enumerate(words): - if i != 0 and words[i-1] in ('DEF', 'USE'): - # ignore anything after DEF, it is a ID and can contain any chars. - pass - elif val[0].isalpha() and val not in ('TRUE', 'FALSE'): - pass - else: - # There is a number in one of the values, therefor we are not a node. - return 0, 0 - - #if node_type==NODE_REFERENCE: - # print words, "REF_!!!!!!!" - return node_type, new_i - -def is_numline(i): - ''' - Does this line start with a number? - ''' - - # Works but too slow. - ''' - l = lines[i] - for w in l.split(): - if w==',': - pass - else: - try: - float(w) - return True - - except: - return False - - return False - ''' - - l = lines[i] - - line_start = 0 - - if l.startswith(', '): - line_start += 2 - - line_end = len(l)-1 - line_end_new = l.find(' ', line_start) # comma's always have a space before them - - if line_end_new != -1: - line_end = line_end_new - - try: - float(l[line_start:line_end]) # works for a float or int - return True - except: - return False - - -class vrmlNode(object): - __slots__ = 'id', 'fields', 'proto_node', 'proto_field_defs', 'proto_fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'PROTO_NAMESPACE', 'x3dNode' - def __init__(self, parent, node_type, lineno): - self.id = None - self.node_type = node_type - self.parent = parent - self.blendObject = None - self.x3dNode = None # for x3d import only - if parent: - parent.children.append(self) - - self.lineno = lineno - - # This is only set from the root nodes. - # Having a filename also denotes a root node - self.filename = None - self.proto_node = None # proto field definition eg: "field SFColor seatColor .6 .6 .1" - - # Store in the root node because each inline file needs its own root node and its own namespace - self.DEF_NAMESPACE = None - self.ROUTE_IPO_NAMESPACE = None - ''' - self.FIELD_NAMESPACE = None - ''' - - - self.PROTO_NAMESPACE = None - - self.reference = None - - if node_type==NODE_REFERENCE: - # For references, only the parent and ID are needed - # the reference its self is assigned on parsing - return - - self.fields = [] # fields have no order, in some cases rool level values are not unique so dont use a dict - - self.proto_field_defs = [] # proto field definition eg: "field SFColor seatColor .6 .6 .1" - self.proto_fields = [] # proto field usage "diffuseColor IS seatColor" - self.children = [] - self.array_data = [] # use for arrays of data - should only be for NODE_ARRAY types - - - # Only available from the root node - ''' - def getFieldDict(self): - if self.FIELD_NAMESPACE != None: - return self.FIELD_NAMESPACE - else: - return self.parent.getFieldDict() - ''' - def getProtoDict(self): - if self.PROTO_NAMESPACE != None: - return self.PROTO_NAMESPACE - else: - return self.parent.getProtoDict() - - def getDefDict(self): - if self.DEF_NAMESPACE != None: - return self.DEF_NAMESPACE - else: - return self.parent.getDefDict() - - def getRouteIpoDict(self): - if self.ROUTE_IPO_NAMESPACE != None: - return self.ROUTE_IPO_NAMESPACE - else: - return self.parent.getRouteIpoDict() - - def setRoot(self, filename): - self.filename = filename - # self.FIELD_NAMESPACE = {} - self.DEF_NAMESPACE = {} - self.ROUTE_IPO_NAMESPACE = {} - self.PROTO_NAMESPACE = {} - - def isRoot(self): - if self.filename == None: - return False - else: - return True - - def getFilename(self): - if self.filename: - return self.filename - elif self.parent: - return self.parent.getFilename() - else: - return None - - def getRealNode(self): - if self.reference: - return self.reference - else: - return self - - def getSpec(self): - self_real = self.getRealNode() - try: - return self_real.id[-1] # its possible this node has no spec - except: - return None - - def findSpecRecursive(self, spec): - self_real = self.getRealNode() - if spec == self_real.getSpec(): - return self - - for child in self_real.children: - if child.findSpecRecursive(spec): - return child - - return None - - def getPrefix(self): - if self.id: - return self.id[0] - return None - - def getSpecialTypeName(self, typename): - self_real = self.getRealNode() - try: return self_real.id[ list(self_real.id).index(typename)+1 ] - except: return None - - - def getDefName(self): - return self.getSpecialTypeName('DEF') - - def getProtoName(self): - return self.getSpecialTypeName('PROTO') - - def getExternprotoName(self): - return self.getSpecialTypeName('EXTERNPROTO') - - def getChildrenBySpec(self, node_spec): # spec could be Transform, Shape, Appearance - self_real = self.getRealNode() - # using getSpec functions allows us to use the spec of USE children that dont have their spec in their ID - if type(node_spec) == str: - return [child for child in self_real.children if child.getSpec()==node_spec] - else: - # Check inside a list of optional types - return [child for child in self_real.children if child.getSpec() in node_spec] - - def getChildBySpec(self, node_spec): # spec could be Transform, Shape, Appearance - # Use in cases where there is only ever 1 child of this type - ls = self.getChildrenBySpec(node_spec) - if ls: return ls[0] - else: return None - - def getChildrenByName(self, node_name): # type could be geometry, children, appearance - self_real = self.getRealNode() - return [child for child in self_real.children if child.id if child.id[0]==node_name] - - def getChildByName(self, node_name): - self_real = self.getRealNode() - for child in self_real.children: - if child.id and child.id[0]==node_name: # and child.id[-1]==node_spec: - return child - - def getSerialized(self, results, ancestry): - ''' Return this node and all its children in a flat list ''' - ancestry = ancestry[:] # always use a copy - - # self_real = self.getRealNode() - - results.append((self, tuple(ancestry))) - ancestry.append(self) - for child in self.getRealNode().children: - if child not in ancestry: - # We dont want to load proto's, they are only references - # We could enforce this elsewhere - - # Only add this in a very special case - # where the parent of this object is not the real parent - # - In this case we have added the proto as a child to a node instancing it. - # This is a bit arbitary, but its how Proto's are done with this importer. - if child.getProtoName() == None and child.getExternprotoName() == None: - child.getSerialized(results, ancestry) - else: - - if DEBUG: print 'getSerialized() is proto:', child.getProtoName(), child.getExternprotoName(), self.getSpec() - - self_spec = self.getSpec() - - if child.getProtoName() == self_spec or child.getExternprotoName() == self_spec: - if DEBUG: "FoundProto!" - child.getSerialized(results, ancestry) - - - - return results - - def searchNodeTypeID(self, node_spec, results): - self_real = self.getRealNode() - # print self.lineno, self.id - if self_real.id and self_real.id[-1]==node_spec: # use last element, could also be only element - results.append(self_real) - for child in self_real.children: - child.searchNodeTypeID(node_spec, results) - return results - - def getFieldName(self, field, ancestry, AS_CHILD=False): - self_real = self.getRealNode() # incase we're an instance - - for f in self_real.fields: - # print f - if f and f[0] == field: - # print '\tfound field', f - - if len(f)>=3 and f[1] == 'IS': # eg: 'diffuseColor IS legColor' - field_id = f[2] - - # print "\n\n\n\n\n\nFOND IS!!!" - f_proto_lookup = None - f_proto_child_lookup = None - i = len(ancestry) - while i: - i -= 1 - node = ancestry[i] - node = node.getRealNode() - - # proto settings are stored in "self.proto_node" - if node.proto_node: - # Get the default value from the proto, this can be overwridden by the proto instace - # 'field SFColor legColor .8 .4 .7' - if AS_CHILD: - for child in node.proto_node.children: - #if child.id and len(child.id) >= 3 and child.id[2]==field_id: - if child.id and ('point' in child.id or 'points' in child.id): - f_proto_child_lookup = child - - else: - for f_def in node.proto_node.proto_field_defs: - if len(f_def) >= 4: - if f_def[0]=='field' and f_def[2]==field_id: - f_proto_lookup = f_def[3:] - - # Node instance, Will be 1 up from the proto-node in the ancestry list. but NOT its parent. - # This is the setting as defined by the instance, including this setting is optional, - # and will override the default PROTO value - # eg: 'legColor 1 0 0' - if AS_CHILD: - for child in node.children: - if child.id and child.id[0]==field_id: - f_proto_child_lookup = child - else: - for f_def in node.fields: - if len(f_def) >= 2: - if f_def[0]==field_id: - if DEBUG: print "getFieldName(), found proto", f_def - f_proto_lookup = f_def[1:] - - - if AS_CHILD: - if f_proto_child_lookup: - if DEBUG: - print "getFieldName() - AS_CHILD=True, child found" - print f_proto_child_lookup - return f_proto_child_lookup - else: - return f_proto_lookup - else: - if AS_CHILD: - return None - else: - # Not using a proto - return f[1:] - - # print '\tfield not found', field - - - # See if this is a proto name - if AS_CHILD: - child_array = None - for child in self_real.children: - if child.id and len(child.id) == 1 and child.id[0] == field: - return child - - return None - - def getFieldAsInt(self, field, default, ancestry): - self_real = self.getRealNode() # incase we're an instance - - f = self_real.getFieldName(field, ancestry) - if f==None: return default - if ',' in f: f = f[:f.index(',')] # strip after the comma - - if len(f) != 1: - print '\t"%s" wrong length for int conversion for field "%s"' % (f, field) - return default - - try: - return int(f[0]) - except: - print '\tvalue "%s" could not be used as an int for field "%s"' % (f[0], field) - return default - - def getFieldAsFloat(self, field, default, ancestry): - self_real = self.getRealNode() # incase we're an instance - - f = self_real.getFieldName(field, ancestry) - if f==None: return default - if ',' in f: f = f[:f.index(',')] # strip after the comma - - if len(f) != 1: - print '\t"%s" wrong length for float conversion for field "%s"' % (f, field) - return default - - try: - return float(f[0]) - except: - print '\tvalue "%s" could not be used as a float for field "%s"' % (f[0], field) - return default - - def getFieldAsFloatTuple(self, field, default, ancestry): - self_real = self.getRealNode() # incase we're an instance - - f = self_real.getFieldName(field, ancestry) - if f==None: return default - # if ',' in f: f = f[:f.index(',')] # strip after the comma - - if len(f) < 1: - print '"%s" wrong length for float tuple conversion for field "%s"' % (f, field) - return default - - ret = [] - for v in f: - if v != ',': - try: ret.append(float(v)) - except: break # quit of first non float, perhaps its a new field name on the same line? - if so we are going to ignore it :/ TODO - # print ret - - if ret: - return ret - if not ret: - print '\tvalue "%s" could not be used as a float tuple for field "%s"' % (f, field) - return default - - def getFieldAsBool(self, field, default, ancestry): - self_real = self.getRealNode() # incase we're an instance - - f = self_real.getFieldName(field, ancestry) - if f==None: return default - if ',' in f: f = f[:f.index(',')] # strip after the comma - - if len(f) != 1: - print '\t"%s" wrong length for bool conversion for field "%s"' % (f, field) - return default - - if f[0].upper()=='"TRUE"' or f[0].upper()=='TRUE': - return True - elif f[0].upper()=='"FALSE"' or f[0].upper()=='FALSE': - return False - else: - print '\t"%s" could not be used as a bool for field "%s"' % (f[1], field) - return default - - def getFieldAsString(self, field, default, ancestry): - self_real = self.getRealNode() # incase we're an instance - - f = self_real.getFieldName(field, ancestry) - if f==None: return default - if len(f) < 1: - print '\t"%s" wrong length for string conversion for field "%s"' % (f, field) - return default - - if len(f) > 1: - # String may contain spaces - st = ' '.join(f) - else: - st = f[0] - - # X3D HACK - if self.x3dNode: - return st - - if st[0]=='"' and st[-1]=='"': - return st[1:-1] - else: - print '\tvalue "%s" could not be used as a string for field "%s"' % (f[0], field) - return default - - def getFieldAsArray(self, field, group, ancestry): - ''' - For this parser arrays are children - ''' - self_real = self.getRealNode() # incase we're an instance - - child_array = self_real.getFieldName(field, ancestry, True) - - #if type(child_array)==list: # happens occasionaly - # array_data = child_array - - if child_array==None: - - # For x3d, should work ok with vrml too - # for x3d arrays are fields, vrml they are nodes, annoying but not tooo bad. - data_split = self.getFieldName(field, ancestry) - if not data_split: - return [] - array_data = ' '.join(data_split) - if array_data == None: - return [] - - array_data = array_data.replace(',', ' ') - data_split = array_data.split() - try: - array_data = [int(val) for val in data_split] - except: - try: - array_data = [float(val) for val in data_split] - except: - print '\tWarning, could not parse array data from field' - array_data = [] - else: - # print child_array - # Normal vrml - array_data = child_array.array_data - - - # print 'array_data', array_data - - if group==-1 or len(array_data)==0: - return array_data - - # We want a flat list - flat = True - for item in array_data: - if type(item) == list: - flat = False - break - - # make a flat array - if flat: - flat_array = array_data # we are alredy flat. - else: - flat_array = [] - - def extend_flat(ls): - for item in ls: - if type(item)==list: extend_flat(item) - else: flat_array.append(item) - - extend_flat(array_data) - - - # We requested a flat array - if group == 0: - return flat_array - - new_array = [] - sub_array = [] - - for item in flat_array: - sub_array.append(item) - if len(sub_array)==group: - new_array.append(sub_array) - sub_array = [] - - if sub_array: - print '\twarning, array was not aligned to requested grouping', group, 'remaining value', sub_array - - return new_array - - def getFieldAsStringArray(self, field, ancestry): - ''' - Get a list of strings - ''' - self_real = self.getRealNode() # incase we're an instance - - child_array = None - for child in self_real.children: - if child.id and len(child.id) == 1 and child.id[0] == field: - child_array = child - break - if not child_array: - return [] - - # each string gets its own list, remove ""'s - try: - new_array = [f[0][1:-1] for f in child_array.fields] - except: - print '\twarning, string array could not be made' - new_array = [] - - return new_array - - - def getLevel(self): - # Ignore self_real - level = 0 - p = self.parent - while p: - level +=1 - p = p.parent - if not p: break - - return level - - def __repr__(self): - level = self.getLevel() - ind = ' ' * level - if self.node_type==NODE_REFERENCE: - brackets = '' - elif self.node_type==NODE_NORMAL: - brackets = '{}' - else: - brackets = '[]' - - if brackets: - text = ind + brackets[0] + '\n' - else: - text = '' - - text += ind + 'ID: ' + str(self.id) + ' ' + str(level) + (' lineno %d\n' % self.lineno) - - if self.node_type==NODE_REFERENCE: - text += ind + "(reference node)\n" - return text - - if self.proto_node: - text += ind + 'PROTO NODE...\n' - text += str(self.proto_node) - text += ind + 'PROTO NODE_DONE\n' - - text += ind + 'FIELDS:' + str(len(self.fields)) + '\n' - - for i,item in enumerate(self.fields): - text += ind + 'FIELD:\n' - text += ind + str(item) +'\n' - - text += ind + 'PROTO_FIELD_DEFS:' + str(len(self.proto_field_defs)) + '\n' - - for i,item in enumerate(self.proto_field_defs): - text += ind + 'PROTO_FIELD:\n' - text += ind + str(item) +'\n' - - text += ind + 'ARRAY: ' + str(len(self.array_data)) + ' ' + str(self.array_data) + '\n' - #text += ind + 'ARRAY: ' + str(len(self.array_data)) + '[...] \n' - - text += ind + 'CHILDREN: ' + str(len(self.children)) + '\n' - for i, child in enumerate(self.children): - text += ind + ('CHILD%d:\n' % i) - text += str(child) - - text += '\n' + ind + brackets[1] - - return text - - def parse(self, i, IS_PROTO_DATA=False): - new_i = self.__parse(i, IS_PROTO_DATA) - - # print self.id, self.getFilename() - - # Check if this node was an inline or externproto - - url_ls = [] - - if self.node_type == NODE_NORMAL and self.getSpec() == 'Inline': - ancestry = [] # Warning! - PROTO's using this wont work at all. - url = self.getFieldAsString('url', None, ancestry) - if url: - url_ls = [(url, None)] - del ancestry - - elif self.getExternprotoName(): - # externproto - url_ls = [] - for f in self.fields: - - if type(f)==str: - f = [f] - - for ff in f: - for f_split in ff.split('"'): - # print f_split - # "someextern.vrml#SomeID" - if '#' in f_split: - - f_split, f_split_id = f_split.split('#') # there should only be 1 # anyway - - url_ls.append( (f_split, f_split_id) ) - else: - url_ls.append( (f_split, None) ) - - - # Was either an Inline or an EXTERNPROTO - if url_ls: - - # print url_ls - - for url, extern_key in url_ls: - print url - urls = [] - urls.append( url ) - urls.append( BPySys.caseInsensitivePath(urls[-1]) ) - - urls.append( dirName(self.getFilename()) + url ) - urls.append( BPySys.caseInsensitivePath(urls[-1]) ) - - urls.append( dirName(self.getFilename()) + baseName(url) ) - urls.append( BPySys.caseInsensitivePath(urls[-1]) ) - - try: - url = [url for url in urls if exists(url)][0] - url_found = True - except: - url_found = False - - if not url_found: - print '\tWarning: Inline URL could not be found:', url - else: - if url==self.getFilename(): - print '\tWarning: cant Inline yourself recursively:', url - else: - - try: - data = gzipOpen(url) - except: - print '\tWarning: cant open the file:', url - data = None - - if data: - # Tricky - inline another VRML - print '\tLoading Inline:"%s"...' % url - - # Watch it! - backup lines - lines_old = lines[:] - - - lines[:] = vrmlFormat( data ) - - lines.insert(0, '{') - lines.insert(0, 'root_node____') - lines.append('}') - ''' - ff = open('/tmp/test.txt', 'w') - ff.writelines([l+'\n' for l in lines]) - ''' - - child = vrmlNode(self, NODE_NORMAL, -1) - child.setRoot(url) # initialized dicts - child.parse(0) - - # if self.getExternprotoName(): - if self.getExternprotoName(): - if not extern_key: # if none is spesified - use the name - extern_key = self.getSpec() - - if extern_key: - - self.children.remove(child) - child.parent = None - - extern_child = child.findSpecRecursive(extern_key) - - if extern_child: - self.children.append(extern_child) - extern_child.parent = self - - if DEBUG: print "\tEXTERNPROTO ID found!:", extern_key - else: - print "\tEXTERNPROTO ID not found!:", extern_key - - # Watch it! - restore lines - lines[:] = lines_old - - return new_i - - def __parse(self, i, IS_PROTO_DATA=False): - ''' - print 'parsing at', i, - print i, self.id, self.lineno - ''' - l = lines[i] - - if l=='[': - # An anonymous list - self.id = None - i+=1 - else: - words = [] - - node_type, new_i = is_nodeline(i, words) - if not node_type: # fail for parsing new node. - print "Failed to parse new node" - raise ValueError - - if self.node_type==NODE_REFERENCE: - # Only assign the reference and quit - key = words[words.index('USE')+1] - self.id = (words[0],) - - self.reference = self.getDefDict()[key] - return new_i - - self.id = tuple(words) - - # fill in DEF/USE - key = self.getDefName() - if key != None: - self.getDefDict()[ key ] = self - - key = self.getProtoName() - if not key: key = self.getExternprotoName() - - proto_dict = self.getProtoDict() - if key != None: - proto_dict[ key ] = self - - # Parse the proto nodes fields - self.proto_node = vrmlNode(self, NODE_ARRAY, new_i) - new_i = self.proto_node.parse(new_i) - - self.children.remove(self.proto_node) - - # print self.proto_node - - new_i += 1 # skip past the { - - - else: # If we're a proto instance, add the proto node as our child. - spec = self.getSpec() - try: - self.children.append( proto_dict[spec] ) - #pass - except: - pass - - del spec - - del proto_dict, key - - i = new_i - - # print self.id - ok = True - while ok: - if i>=len(lines): - return len(lines)-1 - - l = lines[i] - # print '\tDEBUG:', i, self.node_type, l - if l=='': - i+=1 - continue - - if l=='}': - if self.node_type != NODE_NORMAL: # also ends proto nodes, we may want a type for these too. - print 'wrong node ending, expected an } ' + str(i) + ' ' + str(self.node_type) - if DEBUG: - raise ValueError - ### print "returning", i - return i+1 - if l==']': - if self.node_type != NODE_ARRAY: - print 'wrong node ending, expected a ] ' + str(i) + ' ' + str(self.node_type) - if DEBUG: - raise ValueError - ### print "returning", i - return i+1 - - node_type, new_i = is_nodeline(i, []) - if node_type: # check text\n{ - child = vrmlNode(self, node_type, i) - i = child.parse(i) - - elif l=='[': # some files have these anonymous lists - child = vrmlNode(self, NODE_ARRAY, i) - i = child.parse(i) - - elif is_numline(i): - l_split = l.split(',') - - values = None - # See if each item is a float? - - for num_type in (int, float): - try: - values = [num_type(v) for v in l_split ] - break - except: - pass - - - try: - values = [[num_type(v) for v in segment.split()] for segment in l_split ] - break - except: - pass - - if values == None: # dont parse - values = l_split - - # This should not extend over multiple lines however it is possible - # print self.array_data - if values: - self.array_data.extend( values ) - i+=1 - else: - words = l.split() - if len(words) > 2 and words[1] == 'USE': - vrmlNode(self, NODE_REFERENCE, i) - else: - - # print "FIELD", i, l - # - #words = l.split() - ### print '\t\ttag', i - # this is a tag/ - # print words, i, l - value = l - # print i - # javastrips can exist as values. - quote_count = l.count('"') - if quote_count % 2: # odd number? - # print 'MULTILINE' - while 1: - i+=1 - l = lines[i] - quote_count = l.count('"') - if quote_count % 2: # odd number? - value += '\n'+ l[:l.rfind('"')] - break # assume - else: - value += '\n'+ l - - value_all = value.split() - - def iskey(k): - if k[0] != '"' and k[0].isalpha() and k.upper() not in ('TRUE', 'FALSE'): - return True - return False - - def split_fields(value): - ''' - key 0.0 otherkey 1,2,3 opt1 opt1 0.0 - -> [key 0.0], [otherkey 1,2,3], [opt1 opt1 0.0] - ''' - field_list = [] - field_context = [] - - for j in xrange(len(value)): - if iskey(value[j]): - if field_context: - # this IS a key but the previous value was not a key, ot it was a defined field. - if (not iskey(field_context[-1])) or ((len(field_context)==3 and field_context[1]=='IS')): - field_list.append(field_context) - - field_context = [value[j]] - else: - # The last item was not a value, multiple keys are needed in some cases. - field_context.append(value[j]) - else: - # Is empty, just add this on - field_context.append(value[j]) - else: - # Add a value to the list - field_context.append(value[j]) - - if field_context: - field_list.append(field_context) - - return field_list - - - for value in split_fields(value_all): - # Split - - if value[0]=='field': - # field SFFloat creaseAngle 4 - self.proto_field_defs.append(value) - else: - self.fields.append(value) - i+=1 - -def gzipOpen(path): - try: import gzip - except: gzip = None - - data = None - if gzip: - try: data = gzip.open(path, 'r').read() - except: pass - else: - print '\tNote, gzip module could not be imported, compressed files will fail to load' - - if data==None: - try: data = open(path, 'rU').read() - except: pass - - return data - -def vrml_parse(path): - ''' - Sets up the root node and returns it so load_web3d() can deal with the blender side of things. - Return root (vrmlNode, '') or (None, 'Error String') - ''' - data = gzipOpen(path) - - if data==None: - return None, 'Failed to open file: ' + path - - # Stripped above - lines[:] = vrmlFormat( data ) - - lines.insert(0, '{') - lines.insert(0, 'dymmy_node') - lines.append('}') - # Use for testing our parsed output, so we can check on line numbers. - - ''' - ff = open('/tmp/test.txt', 'w') - ff.writelines([l+'\n' for l in lines]) - ff.close() - ''' - - # Now evaluate it - node_type, new_i = is_nodeline(0, []) - if not node_type: - return None, 'Error: VRML file has no starting Node' - - # Trick to make sure we get all root nodes. - lines.insert(0, '{') - lines.insert(0, 'root_node____') # important the name starts with an ascii char - lines.append('}') - - root = vrmlNode(None, NODE_NORMAL, -1) - root.setRoot(path) # we need to set the root so we have a namespace and know the path incase of inlineing - - # Parse recursively - root.parse(0) - - # This prints a load of text - if DEBUG: - print root - - return root, '' - - -# ====================== END VRML - - - -# ====================== X3d Support - -# Sane as vrml but replace the parser -class x3dNode(vrmlNode): - def __init__(self, parent, node_type, x3dNode): - vrmlNode.__init__(self, parent, node_type, -1) - self.x3dNode = x3dNode - - def parse(self, IS_PROTO_DATA=False): - # print self.x3dNode.tagName - - define = self.x3dNode.getAttributeNode('DEF') - if define: - self.getDefDict()[define.value] = self - else: - use = self.x3dNode.getAttributeNode('USE') - if use: - try: - self.reference = self.getDefDict()[use.value] - self.node_type = NODE_REFERENCE - except: - print '\tWarning: reference', use.value, 'not found' - self.parent.children.remove(self) - - return - - for x3dChildNode in self.x3dNode.childNodes: - if x3dChildNode.nodeType in (x3dChildNode.TEXT_NODE, x3dChildNode.COMMENT_NODE, x3dChildNode.CDATA_SECTION_NODE): - continue - - node_type = NODE_NORMAL - # print x3dChildNode, dir(x3dChildNode) - if x3dChildNode.getAttributeNode('USE'): - node_type = NODE_REFERENCE - - child = x3dNode(self, node_type, x3dChildNode) - child.parse() - - # TODO - x3d Inline - - def getSpec(self): - return self.x3dNode.tagName # should match vrml spec - - def getDefName(self): - data = self.x3dNode.getAttributeNode('DEF') - if data: data.value - return None - - # Other funcs operate from vrml, but this means we can wrap XML fields, still use nice utility funcs - # getFieldAsArray getFieldAsBool etc - def getFieldName(self, field, ancestry, AS_CHILD=False): - # ancestry and AS_CHILD are ignored, only used for VRML now - - self_real = self.getRealNode() # incase we're an instance - field_xml = self.x3dNode.getAttributeNode(field) - if field_xml: - value = field_xml.value - - # We may want to edit. for x3d spesific stuff - # Sucks a bit to return the field name in the list but vrml excepts this :/ - return value.split() - else: - return None - -def x3d_parse(path): - ''' - Sets up the root node and returns it so load_web3d() can deal with the blender side of things. - Return root (x3dNode, '') or (None, 'Error String') - ''' - - try: - import xml.dom.minidom - except: - return None, 'Error, import XML parsing module (xml.dom.minidom) failed, install python' - - ''' - try: doc = xml.dom.minidom.parse(path) - except: return None, 'Could not parse this X3D file, XML error' - ''' - - # Could add a try/except here, but a console error is more useful. - data = gzipOpen(path) - - if data==None: - return None, 'Failed to open file: ' + path - - doc = xml.dom.minidom.parseString(data) - - - try: - x3dnode = doc.getElementsByTagName('X3D')[0] - except: - return None, 'Not a valid x3d document, cannot import' - - root = x3dNode(None, NODE_NORMAL, x3dnode) - root.setRoot(path) # so images and Inline's we load have a relative path - root.parse() - - return root, '' - - - -## f = open('/_Cylinder.wrl', 'r') -# f = open('/fe/wrl/Vrml/EGS/TOUCHSN.WRL', 'r') -# vrml_parse('/fe/wrl/Vrml/EGS/TOUCHSN.WRL') -#vrml_parse('/fe/wrl/Vrml/EGS/SCRIPT.WRL') -''' - -import os -files = os.popen('find /fe/wrl -iname "*.wrl"').readlines() -files.sort() -tot = len(files) -for i, f in enumerate(files): - #if i < 801: - # continue - - f = f.strip() - print f, i, tot - vrml_parse(f) -''' - -# NO BLENDER CODE ABOVE THIS LINE. -# ----------------------------------------------------------------------------------- -import bpy -import BPyImage -import BPySys -reload(BPySys) -reload(BPyImage) -import Blender -from Blender import Texture, Material, Mathutils, Mesh, Types, Window -from Blender.Mathutils import TranslationMatrix -from Blender.Mathutils import RotationMatrix -from Blender.Mathutils import Vector -from Blender.Mathutils import Matrix - -RAD_TO_DEG = 57.29578 - -GLOBALS = {'CIRCLE_DETAIL':16} - -def translateRotation(rot): - ''' axis, angle ''' - return RotationMatrix(rot[3]*RAD_TO_DEG, 4, 'r', Vector(rot[:3])) - -def translateScale(sca): - mat = Matrix() # 4x4 default - mat[0][0] = sca[0] - mat[1][1] = sca[1] - mat[2][2] = sca[2] - return mat - -def translateTransform(node, ancestry): - cent = node.getFieldAsFloatTuple('center', None, ancestry) # (0.0, 0.0, 0.0) - rot = node.getFieldAsFloatTuple('rotation', None, ancestry) # (0.0, 0.0, 1.0, 0.0) - sca = node.getFieldAsFloatTuple('scale', None, ancestry) # (1.0, 1.0, 1.0) - scaori = node.getFieldAsFloatTuple('scaleOrientation', None, ancestry) # (0.0, 0.0, 1.0, 0.0) - tx = node.getFieldAsFloatTuple('translation', None, ancestry) # (0.0, 0.0, 0.0) - - if cent: - cent_mat = TranslationMatrix(Vector(cent)).resize4x4() - cent_imat = cent_mat.copy().invert() - else: - cent_mat = cent_imat = None - - if rot: rot_mat = translateRotation(rot) - else: rot_mat = None - - if sca: sca_mat = translateScale(sca) - else: sca_mat = None - - if scaori: - scaori_mat = translateRotation(scaori) - scaori_imat = scaori_mat.copy().invert() - else: - scaori_mat = scaori_imat = None - - if tx: tx_mat = TranslationMatrix(Vector(tx)).resize4x4() - else: tx_mat = None - - new_mat = Matrix() - - mats = [tx_mat, cent_mat, rot_mat, scaori_mat, sca_mat, scaori_imat, cent_imat] - for mtx in mats: - if mtx: - new_mat = mtx * new_mat - - return new_mat - -def translateTexTransform(node, ancestry): - cent = node.getFieldAsFloatTuple('center', None, ancestry) # (0.0, 0.0) - rot = node.getFieldAsFloat('rotation', None, ancestry) # 0.0 - sca = node.getFieldAsFloatTuple('scale', None, ancestry) # (1.0, 1.0) - tx = node.getFieldAsFloatTuple('translation', None, ancestry) # (0.0, 0.0) - - - if cent: - # cent is at a corner by default - cent_mat = TranslationMatrix(Vector(cent).resize3D()).resize4x4() - cent_imat = cent_mat.copy().invert() - else: - cent_mat = cent_imat = None - - if rot: rot_mat = RotationMatrix(rot*RAD_TO_DEG, 4, 'z') # translateRotation(rot) - else: rot_mat = None - - if sca: sca_mat = translateScale((sca[0], sca[1], 0.0)) - else: sca_mat = None - - if tx: tx_mat = TranslationMatrix(Vector(tx).resize3D()).resize4x4() - else: tx_mat = None - - new_mat = Matrix() - - # as specified in VRML97 docs - mats = [cent_imat, sca_mat, rot_mat, cent_mat, tx_mat] - - for mtx in mats: - if mtx: - new_mat = mtx * new_mat - - return new_mat - - - -def getFinalMatrix(node, mtx, ancestry): - - transform_nodes = [node_tx for node_tx in ancestry if node_tx.getSpec() == 'Transform'] - if node.getSpec()=='Transform': - transform_nodes.append(node) - transform_nodes.reverse() - - if mtx==None: - mtx = Matrix() - - for node_tx in transform_nodes: - mat = translateTransform(node_tx, ancestry) - mtx = mtx * mat - - return mtx - -def importMesh_IndexedFaceSet(geom, bpyima, ancestry): - # print geom.lineno, geom.id, vrmlNode.DEF_NAMESPACE.keys() - - ccw = geom.getFieldAsBool('ccw', True, ancestry) - ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True, ancestry) # per vertex or per face - ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry) - - # This is odd how point is inside Coordinate - - # VRML not x3d - #coord = geom.getChildByName('coord') # 'Coordinate' - - coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - - if coord: ifs_points = coord.getFieldAsArray('point', 3, ancestry) - else: coord = [] - - if not coord: - print '\tWarnint: IndexedFaceSet has no points' - return None, ccw - - ifs_faces = geom.getFieldAsArray('coordIndex', 0, ancestry) - - coords_tex = None - if ifs_faces: # In rare cases this causes problems - no faces but UVs??? - - # WORKS - VRML ONLY - # coords_tex = geom.getChildByName('texCoord') - coords_tex = geom.getChildBySpec('TextureCoordinate') - - if coords_tex: - ifs_texpoints = coords_tex.getFieldAsArray('point', 2, ancestry) - ifs_texfaces = geom.getFieldAsArray('texCoordIndex', 0, ancestry) - - if not ifs_texpoints: - # IF we have no coords, then dont bother - coords_tex = None - - - # WORKS - VRML ONLY - # vcolor = geom.getChildByName('color') - vcolor = geom.getChildBySpec('Color') - vcolor_spot = None # spot color when we dont have an array of colors - if vcolor: - # float to char - ifs_vcol = [(0,0,0)] # EEKADOODLE - vertex start at 1 - ifs_vcol.extend([[int(c*256) for c in col] for col in vcolor.getFieldAsArray('color', 3, ancestry)]) - ifs_color_index = geom.getFieldAsArray('colorIndex', 0, ancestry) - - if not ifs_vcol: - vcolor_spot = [int(c*256) for c in vcolor.getFieldAsFloatTuple('color', [], ancestry)] - - # Convert faces into somthing blender can use - edges = [] - - # All lists are aligned! - faces = [] - faces_uv = [] # if ifs_texfaces is empty then the faces_uv will match faces exactly. - faces_orig_index = [] # for ngons, we need to know our original index - - if coords_tex and ifs_texfaces: - do_uvmap = True - else: - do_uvmap = False - - # current_face = [0] # pointer anyone - - def add_face(face, fuvs, orig_index): - l = len(face) - if l==3 or l==4: - faces.append(face) - # faces_orig_index.append(current_face[0]) - if do_uvmap: - faces_uv.append(fuvs) - - faces_orig_index.append(orig_index) - elif l==2: edges.append(face) - elif l>4: - for i in xrange(2, len(face)): - faces.append([face[0], face[i-1], face[i]]) - if do_uvmap: - faces_uv.append([fuvs[0], fuvs[i-1], fuvs[i]]) - faces_orig_index.append(orig_index) - else: - # faces with 1 verts? pfft! - # still will affect index ordering - pass - - face = [] - fuvs = [] - orig_index = 0 - for i, fi in enumerate(ifs_faces): - # ifs_texfaces and ifs_faces should be aligned - if fi != -1: - # face.append(int(fi)) # in rare cases this is a float - # EEKADOODLE!!! - # Annoyance where faces that have a zero index vert get rotated. This will then mess up UVs and VColors - face.append(int(fi)+1) # in rare cases this is a float, +1 because of stupid EEKADOODLE :/ - - if do_uvmap: - if i >= len(ifs_texfaces): - print '\tWarning: UV Texface index out of range' - fuvs.append(ifs_texfaces[0]) - else: - fuvs.append(ifs_texfaces[i]) - else: - add_face(face, fuvs, orig_index) - face = [] - if do_uvmap: - fuvs = [] - orig_index += 1 - - add_face(face, fuvs, orig_index) - del add_face # dont need this func anymore - - bpymesh = bpy.data.meshes.new() - - bpymesh.verts.extend([(0,0,0)]) # EEKADOODLE - bpymesh.verts.extend(ifs_points) - - # print len(ifs_points), faces, edges, ngons - - try: - bpymesh.faces.extend(faces, smooth=True, ignoreDups=True) - except KeyError: - print "one or more vert indicies out of range. corrupt file?" - #for f in faces: - # bpymesh.faces.extend(faces, smooth=True) - - bpymesh.calcNormals() - - if len(bpymesh.faces) != len(faces): - print '\tWarning: adding faces did not work! file is invalid, not adding UVs or vcolors' - return bpymesh, ccw - - # Apply UVs if we have them - if not do_uvmap: - faces_uv = faces # fallback, we didnt need a uvmap in the first place, fallback to the face/vert mapping. - if coords_tex: - #print ifs_texpoints - # print geom - bpymesh.faceUV = True - for i,f in enumerate(bpymesh.faces): - f.image = bpyima - fuv = faces_uv[i] # uv indicies - for j,uv in enumerate(f.uv): - # print fuv, j, len(ifs_texpoints) - try: - uv[:] = ifs_texpoints[fuv[j]] - except: - print '\tWarning: UV Index out of range' - uv[:] = ifs_texpoints[0] - - elif bpyima and len(bpymesh.faces): - # Oh Bugger! - we cant really use blenders ORCO for for texture space since texspace dosnt rotate. - # we have to create VRML's coords as UVs instead. - - # VRML docs - ''' - If the texCoord field is NULL, a default texture coordinate mapping is calculated using the local - coordinate system bounding box of the shape. The longest dimension of the bounding box defines the S coordinates, - and the next longest defines the T coordinates. If two or all three dimensions of the bounding box are equal, - ties shall be broken by choosing the X, Y, or Z dimension in that order of preference. - The value of the S coordinate ranges from 0 to 1, from one end of the bounding box to the other. - The T coordinate ranges between 0 and the ratio of the second greatest dimension of the bounding box to the greatest dimension. - ''' - - # Note, S,T == U,V - # U gets longest, V gets second longest - xmin, ymin, zmin = ifs_points[0] - xmax, ymax, zmax = ifs_points[0] - for co in ifs_points: - x,y,z = co - if x < xmin: xmin = x - if y < ymin: ymin = y - if z < zmin: zmin = z - - if x > xmax: xmax = x - if y > ymax: ymax = y - if z > zmax: zmax = z - - xlen = xmax - xmin - ylen = ymax - ymin - zlen = zmax - zmin - - depth_min = xmin, ymin, zmin - depth_list = [xlen, ylen, zlen] - depth_sort = depth_list[:] - depth_sort.sort() - - depth_idx = [depth_list.index(val) for val in depth_sort] - - axis_u = depth_idx[-1] - axis_v = depth_idx[-2] # second longest - - # Hack, swap these !!! TODO - Why swap??? - it seems to work correctly but should not. - # axis_u,axis_v = axis_v,axis_u - - min_u = depth_min[axis_u] - min_v = depth_min[axis_v] - depth_u = depth_list[axis_u] - depth_v = depth_list[axis_v] - - depth_list[axis_u] - - if axis_u == axis_v: - # This should be safe because when 2 axies have the same length, the lower index will be used. - axis_v += 1 - - bpymesh.faceUV = True - - # HACK !!! - seems to be compatible with Cosmo though. - depth_v = depth_u = max(depth_v, depth_u) - - for f in bpymesh.faces: - f.image = bpyima - fuv = f.uv - - for i,v in enumerate(f): - co = v.co - fuv[i][:] = (co[axis_u]-min_u) / depth_u, (co[axis_v]-min_v) / depth_v - - # Add vcote - if vcolor: - # print ifs_vcol - bpymesh.vertexColors = True - - for f in bpymesh.faces: - fcol = f.col - if ifs_colorPerVertex: - fv = f.verts - for i,c in enumerate(fcol): - color_index = fv[i].index # color index is vert index - if ifs_color_index: - try: - color_index = ifs_color_index[color_index] - except: - print '\tWarning: per vertex color index out of range' - continue - - if color_index < len(ifs_vcol): - c.r, c.g, c.b = ifs_vcol[color_index] - else: - #print '\tWarning: per face color index out of range' - pass - else: - if vcolor_spot: # use 1 color, when ifs_vcol is [] - for c in fcol: - c.r, c.g, c.b = vcolor_spot - else: - color_index = faces_orig_index[f.index] # color index is face index - #print color_index, ifs_color_index - if ifs_color_index: - if color_index <= len(ifs_color_index): - print '\tWarning: per face color index out of range' - color_index = 0 - else: - color_index = ifs_color_index[color_index] - - - col = ifs_vcol[color_index] - for i,c in enumerate(fcol): - try: - c.r, c.g, c.b = col - except: - pass # incase its not between 0 and 255 - - bpymesh.verts.delete([0,]) # EEKADOODLE - - return bpymesh, ccw - -def importMesh_IndexedLineSet(geom, ancestry): - # VRML not x3d - #coord = geom.getChildByName('coord') # 'Coordinate' - coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - if coord: points = coord.getFieldAsArray('point', 3, ancestry) - else: points = [] - - if not points: - print '\tWarning: IndexedLineSet had no points' - return None - - ils_lines = geom.getFieldAsArray('coordIndex', 0, ancestry) - - lines = [] - line = [] - - for il in ils_lines: - if il==-1: - lines.append(line) - line = [] - else: - line.append(int(il)) - lines.append(line) - - # vcolor = geom.getChildByName('color') # blender dosnt have per vertex color - - bpycurve = bpy.data.curves.new('IndexedCurve', 'Curve') - bpycurve.setFlag(1) - - w=t=1 - - curve_index = 0 - - for line in lines: - if not line: - continue - co = points[line[0]] - bpycurve.appendNurb([co[0], co[1], co[2], w, t]) - bpycurve[curve_index].type= 0 # Poly Line - - for il in line[1:]: - co = points[il] - bpycurve.appendPoint(curve_index, [co[0], co[1], co[2], w]) - - - curve_index += 1 - - return bpycurve - - -def importMesh_PointSet(geom, ancestry): - # VRML not x3d - #coord = geom.getChildByName('coord') # 'Coordinate' - coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - if coord: points = coord.getFieldAsArray('point', 3, ancestry) - else: points = [] - - # vcolor = geom.getChildByName('color') # blender dosnt have per vertex color - - bpymesh = bpy.data.meshes.new() - bpymesh.verts.extend(points) - bpymesh.calcNormals() # will just be dummy normals - return bpymesh - -GLOBALS['CIRCLE_DETAIL'] = 12 - -MATRIX_Z_TO_Y = RotationMatrix(90, 4, 'x') - -def importMesh_Sphere(geom, ancestry): - # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('radius', 0.5, ancestry) * 2 # * 2 for the diameter - bpymesh = Mesh.Primitives.UVsphere(GLOBALS['CIRCLE_DETAIL'], GLOBALS['CIRCLE_DETAIL'], diameter) - bpymesh.transform(MATRIX_Z_TO_Y) - return bpymesh - -def importMesh_Cylinder(geom, ancestry): - # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('radius', 1.0, ancestry) * 2 # * 2 for the diameter - height = geom.getFieldAsFloat('height', 2, ancestry) - bpymesh = Mesh.Primitives.Cylinder(GLOBALS['CIRCLE_DETAIL'], diameter, height) - bpymesh.transform(MATRIX_Z_TO_Y) - - # Warning - Rely in the order Blender adds verts - # not nice design but wont change soon. - - bottom = geom.getFieldAsBool('bottom', True, ancestry) - side = geom.getFieldAsBool('side', True, ancestry) - top = geom.getFieldAsBool('top', True, ancestry) - - if not top: # last vert is top center of tri fan. - bpymesh.verts.delete([(GLOBALS['CIRCLE_DETAIL']+GLOBALS['CIRCLE_DETAIL'])+1]) - - if not bottom: # second last vert is bottom of triangle fan - bpymesh.verts.delete([GLOBALS['CIRCLE_DETAIL']+GLOBALS['CIRCLE_DETAIL']]) - - if not side: - # remove all quads - bpymesh.faces.delete(1, [f for f in bpymesh.faces if len(f)==4]) - - return bpymesh - -def importMesh_Cone(geom, ancestry): - # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('bottomRadius', 1.0, ancestry) * 2 # * 2 for the diameter - height = geom.getFieldAsFloat('height', 2, ancestry) - bpymesh = Mesh.Primitives.Cone(GLOBALS['CIRCLE_DETAIL'], diameter, height) - bpymesh.transform(MATRIX_Z_TO_Y) - - # Warning - Rely in the order Blender adds verts - # not nice design but wont change soon. - - bottom = geom.getFieldAsBool('bottom', True, ancestry) - side = geom.getFieldAsBool('side', True, ancestry) - - if not bottom: # last vert is on the bottom - bpymesh.verts.delete([GLOBALS['CIRCLE_DETAIL']+1]) - if not side: # second last vert is on the pointy bit of the cone - bpymesh.verts.delete([GLOBALS['CIRCLE_DETAIL']]) - - return bpymesh - -def importMesh_Box(geom, ancestry): - # bpymesh = bpy.data.meshes.new() - - size = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0), ancestry) - bpymesh = Mesh.Primitives.Cube(1.0) - - # Scale the box to the size set - scale_mat = Matrix([size[0],0,0], [0, size[1], 0], [0, 0, size[2]]) - bpymesh.transform(scale_mat.resize4x4()) - - return bpymesh - -def importShape(node, ancestry): - vrmlname = node.getDefName() - if not vrmlname: vrmlname = 'Shape' - - # works 100% in vrml, but not x3d - #appr = node.getChildByName('appearance') # , 'Appearance' - #geom = node.getChildByName('geometry') # , 'IndexedFaceSet' - - # Works in vrml and x3d - appr = node.getChildBySpec('Appearance') - geom = node.getChildBySpec(['IndexedFaceSet', 'IndexedLineSet', 'PointSet', 'Sphere', 'Box', 'Cylinder', 'Cone']) - - # For now only import IndexedFaceSet's - if geom: - bpymat = None - bpyima = None - texmtx = None - - depth = 0 # so we can set alpha face flag later - - if appr: - - #mat = appr.getChildByName('material') # 'Material' - #ima = appr.getChildByName('texture') # , 'ImageTexture' - #if ima and ima.getSpec() != 'ImageTexture': - # print '\tWarning: texture type "%s" is not supported' % ima.getSpec() - # ima = None - # textx = appr.getChildByName('textureTransform') - - mat = appr.getChildBySpec('Material') - ima = appr.getChildBySpec('ImageTexture') - - textx = appr.getChildBySpec('TextureTransform') - - if textx: - texmtx = translateTexTransform(textx, ancestry) - - - - # print mat, ima - if mat or ima: - - if not mat: - mat = ima # This is a bit dumb, but just means we use default values for all - - # all values between 0.0 and 1.0, defaults from VRML docs - bpymat = bpy.data.materials.new() - bpymat.amb = mat.getFieldAsFloat('ambientIntensity', 0.2, ancestry) - bpymat.rgbCol = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8], ancestry) - - # NOTE - blender dosnt support emmisive color - # Store in mirror color and approximate with emit. - emit = mat.getFieldAsFloatTuple('emissiveColor', [0.0, 0.0, 0.0], ancestry) - bpymat.mirCol = emit - bpymat.emit = (emit[0]+emit[1]+emit[2])/3.0 - - bpymat.hard = int(1+(510*mat.getFieldAsFloat('shininess', 0.2, ancestry))) # 0-1 -> 1-511 - bpymat.specCol = mat.getFieldAsFloatTuple('specularColor', [0.0, 0.0, 0.0], ancestry) - bpymat.alpha = 1.0 - mat.getFieldAsFloat('transparency', 0.0, ancestry) - if bpymat.alpha < 0.999: - bpymat.mode |= Material.Modes.ZTRANSP - - - if ima: - - ima_url = ima.getFieldAsString('url', None, ancestry) - - if ima_url==None: - try: ima_url = ima.getFieldAsStringArray('url', ancestry)[0] # in some cases we get a list of images. - except: ima_url = None - - if ima_url==None: - print "\twarning, image with no URL, this is odd" - else: - bpyima= BPyImage.comprehensiveImageLoad(ima_url, dirName(node.getFilename()), PLACE_HOLDER= False, RECURSIVE= False, CONVERT_CALLBACK= imageConvertCompat) - if bpyima: - texture= bpy.data.textures.new() - texture.setType('Image') - texture.image = bpyima - - # Adds textures for materials (rendering) - try: depth = bpyima.depth - except: depth = -1 - - if depth == 32: - # Image has alpha - bpymat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) - texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') - bpymat.mode |= Material.Modes.ZTRANSP - bpymat.alpha = 0.0 - else: - bpymat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - - ima_repS = ima.getFieldAsBool('repeatS', True, ancestry) - ima_repT = ima.getFieldAsBool('repeatT', True, ancestry) - - # To make this work properly we'd need to scale the UV's too, better to ignore th - # texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512) - - if not ima_repS: bpyima.clampX = True - if not ima_repT: bpyima.clampY = True - - bpydata = None - geom_spec = geom.getSpec() - ccw = True - if geom_spec == 'IndexedFaceSet': - bpydata, ccw = importMesh_IndexedFaceSet(geom, bpyima, ancestry) - elif geom_spec == 'IndexedLineSet': - bpydata = importMesh_IndexedLineSet(geom, ancestry) - elif geom_spec == 'PointSet': - bpydata = importMesh_PointSet(geom, ancestry) - elif geom_spec == 'Sphere': - bpydata = importMesh_Sphere(geom, ancestry) - elif geom_spec == 'Box': - bpydata = importMesh_Box(geom, ancestry) - elif geom_spec == 'Cylinder': - bpydata = importMesh_Cylinder(geom, ancestry) - elif geom_spec == 'Cone': - bpydata = importMesh_Cone(geom, ancestry) - else: - print '\tWarning: unsupported type "%s"' % geom_spec - return - - if bpydata: - vrmlname = vrmlname + geom_spec - - bpydata.name = vrmlname - - bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpydata) - - if type(bpydata) == Types.MeshType: - is_solid = geom.getFieldAsBool('solid', True, ancestry) - creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry) - - if creaseAngle != None: - bpydata.maxSmoothAngle = 1+int(min(79, creaseAngle * RAD_TO_DEG)) - bpydata.mode |= Mesh.Modes.AUTOSMOOTH - - # Only ever 1 material per shape - if bpymat: bpydata.materials = [bpymat] - - if bpydata.faceUV: - - if depth==32: # set the faces alpha flag? - transp = Mesh.FaceTranspModes.ALPHA - for f in bpydata.faces: - f.transp = transp - - if texmtx: - # Apply texture transform? - uv_copy = Vector() - for f in bpydata.faces: - for uv in f.uv: - uv_copy.x = uv.x - uv_copy.y = uv.y - - uv.x, uv.y = (uv_copy * texmtx)[0:2] - # Done transforming the texture - - - # Must be here and not in IndexedFaceSet because it needs an object for the flip func. Messy :/ - if not ccw: bpydata.flipNormals() - - - # else could be a curve for example - - - - # Can transform data or object, better the object so we can instance the data - #bpymesh.transform(getFinalMatrix(node)) - bpyob.setMatrix( getFinalMatrix(node, None, ancestry) ) - - -def importLamp_PointLight(node, ancestry): - vrmlname = node.getDefName() - if not vrmlname: vrmlname = 'PointLight' - - # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0, ancestry) # TODO - # attenuation = node.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0), ancestry) # TODO - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) - intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. - location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0), ancestry) - # is_on = node.getFieldAsBool('on', True, ancestry) # TODO - radius = node.getFieldAsFloat('radius', 100.0, ancestry) - - bpylamp = bpy.data.lamps.new() - bpylamp.setType('Lamp') - bpylamp.energy = intensity - bpylamp.dist = radius - bpylamp.col = color - - mtx = TranslationMatrix(Vector(location)) - - return bpylamp, mtx - -def importLamp_DirectionalLight(node, ancestry): - vrmlname = node.getDefName() - if not vrmlname: vrmlname = 'DirectLight' - - # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0) # TODO - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) - direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0), ancestry) - intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. - # is_on = node.getFieldAsBool('on', True, ancestry) # TODO - - bpylamp = bpy.data.lamps.new(vrmlname) - bpylamp.setType('Sun') - bpylamp.energy = intensity - bpylamp.col = color - - # lamps have their direction as -z, yup - mtx = Vector(direction).toTrackQuat('-z', 'y').toMatrix().resize4x4() - - return bpylamp, mtx - -# looks like default values for beamWidth and cutOffAngle were swapped in VRML docs. - -def importLamp_SpotLight(node, ancestry): - vrmlname = node.getDefName() - if not vrmlname: vrmlname = 'SpotLight' - - # ambientIntensity = geom.getFieldAsFloat('ambientIntensity', 0.0, ancestry) # TODO - # attenuation = geom.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0), ancestry) # TODO - beamWidth = node.getFieldAsFloat('beamWidth', 1.570796, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) - cutOffAngle = node.getFieldAsFloat('cutOffAngle', 0.785398, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0), ancestry) - intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. - location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0), ancestry) - # is_on = node.getFieldAsBool('on', True, ancestry) # TODO - radius = node.getFieldAsFloat('radius', 100.0, ancestry) - - bpylamp = bpy.data.lamps.new(vrmlname) - bpylamp.setType('Spot') - bpylamp.energy = intensity - bpylamp.dist = radius - bpylamp.col = color - bpylamp.spotSize = cutOffAngle - if beamWidth > cutOffAngle: - bpylamp.spotBlend = 0.0 - else: - if cutOffAngle==0.0: #@#$%^&*(!!! - this should never happen - bpylamp.spotBlend = 0.5 - else: - bpylamp.spotBlend = beamWidth / cutOffAngle - - # Convert - - # lamps have their direction as -z, y==up - mtx = Vector(direction).toTrackQuat('-z', 'y').toMatrix().resize4x4() * TranslationMatrix(Vector(location)) - - return bpylamp, mtx - - -def importLamp(node, spec, ancestry): - if spec=='PointLight': - bpylamp,mtx = importLamp_PointLight(node, ancestry) - elif spec=='DirectionalLight': - bpylamp,mtx = importLamp_DirectionalLight(node, ancestry) - elif spec=='SpotLight': - bpylamp,mtx = importLamp_SpotLight(node, ancestry) - else: - print "Error, not a lamp" - raise ValueError - - bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpylamp) - bpyob.setMatrix( getFinalMatrix(node, mtx, ancestry) ) - - -def importViewpoint(node, ancestry): - name = node.getDefName() - if not name: name = 'Viewpoint' - - fieldOfView = node.getFieldAsFloat('fieldOfView', 0.785398, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - # jump = node.getFieldAsBool('jump', True, ancestry) - orientation = node.getFieldAsFloatTuple('orientation', (0.0, 0.0, 1.0, 0.0), ancestry) - position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 0.0), ancestry) - description = node.getFieldAsString('description', '', ancestry) - - bpycam = bpy.data.cameras.new(name) - - bpycam.angle = fieldOfView - - mtx = translateRotation(orientation) * TranslationMatrix(Vector(position)) - - - bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpycam) - bpyob.setMatrix( getFinalMatrix(node, mtx, ancestry) ) - - -def importTransform(node, ancestry): - name = node.getDefName() - if not name: name = 'Transform' - - bpyob = node.blendObject = bpy.data.scenes.active.objects.new('Empty', name) # , name) - bpyob.setMatrix( getFinalMatrix(node, None, ancestry) ) - - # so they are not too annoying - bpyob.emptyShape= Blender.Object.EmptyShapes.AXES - bpyob.drawSize= 0.2 - - -#def importTimeSensor(node): - - -def translatePositionInterpolator(node, ipo, ancestry): - key = node.getFieldAsArray('key', 0, ancestry) - keyValue = node.getFieldAsArray('keyValue', 3, ancestry) - - try: - loc_x = ipo.addCurve('LocX') - loc_y = ipo.addCurve('LocY') - loc_z = ipo.addCurve('LocZ') - except ValueError: - return - - loc_x.interpolation = loc_y.interpolation = loc_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - - for i, time in enumerate(key): - try: x,y,z = keyValue[i] - except: continue - - loc_x.append((time,x)) - loc_y.append((time,y)) - loc_z.append((time,z)) - -def translateOrientationInterpolator(node, ipo, ancestry): - key = node.getFieldAsArray('key', 0, ancestry) - keyValue = node.getFieldAsArray('keyValue', 4, ancestry) - - try: - rot_x = ipo.addCurve('RotX') - rot_y = ipo.addCurve('RotY') - rot_z = ipo.addCurve('RotZ') - except ValueError: - return - - rot_x.interpolation = rot_y.interpolation = rot_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - - for i, time in enumerate(key): - try: x,y,z,w = keyValue[i] - except: continue - - mtx = translateRotation((x,y,z,w)) - eul = mtx.toEuler() - rot_x.append((time,eul.x/10.0)) - rot_y.append((time,eul.y/10.0)) - rot_z.append((time,eul.z/10.0)) - -# Untested! -def translateScalarInterpolator(node, ipo, ancestry): - key = node.getFieldAsArray('key', 0, ancestry) - keyValue = node.getFieldAsArray('keyValue', 4, ancestry) - - try: - sca_x = ipo.addCurve('ScaleX') - sca_y = ipo.addCurve('ScaleY') - sca_z = ipo.addCurve('ScaleZ') - except ValueError: - return - - sca_x.interpolation = sca_y.interpolation = sca_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - - for i, time in enumerate(key): - try: x,y,z = keyValue[i] - except: continue - sca_x.append((time,x/10.0)) - sca_y.append((time,y/10.0)) - sca_z.append((time,z/10.0)) - -def translateTimeSensor(node, ipo, ancestry): - ''' - Apply a time sensor to an IPO, VRML has many combinations of loop/start/stop/cycle times - to give different results, for now just do the basics - ''' - - time_cu = ipo.addCurve('Time') - time_cu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - - cycleInterval = node.getFieldAsFloat('cycleInterval', None, ancestry) - - startTime = node.getFieldAsFloat('startTime', 0.0, ancestry) - stopTime = node.getFieldAsFloat('stopTime', 250.0, ancestry) - - if cycleInterval != None: - stopTime = startTime+cycleInterval - - loop = node.getFieldAsBool('loop', False, ancestry) - - time_cu.append((1+startTime, 0.0)) - time_cu.append((1+stopTime, 1.0/10.0))# anoying, the UI uses /10 - - - if loop: - time_cu.extend = Blender.IpoCurve.ExtendTypes.CYCLIC # or - EXTRAP, CYCLIC_EXTRAP, CONST, - - -def importRoute(node, ancestry): - ''' - Animation route only at the moment - ''' - - if not hasattr(node, 'fields'): - return - - routeIpoDict = node.getRouteIpoDict() - - def getIpo(id): - try: ipo = routeIpoDict[id] - except: ipo = routeIpoDict[id] = bpy.data.ipos.new('web3d_ipo', 'Object') - return ipo - - # for getting definitions - defDict = node.getDefDict() - ''' - Handles routing nodes to eachother - -ROUTE vpPI.value_changed TO champFly001.set_position -ROUTE vpOI.value_changed TO champFly001.set_orientation -ROUTE vpTs.fraction_changed TO vpPI.set_fraction -ROUTE vpTs.fraction_changed TO vpOI.set_fraction -ROUTE champFly001.bindTime TO vpTs.set_startTime - ''' - - #from_id, from_type = node.id[1].split('.') - #to_id, to_type = node.id[3].split('.') - - #value_changed - set_position_node = None - set_orientation_node = None - time_node = None - - for field in node.fields: - if field and field[0]=='ROUTE': - try: - from_id, from_type = field[1].split('.') - to_id, to_type = field[3].split('.') - except: - print "Warning, invalid ROUTE", field - continue - - if from_type == 'value_changed': - if to_type == 'set_position': - ipo = getIpo(to_id) - set_data_from_node = defDict[from_id] - translatePositionInterpolator(set_data_from_node, ipo, ancestry) - - if to_type in ('set_orientation', 'rotation'): - ipo = getIpo(to_id) - set_data_from_node = defDict[from_id] - translateOrientationInterpolator(set_data_from_node, ipo, ancestry) - - if to_type == 'set_scale': - ipo = getIpo(to_id) - set_data_from_node = defDict[from_id] - translateScalarInterpolator(set_data_from_node, ipo, ancestry) - - elif from_type =='bindTime': - ipo = getIpo(from_id) - time_node = defDict[to_id] - translateTimeSensor(time_node, ipo, ancestry) - - - - -def load_web3d(path, PREF_FLAT=False, PREF_CIRCLE_DIV=16, HELPER_FUNC = None): - - # Used when adding blender primitives - GLOBALS['CIRCLE_DETAIL'] = PREF_CIRCLE_DIV - - #root_node = vrml_parse('/_Cylinder.wrl') - if path.lower().endswith('.x3d'): - root_node, msg = x3d_parse(path) - else: - root_node, msg = vrml_parse(path) - - if not root_node: - if Blender.mode == 'background': - print msg - else: - Blender.Draw.PupMenu(msg) - return - - - # fill with tuples - (node, [parents-parent, parent]) - all_nodes = root_node.getSerialized([], []) - - for node, ancestry in all_nodes: - #if 'castle.wrl' not in node.getFilename(): - # continue - - spec = node.getSpec() - ''' - prefix = node.getPrefix() - if prefix=='PROTO': - pass - else - ''' - if HELPER_FUNC and HELPER_FUNC(node, ancestry): - # Note, include this function so the VRML/X3D importer can be extended - # by an external script. - gets first pick - pass - if spec=='Shape': - importShape(node, ancestry) - elif spec in ('PointLight', 'DirectionalLight', 'SpotLight'): - importLamp(node, spec, ancestry) - elif spec=='Viewpoint': - importViewpoint(node, ancestry) - elif spec=='Transform': - # Only use transform nodes when we are not importing a flat object hierarchy - if PREF_FLAT==False: - importTransform(node, ancestry) - ''' - # These are delt with later within importRoute - elif spec=='PositionInterpolator': - ipo = bpy.data.ipos.new('web3d_ipo', 'Object') - translatePositionInterpolator(node, ipo) - ''' - - - - # After we import all nodes, route events - anim paths - for node, ancestry in all_nodes: - importRoute(node, ancestry) - - for node, ancestry in all_nodes: - if node.isRoot(): - # we know that all nodes referenced from will be in - # routeIpoDict so no need to run node.getDefDict() for every node. - routeIpoDict = node.getRouteIpoDict() - defDict = node.getDefDict() - - for key, ipo in routeIpoDict.iteritems(): - - # Assign anim curves - node = defDict[key] - if node.blendObject==None: # Add an object if we need one for animation - node.blendObject = bpy.data.scenes.active.objects.new('Empty', 'AnimOb') # , name) - - node.blendObject.setIpo(ipo) - - - - # Add in hierarchy - if PREF_FLAT==False: - child_dict = {} - for node, ancestry in all_nodes: - if node.blendObject: - blendObject = None - - # Get the last parent - i = len(ancestry) - while i: - i-=1 - blendObject = ancestry[i].blendObject - if blendObject: - break - - if blendObject: - # Parent Slow, - 1 liner but works - # blendObject.makeParent([node.blendObject], 0, 1) - - # Parent FAST - try: child_dict[blendObject].append(node.blendObject) - except: child_dict[blendObject] = [node.blendObject] - - # Parent FAST - for parent, children in child_dict.iteritems(): - parent.makeParent(children, 0, 1) - - # update deps - bpy.data.scenes.active.update(1) - del child_dict - - -def load_ui(path): - Draw = Blender.Draw - PREF_HIERARCHY= Draw.Create(0) - PREF_CIRCLE_DIV= Draw.Create(16) - - # Get USER Options - pup_block= [\ - 'Import...',\ - ('Hierarchy', PREF_HIERARCHY, 'Import transform nodes as empties to create a parent/child hierarchy'),\ - ('Circle Div:', PREF_CIRCLE_DIV, 3, 128, 'Number of divisions to use for circular primitives') - ] - - if not Draw.PupBlock('Import X3D/VRML...', pup_block): - return - - Window.WaitCursor(1) - - load_web3d(path,\ - (not PREF_HIERARCHY.val),\ - PREF_CIRCLE_DIV.val,\ - ) - - Window.WaitCursor(0) - - -if __name__ == '__main__': - Window.FileSelector(load_ui, 'Import X3D/VRML97') - - -# Testing stuff - -# load_web3d('/test.x3d') -# load_web3d('/_Cylinder.x3d') - -# Testing below -# load_web3d('m:\\root\\Desktop\\_Cylinder.wrl') -# load_web3d('/_Cylinder.wrl') -# load_web3d('/fe/wrl/Vrml/EGS/BCKGD.WRL') - -# load_web3d('/fe/wrl/Vrml/EGS/GRNDPLNE.WRL') -# load_web3d('/fe/wrl/Vrml/EGS/INDEXFST.WRL') -# load_web3d('/fe/wrl/panel1c.wrl') -# load_web3d('/test.wrl') -# load_web3d('/fe/wrl/dulcimer.wrl') -# load_web3d('/fe/wrl/rccad/Ju-52.wrl') # Face index out of range -# load_web3d('/fe/wrl/16lat.wrl') # spotlight -# load_web3d('/fe/wrl/Vrml/EGS/FOG.WRL') # spotlight -# load_web3d('/fe/wrl/Vrml/EGS/LOD.WRL') # vcolor per face - -# load_web3d('/fe/wrl/new/daybreak_final.wrl') # no faces in mesh, face duplicate error -# load_web3d('/fe/wrl/new/earth.wrl') -# load_web3d('/fe/wrl/new/hendrix.ei.dtu.dk/vrml/talairach/fourd/TalaDruryRight.wrl') # define/use fields -# load_web3d('/fe/wrl/new/imac.wrl') # extrusion and define/use fields, face index is a float somehow -# load_web3d('/fe/wrl/new/www.igs.net/~mascott/vrml/vrml2/mcastle.wrl') -# load_web3d('/fe/wrl/new/www.igs.net/~mascott/vrml/vrml2/tower.wrl') -# load_web3d('/fe/wrl/new/www.igs.net/~mascott/vrml/vrml2/temple.wrl') -# load_web3d('/fe/wrl/brain.wrl') # field define test 'a IS b' -# load_web3d('/fe/wrl/new/coaster.wrl') # fields that are confusing to read. - -# X3D - -# load_web3d('/fe/x3d/www.web3d.org/x3d/content/examples/Basic/StudentProjects/PlayRoom.x3d') # invalid UVs - - - -def test(): - import os - - files = os.popen('find /fe/wrl -iname "*.wrl"').readlines() - # files = os.popen('find /fe/x3d -iname "*.x3d"').readlines() - # files = os.popen('find /fe/x3d/X3dExamplesSavage -iname "*.x3d"').readlines() - - files.sort() - tot = len(files) - for i, f in enumerate(files): - if i < 124 or i > 1000000: - continue - - #if i != 1068: - # continue - - #if i != 12686: - # continue - - f = f.strip() - print f, i, tot - sce = bpy.data.scenes.new(str(i) + '_' + f.split('/')[-1]) - bpy.data.scenes.active = sce - # Window. - load_web3d(f, PREF_FLAT=True) - -# test() diff --git a/release/scripts/io/engine_render_pov.py b/release/scripts/io/engine_render_pov.py new file mode 100644 index 00000000000..f0247ce532a --- /dev/null +++ b/release/scripts/io/engine_render_pov.py @@ -0,0 +1,912 @@ +import bpy + +from math import atan, pi, degrees +import subprocess +import os +import sys +import time + +import platform as pltfrm + +if pltfrm.architecture()[0] == '64bit': + bitness = 64 +else: + bitness = 32 + +def write_pov(filename, scene=None, info_callback = None): + file = open(filename, 'w') + + # Only for testing + if not scene: + scene = bpy.data.scenes[0] + + render = scene.render_data + world = scene.world + + # --- taken from fbx exporter + ## This was used to make V, but faster not to do all that + ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' + ##v = range(255) + ##for c in valid: v.remove(ord(c)) + 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,42,43,46,47,58,59,60,61,62,63,64,92,94,96,124,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]) + def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name + del v + + # --- done with clean name. + + def uniqueName(name, nameSeq): + + if name not in nameSeq: + return name + + name_orig = name + i = 1 + while name in nameSeq: + name = '%s_%.3d' % (name_orig, i) + i+=1 + + return name + + + def writeMatrix(matrix): + file.write('\tmatrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n' %\ + (matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1], matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2], matrix[3][0], matrix[3][1], matrix[3][2]) ) + + def writeObjectMaterial(material): + if material and material.transparency_method=='RAYTRACE': + file.write('\tinterior { ior %.6f }\n' % material.raytrace_transparency.ior) + + # Other interior args + # fade_distance 2 + # fade_power [Value] + # fade_color + + # dispersion + # dispersion_samples + + materialNames = {} + DEF_MAT_NAME = 'Default' + def writeMaterial(material): + # Assumes only called once on each material + + if material: + name_orig = material.name + else: + name_orig = DEF_MAT_NAME + + name = materialNames[name_orig] = uniqueName(cleanName(name_orig), materialNames) + + file.write('#declare %s = finish {\n' % name) + + if material: + file.write('\tdiffuse %.3g\n' % material.diffuse_intensity) + file.write('\tspecular %.3g\n' % material.specular_intensity) + + file.write('\tambient %.3g\n' % material.ambient) + #file.write('\tambient rgb <%.3g, %.3g, %.3g>\n' % tuple([c*material.ambient for c in world.ambient_color])) # povray blends the global value + + # map hardness between 0.0 and 1.0 + roughness = ((1.0 - ((material.specular_hardness-1.0)/510.0))) + # scale from 0.0 to 0.1 + roughness *= 0.1 + # add a small value because 0.0 is invalid + roughness += (1/511.0) + + file.write('\troughness %.3g\n' % roughness) + + # 'phong 70.0 ' + + if material.raytrace_mirror.enabled: + raytrace_mirror= material.raytrace_mirror + if raytrace_mirror.reflect_factor: + file.write('\treflection {\n') + file.write('\t\trgb <%.3g, %.3g, %.3g>' % tuple(material.mirror_color)) + file.write('\t\tfresnel 1 falloff %.3g exponent %.3g metallic %.3g} ' % (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor, raytrace_mirror.reflect_factor)) + + else: + file.write('\tdiffuse 0.8\n') + file.write('\tspecular 0.2\n') + + + # This is written into the object + ''' + if material and material.transparency_method=='RAYTRACE': + 'interior { ior %.3g} ' % material.raytrace_transparency.ior + ''' + + #file.write('\t\t\tcrand 1.0\n') # Sand granyness + #file.write('\t\t\tmetallic %.6f\n' % material.spec) + #file.write('\t\t\tphong %.6f\n' % material.spec) + #file.write('\t\t\tphong_size %.6f\n' % material.spec) + #file.write('\t\t\tbrilliance %.6f ' % (material.specular_hardness/256.0) # Like hardness + + file.write('}\n') + + def exportCamera(): + camera = scene.camera + matrix = camera.matrix + + # compute resolution + Qsize=float(render.resolution_x)/float(render.resolution_y) + + file.write('camera {\n') + file.write('\tlocation <0, 0, 0>\n') + file.write('\tlook_at <0, 0, -1>\n') + file.write('\tright <%s, 0, 0>\n' % -Qsize) + file.write('\tup <0, 1, 0>\n') + file.write('\tangle %f \n' % (360.0*atan(16.0/camera.data.lens)/pi)) + + file.write('\trotate <%.6f, %.6f, %.6f>\n' % tuple([degrees(e) for e in matrix.rotationPart().toEuler()])) + file.write('\ttranslate <%.6f, %.6f, %.6f>\n' % (matrix[3][0], matrix[3][1], matrix[3][2])) + file.write('}\n') + + def exportLamps(lamps): + # Get all lamps + for ob in lamps: + lamp = ob.data + + matrix = ob.matrix + + color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy + + file.write('light_source {\n') + file.write('\t< 0,0,0 >\n') + file.write('\tcolor rgb<%.3g, %.3g, %.3g>\n' % color) + + if lamp.type == 'POINT': # Point Lamp + pass + elif lamp.type == 'SPOT': # Spot + file.write('\tspotlight\n') + + # Falloff is the main radius from the centre line + file.write('\tfalloff %.2f\n' % (lamp.spot_size/2.0) ) # 1 TO 179 FOR BOTH + file.write('\tradius %.6f\n' % ((lamp.spot_size/2.0) * (1-lamp.spot_blend)) ) + + # Blender does not have a tightness equivilent, 0 is most like blender default. + file.write('\ttightness 0\n') # 0:10f + + file.write('\tpoint_at <0, 0, -1>\n') + elif lamp.type == 'SUN': + file.write('\tparallel\n') + file.write('\tpoint_at <0, 0, -1>\n') # *must* be after 'parallel' + + elif lamp.type == 'AREA': + + size_x = lamp.size + samples_x = lamp.shadow_ray_samples_x + if lamp.shape == 'SQUARE': + size_y = size_x + samples_y = samples_x + else: + size_y = lamp.size_y + samples_y = lamp.shadow_ray_samples_y + + file.write('\tarea_light <%d,0,0>,<0,0,%d> %d, %d\n' % (size_x, size_y, samples_x, samples_y)) + if lamp.shadow_ray_sampling_method == 'CONSTANT_JITTERED': + if lamp.jitter: + file.write('\tjitter\n') + else: + file.write('\tadaptive 1\n') + file.write('\tjitter\n') + + if lamp.shadow_method == 'NOSHADOW': + file.write('\tshadowless\n') + + file.write('\tfade_distance %.6f\n' % lamp.distance) + file.write('\tfade_power %d\n' % 1) # Could use blenders lamp quad? + writeMatrix(matrix) + + file.write('}\n') + + def exportMeta(metas): + + # TODO - blenders 'motherball' naming is not supported. + + for ob in metas: + meta = ob.data + + file.write('blob {\n') + file.write('\t\tthreshold %.4g\n' % meta.threshold) + + try: + material= meta.materials[0] # lame! - blender cant do enything else. + except: + material= None + + for elem in meta.elements: + + if elem.type not in ('BALL', 'ELLIPSOID'): + continue # Not supported + + loc = elem.location + + stiffness= elem.stiffness + if elem.negative: + stiffness = -stiffness + + if elem.type == 'BALL': + + file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x, loc.y, loc.z, elem.radius, stiffness)) + + # After this wecould do something simple like... + # "pigment {Blue} }" + # except we'll write the color + + elif elem.type == 'ELLIPSOID': + # location is modified by scale + file.write('\tsphere { <%.6g, %.6g, %.6g>, %.4g, %.4g ' % (loc.x/elem.size_x, loc.y/elem.size_y, loc.z/elem.size_z, elem.radius, stiffness)) + file.write( 'scale <%.6g, %.6g, %.6g> ' % (elem.size_x, elem.size_y, elem.size_z)) + + if material: + diffuse_color = material.diffuse_color + + if material.transparency and material.transparency_method=='RAYTRACE': trans = 1-material.raytrace_transparency.filter + else: trans = 0.0 + + file.write( + 'pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s} }\n' % \ + (diffuse_color[0], diffuse_color[1], diffuse_color[2], 1-material.alpha, trans, materialNames[material.name]) + ) + + else: + file.write('pigment {rgb<1 1 1>} finish {%s} }\n' % DEF_MAT_NAME) # Write the finish last. + + writeObjectMaterial(material) + + writeMatrix(ob.matrix) + + file.write('}\n') + + def exportMeshs(sel): + + ob_num = 0 + + for ob in sel: + ob_num+= 1 + + if ob.type in ('LAMP', 'CAMERA', 'EMPTY', 'META'): + continue + + me = ob.data + me_materials= me.materials + + me = ob.create_mesh(True, 'RENDER') + + if not me: + continue + + if info_callback: + info_callback('Object %2.d of %2.d (%s)' % (ob_num, len(sel), ob.name)) + + #if ob.type!='MESH': + # continue + # me = ob.data + + matrix = ob.matrix + try: uv_layer = me.active_uv_texture.data + except:uv_layer = None + + try: vcol_layer = me.active_vertex_color.data + except:vcol_layer = None + + faces_verts = [f.verts for f in me.faces] + faces_normals = [tuple(f.normal) for f in me.faces] + verts_normals = [tuple(v.normal) for v in me.verts] + + # quads incur an extra face + quadCount = len([f for f in faces_verts if len(f)==4]) + + file.write('mesh2 {\n') + file.write('\tvertex_vectors {\n') + file.write('\t\t%s' % (len(me.verts))) # vert count + for v in me.verts: + file.write(',\n\t\t<%.6f, %.6f, %.6f>' % tuple(v.co)) # vert count + file.write('\n }\n') + + + # Build unique Normal list + uniqueNormals = {} + for fi, f in enumerate(me.faces): + fv = faces_verts[fi] + # [-1] is a dummy index, use a list so we can modify in place + if f.smooth: # Use vertex normals + for v in fv: + key = verts_normals[v] + uniqueNormals[key] = [-1] + else: # Use face normal + key = faces_normals[fi] + uniqueNormals[key] = [-1] + + file.write('\tnormal_vectors {\n') + file.write('\t\t%d' % len(uniqueNormals)) # vert count + idx = 0 + for no, index in uniqueNormals.items(): + file.write(',\n\t\t<%.6f, %.6f, %.6f>' % no) # vert count + index[0] = idx + idx +=1 + file.write('\n }\n') + + + # Vertex colours + vertCols = {} # Use for material colours also. + + if uv_layer: + # Generate unique UV's + uniqueUVs = {} + + for fi, uv in enumerate(uv_layer): + + if len(faces_verts[fi])==4: + uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4 + else: + uvs = uv.uv1, uv.uv2, uv.uv3 + + for uv in uvs: + uniqueUVs[tuple(uv)] = [-1] + + file.write('\tuv_vectors {\n') + #print unique_uvs + file.write('\t\t%s' % (len(uniqueUVs))) # vert count + idx = 0 + for uv, index in uniqueUVs.items(): + file.write(',\n\t\t<%.6f, %.6f>' % uv) + index[0] = idx + idx +=1 + ''' + else: + # Just add 1 dummy vector, no real UV's + file.write('\t\t1') # vert count + file.write(',\n\t\t<0.0, 0.0>') + ''' + file.write('\n }\n') + + + if me.vertex_colors: + + for fi, f in enumerate(me.faces): + material_index = f.material_index + material = me_materials[material_index] + + if material and material.vertex_color_paint: + + col = vcol_layer[fi] + + if len(faces_verts[fi])==4: + cols = col.color1, col.color2, col.color3, col.color4 + else: + cols = col.color1, col.color2, col.color3 + + for col in cols: + key = col[0], col[1], col[2], material_index # Material index! + vertCols[key] = [-1] + + else: + if material: + diffuse_color = tuple(material.diffuse_color) + key = diffuse_color[0], diffuse_color[1], diffuse_color[2], material_index + vertCols[key] = [-1] + + + else: + # No vertex colours, so write material colours as vertex colours + for i, material in enumerate(me_materials): + + if material: + diffuse_color = tuple(material.diffuse_color) + key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat + vertCols[key] = [-1] + + + # Vert Colours + file.write('\ttexture_list {\n') + file.write('\t\t%s' % (len(vertCols))) # vert count + idx=0 + for col, index in vertCols.items(): + + if me_materials: + material = me_materials[col[3]] + material_finish = materialNames[material.name] + + if material.transparency and material.transparency_method=='RAYTRACE': trans = 1-material.raytrace_transparency.filter + else: trans = 0.0 + + else: + material_finish = DEF_MAT_NAME # not working properly, + trans = 0.0 + + #print material.apl + file.write( ',\n\t\ttexture { pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} finish {%s}}' % + (col[0], col[1], col[2], 1-material.alpha, trans, material_finish) ) + + index[0] = idx + idx+=1 + + file.write( '\n }\n' ) + + # Face indicies + file.write('\tface_indices {\n') + file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count + for fi, f in enumerate(me.faces): + fv = faces_verts[fi] + material_index= f.material_index + if len(fv) == 4: indicies = (0,1,2), (0,2,3) + else: indicies = ((0,1,2),) + + if vcol_layer: + col = vcol_layer[fi] + + if len(fv) == 4: + cols = col.color1, col.color2, col.color3, col.color4 + else: + cols = col.color1, col.color2, col.color3 + + + if not me_materials or me_materials[material_index] == None: # No materials + for i1, i2, i3 in indicies: + file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count + else: + material = me_materials[material_index] + for i1, i2, i3 in indicies: + if me.vertex_colors and material.vertex_color_paint: + # Colour per vertex - vertex colour + + col1 = cols[i1] + col2 = cols[i2] + col3 = cols[i3] + + ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0] + ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0] + ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0] + else: + # Colour per material - flat material colour + diffuse_color= material.diffuse_color + ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0] + + file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count + + + file.write('\n }\n') + + # normal_indices indicies + file.write('\tnormal_indices {\n') + file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count + for fi, fv in enumerate(faces_verts): + + if len(fv) == 4: indicies = (0,1,2), (0,2,3) + else: indicies = ((0,1,2),) + + for i1, i2, i3 in indicies: + if f.smooth: + file.write(',\n\t\t<%d,%d,%d>' %\ + (uniqueNormals[verts_normals[fv[i1]]][0],\ + uniqueNormals[verts_normals[fv[i2]]][0],\ + uniqueNormals[verts_normals[fv[i3]]][0])) # vert count + else: + idx = uniqueNormals[faces_normals[fi]][0] + file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count + + file.write('\n }\n') + + if uv_layer: + file.write('\tuv_indices {\n') + file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count + for fi, fv in enumerate(faces_verts): + + if len(fv) == 4: indicies = (0,1,2), (0,2,3) + else: indicies = ((0,1,2),) + + uv = uv_layer[fi] + if len(faces_verts[fi])==4: + uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4) + else: + uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3) + + for i1, i2, i3 in indicies: + file.write(',\n\t\t<%d,%d,%d>' %\ + (uniqueUVs[uvs[i1]][0],\ + uniqueUVs[uvs[i2]][0],\ + uniqueUVs[uvs[i2]][0])) # vert count + file.write('\n }\n') + + if me.materials: + material = me.materials[0] # dodgy + writeObjectMaterial(material) + + writeMatrix(matrix) + file.write('}\n') + + bpy.data.remove_mesh(me) + + def exportWorld(world): + if not world: + return + + mist = world.mist + + if mist.enabled: + file.write('fog {\n') + file.write('\tdistance %.6f\n' % mist.depth) + file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1-mist.intensity,))) + #file.write('\tfog_offset %.6f\n' % mist.start) + #file.write('\tfog_alt 5\n') + #file.write('\tturbulence 0.2\n') + #file.write('\tturb_depth 0.3\n') + file.write('\tfog_type 1\n') + file.write('}\n') + + def exportGlobalSettings(scene): + + file.write('global_settings {\n') + + if scene.pov_radio_enable: + file.write('\tradiosity {\n') + file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout) + file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample) + file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness) + file.write("\t\tcount %d\n" % scene.pov_radio_count) + file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound) + file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold) + file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor) + file.write("\t\tmedia %d\n" % scene.pov_radio_media) + file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse) + file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count) + file.write("\t\tnormal %d\n" % scene.pov_radio_normal) + file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit) + file.write('\t}\n') + + if world: + file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color)) + + file.write('}\n') + + + # Convert all materials to strings we can access directly per vertex. + writeMaterial(None) # default material + + for material in bpy.data.materials: + writeMaterial(material) + + exportCamera() + #exportMaterials() + sel = scene.objects + exportLamps([l for l in sel if l.type == 'LAMP']) + exportMeta([l for l in sel if l.type == 'META']) + exportMeshs(sel) + exportWorld(scene.world) + exportGlobalSettings(scene) + + file.close() + +def write_pov_ini(filename_ini, filename_pov, filename_image): + scene = bpy.data.scenes[0] + render = scene.render_data + + x= int(render.resolution_x*render.resolution_percentage*0.01) + y= int(render.resolution_y*render.resolution_percentage*0.01) + + file = open(filename_ini, 'w') + + file.write('Input_File_Name="%s"\n' % filename_pov) + file.write('Output_File_Name="%s"\n' % filename_image) + + file.write('Width=%d\n' % x) + file.write('Height=%d\n' % y) + + # Needed for border render. + ''' + file.write('Start_Column=%d\n' % part.x) + file.write('End_Column=%d\n' % (part.x+part.w)) + + file.write('Start_Row=%d\n' % (part.y)) + file.write('End_Row=%d\n' % (part.y+part.h)) + ''' + + file.write('Display=0\n') + file.write('Pause_When_Done=0\n') + file.write('Output_File_Type=T\n') # TGA, best progressive loading + file.write('Output_Alpha=1\n') + + if render.antialiasing: + aa_mapping = {'OVERSAMPLE_5':2, 'OVERSAMPLE_8':3, 'OVERSAMPLE_11':4, 'OVERSAMPLE_16':5} # method 1 assumed + file.write('Antialias=1\n') + file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples]) + else: + file.write('Antialias=0\n') + + file.close() + +# Radiosity panel, use in the scene for now. +FloatProperty= bpy.types.Scene.FloatProperty +IntProperty= bpy.types.Scene.IntProperty +BoolProperty= bpy.types.Scene.BoolProperty + +# Not a real pov option, just to know if we should write +BoolProperty( attr="pov_radio_enable", + name="Enable Radiosity", + description="Enable povrays radiosity calculation.", + default= False) +BoolProperty( attr="pov_radio_display_advanced", + name="Advanced Options", + description="Show advanced options.", + default= False) + +# Real pov options +FloatProperty( attr="pov_radio_adc_bailout", + name="ADC Bailout", + description="The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results.", + min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default= 0.01) + +BoolProperty( attr="pov_radio_always_sample", + name="Always Sample", + description="Only use the data from the pretrace step and not gather any new samples during the final radiosity pass..", + default= True) + +FloatProperty( attr="pov_radio_brightness", + name="Brightness", + description="Ammount objects are brightened before being returned upwards to the rest of the system.", + min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default= 1.0) + +IntProperty( attr="pov_radio_count", + name="Ray Count", + description="number of rays that are sent out whenever a new radiosity value has to be calculated.", + min=1, max=1600, default= 35) + +FloatProperty( attr="pov_radio_error_bound", + name="Error Bound", + description="one of the two main speed/quality tuning values, lower values are more accurate.", + min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default= 1.8) + +FloatProperty( attr="pov_radio_gray_threshold", + name="Gray Threshold", + description="one of the two main speed/quality tuning values, lower values are more accurate.", + min=0.0, max=1.0, soft_min=0, soft_max=1, default= 0.0) + +FloatProperty( attr="pov_radio_low_error_factor", + name="Low Error Factor", + description="If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting.", + min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default= 0.5) + +# max_sample - not available yet +BoolProperty( attr="pov_radio_media", + name="Media", + description="Radiosity estimation can be affected by media.", + default= False) + +FloatProperty( attr="pov_radio_minimum_reuse", + name="Minimum Reuse", + description="Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors).", + min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default= 0.015) + +IntProperty( attr="pov_radio_nearest_count", + name="Nearest Count", + description="Number of old ambient values blended together to create a new interpolated value.", + min=1, max=20, default= 5) + +BoolProperty( attr="pov_radio_normal", + name="Normals", + description="Radiosity estimation can be affected by normals.", + default= False) + +IntProperty( attr="pov_radio_recursion_limit", + name="Recursion Limit", + description="how many recursion levels are used to calculate the diffuse inter-reflection.", + min=1, max=20, default= 3) + + +class PovrayRender(bpy.types.RenderEngine): + __idname__ = 'POVRAY_RENDER' + __label__ = "Povray" + DELAY = 0.02 + + def _export(self, scene): + import tempfile + + self.temp_file_in = tempfile.mktemp(suffix='.pov') + self.temp_file_out = tempfile.mktemp(suffix='.tga') + self.temp_file_ini = tempfile.mktemp(suffix='.ini') + ''' + self.temp_file_in = '/test.pov' + self.temp_file_out = '/test.tga' + self.temp_file_ini = '/test.ini' + ''' + + def info_callback(txt): + self.update_stats("", "POVRAY: " + txt) + + write_pov(self.temp_file_in, scene, info_callback) + + def _render(self): + + try: os.remove(self.temp_file_out) # so as not to load the old file + except: pass + + write_pov_ini(self.temp_file_ini, self.temp_file_in, self.temp_file_out) + + print ("***-STARTING-***") + + pov_binary = "povray" + + if sys.platform=='win32': + import winreg + regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\POV-Ray\\v3.6\\Windows') + + if bitness == 64: + pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine64' + else: + pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine' + + if 1: + self.process = subprocess.Popen([pov_binary, self.temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE + else: + # This works too but means we have to wait until its done + os.system('%s %s' % (pov_binary, self.temp_file_ini)) + + print ("***-DONE-***") + + def _cleanup(self): + for f in (self.temp_file_in, self.temp_file_ini, self.temp_file_out): + try: os.remove(f) + except: pass + + self.update_stats("", "") + + def render(self, scene): + + self.update_stats("", "POVRAY: Exporting data from Blender") + self._export(scene) + self.update_stats("", "POVRAY: Parsing File") + self._render() + + r = scene.render_data + + # compute resolution + x= int(r.resolution_x*r.resolution_percentage*0.01) + y= int(r.resolution_y*r.resolution_percentage*0.01) + + # Wait for the file to be created + while not os.path.exists(self.temp_file_out): + if self.test_break(): + try: self.process.terminate() + except: pass + break + + if self.process.poll() != None: + self.update_stats("", "POVRAY: Failed") + break + + time.sleep(self.DELAY) + + if os.path.exists(self.temp_file_out): + + self.update_stats("", "POVRAY: Rendering") + + prev_size = -1 + + def update_image(): + result = self.begin_result(0, 0, x, y) + lay = result.layers[0] + # possible the image wont load early on. + try: lay.load_from_file(self.temp_file_out) + except: pass + self.end_result(result) + + # Update while povray renders + while True: + + # test if povray exists + if self.process.poll() != None: + update_image(); + break + + # user exit + if self.test_break(): + try: self.process.terminate() + except: pass + + break + + # Would be nice to redirect the output + # stdout_value, stderr_value = self.process.communicate() # locks + + + # check if the file updated + new_size = os.path.getsize(self.temp_file_out) + + if new_size != prev_size: + update_image() + prev_size = new_size + + time.sleep(self.DELAY) + + self._cleanup() + +bpy.types.register(PovrayRender) + +# Use some of the existing buttons. +import buttons_scene +buttons_scene.SCENE_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_scene.SCENE_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_scene.SCENE_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_scene.SCENE_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER') +del buttons_scene + +# Use only a subset of the world panels +import buttons_world +buttons_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER') +buttons_world.WORLD_PT_mist.COMPAT_ENGINES.add('POVRAY_RENDER') +del buttons_world + +# Example of wrapping every class 'as is' +import buttons_material +for member in dir(buttons_material): + subclass = getattr(buttons_material, member) + try: subclass.COMPAT_ENGINES.add('POVRAY_RENDER') + except: pass +del buttons_material + +class RenderButtonsPanel(bpy.types.Panel): + __space_type__ = 'PROPERTIES' + __region_type__ = 'WINDOW' + __context__ = "scene" + # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here + + def poll(self, context): + rd = context.scene.render_data + return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) + +class SCENE_PT_povray_radiosity(RenderButtonsPanel): + __label__ = "Radiosity" + COMPAT_ENGINES = set(['POVRAY_RENDER']) + + def draw_header(self, context): + scene = context.scene + + self.layout.itemR(scene, "pov_radio_enable", text="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + rd = scene.render_data + + layout.active = scene.pov_radio_enable + + split = layout.split() + + col = split.column() + col.itemR(scene, "pov_radio_count", text="Rays") + col.itemR(scene, "pov_radio_recursion_limit", text="Recursions") + col = split.column() + col.itemR(scene, "pov_radio_error_bound", text="Error") + + layout.itemR(scene, "pov_radio_display_advanced") + + if scene.pov_radio_display_advanced: + split = layout.split() + + col = split.column() + col.itemR(scene, "pov_radio_adc_bailout", slider=True) + col.itemR(scene, "pov_radio_gray_threshold", slider=True) + col.itemR(scene, "pov_radio_low_error_factor", slider=True) + + col = split.column() + col.itemR(scene, "pov_radio_brightness") + col.itemR(scene, "pov_radio_minimum_reuse", text="Min Reuse") + col.itemR(scene, "pov_radio_nearest_count") + + split = layout.split() + + col = split.column() + col.itemL(text="Estimation Influence:") + col.itemR(scene, "pov_radio_media") + col.itemR(scene, "pov_radio_normal") + + col = split.column() + col.itemR(scene, "pov_radio_always_sample") + +bpy.types.register(SCENE_PT_povray_radiosity) diff --git a/release/scripts/io/export_3ds.py b/release/scripts/io/export_3ds.py new file mode 100644 index 00000000000..19c12146769 --- /dev/null +++ b/release/scripts/io/export_3ds.py @@ -0,0 +1,1128 @@ +#!BPY +# coding: utf-8 +""" +Name: '3D Studio (.3ds)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to 3DS file format (.3ds).' +""" + +__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__ = "0.90a" +__bpydoc__ = """\ + +3ds Exporter + +This script Exports a 3ds file. + +Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information +from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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 ***** +# -------------------------------------------------------------------------- + + +###################################################### +# Importing modules +###################################################### + +import struct +import os +import time + +import bpy + +# import Blender +# from BPyMesh import getMeshFromObject +# from BPyObject import getDerivedObjects +# try: +# import struct +# except: +# struct = None + +# also used by X3D exporter +# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() +def create_derived_objects(ob): + if ob.parent and ob.parent.dupli_type != 'NONE': + return False, None + + if ob.dupli_type != 'NONE': + ob.create_dupli_list() + return True, [(dob.object, dob.matrix) for dob in ob.dupli_list] + else: + return False, [(ob, ob.matrix)] + +# also used by X3D exporter +def free_derived_objects(ob): + ob.free_dupli_list() + +# So 3ds max can open files, limit names to 12 in length +# this is verry annoying for filenames! +name_unique = [] +name_mapping = {} +def sane_name(name): + name_fixed = name_mapping.get(name) + if name_fixed != None: + return name_fixed + + if len(name) > 12: + new_name = name[:12] + else: + new_name = name + + i = 0 + + while new_name in name_unique: + new_name = new_name[:-4] + '.%.3d' % i + i+=1 + + name_unique.append(new_name) + name_mapping[name] = new_name + return new_name + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will export +#----- Primary Chunk, at the beginning of each file +PRIMARY= int("0x4D4D",16) + +#------ Main Chunks +OBJECTINFO = int("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information +VERSION = int("0x0002",16); #This gives the version of the .3ds file +KFDATA = int("0xB000",16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +MATNAME = int("0xA000",16); # This holds the material name +MATAMBIENT = int("0xA010",16); # Ambient color of the object/material +MATDIFFUSE = int("0xA020",16); # This holds the color of the object/material +MATSPECULAR = int("0xA030",16); # SPecular color of the object/material +MATSHINESS = int("0xA040",16); # ?? +MATMAP = int("0xA200",16); # This is a header for a new material +MATMAPFILE = int("0xA300",16); # This holds the file name of the texture + +RGB1= int("0x0011",16) +RGB2= int("0x0012",16) + +#>------ sub defines of OBJECT +OBJECT_MESH = int("0x4100",16); # This lets us know that we are reading a new object +OBJECT_LIGHT = int("0x4600",16); # This lets un know we are reading a light object +OBJECT_CAMERA= int("0x4700",16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= int("0x4720",16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = int("0x4110",16); # The objects vertices +OBJECT_FACES = int("0x4120",16); # The objects faces +OBJECT_MATERIAL = int("0x4130",16); # This is found if the object has a material, either texture map or color +OBJECT_UV = int("0x4140",16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = int("0x4160",16); # The Object Matrix + +#>------ sub defines of KFDATA +KFDATA_KFHDR = int("0xB00A",16); +KFDATA_KFSEG = int("0xB008",16); +KFDATA_KFCURTIME = int("0xB009",16); +KFDATA_OBJECT_NODE_TAG = int("0xB002",16); + +#>------ sub defines of OBJECT_NODE_TAG +OBJECT_NODE_ID = int("0xB030",16); +OBJECT_NODE_HDR = int("0xB010",16); +OBJECT_PIVOT = int("0xB013",16); +OBJECT_INSTANCE_NAME = int("0xB011",16); +POS_TRACK_TAG = int("0xB020",16); +ROT_TRACK_TAG = int("0xB021",16); +SCL_TRACK_TAG = int("0xB022",16); + +def uv_key(uv): + return round(uv[0], 6), round(uv[1], 6) +# return round(uv.x, 6), round(uv.y, 6) + +# size defines: +SZ_SHORT = 2 +SZ_INT = 4 +SZ_FLOAT = 4 + +class _3ds_short(object): + '''Class representing a short (2-byte integer) for a 3ds file. + *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' + __slots__ = 'value' + def __init__(self, val=0): + self.value=val + + def get_size(self): + return SZ_SHORT + + def write(self,file): + file.write(struct.pack("= mat_ls_len: + mat_index = f.mat = 0 + mat = mat_ls[mat_index] + if mat: mat_name = mat.name + else: mat_name = None + # else there alredy set to none + + img = uf.image +# img = f.image + if img: img_name = img.name + else: img_name = None + + materialDict.setdefault((mat_name, img_name), (mat, img) ) + + + else: + for mat in mat_ls: + if mat: # material may be None so check its not. + materialDict.setdefault((mat.name, None), (mat, None) ) + + # Why 0 Why! + for f in data.faces: + if f.material_index >= mat_ls_len: +# if f.mat >= mat_ls_len: + f.material_index = 0 + # f.mat = 0 + + if free: + free_derived_objects(ob) + + + # Make material chunks for all materials used in the meshes: + for mat_and_image in materialDict.values(): + object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) + + # Give all objects a unique ID and build a dictionary from object name to object id: + """ + name_to_id = {} + for ob, data in mesh_objects: + name_to_id[ob.name]= len(name_to_id) + #for ob in empty_objects: + # name_to_id[ob.name]= len(name_to_id) + """ + + # Create object chunks for all meshes: + i = 0 + for ob, blender_mesh in mesh_objects: + # create a new object chunk + object_chunk = _3ds_chunk(OBJECT) + + # set the object name + object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) + + # make a mesh chunk out of the mesh: + object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) + object_info.add_subchunk(object_chunk) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # make a kf object node for the object: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + ''' +# if not blender_mesh.users: + bpy.data.remove_mesh(blender_mesh) +# blender_mesh.verts = None + + i+=i + + # Create chunks for all empties: + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + for ob in empty_objects: + # Empties only require a kf object node: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + pass + ''' + + # Add main object info chunk to primary chunk: + primary.add_subchunk(object_info) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # Add main keyframe data chunk to primary chunk: + primary.add_subchunk(kfdata) + ''' + + # At this point, the chunk hierarchy is completely built. + + # Check the size: + primary.get_size() + # Open the file for writing: + file = open( filename, 'wb' ) + + # Recursively write the chunks to file: + primary.write(file) + + # Close the file: + file.close() + + # Debugging only: report the exporting time: +# Blender.Window.WaitCursor(0) + print("3ds export time: %.2f" % (time.clock() - time1)) +# print("3ds export time: %.2f" % (Blender.sys.time() - time1)) + + # Debugging only: dump the chunk hierarchy: + #primary.dump() + + +# if __name__=='__main__': +# if struct: +# Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) +# else: +# Blender.Draw.PupMenu("Error%t|This script requires a full python installation") +# # save_3ds('/test_b.3ds') + +class EXPORT_OT_3ds(bpy.types.Operator): + ''' + 3DS Exporter + ''' + __idname__ = "export.3ds" + __label__ = 'Export 3DS' + + # 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 3DS file", maxlen= 1024, default= ""), + ] + + def execute(self, context): + save_3ds(self.filename, context) + 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_3ds) diff --git a/release/scripts/io/export_fbx.py b/release/scripts/io/export_fbx.py new file mode 100644 index 00000000000..aa65473b8d6 --- /dev/null +++ b/release/scripts/io/export_fbx.py @@ -0,0 +1,3457 @@ +#!BPY +""" +Name: 'Autodesk FBX (.fbx)...' +Blender: 249 +Group: 'Export' +Tooltip: 'Selection to an ASCII Autodesk FBX ' +""" +__author__ = "Campbell Barton" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.2" + +__bpydoc__ = """\ +This script is an exporter to the FBX file format. + +http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx +""" +# -------------------------------------------------------------------------- +# FBX Export v0.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 os +import time +import math # math.pi +import shutil # for file copying + +# try: +# import time +# # import os # only needed for batch export, nbot used yet +# except: +# time = None # use this to check if they have python modules installed + +# for python 2.3 support +try: + set() +except: + try: + from sets import Set as set + except: + set = None # so it complains you dont have a ! + +# # os is only needed for batch 'own dir' option +# try: +# import os +# except: +# os = None + +# import Blender +import bpy +import Mathutils +# from Blender.Mathutils import Matrix, Vector, RotationMatrix + +# import BPyObject +# import BPyMesh +# import BPySys +# import BPyMessages + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' +##v = range(255) +##for c in valid: v.remove(ord(c)) +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,42,43,47,58,59,60,61,62,63,64,92,94,96,124,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]) +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name +# del v, i + + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +# XXX not used anymore, images are copied one at a time +def copy_images(dest_dir, textures): + if not dest_dir.endswith(os.sep): + dest_dir += os.sep + + image_paths = set() + for tex in textures: + image_paths.add(Blender.sys.expandpath(tex.filename)) + + # Now copy images + copyCount = 0 + for image_path in image_paths: + if Blender.sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not Blender.sys.exists(dest_image_path): # Image isnt alredy there + print('\tCopying "%s" > "%s"' % (image_path, dest_image_path)) + try: + copy_file(image_path, dest_image_path) + copyCount+=1 + except: + print('\t\tWarning, file failed to copy, skipping.') + + print('\tCopied %d images' % copyCount) + +# I guess FBX uses degrees instead of radians (Arystan). +# Call this function just before writing to FBX. +def eulerRadToDeg(eul): + ret = Mathutils.Euler() + + ret.x = 180 / math.pi * eul[0] + ret.y = 180 / math.pi * eul[1] + ret.z = 180 / math.pi * eul[2] + + return ret + +mtx4_identity = Mathutils.Matrix() + +# testing +mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'x') # used +#mtx_x90n = RotationMatrix(-90, 3, 'x') +#mtx_y90 = RotationMatrix( 90, 3, 'y') +#mtx_y90n = RotationMatrix(-90, 3, 'y') +#mtx_z90 = RotationMatrix( 90, 3, 'z') +#mtx_z90n = RotationMatrix(-90, 3, 'z') + +#mtx4_x90 = RotationMatrix( 90, 4, 'x') +mtx4_x90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'x') # used +#mtx4_y90 = RotationMatrix( 90, 4, 'y') +mtx4_y90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'y') # used +mtx4_z90 = Mathutils.RotationMatrix( math.pi/2, 4, 'z') # used +mtx4_z90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'z') # used + +# def strip_path(p): +# return p.split('\\')[-1].split('/')[-1] + +# Used to add the scene name into the filename without using odd chars +sane_name_mapping_ob = {} +sane_name_mapping_mat = {} +sane_name_mapping_tex = {} +sane_name_mapping_take = {} +sane_name_mapping_group = {} + +# Make sure reserved names are not used +sane_name_mapping_ob['Scene'] = 'Scene_' +sane_name_mapping_ob['blend_root'] = 'blend_root_' + +def increment_string(t): + name = t + num = '' + while name and name[-1].isdigit(): + num = name[-1] + num + name = name[:-1] + if num: return '%s%d' % (name, int(num)+1) + else: return name + '_0' + + + +# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. +def sane_name(data, dct): + #if not data: return None + + if type(data)==tuple: # materials are paired up with images + data, other = data + use_other = True + else: + other = None + use_other = False + + if data: name = data.name + else: name = None + orig_name = name + + if other: + orig_name_other = other.name + name = '%s #%s' % (name, orig_name_other) + else: + orig_name_other = None + + # dont cache, only ever call once for each data type now, + # so as to avoid namespace collision between types - like with objects <-> bones + #try: return dct[name] + #except: pass + + if not name: + name = 'unnamed' # blank string, ASKING FOR TROUBLE! + else: + #name = BPySys.cleanName(name) + name = cleanName(name) # use our own + + while name in iter(dct.values()): name = increment_string(name) + + if use_other: # even if other is None - orig_name_other will be a string or None + dct[orig_name, orig_name_other] = name + else: + dct[orig_name] = name + + return name + +def sane_obname(data): return sane_name(data, sane_name_mapping_ob) +def sane_matname(data): return sane_name(data, sane_name_mapping_mat) +def sane_texname(data): return sane_name(data, sane_name_mapping_tex) +def sane_takename(data): return sane_name(data, sane_name_mapping_take) +def sane_groupname(data): return sane_name(data, sane_name_mapping_group) + +# def derived_paths(fname_orig, basepath, FORCE_CWD=False): +# ''' +# fname_orig - blender path, can be relative +# basepath - fname_rel will be relative to this +# FORCE_CWD - dont use the basepath, just add a ./ to the filename. +# use when we know the file will be in the basepath. +# ''' +# fname = bpy.sys.expandpath(fname_orig) +# # fname = Blender.sys.expandpath(fname_orig) +# fname_strip = os.path.basename(fname) +# # fname_strip = strip_path(fname) +# if FORCE_CWD: +# fname_rel = '.' + os.sep + fname_strip +# else: +# fname_rel = bpy.sys.relpath(fname, basepath) +# # fname_rel = Blender.sys.relpath(fname, basepath) +# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:] +# return fname, fname_strip, fname_rel + + +def mat4x4str(mat): + return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) + +# XXX not used +# duplicated in OBJ exporter +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 + +# ob must be OB_MESH +def BPyMesh_meshWeight2List(ob): + ''' Takes a mesh and return its group names and a list of lists, one list per vertex. + aligning the each vert list with the group names, each list contains float value for the weight. + These 2 lists can be modified and then used with list2MeshWeight to apply the changes. + ''' + + me = ob.data + + # Clear the vert group. + groupNames= [g.name for g in ob.vertex_groups] + len_groupNames= len(groupNames) + + if not len_groupNames: + # no verts? return a vert aligned empty list + return [[] for i in range(len(me.verts))], [] + else: + vWeightList= [[0.0]*len_groupNames for i in range(len(me.verts))] + + for i, v in enumerate(me.verts): + for g in v.groups: + vWeightList[i][g.group] = g.weight + + return groupNames, vWeightList + +def meshNormalizedWeights(me): + try: # account for old bad BPyMesh + groupNames, vWeightList = BPyMesh_meshWeight2List(me) +# groupNames, vWeightList = BPyMesh.meshWeight2List(me) + except: + return [],[] + + if not groupNames: + return [],[] + + for i, vWeights in enumerate(vWeightList): + tot = 0.0 + for w in vWeights: + tot+=w + + if tot: + for j, w in enumerate(vWeights): + vWeights[j] = w/tot + + return groupNames, vWeightList + +header_comment = \ +'''; FBX 6.1.0 project file +; Created by Blender FBX Exporter +; for support mail: ideasman42@gmail.com +; ---------------------------------------------------- + +''' + +# This func can be called with just the filename +def write(filename, batch_objects = None, \ + context = None, + EXP_OBS_SELECTED = True, + EXP_MESH = True, + EXP_MESH_APPLY_MOD = True, +# EXP_MESH_HQ_NORMALS = False, + EXP_ARMATURE = True, + EXP_LAMP = True, + EXP_CAMERA = True, + EXP_EMPTY = True, + EXP_IMAGE_COPY = False, + GLOBAL_MATRIX = Mathutils.Matrix(), + ANIM_ENABLE = True, + ANIM_OPTIMIZE = True, + ANIM_OPTIMIZE_PRECISSION = 6, + ANIM_ACTION_ALL = False, + BATCH_ENABLE = False, + BATCH_GROUP = True, + BATCH_FILE_PREFIX = '', + BATCH_OWN_DIR = False + ): + + # ----------------- Batch support! + if BATCH_ENABLE: + if os == None: BATCH_OWN_DIR = False + + fbxpath = filename + + # get the path component of filename + tmp_exists = bpy.sys.exists(fbxpath) +# tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: # a file, we want a path + fbxpath = os.path.dirname(fbxpath) +# while fbxpath and fbxpath[-1] not in ('/', '\\'): +# fbxpath = fbxpath[:-1] + if not fbxpath: +# if not filename: + # XXX + print('Error%t|Directory does not exist!') +# Draw.PupMenu('Error%t|Directory does not exist!') + return + + tmp_exists = bpy.sys.exists(fbxpath) +# tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: + # XXX + print('Error%t|Directory does not exist!') +# Draw.PupMenu('Error%t|Directory does not exist!') + return + + if not fbxpath.endswith(os.sep): + fbxpath += os.sep + del tmp_exists + + + if BATCH_GROUP: + data_seq = bpy.data.groups + else: + data_seq = bpy.data.scenes + + # call this function within a loop with BATCH_ENABLE == False + orig_sce = context.scene +# orig_sce = bpy.data.scenes.active + + + new_fbxpath = fbxpath # own dir option modifies, we need to keep an original + for data in data_seq: # scene or group + newname = BATCH_FILE_PREFIX + cleanName(data.name) +# newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) + + + if BATCH_OWN_DIR: + new_fbxpath = fbxpath + newname + os.sep + # path may alredy exist + # TODO - might exist but be a file. unlikely but should probably account for it. + + if bpy.sys.exists(new_fbxpath) == 0: +# if Blender.sys.exists(new_fbxpath) == 0: + os.mkdir(new_fbxpath) + + + filename = new_fbxpath + newname + '.fbx' + + print('\nBatch exporting %s as...\n\t"%s"' % (data, filename)) + + # XXX don't know what to do with this, probably do the same? (Arystan) + if BATCH_GROUP: #group + # group, so objects update properly, add a dummy scene. + sce = bpy.data.scenes.new() + sce.Layers = (1<<20) -1 + bpy.data.scenes.active = sce + for ob_base in data.objects: + sce.objects.link(ob_base) + + sce.update(1) + + # TODO - BUMMER! Armatures not in the group wont animate the mesh + + else:# scene + + + data_seq.active = data + + + # Call self with modified args + # Dont pass batch options since we alredy usedt them + write(filename, data.objects, + context, + False, + EXP_MESH, + EXP_MESH_APPLY_MOD, +# EXP_MESH_HQ_NORMALS, + EXP_ARMATURE, + EXP_LAMP, + EXP_CAMERA, + EXP_EMPTY, + EXP_IMAGE_COPY, + GLOBAL_MATRIX, + ANIM_ENABLE, + ANIM_OPTIMIZE, + ANIM_OPTIMIZE_PRECISSION, + ANIM_ACTION_ALL + ) + + if BATCH_GROUP: + # remove temp group scene + bpy.data.remove_scene(sce) +# bpy.data.scenes.unlink(sce) + + bpy.data.scenes.active = orig_sce + + return # so the script wont run after we have batch exported. + + # end batch support + + # Use this for working out paths relative to the export location + basepath = os.path.dirname(filename) or '.' + basepath += os.sep +# basepath = Blender.sys.dirname(filename) + + # ---------------------------------------------- + # storage classes + class my_bone_class: + __slots__ =(\ + 'blenName',\ + 'blenBone',\ + 'blenMeshes',\ + 'restMatrix',\ + 'parent',\ + 'blenName',\ + 'fbxName',\ + 'fbxArm',\ + '__pose_bone',\ + '__anim_poselist') + + def __init__(self, blenBone, fbxArm): + + # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace + self.fbxName = sane_obname(blenBone) + + self.blenName = blenBone.name + self.blenBone = blenBone + self.blenMeshes = {} # fbxMeshObName : mesh + self.fbxArm = fbxArm + self.restMatrix = blenBone.armature_matrix +# self.restMatrix = blenBone.matrix['ARMATURESPACE'] + + # not used yet + # self.restMatrixInv = self.restMatrix.copy().invert() + # self.restMatrixLocal = None # set later, need parent matrix + + self.parent = None + + # not public + pose = fbxArm.blenObject.pose +# pose = fbxArm.blenObject.getPose() + self.__pose_bone = pose.pose_channels[self.blenName] +# self.__pose_bone = pose.bones[self.blenName] + + # store a list if matricies here, (poseMatrix, head, tail) + # {frame:posematrix, frame:posematrix, ...} + self.__anim_poselist = {} + + ''' + def calcRestMatrixLocal(self): + if self.parent: + self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() + else: + self.restMatrixLocal = self.restMatrix.copy() + ''' + def setPoseFrame(self, f): + # cache pose info here, frame must be set beforehand + + # Didnt end up needing head or tail, if we do - here it is. + ''' + self.__anim_poselist[f] = (\ + self.__pose_bone.poseMatrix.copy(),\ + self.__pose_bone.head.copy(),\ + self.__pose_bone.tail.copy() ) + ''' + + self.__anim_poselist[f] = self.__pose_bone.pose_matrix.copy() +# self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() + + # get pose from frame. + def getPoseMatrix(self, f):# ---------------------------------------------- + return self.__anim_poselist[f] + ''' + def getPoseHead(self, f): + #return self.__pose_bone.head.copy() + return self.__anim_poselist[f][1].copy() + def getPoseTail(self, f): + #return self.__pose_bone.tail.copy() + return self.__anim_poselist[f][2].copy() + ''' + # end + + def getAnimParRelMatrix(self, frame): + #arm_mat = self.fbxArm.matrixWorld + #arm_mat = self.fbxArm.parRelMatrix() + if not self.parent: + #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore + return mtx4_z90 * self.getPoseMatrix(frame) + else: + #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() + return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() + + # we need thes because cameras and lights modified rotations + def getAnimParRelMatrixRot(self, frame): + return self.getAnimParRelMatrix(frame) + + def flushAnimData(self): + self.__anim_poselist.clear() + + + class my_object_generic: + # Other settings can be applied for each type - mesh, armature etc. + def __init__(self, ob, matrixWorld = None): + self.fbxName = sane_obname(ob) + self.blenObject = ob + self.fbxGroupNames = [] + self.fbxParent = None # set later on IF the parent is in the selection. + if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX + else: self.matrixWorld = ob.matrix * GLOBAL_MATRIX +# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + self.__anim_poselist = {} # we should only access this + + def parRelMatrix(self): + if self.fbxParent: + return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() + else: + return self.matrixWorld + + def setPoseFrame(self, f): + self.__anim_poselist[f] = self.blenObject.matrix.copy() +# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + + def getAnimParRelMatrix(self, frame): + if self.fbxParent: + #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX + return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() + else: + return self.__anim_poselist[frame] * GLOBAL_MATRIX + + def getAnimParRelMatrixRot(self, frame): + type = self.blenObject.type + if self.fbxParent: + matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() + else: + matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() + + # Lamps need to be rotated + if type =='LAMP': + matrix_rot = mtx_x90 * matrix_rot + elif type =='CAMERA': +# elif ob and type =='Camera': + y = Mathutils.Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) + + return matrix_rot + + # ---------------------------------------------- + + + + + + print('\nFBX export starting...', filename) + start_time = time.clock() +# start_time = Blender.sys.time() + try: + file = open(filename, 'w') + except: + return False + + sce = context.scene +# sce = bpy.data.scenes.active + world = sce.world + + + # ---------------------------- Write the header first + file.write(header_comment) + if time: + curtime = time.localtime()[0:6] + else: + curtime = (0,0,0,0,0,0) + # + file.write(\ +'''FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 6100 + CreationTimeStamp: { + Version: 1000 + Year: %.4i + Month: %.2i + Day: %.2i + Hour: %.2i + Minute: %.2i + Second: %.2i + Millisecond: 0 + } + Creator: "FBX SDK/FBX Plugins build 20070228" + OtherFlags: { + FlagPLE: 0 + } +}''' % (curtime)) + + file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) + file.write('\nCreator: "Blender3D version 2.5"') +# file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + + pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way + + # --------------- funcs for exporting + def object_tx(ob, loc, matrix, matrix_mod = None): + ''' + Matrix mod is so armature objects can modify their bone matricies + ''' + if isinstance(ob, bpy.types.Bone): +# if isinstance(ob, Blender.Types.BoneType): + + # we know we have a matrix + # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) + matrix = mtx4_z90 * ob.armature_matrix # dont apply armature matrix anymore +# matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + + parent = ob.parent + if parent: + #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) + par_matrix = mtx4_z90 * parent.armature_matrix # dont apply armature matrix anymore +# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + matrix = matrix * par_matrix.copy().invert() + + matrix_rot = matrix.rotationPart() + + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + rot = tuple(matrix_rot.toEuler()) + + else: + # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore + #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX + if ob and not matrix: raise Exception("error: this should never happen!") + + matrix_rot = matrix + #if matrix: + # matrix = matrix_scale * matrix + + if matrix: + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + + matrix_rot = matrix.rotationPart() + # Lamps need to be rotated + if ob and ob.type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + rot = tuple(matrix_rot.toEuler()) + elif ob and ob.type =='Camera': + y = Mathutils.Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y) + rot = tuple(matrix_rot.toEuler()) + else: + rot = tuple(matrix_rot.toEuler()) + else: + if not loc: + loc = 0,0,0 + scale = 1,1,1 + rot = 0,0,0 + + return loc, rot, scale, matrix, matrix_rot + + def write_object_tx(ob, loc, matrix, matrix_mod= None): + ''' + We have loc to set the location if non blender objects that have a location + + matrix_mod is only used for bones at the moment + ''' + loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) + + file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple(eulerRadToDeg(rot))) +# file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) + file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) + return loc, rot, scale, matrix, matrix_rot + + def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): + # if the type is 0 its an empty otherwise its a mesh + # only difference at the moment is one has a color + file.write(''' + Properties60: { + Property: "QuaternionInterpolate", "bool", "",0 + Property: "Visibility", "Visibility", "A+",1''') + + loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) + + # Rotation order, note, for FBX files Iv loaded normal order is 1 + # setting to zero. + # eEULER_XYZ = 0 + # eEULER_XZY + # eEULER_YZX + # eEULER_YXZ + # eEULER_ZXY + # eEULER_ZYX + + file.write(''' + Property: "RotationOffset", "Vector3D", "",0,0,0 + Property: "RotationPivot", "Vector3D", "",0,0,0 + Property: "ScalingOffset", "Vector3D", "",0,0,0 + Property: "ScalingPivot", "Vector3D", "",0,0,0 + Property: "TranslationActive", "bool", "",0 + Property: "TranslationMin", "Vector3D", "",0,0,0 + Property: "TranslationMax", "Vector3D", "",0,0,0 + Property: "TranslationMinX", "bool", "",0 + Property: "TranslationMinY", "bool", "",0 + Property: "TranslationMinZ", "bool", "",0 + Property: "TranslationMaxX", "bool", "",0 + Property: "TranslationMaxY", "bool", "",0 + Property: "TranslationMaxZ", "bool", "",0 + Property: "RotationOrder", "enum", "",0 + Property: "RotationSpaceForLimitOnly", "bool", "",0 + Property: "AxisLen", "double", "",10 + Property: "PreRotation", "Vector3D", "",0,0,0 + Property: "PostRotation", "Vector3D", "",0,0,0 + Property: "RotationActive", "bool", "",0 + Property: "RotationMin", "Vector3D", "",0,0,0 + Property: "RotationMax", "Vector3D", "",0,0,0 + Property: "RotationMinX", "bool", "",0 + Property: "RotationMinY", "bool", "",0 + Property: "RotationMinZ", "bool", "",0 + Property: "RotationMaxX", "bool", "",0 + Property: "RotationMaxY", "bool", "",0 + Property: "RotationMaxZ", "bool", "",0 + Property: "RotationStiffnessX", "double", "",0 + Property: "RotationStiffnessY", "double", "",0 + Property: "RotationStiffnessZ", "double", "",0 + Property: "MinDampRangeX", "double", "",0 + Property: "MinDampRangeY", "double", "",0 + Property: "MinDampRangeZ", "double", "",0 + Property: "MaxDampRangeX", "double", "",0 + Property: "MaxDampRangeY", "double", "",0 + Property: "MaxDampRangeZ", "double", "",0 + Property: "MinDampStrengthX", "double", "",0 + Property: "MinDampStrengthY", "double", "",0 + Property: "MinDampStrengthZ", "double", "",0 + Property: "MaxDampStrengthX", "double", "",0 + Property: "MaxDampStrengthY", "double", "",0 + Property: "MaxDampStrengthZ", "double", "",0 + Property: "PreferedAngleX", "double", "",0 + Property: "PreferedAngleY", "double", "",0 + Property: "PreferedAngleZ", "double", "",0 + Property: "InheritType", "enum", "",0 + Property: "ScalingActive", "bool", "",0 + Property: "ScalingMin", "Vector3D", "",1,1,1 + Property: "ScalingMax", "Vector3D", "",1,1,1 + Property: "ScalingMinX", "bool", "",0 + Property: "ScalingMinY", "bool", "",0 + Property: "ScalingMinZ", "bool", "",0 + Property: "ScalingMaxX", "bool", "",0 + Property: "ScalingMaxY", "bool", "",0 + Property: "ScalingMaxZ", "bool", "",0 + Property: "GeometricTranslation", "Vector3D", "",0,0,0 + Property: "GeometricRotation", "Vector3D", "",0,0,0 + Property: "GeometricScaling", "Vector3D", "",1,1,1 + Property: "LookAtProperty", "object", "" + Property: "UpVectorProperty", "object", "" + Property: "Show", "bool", "",1 + Property: "NegativePercentShapeSupport", "bool", "",1 + Property: "DefaultAttributeIndex", "int", "",0''') + if ob and not isinstance(ob, bpy.types.Bone): +# if ob and type(ob) != Blender.Types.BoneType: + # Only mesh objects have color + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Size", "double", "",100') + file.write('\n\t\t\tProperty: "Look", "enum", "",1') + + return loc, rot, scale, matrix, matrix_rot + + + # -------------------------------------------- Armatures + #def write_bone(bone, name, matrix_mod): + def write_bone(my_bone): + file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) + file.write('\n\t\tVersion: 232') + + #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] + poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore + pose_items.append( (my_bone.fbxName, poseMatrix) ) + + + # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + file.write('\n\t\t\tProperty: "Size", "double", "",1') + + #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) + + """ + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + """ + + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % + (my_bone.blenBone.armature_head - my_bone.blenBone.armature_tail).length) +# (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) + + #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') + file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Skeleton"') + file.write('\n\t}') + + def write_camera_switch(): + file.write(''' + Model: "Model::Camera Switcher", "CameraSwitcher" { + Version: 232''') + + write_object_props() + file.write(''' + Property: "Color", "Color", "A",0.8,0.8,0.8 + Property: "Camera Index", "Integer", "A+",100 + } + MultiLayer: 0 + MultiTake: 1 + Hidden: "True" + Shading: W + Culling: "CullingOff" + Version: 101 + Name: "Model::Camera Switcher" + CameraId: 0 + CameraName: 100 + CameraIndexName: + }''') + + def write_camera_dummy(name, loc, near, far, proj_type, up): + file.write('\n\tModel: "Model::%s", "Camera" {' % name ) + file.write('\n\t\tVersion: 232') + write_object_props(None, loc) + + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",320') + file.write('\n\t\t\tProperty: "AspectH", "double", "",200') + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tHidden: "True"') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %i,%i,%i' % up) + file.write('\n\t\tLookAt: 0,0,0') + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_camera_default(): + # This sucks but to match FBX converter its easier to + # write the cameras though they are not needed. + write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) + write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) + + def write_camera(my_cam): + ''' + Write a blender camera + ''' + render = sce.render_data + width = render.resolution_x + height = render.resolution_y +# render = sce.render +# width = render.sizeX +# height = render.sizeY + aspect = float(width)/height + + data = my_cam.blenObject.data + + file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) + file.write('\n\t\tVersion: 232') + loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) + + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units? +# file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto +# file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) + file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) + + '''Camera aspect ratio modes. + 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. + 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. + 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. + 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. + 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. + + Definition at line 234 of file kfbxcamera.h. ''' + + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') + + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clip_start) +# file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clip_end) +# file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,1,0) * matrix_rot) ) + file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,0,-1)*matrix_rot) ) + + #file.write('\n\t\tUp: 0,0,0' ) + #file.write('\n\t\tLookAt: 0,0,0' ) + + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_light(my_light): + light = my_light.blenObject.data + file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) + file.write('\n\t\tVersion: 232') + + write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) + + # Why are these values here twice?????? - oh well, follow the holy sdk's output + + # Blender light types match FBX's, funny coincidence, we just need to + # be sure that all unsupported types are made into a point light + #ePOINT, + #eDIRECTIONAL + #eSPOT + light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 4} + light_type = light_type_items[light.type] +# light_type = light.type + if light_type > 2: light_type = 1 # hemi and area lights become directional + +# mode = light.mode + if light.shadow_method == 'RAY_SHADOW' or light.shadow_method == 'BUFFER_SHADOW': +# if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: + do_shadow = 1 + else: + do_shadow = 0 + + if light.only_shadow or (not light.diffuse and not light.specular): +# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): + do_light = 0 + else: + do_light = 1 + + scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case + + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + if light.type == 'SPOT': + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spot_size * scale)) +# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.color)) +# file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 +# + # duplication? see ^ (Arystan) +# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') + file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.distance) +# file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) + file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) + file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Light"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t}') + + # matrixOnly is not used at the moment + def write_null(my_null = None, fbxName = None, matrixOnly = None): + # ob can be null + if not fbxName: fbxName = my_null.fbxName + + file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) + file.write('\n\t\tVersion: 232') + + # only use this for the root matrix at the moment + if matrixOnly: + poseMatrix = write_object_props(None, None, matrixOnly)[3] + + else: # all other Null's + if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] + else: poseMatrix = write_object_props()[3] + + pose_items.append((fbxName, poseMatrix)) + + file.write(''' + } + MultiLayer: 0 + MultiTake: 1 + Shading: Y + Culling: "CullingOff" + TypeFlags: "Null" + }''') + + # Material Settings + if world: world_amb = tuple(world.ambient_color) +# if world: world_amb = world.getAmb() + else: world_amb = (0,0,0) # Default value + + def write_material(matname, mat): + file.write('\n\tMaterial: "Material::%s", "" {' % matname) + + # Todo, add more material Properties. + if mat: + mat_cold = tuple(mat.diffuse_color) +# mat_cold = tuple(mat.rgbCol) + mat_cols = tuple(mat.specular_color) +# mat_cols = tuple(mat.specCol) + #mat_colm = tuple(mat.mirCol) # we wont use the mirror color + mat_colamb = world_amb +# mat_colamb = tuple([c for c in world_amb]) + + mat_dif = mat.diffuse_reflection +# mat_dif = mat.ref + mat_amb = mat.ambient +# mat_amb = mat.amb + mat_hard = (float(mat.specular_hardness)-1)/5.10 +# mat_hard = (float(mat.hard)-1)/5.10 + mat_spec = mat.specular_reflection/2.0 +# mat_spec = mat.spec/2.0 + mat_alpha = mat.alpha + mat_emit = mat.emit + mat_shadeless = mat.shadeless +# mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS + if mat_shadeless: + mat_shader = 'Lambert' + else: + if mat.diffuse_shader == 'LAMBERT': +# if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: + mat_shader = 'Lambert' + else: + mat_shader = 'Phong' + else: + mat_cols = mat_cold = 0.8, 0.8, 0.8 + mat_colamb = 0.0,0.0,0.0 + # mat_colm + mat_dif = 1.0 + mat_amb = 0.5 + mat_hard = 20.0 + mat_spec = 0.2 + mat_alpha = 1.0 + mat_emit = 0.0 + mat_shadeless = False + mat_shader = 'Phong' + + file.write('\n\t\tVersion: 102') + file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) + file.write('\n\t\tMultiLayer: 0') + + file.write('\n\t\tProperties60: {') + file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) + file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') + file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender + file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_emit) + + file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) + file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) + file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) + file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_dif) + file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') + file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') + file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) + file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) + file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') + file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') + file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) + file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) + file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) + file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') + + file.write('\n\t\t}') + file.write('\n\t}') + + def copy_image(image): + + rel = image.get_export_path(basepath, True) + base = os.path.basename(rel) + + if EXP_IMAGE_COPY: + absp = image.get_export_path(basepath, False) + if not os.path.exists(absp): + shutil.copy(image.get_abs_filename(), absp) + + return (rel, base) + + # tex is an Image (Arystan) + def write_video(texname, tex): + # Same as texture really! + file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) + + file.write(''' + Type: "Clip" + Properties60: { + Property: "FrameRate", "double", "",0 + Property: "LastFrame", "int", "",0 + Property: "Width", "int", "",0 + Property: "Height", "int", "",0''') + if tex: + fname_rel, fname_strip = copy_image(tex) +# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + else: + fname = fname_strip = fname_rel = '' + + file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) + + + file.write(''' + Property: "StartFrame", "int", "",0 + Property: "StopFrame", "int", "",0 + Property: "PlaySpeed", "double", "",1 + Property: "Offset", "KTime", "",0 + Property: "InterlaceMode", "enum", "",0 + Property: "FreeRunning", "bool", "",0 + Property: "Loop", "bool", "",0 + Property: "AccessMode", "enum", "",0 + } + UseMipMap: 0''') + + file.write('\n\t\tFilename: "%s"' % fname_strip) + if fname_strip: fname_strip = '/' + fname_strip + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative + file.write('\n\t}') + + + def write_texture(texname, tex, num): + # if tex == None then this is a dummy tex + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) + file.write('\n\t\tType: "TextureVideoClip"') + file.write('\n\t\tVersion: 202') + # TODO, rare case _empty_ exists as a name. + file.write('\n\t\tTextureName: "Texture::%s"' % texname) + + file.write(''' + Properties60: { + Property: "Translation", "Vector", "A+",0,0,0 + Property: "Rotation", "Vector", "A+",0,0,0 + Property: "Scaling", "Vector", "A+",1,1,1''') + file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) + + + # WrapModeU/V 0==rep, 1==clamp, TODO add support + file.write(''' + Property: "TextureTypeUse", "enum", "",0 + Property: "CurrentTextureBlendMode", "enum", "",1 + Property: "UseMaterial", "bool", "",0 + Property: "UseMipMap", "bool", "",0 + Property: "CurrentMappingType", "enum", "",0 + Property: "UVSwap", "bool", "",0''') + + file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clamp_x) +# file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) + file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clamp_y) +# file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) + + file.write(''' + Property: "TextureRotationPivot", "Vector3D", "",0,0,0 + Property: "TextureScalingPivot", "Vector3D", "",0,0,0 + Property: "VideoProperty", "object", "" + }''') + + file.write('\n\t\tMedia: "Video::%s"' % texname) + + if tex: + fname_rel, fname_strip = copy_image(tex) +# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) + else: + fname = fname_strip = fname_rel = '' + + file.write('\n\t\tFileName: "%s"' % fname_strip) + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command + + file.write(''' + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + }''') + + def write_deformer_skin(obname): + ''' + Each mesh has its own deformer + ''' + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Skin" + Properties60: { + } + Link_DeformAcuracy: 50 + }''') + + # in the example was 'Bip01 L Thigh_2' + def write_sub_deformer_skin(my_mesh, my_bone, weights): + + ''' + Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers + So the SubDeformer needs the mesh-object name as a prefix to make it unique + + Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, + a but silly but dosnt really matter + ''' + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) + + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Cluster" + Properties60: { + Property: "SrcModel", "object", "" + Property: "SrcModelReference", "object", "" + } + UserData: "", ""''') + + # Support for bone parents + if my_mesh.fbxBoneParent: + if my_mesh.fbxBoneParent == my_bone: + # TODO - this is a bit lazy, we could have a simple write loop + # for this case because all weights are 1.0 but for now this is ok + # Parent Bones arent used all that much anyway. + vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.verts))] + else: + # This bone is not a parent of this mesh object, no weights + vgroup_data = [] + + else: + # Normal weight painted mesh + if my_bone.blenName in weights[0]: + # Before we used normalized wright list + #vgroup_data = me.getVertsFromGroup(bone.name, 1) + group_index = weights[0].index(my_bone.blenName) + vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] + else: + vgroup_data = [] + + file.write('\n\t\tIndexes: ') + + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%i' % vg[0]) + i=0 + else: + if i==23: + file.write('\n\t\t') + i=0 + file.write(',%i' % vg[0]) + i+=1 + + file.write('\n\t\tWeights: ') + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%.8f' % vg[1]) + i=0 + else: + if i==38: + file.write('\n\t\t') + i=0 + file.write(',%.8f' % vg[1]) + i+=1 + + if my_mesh.fbxParent: + # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + else: + # Yes! this is it... - but dosnt work when the mesh is a. + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + + #m = mtx4_z90 * my_bone.restMatrix + matstr = mat4x4str(m) + matstr_i = mat4x4str(m.invert()) + + file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ + file.write('\n\t\tTransformLink: %s' % matstr) + file.write('\n\t}') + + def write_mesh(my_mesh): + + me = my_mesh.blenData + + # if there are non NULL materials on this mesh + if my_mesh.blenMaterials: do_materials = True + else: do_materials = False + + if my_mesh.blenTextures: do_textures = True + else: do_textures = False + + do_uvs = len(me.uv_textures) > 0 +# do_uvs = me.faceUV + + + file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) + file.write('\n\t\tVersion: 232') # newline is added in write_object_props + + poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3] + pose_items.append((my_mesh.fbxName, poseMatrix)) + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + + + # Write the Real Mesh data here + file.write('\n\t\tVertices: ') + i=-1 + + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) + i+=1 + + file.write('\n\t\tPolygonVertexIndex: ') + i=-1 + for f in me.faces: + fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3] +# fi = [v.index for v in f] + + # flip the last index, odd but it looks like + # this is how fbx tells one face from another + fi[-1] = -(fi[-1]+1) + fi = tuple(fi) + if i==-1: + if len(fi) == 3: file.write('%i,%i,%i' % fi ) +# if len(f) == 3: file.write('%i,%i,%i' % fi ) + else: file.write('%i,%i,%i,%i' % fi ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + if len(fi) == 3: file.write(',%i,%i,%i' % fi ) +# if len(f) == 3: file.write(',%i,%i,%i' % fi ) + else: file.write(',%i,%i,%i,%i' % fi ) + i+=1 + + file.write('\n\t\tEdges: ') + i=-1 + for ed in me.edges: + if i==-1: + file.write('%i,%i' % (ed.verts[0], ed.verts[1])) +# file.write('%i,%i' % (ed.v1.index, ed.v2.index)) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + file.write(',%i,%i' % (ed.verts[0], ed.verts[1])) +# file.write(',%i,%i' % (ed.v1.index, ed.v2.index)) + i+=1 + + file.write('\n\t\tGeometryVersion: 124') + + file.write(''' + LayerElementNormal: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByVertice" + ReferenceInformationType: "Direct" + Normals: ''') + + i=-1 + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.normal)); i=0 +# file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.normal)) +# file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + i+=1 + file.write('\n\t\t}') + + # Write Face Smoothing + file.write(''' + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygon" + ReferenceInformationType: "Direct" + Smoothing: ''') + + i=-1 + for f in me.faces: + if i==-1: + file.write('%i' % f.smooth); i=0 + else: + if i==54: + file.write('\n '); i=0 + file.write(',%i' % f.smooth) + i+=1 + + file.write('\n\t\t}') + + # Write Edge Smoothing + file.write(''' + LayerElementSmoothing: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: ''') + +# SHARP = Blender.Mesh.EdgeFlags.SHARP + i=-1 + for ed in me.edges: + if i==-1: + file.write('%i' % (ed.sharp)); i=0 +# file.write('%i' % ((ed.flag&SHARP)!=0)); i=0 + else: + if i==54: + file.write('\n '); i=0 + file.write(',%i' % (ed.sharp)) +# file.write(',%i' % ((ed.flag&SHARP)!=0)) + i+=1 + + file.write('\n\t\t}') +# del SHARP + + # small utility function + # returns a slice of data depending on number of face verts + # data is either a MeshTextureFace or MeshColor + def face_data(data, face): + if f.verts[3] == 0: + totvert = 3 + else: + totvert = 4 + + return data[:totvert] + + + # Write VertexColor Layers + # note, no programs seem to use this info :/ + collayers = [] + if len(me.vertex_colors): +# if me.vertexColors: + collayers = me.vertex_colors +# collayers = me.getColorLayerNames() + collayer_orig = me.active_vertex_color +# collayer_orig = me.activeColorLayer + for colindex, collayer in enumerate(collayers): +# me.activeColorLayer = collayer + file.write('\n\t\tLayerElementColor: %i {' % colindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % collayer.name) +# file.write('\n\t\t\tName: "%s"' % collayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + Colors: ''') + + i = -1 + ii = 0 # Count how many Colors we write + + for f, cf in zip(me.faces, collayer.data): + colors = [cf.color1, cf.color2, cf.color3, cf.color4] + + # determine number of verts + colors = face_data(colors, f) + + for col in colors: + if i==-1: + file.write('%.4f,%.4f,%.4f,1' % tuple(col)) + i=0 + else: + if i==7: + file.write('\n\t\t\t\t') + i=0 + file.write(',%.4f,%.4f,%.4f,1' % tuple(col)) + i+=1 + ii+=1 # One more Color + +# for f in me.faces: +# for col in f.col: +# if i==-1: +# file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) +# i=0 +# else: +# if i==7: +# file.write('\n\t\t\t\t') +# i=0 +# file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0)) +# i+=1 +# ii+=1 # One more Color + + file.write('\n\t\t\tColorIndex: ') + i = -1 + for j in range(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + + + # Write UV and texture layers. + uvlayers = [] + if do_uvs: + uvlayers = me.uv_textures +# uvlayers = me.getUVLayerNames() + uvlayer_orig = me.active_uv_texture +# uvlayer_orig = me.activeUVLayer + for uvindex, uvlayer in enumerate(me.uv_textures): +# for uvindex, uvlayer in enumerate(uvlayers): +# me.activeUVLayer = uvlayer + file.write('\n\t\tLayerElementUV: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer.name) +# file.write('\n\t\t\tName: "%s"' % uvlayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: ''') + + i = -1 + ii = 0 # Count how many UVs we write + + for f, uf in zip(me.faces, uvlayer.data): +# for f in me.faces: + uvs = [uf.uv1, uf.uv2, uf.uv3, uf.uv4] + uvs = face_data(uvs, f) + + for uv in uvs: +# for uv in f.uv: + if i==-1: + file.write('%.6f,%.6f' % tuple(uv)) + i=0 + else: + if i==7: + file.write('\n ') + i=0 + file.write(',%.6f,%.6f' % tuple(uv)) + i+=1 + ii+=1 # One more UV + + file.write('\n\t\t\tUVIndex: ') + i = -1 + for j in range(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + if do_textures: + file.write('\n\t\tLayerElementTexture: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer.name) +# file.write('\n\t\t\tName: "%s"' % uvlayer) + + if len(my_mesh.blenTextures) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tBlendMode: "Translucent"') + file.write('\n\t\t\tTextureAlpha: 1') + file.write('\n\t\t\tTextureId: ') + + if len(my_mesh.blenTextures) == 1: + file.write('0') + else: + texture_mapping_local = {None:-1} + + i = 0 # 1 for dummy + for tex in my_mesh.blenTextures: + if tex: # None is set above + texture_mapping_local[tex] = i + i+=1 + + i=-1 + for f in uvlayer.data: +# for f in me.faces: + img_key = f.image + + if i==-1: + i=0 + file.write( '%s' % texture_mapping_local[img_key]) + else: + if i==55: + file.write('\n ') + i=0 + + file.write(',%s' % texture_mapping_local[img_key]) + i+=1 + + else: + file.write(''' + LayerElementTexture: 0 { + Version: 101 + Name: "" + MappingInformationType: "NoMappingInformation" + ReferenceInformationType: "IndexToDirect" + BlendMode: "Translucent" + TextureAlpha: 1 + TextureId: ''') + file.write('\n\t\t}') + +# me.activeUVLayer = uvlayer_orig + + # Done with UV/textures. + + if do_materials: + file.write('\n\t\tLayerElementMaterial: 0 {') + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: ""') + + if len(my_mesh.blenMaterials) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tMaterials: ') + + if len(my_mesh.blenMaterials) == 1: + file.write('0') + else: + # Build a material mapping for this + material_mapping_local = {} # local-mat & tex : global index. + + for j, mat_tex_pair in enumerate(my_mesh.blenMaterials): + material_mapping_local[mat_tex_pair] = j + + len_material_mapping_local = len(material_mapping_local) + + mats = my_mesh.blenMaterialList + + if me.active_uv_texture: + uv_faces = me.active_uv_texture.data + else: + uv_faces = [None] * len(me.faces) + + i=-1 + for f, uf in zip(me.faces, uv_faces): +# for f in me.faces: + try: mat = mats[f.material_index] +# try: mat = mats[f.mat] + except:mat = None + + if do_uvs: tex = uf.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ +# if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/ + else: tex = None + + if i==-1: + i=0 + file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + + file.write(',%s' % (material_mapping_local[mat, tex])) + i+=1 + + file.write('\n\t\t}') + + file.write(''' + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + }''') + + if do_materials: + file.write(''' + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + }''') + + # Always write this + if do_textures: + file.write(''' + LayerElement: { + Type: "LayerElementTexture" + TypedIndex: 0 + }''') + + if me.vertex_colors: +# if me.vertexColors: + file.write(''' + LayerElement: { + Type: "LayerElementColor" + TypedIndex: 0 + }''') + + if do_uvs: # same as me.faceUV + file.write(''' + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + }''') + + + file.write('\n\t\t}') + + if len(uvlayers) > 1: + for i in range(1, len(uvlayers)): + + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementUV"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + if do_textures: + + file.write(''' + LayerElement: { + Type: "LayerElementTexture"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + file.write('\n\t\t}') + + if len(collayers) > 1: + # Take into account any UV layers + layer_offset = 0 + if uvlayers: layer_offset = len(uvlayers)-1 + + for i in range(layer_offset, len(collayers)+layer_offset): + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementColor"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + file.write('\n\t\t}') + file.write('\n\t}') + + def write_group(name): + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) + + file.write(''' + Properties60: { + Property: "MultiLayer", "bool", "",0 + Property: "Pickable", "bool", "",1 + Property: "Transformable", "bool", "",1 + Property: "Show", "bool", "",1 + } + MultiLayer: 0 + }''') + + + # add meshes here to clear because they are not used anywhere. + meshes_to_clear = [] + + ob_meshes = [] + ob_lights = [] + ob_cameras = [] + # in fbx we export bones as children of the mesh + # armatures not a part of a mesh, will be added to ob_arms + ob_bones = [] + ob_arms = [] + ob_null = [] # emptys + + # List of types that have blender objects (not bones) + ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] + + groups = [] # blender groups, only add ones that have objects in the selections + materials = {} # (mat, image) keys, should be a set() + textures = {} # should be a set() + + tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error + + # if EXP_OBS_SELECTED is false, use sceens objects + if not batch_objects: + if EXP_OBS_SELECTED: tmp_objects = context.selected_objects +# if EXP_OBS_SELECTED: tmp_objects = sce.objects.context + else: tmp_objects = sce.objects + else: + tmp_objects = batch_objects + + if EXP_ARMATURE: + # This is needed so applying modifiers dosnt apply the armature deformation, its also needed + # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. + # set every armature to its rest, backup the original values so we done mess up the scene + ob_arms_orig_rest = [arm.rest_position for arm in bpy.data.armatures] +# ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] + + for arm in bpy.data.armatures: + arm.rest_position = True +# arm.restPosition = True + + if ob_arms_orig_rest: + for ob_base in bpy.data.objects: + #if ob_base.type == 'Armature': + ob_base.make_display_list() +# ob_base.makeDisplayList() + + # This causes the makeDisplayList command to effect the mesh + sce.set_frame(sce.current_frame) +# Blender.Set('curframe', Blender.Get('curframe')) + + + for ob_base in tmp_objects: + + # ignore dupli children + if ob_base.parent and ob_base.parent.dupli_type != 'NONE': + continue + + obs = [(ob_base, ob_base.matrix)] + if ob_base.dupli_type != 'NONE': + ob_base.create_dupli_list() + obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list] + + for ob, mtx in obs: +# for ob, mtx in BPyObject.getDerivedObjects(ob_base): + tmp_ob_type = ob.type + if tmp_ob_type == 'CAMERA': +# if tmp_ob_type == 'Camera': + if EXP_CAMERA: + ob_cameras.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'LAMP': +# elif tmp_ob_type == 'Lamp': + if EXP_LAMP: + ob_lights.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'ARMATURE': +# elif tmp_ob_type == 'Armature': + if EXP_ARMATURE: + # TODO - armatures dont work in dupligroups! + if ob not in ob_arms: ob_arms.append(ob) + # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" + elif tmp_ob_type == 'EMPTY': +# elif tmp_ob_type == 'Empty': + if EXP_EMPTY: + ob_null.append(my_object_generic(ob, mtx)) + elif EXP_MESH: + origData = True + if tmp_ob_type != 'MESH': +# if tmp_ob_type != 'Mesh': +# me = bpy.data.meshes.new() + try: me = ob.create_mesh(True, 'PREVIEW') +# try: me.getFromObject(ob) + except: me = None + if me: + meshes_to_clear.append( me ) + mats = me.materials + origData = False + else: + # Mesh Type! + if EXP_MESH_APPLY_MOD: +# me = bpy.data.meshes.new() + me = ob.create_mesh(True, 'PREVIEW') +# me.getFromObject(ob) + + # so we keep the vert groups +# if EXP_ARMATURE: +# orig_mesh = ob.getData(mesh=1) +# if orig_mesh.getVertGroupNames(): +# ob.copy().link(me) +# # If new mesh has no vgroups we can try add if verts are teh same +# if not me.getVertGroupNames(): # vgroups were not kept by the modifier +# if len(me.verts) == len(orig_mesh.verts): +# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) +# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + + # print ob, me, me.getVertGroupNames() + meshes_to_clear.append( me ) + origData = False + mats = me.materials + else: + me = ob.data +# me = ob.getData(mesh=1) + mats = me.materials + +# # Support object colors +# tmp_colbits = ob.colbits +# if tmp_colbits: +# tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. +# for i in xrange(16): +# if tmp_colbits & (1< 0: +# if me.faceUV: + uvlayer_orig = me.active_uv_texture +# uvlayer_orig = me.activeUVLayer + for uvlayer in me.uv_textures: +# for uvlayer in me.getUVLayerNames(): +# me.activeUVLayer = uvlayer + for f, uf in zip(me.faces, uvlayer.data): +# for f in me.faces: + tex = uf.image +# tex = f.image + textures[tex] = texture_mapping_local[tex] = None + + try: mat = mats[f.material_index] +# try: mat = mats[f.mat] + except: mat = None + + materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5 + + +# me.activeUVLayer = uvlayer_orig + else: + for mat in mats: + # 2.44 use mat.lib too for uniqueness + materials[mat, None] = material_mapping_local[mat, None] = None + else: + materials[None, None] = None + + if EXP_ARMATURE: + armob = ob.find_armature() + blenParentBoneName = None + + # parent bone - special case + if (not armob) and ob.parent and ob.parent.type == 'ARMATURE' and \ + ob.parent_type == 'BONE': +# if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE: + armob = ob.parent + blenParentBoneName = ob.parent_bone +# blenParentBoneName = ob.parentbonename + + + if armob and armob not in ob_arms: + ob_arms.append(armob) + + else: + blenParentBoneName = armob = None + + my_mesh = my_object_generic(ob, mtx) + my_mesh.blenData = me + my_mesh.origData = origData + my_mesh.blenMaterials = list(material_mapping_local.keys()) + my_mesh.blenMaterialList = mats + my_mesh.blenTextures = list(texture_mapping_local.keys()) + + # if only 1 null texture then empty the list + if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None: + my_mesh.blenTextures = [] + + my_mesh.fbxArm = armob # replace with my_object_generic armature instance later + my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later + + ob_meshes.append( my_mesh ) + + # not forgetting to free dupli_list + if ob_base.dupli_list: ob_base.free_dupli_list() + + + if EXP_ARMATURE: + # now we have the meshes, restore the rest arm position + for i, arm in enumerate(bpy.data.armatures): + arm.rest_position = ob_arms_orig_rest[i] +# arm.restPosition = ob_arms_orig_rest[i] + + if ob_arms_orig_rest: + for ob_base in bpy.data.objects: + if ob_base.type == 'ARMATURE': +# if ob_base.type == 'Armature': + ob_base.make_display_list() +# ob_base.makeDisplayList() + # This causes the makeDisplayList command to effect the mesh + sce.set_frame(sce.current_frame) +# Blender.Set('curframe', Blender.Get('curframe')) + + del tmp_ob_type, tmp_objects + + # now we have collected all armatures, add bones + for i, ob in enumerate(ob_arms): + + ob_arms[i] = my_arm = my_object_generic(ob) + + my_arm.fbxBones = [] + my_arm.blenData = ob.data + if ob.animation_data: + my_arm.blenAction = ob.animation_data.action + else: + my_arm.blenAction = None +# my_arm.blenAction = ob.action + my_arm.blenActionList = [] + + # fbxName, blenderObject, my_bones, blenderActions + #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, []) + + for bone in my_arm.blenData.bones: +# for bone in my_arm.blenData.bones.values(): + my_bone = my_bone_class(bone, my_arm) + my_arm.fbxBones.append( my_bone ) + ob_bones.append( my_bone ) + + # add the meshes to the bones and replace the meshes armature with own armature class + #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: + for my_mesh in ob_meshes: + # Replace + # ...this could be sped up with dictionary mapping but its unlikely for + # it ever to be a bottleneck - (would need 100+ meshes using armatures) + if my_mesh.fbxArm: + for my_arm in ob_arms: + if my_arm.blenObject == my_mesh.fbxArm: + my_mesh.fbxArm = my_arm + break + + for my_bone in ob_bones: + + # The mesh uses this bones armature! + if my_bone.fbxArm == my_mesh.fbxArm: + my_bone.blenMeshes[my_mesh.fbxName] = me + + + # parent bone: replace bone names with our class instances + # my_mesh.fbxBoneParent is None or a blender bone name initialy, replacing if the names match. + if my_mesh.fbxBoneParent == my_bone.blenName: + my_mesh.fbxBoneParent = my_bone + + bone_deformer_count = 0 # count how many bones deform a mesh + my_bone_blenParent = None + for my_bone in ob_bones: + my_bone_blenParent = my_bone.blenBone.parent + if my_bone_blenParent: + for my_bone_parent in ob_bones: + # Note 2.45rc2 you can compare bones normally + if my_bone_blenParent.name == my_bone_parent.blenName and my_bone.fbxArm == my_bone_parent.fbxArm: + my_bone.parent = my_bone_parent + break + + # Not used at the moment + # my_bone.calcRestMatrixLocal() + bone_deformer_count += len(my_bone.blenMeshes) + + del my_bone_blenParent + + + # Build blenObject -> fbxObject mapping + # this is needed for groups as well as fbxParenting +# for ob in bpy.data.objects: ob.tag = False +# bpy.data.objects.tag = False + + # using a list of object names for tagging (Arystan) + tagged_objects = [] + + tmp_obmapping = {} + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + tagged_objects.append(ob_base.blenObject.name) +# ob_base.blenObject.tag = True + tmp_obmapping[ob_base.blenObject] = ob_base + + # Build Groups from objects we export + for blenGroup in bpy.data.groups: + fbxGroupName = None + for ob in blenGroup.objects: + if ob.name in tagged_objects: +# if ob.tag: + if fbxGroupName == None: + fbxGroupName = sane_groupname(blenGroup) + groups.append((fbxGroupName, blenGroup)) + + tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames + + groups.sort() # not really needed + + # Assign parents using this mapping + for ob_generic in ob_all_typegroups: + for my_ob in ob_generic: + parent = my_ob.blenObject.parent + if parent and parent.name in tagged_objects: # does it exist and is it in the mapping +# if parent and parent.tag: # does it exist and is it in the mapping + my_ob.fbxParent = tmp_obmapping[parent] + + + del tmp_obmapping + # Finished finding groups we use + + + materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.keys()] + textures = [(sane_texname(tex), tex) for tex in textures.keys() if tex] + materials.sort() # sort by name + textures.sort() + + camera_count = 8 + file.write(''' + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: %i''' % (\ + 1+1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones)+\ + bone_deformer_count+\ + len(materials)+\ + (len(textures)*2))) # add 1 for the root model 1 for global settings + + del bone_deformer_count + + file.write(''' + ObjectType: "Model" { + Count: %i + }''' % (\ + 1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones))) # add 1 for the root model + + file.write(''' + ObjectType: "Geometry" { + Count: %i + }''' % len(ob_meshes)) + + if materials: + file.write(''' + ObjectType: "Material" { + Count: %i + }''' % len(materials)) + + if textures: + file.write(''' + ObjectType: "Texture" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + file.write(''' + ObjectType: "Video" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + + tmp = 0 + # Add deformer nodes + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + tmp+=1 + + # Add subdeformers + for my_bone in ob_bones: + tmp += len(my_bone.blenMeshes) + + if tmp: + file.write(''' + ObjectType: "Deformer" { + Count: %i + }''' % tmp) + del tmp + + # we could avoid writing this possibly but for now just write it + + file.write(''' + ObjectType: "Pose" { + Count: 1 + }''') + + if groups: + file.write(''' + ObjectType: "GroupSelection" { + Count: %i + }''' % len(groups)) + + file.write(''' + ObjectType: "GlobalSettings" { + Count: 1 + } +}''') + + file.write(''' + +; Object properties +;------------------------------------------------------------------ + +Objects: {''') + + # To comply with other FBX FILES + write_camera_switch() + + # Write the null object + write_null(None, 'blend_root')# , GLOBAL_MATRIX) + + for my_null in ob_null: + write_null(my_null) + + for my_arm in ob_arms: + write_null(my_arm) + + for my_cam in ob_cameras: + write_camera(my_cam) + + for my_light in ob_lights: + write_light(my_light) + + for my_mesh in ob_meshes: + write_mesh(my_mesh) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + write_bone(my_bone) + + write_camera_default() + + for matname, (mat, tex) in materials: + write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard) + + # each texture uses a video, odd + for texname, tex in textures: + write_video(texname, tex) + i = 0 + for texname, tex in textures: + write_texture(texname, tex, i) + i+=1 + + for groupname, group in groups: + write_group(groupname) + + # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. + + # Write armature modifiers + # TODO - add another MODEL? - because of this skin definition. + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + write_deformer_skin(my_mesh.fbxName) + + # Get normalized weights for temorary use + if my_mesh.fbxBoneParent: + weights = None + else: + weights = meshNormalizedWeights(my_mesh.blenObject) +# weights = meshNormalizedWeights(my_mesh.blenData) + + #for bonename, bone, obname, bone_mesh, armob in ob_bones: + for my_bone in ob_bones: + if me in iter(my_bone.blenMeshes.values()): + write_sub_deformer_skin(my_mesh, my_bone, weights) + + # Write pose's really weired, only needed when an armature and mesh are used together + # each by themselves dont need pose data. for now only pose meshes and bones + + file.write(''' + Pose: "Pose::BIND_POSES", "BindPose" { + Type: "BindPose" + Version: 100 + Properties60: { + } + NbPoseNodes: ''') + file.write(str(len(pose_items))) + + + for fbxName, matrix in pose_items: + file.write('\n\t\tPoseNode: {') + file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) + if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) + else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) + file.write('\n\t\t}') + + file.write('\n\t}') + + + # Finish Writing Objects + # Write global settings + file.write(''' + GlobalSettings: { + Version: 1000 + Properties60: { + Property: "UpAxis", "int", "",1 + Property: "UpAxisSign", "int", "",1 + Property: "FrontAxis", "int", "",2 + Property: "FrontAxisSign", "int", "",1 + Property: "CoordAxis", "int", "",0 + Property: "CoordAxisSign", "int", "",1 + Property: "UnitScaleFactor", "double", "",100 + } + } +''') + file.write('}') + + file.write(''' + +; Object relations +;------------------------------------------------------------------ + +Relations: {''') + + file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') + + for my_null in ob_null: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) + + for my_arm in ob_arms: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) + + for my_mesh in ob_meshes: + file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) + + # TODO - limbs can have the same name for multiple armatures, should prefix. + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) + + for my_cam in ob_cameras: + file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) + + for my_light in ob_lights: + file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) + + file.write(''' + Model: "Model::Producer Perspective", "Camera" { + } + Model: "Model::Producer Top", "Camera" { + } + Model: "Model::Producer Bottom", "Camera" { + } + Model: "Model::Producer Front", "Camera" { + } + Model: "Model::Producer Back", "Camera" { + } + Model: "Model::Producer Right", "Camera" { + } + Model: "Model::Producer Left", "Camera" { + } + Model: "Model::Camera Switcher", "CameraSwitcher" { + }''') + + for matname, (mat, tex) in materials: + file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) + + if textures: + for texname, tex in textures: + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) + for texname, tex in textures: + file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) + + # deformers - modifiers + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName + # is this bone effecting a mesh? + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) + + # This should be at the end + # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') + + for groupname, group in groups: + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) + + file.write('\n}') + file.write(''' + +; Object connections +;------------------------------------------------------------------ + +Connections: {''') + + # NOTE - The FBX SDK dosnt care about the order but some importers DO! + # for instance, defining the material->mesh connection + # before the mesh->blend_root crashes cinema4d + + + # write the fake root node + file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') + + for ob_generic in ob_all_typegroups: # all blender 'Object's we support + for my_ob in ob_generic: + if my_ob.fbxParent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) + else: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) + + if materials: + for my_mesh in ob_meshes: + # Connect all materials to all objects, not good form but ok for now. + for mat, tex in my_mesh.blenMaterials: + if mat: mat_name = mat.name + else: mat_name = None + + if tex: tex_name = tex.name + else: tex_name = None + + file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName)) + + if textures: + for my_mesh in ob_meshes: + if my_mesh.blenTextures: + # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) + for tex in my_mesh.blenTextures: + if tex: + file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) + + for texname, tex in textures: + file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) + + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) + + # limbs -> deformers + # for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) + + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + # Always parent to armature now + if my_bone.parent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) + else: + # the armature object is written as an empty and all root level bones connect to it + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) + + # groups + if groups: + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + for fbxGroupName in ob_base.fbxGroupNames: + file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) + + for my_arm in ob_arms: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) + + file.write('\n}') + + + # Needed for scene footer as well as animation + render = sce.render_data +# render = sce.render + + # from the FBX sdk + #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) + def fbx_time(t): + # 0.5 + val is the same as rounding. + return int(0.5 + ((t/fps) * 46186158000)) + + fps = float(render.fps) + start = sce.start_frame +# start = render.sFrame + end = sce.end_frame +# end = render.eFrame + if end < start: start, end = end, start + if start==end: ANIM_ENABLE = False + + # animations for these object types + ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms + + if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: + + frame_orig = sce.current_frame +# frame_orig = Blender.Get('curframe') + + if ANIM_OPTIMIZE: + ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION + + # default action, when no actions are avaioable + tmp_actions = [None] # None is the default action + blenActionDefault = None + action_lastcompat = None + + # instead of tagging + tagged_actions = [] + + if ANIM_ACTION_ALL: +# bpy.data.actions.tag = False + tmp_actions = list(bpy.data.actions) + + + # find which actions are compatible with the armatures + # blenActions is not yet initialized so do it now. + tmp_act_count = 0 + for my_arm in ob_arms: + + # get the default name + if not blenActionDefault: + blenActionDefault = my_arm.blenAction + + arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) + + for action in tmp_actions: + + action_chan_names = arm_bone_names.intersection( set([g.name for g in action.groups]) ) +# action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) + + if action_chan_names: # at least one channel matches. + my_arm.blenActionList.append(action) + tagged_actions.append(action.name) +# action.tag = True + tmp_act_count += 1 + + # incase there is no actions applied to armatures + action_lastcompat = action + + if tmp_act_count: + # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. + if not blenActionDefault: + blenActionDefault = action_lastcompat + + del action_lastcompat + + file.write(''' +;Takes and animation section +;---------------------------------------------------- + +Takes: {''') + + if blenActionDefault: + file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) + else: + file.write('\n\tCurrent: "Default Take"') + + for blenAction in tmp_actions: + # we have tagged all actious that are used be selected armatures + if blenAction: + if blenAction.name in tagged_actions: +# if blenAction.tag: + print('\taction: "%s" exporting...' % blenAction.name) + else: + print('\taction: "%s" has no armature using it, skipping' % blenAction.name) + continue + + if blenAction == None: + # Warning, this only accounts for tmp_actions being [None] + file.write('\n\tTake: "Default Take" {') + act_start = start + act_end = end + else: + # use existing name + if blenAction == blenActionDefault: # have we alredy got the name + file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) + else: + file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) + + act_start, act_end = blenAction.get_frame_range() +# tmp = blenAction.getFrameNumbers() +# if tmp: +# act_start = min(tmp) +# act_end = max(tmp) +# del tmp +# else: +# # Fallback on this, theres not much else we can do? :/ +# # when an action has no length +# act_start = start +# act_end = end + + # Set the action active + for my_bone in ob_arms: + if blenAction in my_bone.blenActionList: + ob.action = blenAction + # print '\t\tSetting Action!', blenAction + # sce.update(1) + + file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed + file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + + file.write(''' + + ;Models animation + ;----------------------------------------------------''') + + + # set pose data for all bones + # do this here incase the action changes + ''' + for my_bone in ob_bones: + my_bone.flushAnimData() + ''' + i = act_start + while i <= act_end: + sce.set_frame(i) +# Blender.Set('curframe', i) + for ob_generic in ob_anim_lists: + for my_ob in ob_generic: + #Blender.Window.RedrawAll() + if ob_generic == ob_meshes and my_ob.fbxArm: + # We cant animate armature meshes! + pass + else: + my_ob.setPoseFrame(i) + + i+=1 + + + #for bonename, bone, obname, me, armob in ob_bones: + for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): + + for my_ob in ob_generic: + + if ob_generic == ob_meshes and my_ob.fbxArm: + # do nothing, + pass + else: + + file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed + file.write('\n\t\t\tVersion: 1.1') + file.write('\n\t\t\tChannel: "Transform" {') + + context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end+1) ] + + # ---------------- + # ---------------- + for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale + + if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='S': context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='R': + # Was.... + # elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] + # + # ...but we need to use the previous euler for compatible conversion. + context_bone_anim_vecs = [] + prev_eul = None + for mtx in context_bone_anim_mats: + if prev_eul: prev_eul = mtx[1].toEuler(prev_eul) + else: prev_eul = mtx[1].toEuler() + context_bone_anim_vecs.append(eulerRadToDeg(prev_eul)) +# context_bone_anim_vecs.append(prev_eul) + + file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation + + for i in range(3): + # Loop on each axis of the bone + file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation + file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) + file.write('\n\t\t\t\t\t\tKeyVer: 4005') + + if not ANIM_OPTIMIZE: + # Just write all frames, simple but in-eficient + file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) + file.write('\n\t\t\t\t\t\tKey: ') + frame = act_start + while frame <= act_end: + if frame!=act_start: + file.write(',') + + # Curve types are 'C,n' for constant, 'L' for linear + # C,n is for bezier? - linear is best for now so we can do simple keyframe removal + file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + frame+=1 + else: + # remove unneeded keys, j is the frame, needed when some frames are removed. + context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + + # last frame to fisrt frame, missing 1 frame on either side. + # removeing in a backwards loop is faster + #for j in xrange( (act_end-act_start)-1, 0, -1 ): + # j = (act_end-act_start)-1 + j = len(context_bone_anim_keys)-2 + while j > 0 and len(context_bone_anim_keys) > 2: + # print j, len(context_bone_anim_keys) + # Is this key the same as the ones next to it? + + # co-linear horizontal... + if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ + abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + + del context_bone_anim_keys[j] + + else: + frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1]) + frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range + frame_range_fac2 = 1.0 - frame_range_fac1 + + if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + del context_bone_anim_keys[j] + else: + j-=1 + + # keep the index below the list length + if j > len(context_bone_anim_keys)-2: + j = len(context_bone_anim_keys)-2 + + if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: + # This axis has no moton, its okay to skip KeyCount and Keys in this case + pass + else: + # We only need to write these if there is at least one + file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) + file.write('\n\t\t\t\t\t\tKey: ') + for val, frame in context_bone_anim_keys: + if frame != context_bone_anim_keys[0][1]: # not the first + file.write(',') + # frame is alredy one less then blenders frame + file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + + if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') + elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') + elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + + file.write('\n\t\t\t\t\t}') + file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) + file.write('\n\t\t\t\t}') + + # --------------- + + file.write('\n\t\t\t}') + file.write('\n\t\t}') + + # end the take + file.write('\n\t}') + + # end action loop. set original actions + # do this after every loop incase actions effect eachother. + for my_bone in ob_arms: + my_bone.blenObject.action = my_bone.blenAction + + file.write('\n}') + + sce.set_frame(frame_orig) +# Blender.Set('curframe', frame_orig) + + else: + # no animation + file.write('\n;Takes and animation section') + file.write('\n;----------------------------------------------------') + file.write('\n') + file.write('\nTakes: {') + file.write('\n\tCurrent: ""') + file.write('\n}') + + + # write meshes animation + #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: + + + # Clear mesh data Only when writing with modifiers applied + for me in meshes_to_clear: + bpy.data.remove_mesh(me) +# me.verts = None + + # --------------------------- Footer + if world: + m = world.mist + has_mist = m.enabled +# has_mist = world.mode & 1 + mist_intense = m.intensity + mist_start = m.start + mist_end = m.depth + mist_height = m.height +# mist_intense, mist_start, mist_end, mist_height = world.mist + world_hor = world.horizon_color +# world_hor = world.hor + else: + has_mist = mist_intense = mist_start = mist_end = mist_height = 0 + world_hor = 0,0,0 + + file.write('\n;Version 5 settings') + file.write('\n;------------------------------------------------------------------') + file.write('\n') + file.write('\nVersion5: {') + file.write('\n\tAmbientRenderSettings: {') + file.write('\n\t\tVersion: 101') + file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) + file.write('\n\t}') + file.write('\n\tFogOptions: {') + file.write('\n\t\tFlogEnable: %i' % has_mist) + file.write('\n\t\tFogMode: 0') + file.write('\n\t\tFogDensity: %.3f' % mist_intense) + file.write('\n\t\tFogStart: %.3f' % mist_start) + file.write('\n\t\tFogEnd: %.3f' % mist_end) + file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) + file.write('\n\t}') + file.write('\n\tSettings: {') + file.write('\n\t\tFrameRate: "%i"' % int(fps)) + file.write('\n\t\tTimeFormat: 1') + file.write('\n\t\tSnapOnFrames: 0') + file.write('\n\t\tReferenceTimeIndex: -1') + file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) + file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) + file.write('\n\t}') + file.write('\n\tRendererSetting: {') + file.write('\n\t\tDefaultCamera: "Producer Perspective"') + file.write('\n\t\tDefaultViewingMode: 0') + file.write('\n\t}') + file.write('\n}') + file.write('\n') + + # Incase sombody imports this, clean up by clearing global dicts + sane_name_mapping_ob.clear() + sane_name_mapping_mat.clear() + sane_name_mapping_tex.clear() + + ob_arms[:] = [] + ob_bones[:] = [] + ob_cameras[:] = [] + ob_lights[:] = [] + ob_meshes[:] = [] + ob_null[:] = [] + + + # copy images if enabled +# if EXP_IMAGE_COPY: +# # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) +# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath) + + print('export finished in %.4f sec.' % (time.clock() - start_time)) +# print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) + return True + + +# -------------------------------------------- +# UI Function - not a part of the exporter. +# this is to seperate the user interface from the rest of the exporter. +# from Blender import Draw, Window +EVENT_NONE = 0 +EVENT_EXIT = 1 +EVENT_REDRAW = 2 +EVENT_FILESEL = 3 + +GLOBALS = {} + +# export opts + +def do_redraw(e,v): GLOBALS['EVENT'] = e + +# toggle between these 2, only allow one on at once +def do_obs_sel(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 0 + GLOBALS['EXP_OBS_SELECTED'].val = 1 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_batch_type_grp(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 1 + GLOBALS['BATCH_SCENE'].val = 0 + +def do_batch_type_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 0 + GLOBALS['BATCH_SCENE'].val = 1 + +def do_anim_act_all(e,v): + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + +def do_anim_act_cur(e,v): + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: + Draw.PupMenu('Warning%t|Cant use this with batch export group option') + else: + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 0 + GLOBALS['ANIM_ACTION_ALL'][1].val = 1 + +def fbx_ui_exit(e,v): + GLOBALS['EVENT'] = e + +def do_help(e,v): + url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' + print('Trying to open web browser with documentation at this address...') + print('\t' + url) + + try: + import webbrowser + webbrowser.open(url) + except: + Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation") + print('...could not open a browser window.') + + + +# run when export is pressed +#def fbx_ui_write(e,v): +def fbx_ui_write(filename, context): + + # Dont allow overwriting files when saving normally + if not GLOBALS['BATCH_ENABLE'].val: + if not BPyMessages.Warning_SaveOver(filename): + return + + GLOBALS['EVENT'] = EVENT_EXIT + + # Keep the order the same as above for simplicity + # the [] is a dummy arg used for objects + + Blender.Window.WaitCursor(1) + + # Make the matrix + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val + if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + ret = write(\ + filename, None,\ + context, + GLOBALS['EXP_OBS_SELECTED'].val,\ + GLOBALS['EXP_MESH'].val,\ + GLOBALS['EXP_MESH_APPLY_MOD'].val,\ + GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ + GLOBALS['EXP_ARMATURE'].val,\ + GLOBALS['EXP_LAMP'].val,\ + GLOBALS['EXP_CAMERA'].val,\ + GLOBALS['EXP_EMPTY'].val,\ + GLOBALS['EXP_IMAGE_COPY'].val,\ + GLOBAL_MATRIX,\ + GLOBALS['ANIM_ENABLE'].val,\ + GLOBALS['ANIM_OPTIMIZE'].val,\ + GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ + GLOBALS['ANIM_ACTION_ALL'][0].val,\ + GLOBALS['BATCH_ENABLE'].val,\ + GLOBALS['BATCH_GROUP'].val,\ + GLOBALS['BATCH_SCENE'].val,\ + GLOBALS['BATCH_FILE_PREFIX'].val,\ + GLOBALS['BATCH_OWN_DIR'].val,\ + ) + + Blender.Window.WaitCursor(0) + GLOBALS.clear() + + if ret == False: + Draw.PupMenu('Error%t|Path cannot be written to!') + + +def fbx_ui(): + # Only to center the UI + x,y = GLOBALS['MOUSE'] + x-=180; y-=0 # offset... just to get it centered + + Draw.Label('Export Objects...', x+20,y+165, 200, 20) + + if not GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) + GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') + GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') + GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') + GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') + Draw.EndAlign() + + y -= 35 + + Draw.BeginAlign() + GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') + GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') + GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') + GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') + GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) + Draw.EndAlign() + + if GLOBALS['EXP_MESH'].val: + # below mesh but + Draw.BeginAlign() + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) + Draw.EndAlign() + + GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) + + + Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) + + GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) + if GLOBALS['ANIM_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) + if GLOBALS['ANIM_OPTIMIZE'].val: + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 1, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) + GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) + Draw.EndAlign() + + + Draw.Label('Export Batch...', x+20,y-60, 300, 20) + GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) + + if GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) + GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) + + # Own dir requires OS module + if os: + GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + else: + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + + + Draw.EndAlign() + + #y+=80 + + ''' + Draw.BeginAlign() + GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') + Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) + ''' + # Until batch is added + # + + + #Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) + Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) + + #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) + #Draw.EndAlign() + + # exit when mouse out of the view? + # GLOBALS['EVENT'] = EVENT_EXIT + +#def write_ui(filename): +def write_ui(): + + # globals + GLOBALS['EVENT'] = EVENT_REDRAW + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + GLOBALS['FILENAME'] = '' + ''' + # IF called from the fileselector + if filename == None: + GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) + else: + GLOBALS['FILENAME'].val = filename + ''' + GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity + GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) + + GLOBALS['EXP_MESH'] = Draw.Create(1) + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) + GLOBALS['EXP_ARMATURE'] = Draw.Create(1) + GLOBALS['EXP_LAMP'] = Draw.Create(1) + GLOBALS['EXP_CAMERA'] = Draw.Create(1) + GLOBALS['EXP_EMPTY'] = Draw.Create(1) + GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) + # animation opts + GLOBALS['ANIM_ENABLE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(4) # decimal places + GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action + + # batch export options + GLOBALS['BATCH_ENABLE'] = Draw.Create(0) + GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. + GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above + GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) + GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) + # done setting globals + + # Used by the user interface + GLOBALS['_SCALE'] = Draw.Create(1.0) + GLOBALS['_XROT90'] = Draw.Create(True) + GLOBALS['_YROT90'] = Draw.Create(False) + GLOBALS['_ZROT90'] = Draw.Create(False) + + # best not do move the cursor + # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] != EVENT_EXIT: + + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: + #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + + if GLOBALS['EVENT'] == EVENT_FILESEL: + if GLOBALS['BATCH_ENABLE'].val: + txt = 'Batch FBX Dir' + name = Blender.sys.expandpath('//') + else: + txt = 'Export FBX' + name = Blender.sys.makename(ext='.fbx') + + Blender.Window.FileSelector(fbx_ui_write, txt, name) + #fbx_ui_write('/test.fbx') + break + + Draw.UIBlock(fbx_ui, 0) + + + # GLOBALS.clear() + +class EXPORT_OT_fbx(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "export.fbx" + __label__ = "Export FBX" + + # 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=""), + bpy.props.BoolProperty(attr="EXP_OBS_SELECTED", name="Selected Objects", description="Export selected objects on visible layers", default=True), +# bpy.props.BoolProperty(attr="EXP_OBS_SCENE", name="Scene Objects", description="Export all objects in this scene", default=True), + bpy.props.FloatProperty(attr="_SCALE", name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0), + bpy.props.BoolProperty(attr="_XROT90", name="Rot X90", description="Rotate all objects 90 degrese about the X axis", default=True), + bpy.props.BoolProperty(attr="_YROT90", name="Rot Y90", description="Rotate all objects 90 degrese about the Y axis", default=False), + bpy.props.BoolProperty(attr="_ZROT90", name="Rot Z90", description="Rotate all objects 90 degrese about the Z axis", default=False), + bpy.props.BoolProperty(attr="EXP_EMPTY", name="Empties", description="Export empty objects", default=True), + bpy.props.BoolProperty(attr="EXP_CAMERA", name="Cameras", description="Export camera objects", default=True), + bpy.props.BoolProperty(attr="EXP_LAMP", name="Lamps", description="Export lamp objects", default=True), + bpy.props.BoolProperty(attr="EXP_ARMATURE", name="Armatures", description="Export armature objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH", name="Meshes", description="Export mesh objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH_APPLY_MOD", name="Modifiers", description="Apply modifiers to mesh objects", default=True), + bpy.props.BoolProperty(attr="EXP_MESH_HQ_NORMALS", name="HQ Normals", description="Generate high quality normals", default=True), + bpy.props.BoolProperty(attr="EXP_IMAGE_COPY", name="Copy Image Files", description="Copy image files to the destination path", default=False), + # armature animation + bpy.props.BoolProperty(attr="ANIM_ENABLE", name="Enable Animation", description="Export keyframe animation", default=True), + bpy.props.BoolProperty(attr="ANIM_OPTIMIZE", name="Optimize Keyframes", description="Remove double keyframes", default=True), + bpy.props.FloatProperty(attr="ANIM_OPTIMIZE_PRECISSION", name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0), +# bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True), + bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures, if false, use current action", default=False), + # batch + bpy.props.BoolProperty(attr="BATCH_ENABLE", name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False), + bpy.props.BoolProperty(attr="BATCH_GROUP", name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False), + bpy.props.BoolProperty(attr="BATCH_OWN_DIR", name="Own Dir", description="Create a dir for each exported file", default=True), + bpy.props.StringProperty(attr="BATCH_FILE_PREFIX", name="Prefix", description="Prefix each file with this name", maxlen= 1024, default=""), + ] + + def poll(self, context): + print("Poll") + return context.active_object != None + + def execute(self, context): + if not self.filename: + raise Exception("filename not set") + + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self._SCALE + if self._XROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if self._YROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if self._ZROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + write(self.filename, + None, # XXX + context, + self.EXP_OBS_SELECTED, + self.EXP_MESH, + self.EXP_MESH_APPLY_MOD, +# self.EXP_MESH_HQ_NORMALS, + self.EXP_ARMATURE, + self.EXP_LAMP, + self.EXP_CAMERA, + self.EXP_EMPTY, + self.EXP_IMAGE_COPY, + GLOBAL_MATRIX, + self.ANIM_ENABLE, + self.ANIM_OPTIMIZE, + self.ANIM_OPTIMIZE_PRECISSION, + self.ANIM_ACTION_ALL, + self.BATCH_ENABLE, + self.BATCH_GROUP, + self.BATCH_FILE_PREFIX, + self.BATCH_OWN_DIR) + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + + +bpy.ops.add(EXPORT_OT_fbx) + +# if __name__ == "__main__": +# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply") + + +# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts) +# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print +# - get rid of cleanName somehow +# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565 +# + get rid of BPyObject_getObjectArmature, move it in RNA? +# - BATCH_ENABLE and BATCH_GROUP options: line 327 +# - implement all BPyMesh_* used here with RNA +# - getDerivedObjects is not fully replicated with .dupli* funcs +# - talk to Campbell, this code won't work? lines 1867-1875 +# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893 +# - no hq normals: 1900-1901 + +# TODO + +# - bpy.data.remove_scene: line 366 +# - bpy.sys.time move to bpy.sys.util? +# - new scene creation, activation: lines 327-342, 368 +# - uses bpy.sys.expandpath, *.relpath - replace at least relpath + +# SMALL or COSMETICAL +# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version') diff --git a/release/scripts/io/export_obj.py b/release/scripts/io/export_obj.py new file mode 100644 index 00000000000..e2ac78798bd --- /dev/null +++ b/release/scripts/io/export_obj.py @@ -0,0 +1,993 @@ +#!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 math and other in functions that use them for the sake of fast Blender startup +# import math +import os +import time + +import bpy +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, copy_images): + + world = scene.world + worldAmb = world.ambient_color + + dest_dir = os.path.dirname(filename) + + def copy_image(image): + rel = image.get_export_path(dest_dir, True) + + if copy_images: + abspath = image.get_export_path(dest_dir, False) + if not os.path.exists(abs_path): + shutil.copy(image.get_abs_filename(), abs_path) + + return rel + + + 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_intensity for c in mat.diffuse_color]) ) # Diffuse + file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular + if hasattr(mat, "ior"): + file.write('Ni %.6f\n' % mat.ior) # Refraction index + else: + file.write('Ni %.6f\n' % 1.0) + 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_intensity == 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! + # write relative image path + rel = copy_image(img) + file.write('map_Kd %s\n' % rel) # Diffuse mapping image +# 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 = copy_image(mtex.texture.image) +# 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() + +# XXX not used +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +# XXX not used +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 + +# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir) + + print('\tCopied %d images' % copyCount) +# print('\tCopied %d images' % copyCount) + +# XXX not converted +def test_nurbs_compat(ob): + if ob.type != 'Curve': + return False + + for nu in ob.data: + if (not nu.knotsV) and nu.type != 1: # not a surface and not bezier + return True + + return False + + +# 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. + ''' + + # XXX + import math + + 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 = time.clock() +# 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(-math.pi/2, 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: + + # 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': + # XXX + print('creating dupli_list on', ob_main.name) + ob_main.create_dupli_list() + + obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list] + + # XXX debug print + print(ob_main.name, 'has', len(obs), 'dupli children') + else: + obs = [(ob_main, ob_main.matrix)] + + for ob, ob_mat in obs: + + # XXX postponed +# # Nurbs curve support +# if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): +# if EXPORT_ROTX90: +# ob_mat = ob_mat * mat_xrot90 + +# totverts += write_nurb(file, ob, ob_mat) + +# continue +# end nurbs + + if ob.type != 'MESH': + continue + + me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') + + if EXPORT_ROTX90: + me.transform(ob_mat * mat_xrot90) + else: + 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_textures) > 0 + else: + faceuv = False + + # XXX - todo, find a better way to do triangulation + # ...removed convert_to_triface because it relies on editmesh + ''' + # 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: + me.calc_normals() +# 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_texture.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_texture + 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_texture.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, EXPORT_COPY_IMAGES) +# if EXPORT_COPY_IMAGES: +# dest_dir = os.path.basename(filename) +# # 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" % (time.clock() - 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 + ''' + __idname__ = "export.obj" + __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 OBJ file", maxlen= 1024, default= ""), + + # context group + bpy.props.BoolProperty(attr="use_selection", name="Selection Only", description="", default= False), + 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 +# - get rid of cleanName somehow diff --git a/release/scripts/io/export_ply.py b/release/scripts/io/export_ply.py new file mode 100644 index 00000000000..8e79c3741bb --- /dev/null +++ b/release/scripts/io/export_ply.py @@ -0,0 +1,279 @@ +import bpy + +__author__ = "Bruce Merry" +__version__ = "0.93" +__bpydoc__ = """\ +This script exports Stanford PLY files from Blender. It supports normals, +colours, and texture coordinates per face or per vertex. +Only one mesh can be exported at a time. +""" + +# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za +# +# 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. +# Vector rounding se we can use as keys +# +# Updated on Aug 11, 2008 by Campbell Barton +# - added 'comment' prefix to comments - Needed to comply with the PLY spec. +# +# Updated on Jan 1, 2007 by Gabe Ghearing +# - fixed normals so they are correctly smooth/flat +# - fixed crash when the model doesn't have uv coords or vertex colors +# - fixed crash when the model has vertex colors but doesn't have uv coords +# - changed float32 to float and uint8 to uchar for compatibility +# Errata/Notes as of Jan 1, 2007 +# - script exports texture coords if they exist even if TexFace isn't selected (not a big deal to me) +# - ST(R) should probably be renamed UV(T) like in most PLY files (importer needs to be updated to take either) +# +# Updated on Jan 3, 2007 by Gabe Ghearing +# - fixed "sticky" vertex UV exporting +# - added pupmenu to enable/disable exporting normals, uv coords, and colors +# Errata/Notes as of Jan 3, 2007 +# - ST(R) coords should probably be renamed UV(T) like in most PLY files (importer needs to be updated to take either) +# - edges should be exported since PLY files support them +# - code is getting spaghettish, it should be refactored... +# + + +def rvec3d(v): return round(v[0], 6), round(v[1], 6), round(v[2], 6) +def rvec2d(v): return round(v[0], 6), round(v[1], 6) + +def write(filename, scene, ob, \ + EXPORT_APPLY_MODIFIERS= True,\ + EXPORT_NORMALS= True,\ + EXPORT_UV= True,\ + EXPORT_COLORS= True\ + ): + + if not filename.lower().endswith('.ply'): + filename += '.ply' + + if not ob: + raise Exception("Error, Select 1 active object") + return + + file = open(filename, 'w') + + + #EXPORT_EDGES = Draw.Create(0) + """ + is_editmode = Blender.Window.EditMode() + if is_editmode: + Blender.Window.EditMode(0, '', 0) + + Window.WaitCursor(1) + """ + + #mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX + if EXPORT_APPLY_MODIFIERS: + mesh = ob.create_mesh(True, 'PREVIEW') + else: + mesh = ob.data + + if not mesh: + raise ("Error, could not get mesh data from active object") + return + + # mesh.transform(ob.matrixWorld) # XXX + + faceUV = len(mesh.uv_textures) > 0 + vertexUV = len(mesh.sticky) > 0 + vertexColors = len(mesh.vertex_colors) > 0 + + if (not faceUV) and (not vertexUV): EXPORT_UV = False + if not vertexColors: EXPORT_COLORS = False + + if not EXPORT_UV: faceUV = vertexUV = False + if not EXPORT_COLORS: vertexColors = False + + if faceUV: + active_uv_layer = None + for lay in mesh.uv_textures: + if lay.active: + active_uv_layer= lay.data + break + if not active_uv_layer: + EXPORT_UV = False + faceUV = None + + if vertexColors: + active_col_layer = None + for lay in mesh.vertex_colors: + if lay.active: + active_col_layer= lay.data + if not active_col_layer: + EXPORT_COLORS = False + vertexColors = None + + # incase + color = uvcoord = uvcoord_key = normal = normal_key = None + + mesh_verts = mesh.verts # save a lookup + ply_verts = [] # list of dictionaries + # vdict = {} # (index, normal, uv) -> new index + 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): + + + smooth = f.smooth + if not smooth: + normal = tuple(f.normal) + normal_key = rvec3d(normal) + + if faceUV: + uv = active_uv_layer[i] + uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/ + if vertexColors: + col = active_col_layer[i] + col = col.color1, col.color2, col.color3, col.color4 + + f_verts= f.verts + + pf= ply_faces[i] + for j, vidx in enumerate(f_verts): + v = mesh_verts[vidx] + + if smooth: + normal= tuple(v.normal) + normal_key = rvec3d(normal) + + if faceUV: + uvcoord= uv[j][0], 1.0-uv[j][1] + uvcoord_key = rvec2d(uvcoord) + elif vertexUV: + uvcoord= v.uvco[0], 1.0-v.uvco[1] + uvcoord_key = rvec2d(uvcoord) + + if vertexColors: + color= col[j] + color= int(color[0]*255.0), int(color[1]*255.0), int(color[2]*255.0) + + + key = normal_key, uvcoord_key, color + + vdict_local = vdict[vidx] + pf_vidx = vdict_local.get(key) # Will be None initially + + if pf_vidx == None: # same as vdict_local.has_key(key) + pf_vidx = vdict_local[key] = vert_count; + ply_verts.append((vidx, normal, uvcoord, color)) + vert_count += 1 + + pf.append(pf_vidx) + + file.write('ply\n') + file.write('format ascii 1.0\n') + version = "2.5" # Blender.Get('version') + file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1] )) + + file.write('element vertex %d\n' % len(ply_verts)) + + file.write('property float x\n') + file.write('property float y\n') + file.write('property float z\n') + + # XXX + """ + if EXPORT_NORMALS: + file.write('property float nx\n') + file.write('property float ny\n') + file.write('property float nz\n') + """ + if EXPORT_UV: + file.write('property float s\n') + file.write('property float t\n') + if EXPORT_COLORS: + file.write('property uchar red\n') + file.write('property uchar green\n') + file.write('property uchar blue\n') + + file.write('element face %d\n' % len(mesh.faces)) + file.write('property list uchar uint vertex_indices\n') + file.write('end_header\n') + + for i, v in enumerate(ply_verts): + file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co + """ + if EXPORT_NORMALS: + file.write('%.6f %.6f %.6f ' % v[1]) # no + """ + if EXPORT_UV: file.write('%.6f %.6f ' % v[2]) # uv + if EXPORT_COLORS: file.write('%u %u %u' % v[3]) # col + file.write('\n') + + for pf in ply_faces: + if len(pf)==3: file.write('3 %d %d %d\n' % tuple(pf)) + else: file.write('4 %d %d %d %d\n' % tuple(pf)) + + file.close() + print("writing", filename, "done") + + if EXPORT_APPLY_MODIFIERS: + bpy.data.remove_mesh(mesh) + + # XXX + """ + if is_editmode: + Blender.Window.EditMode(1, '', 0) + """ + +class EXPORT_OT_ply(bpy.types.Operator): + '''Export a single object as a stanford PLY with normals, colours and texture coordinates.''' + __idname__ = "export.ply" + __label__ = "Export PLY" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [ + bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= ""), + bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True), + bpy.props.BoolProperty(attr="use_normals", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True), + bpy.props.BoolProperty(attr="use_uvs", name="Export UVs", description="Exort the active UV layer", default= True), + bpy.props.BoolProperty(attr="use_colors", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True) + ] + + def poll(self, context): + return context.active_object != None + + def execute(self, context): + # print("Selected: " + context.active_object.name) + + if not self.path: + raise Exception("filename not set") + + write(self.path, context.scene, context.active_object,\ + EXPORT_APPLY_MODIFIERS = self.use_modifiers, + EXPORT_NORMALS = self.use_normals, + EXPORT_UV = self.use_uvs, + EXPORT_COLORS = self.use_colors, + ) + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + + +bpy.ops.add(EXPORT_OT_ply) + +if __name__ == "__main__": + bpy.ops.EXPORT_OT_ply(path="/tmp/test.ply") + + diff --git a/release/scripts/io/export_x3d.py b/release/scripts/io/export_x3d.py new file mode 100644 index 00000000000..f23ccf8d2dc --- /dev/null +++ b/release/scripts/io/export_x3d.py @@ -0,0 +1,1239 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'X3D Extensible 3D (.x3d)...' +Blender: 245 +Group: 'Export' +Tooltip: 'Export selection to Extensible 3D file (.x3d)' +""" + +__author__ = ("Bart", "Campbell Barton") +__email__ = ["Bart, bart:neeneenee*de"] +__url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml"] +__version__ = "2006/01/17" +__bpydoc__ = """\ +This script exports to X3D format. + +Usage: + +Run this script from "File->Export" menu. A pop-up will ask whether you +want to export only selected or all relevant objects. + +Known issues:
+ Doesn't handle multiple materials (don't use material indices);
+ Doesn't handle multiple UV textures on a single mesh (create a mesh for each texture);
+ Can't get the texture array associated with material * not the UV ones; +""" + + +# $Id$ +# +#------------------------------------------------------------------------ +# X3D exporter for blender 2.36 or above +# +# ***** 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 ***** +# + +#################################### +# Library dependancies +#################################### + +import math +import os + +import bpy +import Mathutils + +from export_3ds import create_derived_objects, free_derived_objects + +# import Blender +# from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh +# from Blender.Scene import Render +# import BPyObject +# import BPyMesh + +# +DEG2RAD=0.017453292519943295 +MATWORLD= Mathutils.RotationMatrix(-90, 4, 'x') + +#################################### +# Global Variables +#################################### + +filename = "" +# filename = Blender.Get('filename') +_safeOverwrite = True + +extension = '' + +########################################################## +# Functions for writing output file +########################################################## + +class x3d_class: + + def __init__(self, filename): + #--- public you can change these --- + self.writingcolor = 0 + self.writingtexture = 0 + self.writingcoords = 0 + self.proto = 1 + self.matonly = 0 + self.share = 0 + self.billnode = 0 + self.halonode = 0 + self.collnode = 0 + self.tilenode = 0 + self.verbose=2 # level of verbosity in console 0-none, 1-some, 2-most + self.cp=3 # decimals for material color values 0.000 - 1.000 + self.vp=3 # decimals for vertex coordinate values 0.000 - n.000 + self.tp=3 # decimals for texture coordinate values 0.000 - 1.000 + self.it=3 + + #--- class private don't touch --- + self.texNames={} # dictionary of textureNames + self.matNames={} # dictionary of materiaNames + self.meshNames={} # dictionary of meshNames + self.indentLevel=0 # keeps track of current indenting + self.filename=filename + self.file = None + if filename.lower().endswith('.x3dz'): + try: + import gzip + self.file = gzip.open(filename, "w") + except: + print("failed to import compression modules, exporting uncompressed") + self.filename = filename[:-1] # remove trailing z + + if self.file == None: + self.file = open(self.filename, "w") + + self.bNav=0 + self.nodeID=0 + self.namesReserved=[ "Anchor","Appearance","Arc2D","ArcClose2D","AudioClip","Background","Billboard", + "BooleanFilter","BooleanSequencer","BooleanToggle","BooleanTrigger","Box","Circle2D", + "Collision","Color","ColorInterpolator","ColorRGBA","component","Cone","connect", + "Contour2D","ContourPolyline2D","Coordinate","CoordinateDouble","CoordinateInterpolator", + "CoordinateInterpolator2D","Cylinder","CylinderSensor","DirectionalLight","Disk2D", + "ElevationGrid","EspduTransform","EXPORT","ExternProtoDeclare","Extrusion","field", + "fieldValue","FillProperties","Fog","FontStyle","GeoCoordinate","GeoElevationGrid", + "GeoLocationLocation","GeoLOD","GeoMetadata","GeoOrigin","GeoPositionInterpolator", + "GeoTouchSensor","GeoViewpoint","Group","HAnimDisplacer","HAnimHumanoid","HAnimJoint", + "HAnimSegment","HAnimSite","head","ImageTexture","IMPORT","IndexedFaceSet", + "IndexedLineSet","IndexedTriangleFanSet","IndexedTriangleSet","IndexedTriangleStripSet", + "Inline","IntegerSequencer","IntegerTrigger","IS","KeySensor","LineProperties","LineSet", + "LoadSensor","LOD","Material","meta","MetadataDouble","MetadataFloat","MetadataInteger", + "MetadataSet","MetadataString","MovieTexture","MultiTexture","MultiTextureCoordinate", + "MultiTextureTransform","NavigationInfo","Normal","NormalInterpolator","NurbsCurve", + "NurbsCurve2D","NurbsOrientationInterpolator","NurbsPatchSurface", + "NurbsPositionInterpolator","NurbsSet","NurbsSurfaceInterpolator","NurbsSweptSurface", + "NurbsSwungSurface","NurbsTextureCoordinate","NurbsTrimmedSurface","OrientationInterpolator", + "PixelTexture","PlaneSensor","PointLight","PointSet","Polyline2D","Polypoint2D", + "PositionInterpolator","PositionInterpolator2D","ProtoBody","ProtoDeclare","ProtoInstance", + "ProtoInterface","ProximitySensor","ReceiverPdu","Rectangle2D","ROUTE","ScalarInterpolator", + "Scene","Script","Shape","SignalPdu","Sound","Sphere","SphereSensor","SpotLight","StaticGroup", + "StringSensor","Switch","Text","TextureBackground","TextureCoordinate","TextureCoordinateGenerator", + "TextureTransform","TimeSensor","TimeTrigger","TouchSensor","Transform","TransmitterPdu", + "TriangleFanSet","TriangleSet","TriangleSet2D","TriangleStripSet","Viewpoint","VisibilitySensor", + "WorldInfo","X3D","XvlShell","VertexShader","FragmentShader","MultiShaderAppearance","ShaderAppearance" ] + self.namesStandard=[ "Empty","Empty.000","Empty.001","Empty.002","Empty.003","Empty.004","Empty.005", + "Empty.006","Empty.007","Empty.008","Empty.009","Empty.010","Empty.011","Empty.012", + "Scene.001","Scene.002","Scene.003","Scene.004","Scene.005","Scene.06","Scene.013", + "Scene.006","Scene.007","Scene.008","Scene.009","Scene.010","Scene.011","Scene.012", + "World","World.000","World.001","World.002","World.003","World.004","World.005" ] + self.namesFog=[ "","LINEAR","EXPONENTIAL","" ] + +########################################################## +# Writing nodes routines +########################################################## + + def writeHeader(self): + #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '<').replace('>', '>') + bfile = self.filename.replace('<', '<').replace('>', '>') # use outfile name + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\n") + self.file.write("\t\n" % os.path.basename(bfile)) + # self.file.write("\t\n" % sys.basename(bfile)) + self.file.write("\t\n" % '2.5') + # self.file.write("\t\n" % Blender.Get('version')) + self.file.write("\t\n") + self.file.write("\n") + self.file.write("\n") + + # This functionality is poorly defined, disabling for now - campbell + ''' + def writeInline(self): + inlines = Blender.Scene.Get() + allinlines = len(inlines) + if scene != inlines[0]: + return + else: + for i in xrange(allinlines): + nameinline=inlines[i].name + if (nameinline not in self.namesStandard) and (i > 0): + self.file.write("" % nameinline) + self.file.write("\n\n") + + + def writeScript(self): + textEditor = Blender.Text.Get() + alltext = len(textEditor) + for i in xrange(alltext): + nametext = textEditor[i].name + nlines = textEditor[i].getNLines() + if (self.proto == 1): + if (nametext == "proto" or nametext == "proto.js" or nametext == "proto.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in xrange(nalllines): + self.writeIndented(alllines[j] + "\n") + elif (self.proto == 0): + if (nametext == "route" or nametext == "route.js" or nametext == "route.txt") and (nlines != None): + nalllines = len(textEditor[i].asLines()) + alllines = textEditor[i].asLines() + for j in xrange(nalllines): + self.writeIndented(alllines[j] + "\n") + self.writeIndented("\n") + ''' + + def writeViewpoint(self, ob, mat, scene): + context = scene.render_data + # context = scene.render + ratio = float(context.resolution_x)/float(context.resolution_y) + # ratio = float(context.imageSizeY())/float(context.imageSizeX()) + lens = (360* (math.atan(ratio *16 / ob.data.lens) / math.pi))*(math.pi/180) + # lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180) + lens = min(lens, math.pi) + + # get the camera location, subtract 90 degress from X to orient like X3D does + # mat = ob.matrixWorld - mat is now passed! + + loc = self.rotatePointForVRML(mat.translationPart()) + rot = mat.toEuler() + rot = (((rot[0]-90)), rot[1], rot[2]) + # rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD) + nRot = self.rotatePointForVRML( rot ) + # convert to Quaternion and to Angle Axis + Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2]) + Q1 = self.multiplyQuaternions(Q[0], Q[1]) + Qf = self.multiplyQuaternions(Q1, Q[2]) + angleAxis = self.quaternionToAngleAxis(Qf) + self.file.write("\n\n" % (lens)) + + def writeFog(self, world): + if world: + mtype = world.mist.falloff + # mtype = world.getMistype() + mparam = world.mist + # mparam = world.getMist() + grd = world.horizon_color + # grd = world.getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + else: + return + if (mtype == 'LINEAR' or mtype == 'INVERSE_QUADRATIC'): + mtype = 1 if mtype == 'LINEAR' else 2 + # if (mtype == 1 or mtype == 2): + self.file.write("\n\n" % round(mparam[2],self.cp)) + else: + return + + def writeNavigationInfo(self, scene): + self.file.write('\n') + + def writeSpotLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.ambient_color + # ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + # compute cutoff and beamwidth + intensity=min(lamp.energy/1.75,1.0) + beamWidth=((lamp.spot_size*math.pi)/180.0)*.37; + # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37; + cutOffAngle=beamWidth*1.3 + + dx,dy,dz=self.computeDirection(mtx) + # note -dx seems to equal om[3][0] + # note -dz seems to equal om[3][1] + # note dy seems to equal om[3][2] + + #location=(ob.matrixWorld*MATWORLD).translationPart() # now passed + location=(mtx*MATWORLD).translationPart() + + radius = lamp.distance*math.cos(beamWidth) + # radius = lamp.dist*math.cos(beamWidth) + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + + + def writeDirectionalLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.ambient_color + # ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + intensity=min(lamp.energy/1.75,1.0) + (dx,dy,dz)=self.computeDirection(mtx) + self.file.write("\n\n" % (round(dx,4),round(dy,4),round(dz,4))) + + def writePointLight(self, ob, mtx, lamp, world): + safeName = self.cleanStr(ob.name) + if world: + ambi = world.ambient_color + # ambi = world.amb + ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5 + else: + ambi = 0 + ambientIntensity = 0 + + # location=(ob.matrixWorld*MATWORLD).translationPart() # now passed + location= (mtx*MATWORLD).translationPart() + + self.file.write("\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + ''' + def writeNode(self, ob, mtx): + obname=str(ob.name) + if obname in self.namesStandard: + return + else: + dx,dy,dz = self.computeDirection(mtx) + # location=(ob.matrixWorld*MATWORLD).translationPart() + location=(mtx*MATWORLD).translationPart() + self.writeIndented("<%s\n" % obname,1) + self.writeIndented("direction=\"%s %s %s\"\n" % (round(dx,3),round(dy,3),round(dz,3))) + self.writeIndented("location=\"%s %s %s\"\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) + self.writeIndented("/>\n",-1) + self.writeIndented("\n") + ''' + def secureName(self, name): + name = name + str(self.nodeID) + self.nodeID=self.nodeID+1 + if len(name) <= 3: + newname = "_" + str(self.nodeID) + return "%s" % (newname) + else: + for bad in ['"','#',"'",',','.','[','\\',']','{','}']: + name=name.replace(bad,'_') + if name in self.namesReserved: + newname = name[0:3] + "_" + str(self.nodeID) + return "%s" % (newname) + elif name[0].isdigit(): + newname = "_" + name + str(self.nodeID) + return "%s" % (newname) + else: + newname = name + return "%s" % (newname) + + def writeIndexedFaceSet(self, ob, mesh, mtx, world, EXPORT_TRI = False): + imageMap={} # set of used images + sided={} # 'one':cnt , 'two':cnt + vColors={} # 'multi':1 + meshName = self.cleanStr(ob.name) + + meshME = self.cleanStr(ob.data.name) # We dont care if its the mesh name or not + # meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not + if len(mesh.faces) == 0: return + mode = [] + # mode = 0 + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + if face.halo and 'HALO' not in mode: + mode += ['HALO'] + if face.billboard and 'BILLBOARD' not in mode: + mode += ['BILLBOARD'] + if face.object_color and 'OBJECT_COLOR' not in mode: + mode += ['OBJECT_COLOR'] + if face.collision and 'COLLISION' not in mode: + mode += ['COLLISION'] + # mode |= face.mode + + if 'HALO' in mode and self.halonode == 0: + # if mode & Mesh.FaceModes.HALO and self.halonode == 0: + self.writeIndented("\n",1) + self.halonode = 1 + elif 'BILLBOARD' in mode and self.billnode == 0: + # elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: + self.writeIndented("\n",1) + self.billnode = 1 + elif 'OBJECT_COLOR' in mode and self.matonly == 0: + # elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0: + self.matonly = 1 + # TF_TILES is marked as deprecated in DNA_meshdata_types.h + # elif mode & Mesh.FaceModes.TILES and self.tilenode == 0: + # self.tilenode = 1 + elif 'COLLISION' not in mode and self.collnode == 0: + # elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0: + self.writeIndented("\n",1) + self.collnode = 1 + + nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) + + if nIFSCnt > 1: + self.writeIndented("\n" % ("G_", meshName),1) + + if 'two' in sided and sided['two'] > 0: + bTwoSided=1 + else: + bTwoSided=0 + + # mtx = ob.matrixWorld * MATWORLD # mtx is now passed + mtx = mtx * MATWORLD + + loc= mtx.translationPart() + sca= mtx.scalePart() + quat = mtx.toQuat() + rot= quat.axis + + self.writeIndented('\n' % \ + (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle) ) + # self.writeIndented('\n' % \ + # (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) ) + + self.writeIndented("\n",1) + maters=mesh.materials + hasImageTexture=0 + issmooth=0 + + if len(maters) > 0 or mesh.active_uv_texture: + # if len(maters) > 0 or mesh.faceUV: + self.writeIndented("\n", 1) + # right now this script can only handle a single material per mesh. + if len(maters) >= 1: + mat=maters[0] + # matFlags = mat.getMode() + if not mat.face_texture: + # if not matFlags & Blender.Material.Modes['TEXFACE']: + self.writeMaterial(mat, self.cleanStr(mat.name,''), world) + # self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world) + if len(maters) > 1: + print("Warning: mesh named %s has multiple materials" % meshName) + print("Warning: only one material per object handled") + + #-- textures + face = None + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + if face.image: + # if (hasImageTexture == 0) and (face.image): + self.writeImageTexture(face.image) + # hasImageTexture=1 # keep track of face texture + break + if self.tilenode == 1 and face and face.image: + # if self.tilenode == 1: + self.writeIndented("\n" % (face.image.xrep, face.image.yrep)) + self.tilenode = 0 + self.writeIndented("\n", -1) + + #-- IndexedFaceSet or IndexedLineSet + + # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5 + ifStyle="IndexedFaceSet" + # look up mesh name, use it if available + if meshME in self.meshNames: + self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1) + self.meshNames[meshME]+=1 + else: + if int(mesh.users) > 1: + self.writeIndented("<%s DEF=\"ME_%s\" " % (ifStyle, meshME), 1) + self.meshNames[meshME]=1 + else: + self.writeIndented("<%s " % ifStyle, 1) + + if bTwoSided == 1: + self.file.write("solid=\"false\" ") + else: + self.file.write("solid=\"true\" ") + + for face in mesh.faces: + if face.smooth: + issmooth=1 + break + if issmooth==1: + creaseAngle=(mesh.autosmooth_angle)*(math.pi/180.0) + # creaseAngle=(mesh.degr)*(math.pi/180.0) + self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) + + #--- output textureCoordinates if UV texture used + if mesh.active_uv_texture: + # if mesh.faceUV: + if self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + elif hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + #--- output coordinates + self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) + + self.writingcoords = 1 + self.writingtexture = 1 + self.writingcolor = 1 + self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI) + + #--- output textureCoordinates if UV texture used + if mesh.active_uv_texture: + # if mesh.faceUV: + if hasImageTexture == 1: + self.writeTextureCoordinates(mesh) + elif self.matonly == 1 and self.share == 1: + self.writeFaceColors(mesh) + #--- output vertexColors + self.matonly = 0 + self.share = 0 + + self.writingcoords = 0 + self.writingtexture = 0 + self.writingcolor = 0 + #--- output closing braces + self.writeIndented("\n" % ifStyle, -1) + self.writeIndented("\n", -1) + self.writeIndented("\n", -1) + + if self.halonode == 1: + self.writeIndented("\n", -1) + self.halonode = 0 + + if self.billnode == 1: + self.writeIndented("\n", -1) + self.billnode = 0 + + if self.collnode == 1: + self.writeIndented("\n", -1) + self.collnode = 0 + + if nIFSCnt > 1: + self.writeIndented("\n", -1) + + self.file.write("\n") + + def writeCoordinates(self, ob, mesh, meshName, EXPORT_TRI = False): + # create vertex list and pre rotate -90 degrees X for VRML + + if self.writingcoords == 0: + self.file.write('coordIndex="') + for face in mesh.faces: + fv = face.verts + # fv = face.v + + if len(fv)==3: + # if len(face)==3: + self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + else: + if EXPORT_TRI: + self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index)) + self.file.write("%i %i %i -1, " % (fv[0], fv[2], fv[3])) + # self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index)) + else: + self.file.write("%i %i %i %i -1, " % (fv[0], fv[1], fv[2], fv[3])) + # self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index)) + + self.file.write("\">\n") + else: + #-- vertices + # mesh.transform(ob.matrixWorld) + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeTextureCoordinates(self, mesh): + texCoordList=[] + texIndexList=[] + j=0 + + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.verts[3] else [face.uv1, face.uv2, face.uv3] + + for uv in uvs: + # for uv in face.uv: + texIndexList.append(j) + texCoordList.append(uv) + j=j+1 + texIndexList.append(-1) + if self.writingtexture == 0: + self.file.write("\n\t\t\ttexCoordIndex=\"") + texIndxStr="" + for i in range(len(texIndexList)): + texIndxStr = texIndxStr + "%d, " % texIndexList[i] + if texIndexList[i]==-1: + self.file.write(texIndxStr) + texIndxStr="" + self.file.write("\"\n\t\t\t") + else: + self.writeIndented("") + self.writeIndented("\n", -1) + + def writeFaceColors(self, mesh): + if self.writingcolor == 0: + self.file.write("colorPerVertex=\"false\" ") + elif mesh.active_vertex_color: + # else: + self.writeIndented(" 2: + print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2])) + # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) + aColor = self.rgbToFS(c) + self.file.write("%s, " % aColor) + + # for face in mesh.faces: + # if face.col: + # c=face.col[0] + # if self.verbose > 2: + # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)) + # aColor = self.rgbToFS(c) + # self.file.write("%s, " % aColor) + self.file.write("\" />") + self.writeIndented("\n",-1) + + def writeMaterial(self, mat, matName, world): + # look up material name, use it if available + if matName in self.matNames: + self.writeIndented("\n" % matName) + self.matNames[matName]+=1 + return; + + self.matNames[matName]=1 + + ambient = mat.ambient/3 + # ambient = mat.amb/3 + diffuseR, diffuseG, diffuseB = tuple(mat.diffuse_color) + # diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2] + if world: + ambi = world.ambient_color + # ambi = world.getAmb() + ambi0, ambi1, ambi2 = (ambi[0]*mat.ambient)*2, (ambi[1]*mat.ambient)*2, (ambi[2]*mat.ambient)*2 + # ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2 + else: + ambi0, ambi1, ambi2 = 0, 0, 0 + emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2 + + shininess = mat.specular_hardness/512.0 + # shininess = mat.hard/512.0 + specR = (mat.specular_color[0]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001)) + specG = (mat.specular_color[1]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001)) + specB = (mat.specular_color[2]+0.001)/(1.25/(mat.specular_reflection+0.001)) + # specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001)) + transp = 1-mat.alpha + # matFlags = mat.getMode() + if mat.shadeless: + # if matFlags & Blender.Material.Modes['SHADELESS']: + ambient = 1 + shine = 1 + specR = emitR = diffuseR + specG = emitG = diffuseG + specB = emitB = diffuseB + self.writeIndented("" % (round(transp,self.cp))) + self.writeIndented("\n",-1) + + def writeImageTexture(self, image): + name = image.name + filename = image.filename.split('/')[-1].split('\\')[-1] + if name in self.texNames: + self.writeIndented("\n" % self.cleanStr(name)) + self.texNames[name] += 1 + return + else: + self.writeIndented("" % name) + self.writeIndented("\n",-1) + self.texNames[name] = 1 + + def writeBackground(self, world, alltextures): + if world: worldname = world.name + else: return + blending = (world.blend_sky, world.paper_sky, world.real_sky) + # blending = world.getSkytype() + grd = world.horizon_color + # grd = world.getHor() + grd0, grd1, grd2 = grd[0], grd[1], grd[2] + sky = world.zenith_color + # sky = world.getZen() + sky0, sky1, sky2 = sky[0], sky[1], sky[2] + mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2] + mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2 + self.file.write("\n\n") + +########################################################## +# export routine +########################################################## + + def export(self, scene, world, alltextures,\ + EXPORT_APPLY_MODIFIERS = False,\ + EXPORT_TRI= False,\ + ): + + print("Info: starting X3D export to " + self.filename + "...") + self.writeHeader() + # self.writeScript() + self.writeNavigationInfo(scene) + self.writeBackground(world, alltextures) + self.writeFog(world) + self.proto = 0 + + + # # COPIED FROM OBJ EXPORTER + # if EXPORT_APPLY_MODIFIERS: + # temp_mesh_name = '~tmp-mesh' + + # # Get the container mesh. - used for applying modifiers and non mesh objects. + # containerMesh = meshName = tempMesh = None + # for meshName in Blender.NMesh.GetNames(): + # if meshName.startswith(temp_mesh_name): + # tempMesh = Mesh.Get(meshName) + # if not tempMesh.users: + # containerMesh = tempMesh + # if not containerMesh: + # containerMesh = Mesh.New(temp_mesh_name) + # -------------------------- + + + for ob_main in [o for o in scene.objects if o.is_visible()]: + # for ob_main in scene.objects.context: + + free, derived = create_derived_objects(ob_main) + + if derived == None: continue + + for ob, ob_mat in derived: + # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + objType=ob.type + objName=ob.name + self.matonly = 0 + if objType == "CAMERA": + # if objType == "Camera": + self.writeViewpoint(ob, ob_mat, scene) + elif objType in ("MESH", "CURVE", "SURF", "TEXT") : + # elif objType in ("Mesh", "Curve", "Surf", "Text") : + if EXPORT_APPLY_MODIFIERS or objType != 'MESH': + # if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': + me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') + # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) + else: + me = ob.data + # me = ob.getData(mesh=1) + + self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI) + + # free mesh created with create_mesh() + if me != ob.data: + bpy.data.remove_mesh(me) + + elif objType == "LAMP": + # elif objType == "Lamp": + data= ob.data + datatype=data.type + if datatype == 'POINT': + # if datatype == Lamp.Types.Lamp: + self.writePointLight(ob, ob_mat, data, world) + elif datatype == 'SPOT': + # elif datatype == Lamp.Types.Spot: + self.writeSpotLight(ob, ob_mat, data, world) + elif datatype == 'SUN': + # elif datatype == Lamp.Types.Sun: + self.writeDirectionalLight(ob, ob_mat, data, world) + else: + self.writeDirectionalLight(ob, ob_mat, data, world) + # do you think x3d could document what to do with dummy objects? + #elif objType == "Empty" and objName != "Empty": + # self.writeNode(ob, ob_mat) + else: + #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) + pass + + if free: + free_derived_objects(ob_main) + + self.file.write("\n\n") + + # if EXPORT_APPLY_MODIFIERS: + # if containerMesh: + # containerMesh.verts = None + + self.cleanup() + +########################################################## +# Utility methods +########################################################## + + def cleanup(self): + self.file.close() + self.texNames={} + self.matNames={} + self.indentLevel=0 + print("Info: finished X3D export to %s\n" % self.filename) + + def cleanStr(self, name, prefix='rsvd_'): + """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name""" + + newName=name[:] + if len(newName) == 0: + self.nNodeID+=1 + return "%s%d" % (prefix, self.nNodeID) + + if newName in self.namesReserved: + newName='%s%s' % (prefix,newName) + + if newName[0].isdigit(): + newName='%s%s' % ('_',newName) + + for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']: + newName=newName.replace(bad,'_') + return newName + + def countIFSSetsNeeded(self, mesh, imageMap, sided, vColors): + """ + countIFFSetsNeeded() - should look at a blender mesh to determine + how many VRML IndexFaceSets or IndexLineSets are needed. A + new mesh created under the following conditions: + + o - split by UV Textures / one per mesh + o - split by face, one sided and two sided + o - split by smooth and flat faces + o - split when faces only have 2 vertices * needs to be an IndexLineSet + """ + + imageNameMap={} + faceMap={} + nFaceIndx=0 + + if mesh.active_uv_texture: + # if mesh.faceUV: + for face in mesh.active_uv_texture.data: + # for face in mesh.faces: + sidename=''; + if face.twoside: + # if face.mode & Mesh.FaceModes.TWOSIDE: + sidename='two' + else: + sidename='one' + + if sidename in sided: + sided[sidename]+=1 + else: + sided[sidename]=1 + + image = face.image + if image: + faceName="%s_%s" % (face.image.name, sidename); + try: + imageMap[faceName].append(face) + except: + imageMap[faceName]=[face.image.name,sidename,face] + + if self.verbose > 2: + for faceName in imageMap.keys(): + ifs=imageMap[faceName] + print("Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \ + (faceName, ifs[0], ifs[1], len(ifs)-2)) + + return len(imageMap) + + def faceToString(self,face): + + print("Debug: face.flag=0x%x (bitflags)" % face.flag) + if face.sel: + print("Debug: face.sel=true") + + print("Debug: face.mode=0x%x (bitflags)" % face.mode) + if face.mode & Mesh.FaceModes.TWOSIDE: + print("Debug: face.mode twosided") + + print("Debug: face.transp=0x%x (enum)" % face.transp) + if face.transp == Mesh.FaceTranspModes.SOLID: + print("Debug: face.transp.SOLID") + + if face.image: + print("Debug: face.image=%s" % face.image.name) + print("Debug: face.materialIndex=%d" % face.materialIndex) + + # XXX not used + # def getVertexColorByIndx(self, mesh, indx): + # c = None + # for face in mesh.faces: + # j=0 + # for vertex in face.v: + # if vertex.index == indx: + # c=face.col[j] + # break + # j=j+1 + # if c: break + # return c + + def meshToString(self,mesh): + # print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors) + print("Debug: mesh.faceUV=%d" % (len(mesh.uv_textures) > 0)) + # print("Debug: mesh.faceUV=%d" % mesh.faceUV) + print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0)) + # print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()) + print("Debug: mesh.verts=%d" % len(mesh.verts)) + print("Debug: mesh.faces=%d" % len(mesh.faces)) + print("Debug: mesh.materials=%d" % len(mesh.materials)) + + def rgbToFS(self, c): + s="%s %s %s" % (round(c[0]/255.0,self.cp), + round(c[1]/255.0,self.cp), + round(c[2]/255.0,self.cp)) + + # s="%s %s %s" % ( + # round(c.r/255.0,self.cp), + # round(c.g/255.0,self.cp), + # round(c.b/255.0,self.cp)) + return s + + def computeDirection(self, mtx): + x,y,z=(0,-1.0,0) # point down + + ax,ay,az = (mtx*MATWORLD).toEuler() + + # ax *= DEG2RAD + # ay *= DEG2RAD + # az *= DEG2RAD + + # rot X + x1=x + y1=y*math.cos(ax)-z*math.sin(ax) + z1=y*math.sin(ax)+z*math.cos(ax) + + # rot Y + x2=x1*math.cos(ay)+z1*math.sin(ay) + y2=y1 + z2=z1*math.cos(ay)-x1*math.sin(ay) + + # rot Z + x3=x2*math.cos(az)-y2*math.sin(az) + y3=x2*math.sin(az)+y2*math.cos(az) + z3=z2 + + return [x3,y3,z3] + + + # swap Y and Z to handle axis difference between Blender and VRML + #------------------------------------------------------------------------ + def rotatePointForVRML(self, v): + x = v[0] + y = v[2] + z = -v[1] + + vrmlPoint=[x, y, z] + return vrmlPoint + + # For writing well formed VRML code + #------------------------------------------------------------------------ + def writeIndented(self, s, inc=0): + if inc < 1: + self.indentLevel = self.indentLevel + inc + + spaces="" + for x in range(self.indentLevel): + spaces = spaces + "\t" + self.file.write(spaces + s) + + if inc > 0: + self.indentLevel = self.indentLevel + inc + + # Converts a Euler to three new Quaternions + # Angles of Euler are passed in as radians + #------------------------------------------------------------------------ + def eulerToQuaternions(self, x, y, z): + Qx = [math.cos(x/2), math.sin(x/2), 0, 0] + Qy = [math.cos(y/2), 0, math.sin(y/2), 0] + Qz = [math.cos(z/2), 0, 0, math.sin(z/2)] + + quaternionVec=[Qx,Qy,Qz] + return quaternionVec + + # Multiply two Quaternions together to get a new Quaternion + #------------------------------------------------------------------------ + def multiplyQuaternions(self, Q1, Q2): + result = [((Q1[0] * Q2[0]) - (Q1[1] * Q2[1]) - (Q1[2] * Q2[2]) - (Q1[3] * Q2[3])), + ((Q1[0] * Q2[1]) + (Q1[1] * Q2[0]) + (Q1[2] * Q2[3]) - (Q1[3] * Q2[2])), + ((Q1[0] * Q2[2]) + (Q1[2] * Q2[0]) + (Q1[3] * Q2[1]) - (Q1[1] * Q2[3])), + ((Q1[0] * Q2[3]) + (Q1[3] * Q2[0]) + (Q1[1] * Q2[2]) - (Q1[2] * Q2[1]))] + + return result + + # Convert a Quaternion to an Angle Axis (ax, ay, az, angle) + # angle is in radians + #------------------------------------------------------------------------ + def quaternionToAngleAxis(self, Qf): + scale = math.pow(Qf[1],2) + math.pow(Qf[2],2) + math.pow(Qf[3],2) + ax = Qf[1] + ay = Qf[2] + az = Qf[3] + + if scale > .0001: + ax/=scale + ay/=scale + az/=scale + + angle = 2 * math.acos(Qf[0]) + + result = [ax, ay, az, angle] + return result + +########################################################## +# Callbacks, needed before Main +########################################################## + +def x3d_export(filename, + context, + EXPORT_APPLY_MODIFIERS=False, + EXPORT_TRI=False, + EXPORT_GZIP=False): + + if EXPORT_GZIP: + if not filename.lower().endswith('.x3dz'): + filename = '.'.join(filename.split('.')[:-1]) + '.x3dz' + else: + if not filename.lower().endswith('.x3d'): + filename = '.'.join(filename.split('.')[:-1]) + '.x3d' + + + scene = context.scene + # scene = Blender.Scene.GetCurrent() + world = scene.world + + # XXX these are global textures while .Get() returned only scene's? + alltextures = bpy.data.textures + # alltextures = Blender.Texture.Get() + + wrlexport=x3d_class(filename) + wrlexport.export(\ + scene,\ + world,\ + alltextures,\ + \ + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS,\ + EXPORT_TRI = EXPORT_TRI,\ + ) + + +def x3d_export_ui(filename): + if not filename.endswith(extension): + filename += extension + #if _safeOverwrite and sys.exists(filename): + # result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0") + #if(result != 1): + # return + + # Get user options + EXPORT_APPLY_MODIFIERS = Draw.Create(1) + EXPORT_TRI = Draw.Create(0) + EXPORT_GZIP = Draw.Create( filename.lower().endswith('.x3dz') ) + + # Get USER Options + pup_block = [\ + ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object.'),\ + ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ + ('Compress', EXPORT_GZIP, 'GZip the resulting file, requires a full python install'),\ + ] + + if not Draw.PupBlock('Export...', pup_block): + return + + Blender.Window.EditMode(0) + Blender.Window.WaitCursor(1) + + x3d_export(filename,\ + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val,\ + EXPORT_TRI = EXPORT_TRI.val,\ + EXPORT_GZIP = EXPORT_GZIP.val\ + ) + + Blender.Window.WaitCursor(0) + + + +######################################################### +# main routine +######################################################### + + +# if __name__ == '__main__': +# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) + +class EXPORT_OT_x3d(bpy.types.Operator): + ''' + X3D Exporter + ''' + __idname__ = "export.x3d" + __label__ = 'Export X3D' + + # 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 X3D file", maxlen=1024, default=""), + + bpy.props.BoolProperty(attr="apply_modifiers", name="Apply Modifiers", description="Use transformed mesh data from each object.", default=True), + bpy.props.BoolProperty(attr="triangulate", name="Triangulate", description="Triangulate quads.", default=False), + bpy.props.BoolProperty(attr="compress", name="Compress", description="GZip the resulting file, requires a full python install.", default=False), + ] + + def execute(self, context): + x3d_export(self.filename, context, self.apply_modifiers, self.triangulate, self.compress) + 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_x3d) + +# NOTES +# - blender version is hardcoded diff --git a/release/scripts/io/import_3ds.py b/release/scripts/io/import_3ds.py new file mode 100644 index 00000000000..99825471764 --- /dev/null +++ b/release/scripts/io/import_3ds.py @@ -0,0 +1,1166 @@ +#!BPY +""" +Name: '3D Studio (.3ds)...' +Blender: 244 +Group: 'Import' +Tooltip: 'Import from 3DS file format (.3ds)' +""" + +__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton', 'Mario Lapin'] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__= '0.996' +__bpydoc__= '''\ + +3ds Importer + +This script imports a 3ds file and the materials into Blender for editing. + +Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). + +0.996 by Mario Lapin (mario.lapin@gmail.com) 13/04/200
+ - Implemented workaround to correct association between name, geometry and materials of + imported meshes. + + Without this patch, version 0.995 of this importer would associate to each mesh object the + geometry and the materials of the previously parsed mesh object. By so, the name of the + first mesh object would be thrown away, and the name of the last mesh object would be + automatically merged with a '.001' at the end. No object would desappear, however object's + names and materials would be completely jumbled. + +0.995 by Campbell Barton
+- workaround for buggy mesh vert delete +- minor tweaks + +0.99 by Bob Holcomb
+- added support for floating point color values that previously broke on import. + +0.98 by Campbell Barton
+- import faces and verts to lists instead of a mesh, convert to a mesh later +- use new index mapping feature of mesh to re-map faces that were not added. + +0.97 by Campbell Barton
+- Strip material names of spaces +- Added import as instance to import the 3ds into its own + scene and add a group instance to the current scene +- New option to scale down imported objects so they are within a limited bounding area. + +0.96 by Campbell Barton
+- Added workaround for bug in setting UV's for Zero vert index UV faces. +- Removed unique name function, let blender make the names unique. + +0.95 by Campbell Barton
+- Removed workarounds for Blender 2.41 +- Mesh objects split by material- many 3ds objects used more then 16 per mesh. +- Removed a lot of unneeded variable creation. + +0.94 by Campbell Barton
+- Face import tested to be about overall 16x speedup over 0.93. +- Material importing speedup. +- Tested with more models. +- Support some corrupt models. + +0.93 by Campbell Barton
+- Tested with 400 3ds files from turbosquid and samples. +- Tactfully ignore faces that used the same verts twice. +- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. +- Converted from NMesh to Mesh. +- Faster and cleaner new names. +- Use external comprehensive image loader. +- Re intergrated 0.92 and 0.9 changes +- Fixes for 2.41 compat. +- Non textured faces do not use a texture flag. + +0.92
+- Added support for diffuse, alpha, spec, bump maps in a single material + +0.9
+- Reorganized code into object/material block functions
+- Use of Matrix() to copy matrix data
+- added support for material transparency
+ +0.83 2005-08-07: Campell Barton +- Aggressive image finding and case insensitivy for posisx systems. + +0.82a 2005-07-22 +- image texture loading (both for face uv and renderer) + +0.82 - image texture loading (for face uv) + +0.81a (fork- not 0.9) Campbell Barton 2005-06-08 +- Simplified import code +- Never overwrite data +- Faster list handling +- Leaves import selected + +0.81 Damien McGinnes 2005-01-09 +- handle missing images better + +0.8 Damien McGinnes 2005-01-08 +- copies sticky UV coords to face ones +- handles images better +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script + +''' + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# 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 ***** +# -------------------------------------------------------------------------- + +# Importing modules + +import os +import time +import struct + +from import_obj import unpack_face_list, load_image + +import bpy +import Mathutils + +# import Blender +# from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils +# from Blender.Mathutils import Vector +# import BPyImage + +# import BPyMessages + +# try: +# from struct import calcsize, unpack +# except: +# calcsize= unpack= None + + + +# # If python version is less than 2.4, try to get set stuff from module +# try: +# set +# except: +# from sets import Set as set + +BOUNDS_3DS = [] + + +#this script imports uvcoords as sticky vertex coords +#this parameter enables copying these to face uv coords +#which shold be more useful. + +def createBlenderTexture(material, name, image): + texture = bpy.data.textures.new(name) + texture.setType('Image') + texture.image = image + material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will see +#----- Primary Chunk, at the beginning of each file +PRIMARY = int('0x4D4D',16) + +#------ Main Chunks +OBJECTINFO = int('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information +VERSION = int('0x0002',16); #This gives the version of the .3ds file +EDITKEYFRAME= int('0xB000',16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL = 45055 #0xAFFF // This stored the texture info +OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +#------ sub defines of MATERIAL_BLOCK +MAT_NAME = int('0xA000',16) # This holds the material name +MAT_AMBIENT = int('0xA010',16) # Ambient color of the object/material +MAT_DIFFUSE = int('0xA020',16) # This holds the color of the object/material +MAT_SPECULAR = int('0xA030',16) # SPecular color of the object/material +MAT_SHINESS = int('0xA040',16) # ?? +MAT_TRANSPARENCY= int('0xA050',16) # Transparency value of material +MAT_SELF_ILLUM = int('0xA080',16) # Self Illumination value of material +MAT_WIRE = int('0xA085',16) # Only render's wireframe + +MAT_TEXTURE_MAP = int('0xA200',16) # This is a header for a new texture map +MAT_SPECULAR_MAP= int('0xA204',16) # This is a header for a new specular map +MAT_OPACITY_MAP = int('0xA210',16) # This is a header for a new opacity map +MAT_REFLECTION_MAP= int('0xA220',16) # This is a header for a new reflection map +MAT_BUMP_MAP = int('0xA230',16) # This is a header for a new bump map +MAT_MAP_FILENAME = int('0xA300',16) # This holds the file name of the texture + +MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats +MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes + +#>------ sub defines of OBJECT +OBJECT_MESH = int('0x4100',16); # This lets us know that we are reading a new object +OBJECT_LAMP = int('0x4600',16); # This lets un know we are reading a light object +OBJECT_LAMP_SPOT = int('0x4610',16); # The light is a spotloght. +OBJECT_LAMP_OFF = int('0x4620',16); # The light off. +OBJECT_LAMP_ATTENUATE = int('0x4625',16); +OBJECT_LAMP_RAYSHADE = int('0x4627',16); +OBJECT_LAMP_SHADOWED = int('0x4630',16); +OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16); +OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16); +OBJECT_LAMP_SEE_CONE = int('0x4650',16); +OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16); +OBJECT_LAMP_EXCLUDE = int('0x4654',16); +OBJECT_LAMP_RANGE = int('0x4655',16); +OBJECT_LAMP_ROLL = int('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16); +OBJECT_LAMP_RAY_BIAS = int('0x4658',16); +OBJECT_LAMP_INNER_RANGE = int('0x4659',16); +OBJECT_LAMP_OUTER_RANGE = int('0x465A',16); +OBJECT_LAMP_MULTIPLIER = int('0x465B',16); +OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16); + + + +OBJECT_CAMERA= int('0x4700',16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= int('0x4720',16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = int('0x4110',16); # The objects vertices +OBJECT_FACES = int('0x4120',16); # The objects faces +OBJECT_MATERIAL = int('0x4130',16); # This is found if the object has a material, either texture map or color +OBJECT_UV = int('0x4140',16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = int('0x4160',16); # The Object Matrix + +global scn +scn = None + +#the chunk class +class chunk: + ID = 0 + length = 0 + bytes_read = 0 + + #we don't read in the bytes_read, we compute that + binary_format=' 3): + print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version) + + #is it an object info chunk? + elif (new_chunk.ID == OBJECTINFO): + #print 'elif (new_chunk.ID == OBJECTINFO):' + # print 'found an OBJECTINFO chunk' + process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) + + #keep track of how much we read in the main chunk + new_chunk.bytes_read += temp_chunk.bytes_read + + #is it an object chunk? + elif (new_chunk.ID == OBJECT): + + if CreateBlenderObject: + putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) + contextMesh_vertls = []; contextMesh_facels = [] + + ## preparando para receber o proximo objeto + contextMeshMaterials = {} # matname:[face_idxs] + contextMeshUV = None + #contextMesh.vertexUV = 1 # Make sticky coords. + # Reset matrix + contextMatrix_rot = None + #contextMatrix_tx = None + + CreateBlenderObject = True + tempName = read_string(file) + contextObName = tempName + new_chunk.bytes_read += len(tempName)+1 + + #is it a material chunk? + elif (new_chunk.ID == MATERIAL): + +# print("read material") + + #print 'elif (new_chunk.ID == MATERIAL):' + contextMaterial = bpy.data.add_material('Material') +# contextMaterial = bpy.data.materials.new('Material') + + elif (new_chunk.ID == MAT_NAME): + #print 'elif (new_chunk.ID == MAT_NAME):' + material_name = read_string(file) + +# print("material name", material_name) + + #plus one for the null character that ended the string + new_chunk.bytes_read += len(material_name)+1 + + contextMaterial.name = material_name.rstrip() # remove trailing whitespace + MATDICT[material_name]= (contextMaterial.name, contextMaterial) + + elif (new_chunk.ID == MAT_AMBIENT): + #print 'elif (new_chunk.ID == MAT_AMBIENT):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.mirror_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.mirror_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read += temp_chunk.bytes_read + + elif (new_chunk.ID == MAT_DIFFUSE): + #print 'elif (new_chunk.ID == MAT_DIFFUSE):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.diffuse_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.diffuse_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + +# print("read material diffuse color", contextMaterial.diffuse_color) + + new_chunk.bytes_read += temp_chunk.bytes_read + + elif (new_chunk.ID == MAT_SPECULAR): + #print 'elif (new_chunk.ID == MAT_SPECULAR):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID == MAT_FLOAT_COLOR): + contextMaterial.specular_color = read_float_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3f')) +# temp_chunk.bytes_read += 12 +# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)] + elif (temp_chunk.ID == MAT_24BIT_COLOR): + contextMaterial.specular_color = read_byte_color(temp_chunk) +# temp_data = file.read(struct.calcsize('3B')) +# temp_chunk.bytes_read += 3 +# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read += temp_chunk.bytes_read + + elif (new_chunk.ID == MAT_TEXTURE_MAP): + read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR") +# #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' +# new_texture= bpy.data.textures.new('Diffuse') +# new_texture.setType('Image') +# img = None +# while (new_chunk.bytes_read BOUNDS_3DS[i + 3]: + BOUNDS_3DS[i + 3]= v[i] # min + + # Get the max axis x/y/z + max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) + # print max_axis + if max_axis < 1 << 30: # Should never be false but just make sure. + + # Get a new scale factor if set as an option + SCALE = 1.0 + while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS: + SCALE/=10 + + # SCALE Matrix + SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) +# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + + for ob in importedObjects: + ob.setMatrix(ob.matrixWorld * SCALE_MAT) + + # Done constraining to bounds. + + # Select all new objects. + print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1))) +# print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))) + file.close() +# Blender.Window.WaitCursor(0) + + +DEBUG = False +# if __name__=='__main__' and not DEBUG: +# if calcsize == None: +# Blender.Draw.PupMenu('Error%t|a full python installation not found') +# else: +# Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') + +# For testing compatibility +#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) +#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) +''' + +else: + import os + # DEBUG ONLY + TIME = Blender.sys.time() + import os + print 'Searching for files' + os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') + # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') + print '...Done' + file = open('/tmp/temp3ds_list', 'r') + lines = file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _3ds in enumerate(lines): + if between(i, 650,800): + #_3ds= _3ds[:-1] + print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) + _3ds_file= _3ds.split('/')[-1].split('\\')[-1] + newScn = Blender.Scene.New(_3ds_file) + newScn.makeCurrent() + load_3ds(_3ds, False) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) + +''' + +class IMPORT_OT_3ds(bpy.types.Operator): + ''' + 3DS Importer + ''' + __idname__ = "import.3ds" + __label__ = 'Import 3DS' + + # 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 importing the 3DS file", maxlen=1024, default= ""), +# bpy.props.FloatProperty(attr="size_constraint", name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0), +# bpy.props.BoolProperty(attr="search_images", name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True), +# bpy.props.BoolProperty(attr="apply_matrix", name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False), + ] + + def execute(self, context): + load_3ds(self.filename, context, 0.0, False, False) + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + ''' + def poll(self, context): + print("Poll") + return context.active_object != None''' + +bpy.ops.add(IMPORT_OT_3ds) + +# NOTES: +# why add 1 extra vertex? and remove it when done? +# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time) diff --git a/release/scripts/io/import_obj.py b/release/scripts/io/import_obj.py new file mode 100644 index 00000000000..9a00dc1cc2a --- /dev/null +++ b/release/scripts/io/import_obj.py @@ -0,0 +1,1633 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 249 +Group: 'Import' +Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' +""" + +__author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone" +__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org'] +__version__= "2.11" + +__bpydoc__= """\ +This script imports a Wavefront OBJ files to Blender. + +Usage: +Run this script from "File->Import" menu and then load the desired OBJ file. +Note, This loads mesh objects and materials only, nurbs and curves are not supported. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2007 +# +# 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 os +import time +import bpy +import Mathutils +import Geometry + +# from Blender import Mesh, Draw, Window, Texture, Material, sys +# # import BPyMesh +# import BPyImage +# import BPyMessages + +# try: import os +# except: os= False + +# Generic path functions +def stripFile(path): + '''Return directory, where the file is''' + lastSlash= max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path= path[:lastSlash] + return '%s%s' % (path, os.sep) +# return '%s%s' % (path, sys.sep) + +def stripPath(path): + '''Strips the slashes from the back of a string''' + return path.split('/')[-1].split('\\')[-1] + +def stripExt(name): # name is a string + '''Strips the prefix off the name before writing''' + index= name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name +# end path funcs + +def unpack_list(list_of_tuples): + l = [] + for t in list_of_tuples: + l.extend(t) + return l + +# same as above except that it adds 0 for triangle faces +def unpack_face_list(list_of_tuples): + l = [] + for t in list_of_tuples: + face = [i for i in t] + if len(face) != 3 and len(face) != 4: + raise RuntimeError("{0} vertices in face.".format(len(face))) + if len(face) == 3: + face.append(0) + l.extend(face) + return l + +def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True): + ''' + Takes a polyline of indices (fgon) + and returns a list of face indicie lists. + Designed to be used for importers that need indices for an fgon to create from existing verts. + + from_data: either a mesh, or a list/tuple of vectors. + indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. + PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. + ''' + + if not set: # Need sets for this, otherwise do a normal fill. + PREF_FIX_LOOPS= False + + Vector= Mathutils.Vector + if not indices: + return [] + + # return [] + def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) + def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length + + def vert_treplet(v, i): + return v, rvec(v), i, mlen(v) + + def ed_key_mlen(v1, v2): + if v1[3] > v2[3]: + return v2[1], v1[1] + else: + return v1[1], v2[1] + + + if not PREF_FIX_LOOPS: + ''' + Normal single concave loop filling + ''' + if type(from_data) in (tuple, list): + verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] + else: + verts= [from_data.verts[i].co for ii, i in enumerate(indices)] + + for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): + if verts[i][1]==verts[i-1][0]: + verts.pop(i-1) + + fill= Geometry.PolyFill([verts]) + + else: + ''' + Seperate this loop into multiple loops be finding edges that are used twice + This is used by lightwave LWO files a lot + ''' + + if type(from_data) in (tuple, list): + verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] + else: + verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] + + edges= [(i, i-1) for i in range(len(verts))] + if edges: + edges[0]= (0,len(verts)-1) + + if not verts: + return [] + + + edges_used= set() + edges_doubles= set() + # We need to check if any edges are used twice location based. + for ed in edges: + edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) + if edkey in edges_used: + edges_doubles.add(edkey) + else: + edges_used.add(edkey) + + # Store a list of unconnected loop segments split by double edges. + # will join later + loop_segments= [] + + v_prev= verts[0] + context_loop= [v_prev] + loop_segments= [context_loop] + + for v in verts: + if v!=v_prev: + # Are we crossing an edge we removed? + if ed_key_mlen(v, v_prev) in edges_doubles: + context_loop= [v] + loop_segments.append(context_loop) + else: + if context_loop and context_loop[-1][1]==v[1]: + #raise "as" + pass + else: + context_loop.append(v) + + v_prev= v + # Now join loop segments + + def join_seg(s1,s2): + if s2[-1][1]==s1[0][1]: # + s1,s2= s2,s1 + elif s1[-1][1]==s2[0][1]: + pass + else: + return False + + # If were stuill here s1 and s2 are 2 segments in the same polyline + s1.pop() # remove the last vert from s1 + s1.extend(s2) # add segment 2 to segment 1 + + if s1[0][1]==s1[-1][1]: # remove endpoints double + s1.pop() + + s2[:]= [] # Empty this segment s2 so we dont use it again. + return True + + joining_segments= True + while joining_segments: + joining_segments= False + segcount= len(loop_segments) + + for j in range(segcount-1, -1, -1): #reversed(range(segcount)): + seg_j= loop_segments[j] + if seg_j: + for k in range(j-1, -1, -1): # reversed(range(j)): + if not seg_j: + break + seg_k= loop_segments[k] + + if seg_k and join_seg(seg_j, seg_k): + joining_segments= True + + loop_list= loop_segments + + for verts in loop_list: + while verts and verts[0][1]==verts[-1][1]: + verts.pop() + + loop_list= [verts for verts in loop_list if len(verts)>2] + # DONE DEALING WITH LOOP FIXING + + + # vert mapping + vert_map= [None]*len(indices) + ii=0 + for verts in loop_list: + if len(verts)>2: + for i, vert in enumerate(verts): + vert_map[i+ii]= vert[2] + ii+=len(verts) + + fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) + #draw_loops(loop_list) + #raise 'done loop' + # map to original indicies + fill= [[vert_map[i] for i in reversed(f)] for f in fill] + + + if not fill: + print('Warning Cannot scanfill, fallback on a triangle fan.') + fill= [ [0, i-1, i] for i in range(2, len(indices)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in fill: + if flip != None: + break + for i, vi in enumerate(fi): + if vi==0 and fi[i-1]==1: + flip= False + break + elif vi==1 and fi[i-1]==0: + flip= True + break + + if not flip: + for i, fi in enumerate(fill): + fill[i]= tuple([ii for ii in reversed(fi)]) + + return fill + +def line_value(line_split): + ''' + Returns 1 string represneting the value for this line + None will be returned if theres only 1 word + ''' + length= len(line_split) + if length == 1: + return None + + elif length == 2: + return line_split[1] + + elif length > 2: + return ' '.join( line_split[1:] ) + +# limited replacement for BPyImage.comprehensiveImageLoad +def load_image(imagepath, dirname): + + if os.path.exists(imagepath): + return bpy.data.add_image(imagepath) + + variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))] + + for path in variants: + if os.path.exists(path): + return bpy.data.add_image(path) + else: + print(path, "doesn't exist") + + # TODO comprehensiveImageLoad also searched in bpy.config.textureDir + return None + +def obj_image_load(imagepath, DIR, IMAGE_SEARCH): + + if '_' in imagepath: + image= load_image(imagepath.replace('_', ' '), DIR) + if image: return image + + return load_image(imagepath, DIR) + +# def obj_image_load(imagepath, DIR, IMAGE_SEARCH): +# ''' +# Mainly uses comprehensiveImageLoad +# but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. +# ''' + +# if '_' in imagepath: +# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) +# if image: return image +# # Did the exporter rename the image? +# image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) +# if image: return image + +# # Return an image, placeholder if it dosnt exist +# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) +# return image + + +def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): + ''' + Create all the used materials in this obj, + assign colors and images to the materials from all referenced material libs + ''' + DIR= stripFile(filepath) + + #==================================================================================# + # This function sets textures defined in .mtl file # + #==================================================================================# + def load_material_image(blender_material, context_material_name, imagepath, type): + + texture= bpy.data.add_texture(type) + texture.type= 'IMAGE' +# texture= bpy.data.textures.new(type) +# texture.setType('Image') + + # Absolute path - c:\.. etc would work here + image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) + has_data = image.has_data if image else False + + if image: + texture.image = image + + # Adds textures for materials (rendering) + if type == 'Kd': + if has_data and image.depth == 32: + # Image has alpha + + # XXX bitmask won't work? + blender_material.add_texture(texture, "UV", ("COLOR", "ALPHA")) + texture.mipmap = True + texture.interpolation = True + texture.use_alpha = True + blender_material.z_transparency = True + blender_material.alpha = 0.0 + +# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) +# texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') +# blender_material.mode |= Material.Modes.ZTRANSP +# blender_material.alpha = 0.0 + else: + blender_material.add_texture(texture, "UV", "COLOR") +# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + # adds textures to faces (Textured/Alt-Z mode) + # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. + unique_material_images[context_material_name]= image, has_data # set the texface image + + elif type == 'Ka': + blender_material.add_texture(texture, "UV", "AMBIENT") +# blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API + + elif type == 'Ks': + blender_material.add_texture(texture, "UV", "SPECULARITY") +# blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + + elif type == 'Bump': + blender_material.add_texture(texture, "UV", "NORMAL") +# blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) + elif type == 'D': + blender_material.add_texture(texture, "UV", "ALPHA") + blender_material.z_transparency = True + blender_material.alpha = 0.0 +# blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) +# blender_material.mode |= Material.Modes.ZTRANSP +# blender_material.alpha = 0.0 + # Todo, unset deffuse material alpha if it has an alpha channel + + elif type == 'refl': + blender_material.add_texture(texture, "UV", "REFLECTION") +# blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) + + + # Add an MTL with the same name as the obj if no MTLs are spesified. + temp_mtl= stripExt(stripPath(filepath))+ '.mtl' + + if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs: +# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: + material_libs.append( temp_mtl ) + del temp_mtl + + #Create new materials + for name in unique_materials: # .keys() + if name != None: + unique_materials[name]= bpy.data.add_material(name) +# unique_materials[name]= bpy.data.materials.new(name) + unique_material_images[name]= None, False # assign None to all material images to start with, add to later. + + unique_materials[None]= None + unique_material_images[None]= None, False + + for libname in material_libs: + mtlpath= DIR + libname + if not os.path.exists(mtlpath): +# if not sys.exists(mtlpath): + #print '\tError Missing MTL: "%s"' % mtlpath + pass + else: + #print '\t\tloading mtl: "%s"' % mtlpath + context_material= None + mtl= open(mtlpath, 'rU') + for line in mtl: #.xreadlines(): + if line.startswith('newmtl'): + context_material_name= line_value(line.split()) + if context_material_name in unique_materials: + context_material = unique_materials[ context_material_name ] + else: + context_material = None + + elif context_material: + # we need to make a material to assign properties to it. + line_split= line.split() + line_lower= line.lower().lstrip() + if line_lower.startswith('ka'): + context_material.mirror_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('kd'): + context_material.diffuse_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ks'): + context_material.specular_color = (float(line_split[1]), float(line_split[2]), float(line_split[3])) +# context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ns'): + context_material.specular_hardness = int((float(line_split[1])*0.51)) +# context_material.setHardness( int((float(line_split[1])*0.51)) ) + elif line_lower.startswith('ni'): # Refraction index + context_material.ior = max(1, min(float(line_split[1]), 3)) +# context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 + elif line_lower.startswith('d') or line_lower.startswith('tr'): + context_material.alpha = float(line_split[1]) +# context_material.setAlpha(float(line_split[1])) + elif line_lower.startswith('map_ka'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ka') + elif line_lower.startswith('map_ks'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ks') + elif line_lower.startswith('map_kd'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Kd') + elif line_lower.startswith('map_bump'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Bump') + elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'D') + + elif line_lower.startswith('refl'): # Reflectionmap + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'refl') + mtl.close() + + + + +def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + ''' + Takes vert_loc and faces, and seperates into multiple sets of + (verts_loc, faces, unique_materials, dataname) + This is done so objects do not overload the 16 material limit. + ''' + + filename = stripExt(stripPath(filepath)) + + if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + # use the filename for the object name since we arnt chopping up the mesh. + return [(verts_loc, faces, unique_materials, filename)] + + + def key_to_name(key): + # if the key is a tuple, join it to make a string + if type(key) == tuple: + return '%s_%s' % key + elif not key: + return filename # assume its a string. make sure this is true if the splitting code is changed + else: + return key + + # Return a key that makes the faces unique. + if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + def face_key(face): + return face[4] # object + + elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: + def face_key(face): + return face[2] # material + + else: # Both + def face_key(face): + return face[4], face[2] # object,material + + + face_split_dict= {} + + oldkey= -1 # initialize to a value that will never match the key + + for face in faces: + + key= face_key(face) + + if oldkey != key: + # Check the key has changed. + try: + verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] + except KeyError: + faces_split= [] + verts_split= [] + unique_materials_split= {} + vert_remap= [-1]*len(verts_loc) + + face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) + + oldkey= key + + face_vert_loc_indicies= face[0] + + # Remap verts to new vert list and add where needed + for enum, i in enumerate(face_vert_loc_indicies): + if vert_remap[i] == -1: + new_index= len(verts_split) + vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. + face_vert_loc_indicies[enum] = new_index # remap to the local index + verts_split.append( verts_loc[i] ) # add the vert to the local verts + + else: + face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index + + matname= face[2] + if matname and matname not in unique_materials_split: + unique_materials_split[matname] = unique_materials[matname] + + faces_split.append(face) + + + # remove one of the itemas and reorder + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())] + + +def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname): + ''' + Takes all the data gathered and generates a mesh, adding the new object to new_objects + deals with fgons, sharp edges and assigning materials + ''' + if not has_ngons: + CREATE_FGONS= False + + if unique_smooth_groups: + sharp_edges= {} + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ]) + context_smooth_group_old= -1 + + # Split fgons into tri's + fgon_edges= {} # Used for storing fgon keys + if CREATE_EDGES: + edges= [] + + context_object= None + + # reverse loop through face indicies + for f_idx in range(len(faces)-1, -1, -1): + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= faces[f_idx] + + len_face_vert_loc_indicies = len(face_vert_loc_indicies) + + if len_face_vert_loc_indicies==1: + faces.pop(f_idx)# cant add single vert faces + + elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines + if CREATE_EDGES: + # generators are better in python 2.4+ but can't be used in 2.3 + # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) + edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in range(len_face_vert_loc_indicies-1)] ) + + faces.pop(f_idx) + else: + + # Smooth Group + if unique_smooth_groups and context_smooth_group: + # Is a part of of a smooth group and is a face + if context_smooth_group_old is not context_smooth_group: + edge_dict= smooth_group_users[context_smooth_group] + context_smooth_group_old= context_smooth_group + + for i in range(len_face_vert_loc_indicies): + i1= face_vert_loc_indicies[i] + i2= face_vert_loc_indicies[i-1] + if i1>i2: i1,i2= i2,i1 + + try: + edge_dict[i1,i2]+= 1 + except KeyError: + edge_dict[i1,i2]= 1 + + # FGons into triangles + if has_ngons and len_face_vert_loc_indicies > 4: + + ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies) + faces.extend(\ + [(\ + [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ + [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ + context_material,\ + context_smooth_group,\ + context_object)\ + for ngon in ngon_face_indices]\ + ) + + # edges to make fgons + if CREATE_FGONS: + edge_users= {} + for ngon in ngon_face_indices: + for i in (0,1,2): + i1= face_vert_loc_indicies[ngon[i ]] + i2= face_vert_loc_indicies[ngon[i-1]] + if i1>i2: i1,i2= i2,i1 + + try: + edge_users[i1,i2]+=1 + except KeyError: + edge_users[i1,i2]= 1 + + for key, users in edge_users.items(): + if users>1: + fgon_edges[key]= None + + # remove all after 3, means we dont have to pop this one. + faces.pop(f_idx) + + + # Build sharp edges + if unique_smooth_groups: + for edge_dict in list(smooth_group_users.values()): + for key, users in list(edge_dict.items()): + if users==1: # This edge is on the boundry of a group + sharp_edges[key]= None + + + # map the material names to an index + material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys() + + materials= [None] * len(unique_materials) + + for name, index in list(material_mapping.items()): + materials[index]= unique_materials[name] + + me= bpy.data.add_mesh(dataname) +# me= bpy.data.meshes.new(dataname) + + # make sure the list isnt too big + for material in materials[0:16]: + me.add_material(material) +# me.materials= materials[0:16] # make sure the list isnt too big. + #me.verts.extend([(0,0,0)]) # dummy vert + + me.add_geometry(len(verts_loc), 0, len(faces)) + + # verts_loc is a list of (x, y, z) tuples + me.verts.foreach_set("co", unpack_list(verts_loc)) +# me.verts.extend(verts_loc) + + # faces is a list of (vert_indices, texco_indices, ...) tuples + # XXX faces should not contain edges + # XXX no check for valid face indices + me.faces.foreach_set("verts", unpack_face_list([f[0] for f in faces])) +# face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) + + if verts_tex and me.faces: + me.add_uv_texture() +# me.faceUV= 1 + # TEXMODE= Mesh.FaceModes['TEX'] + + context_material_old= -1 # avoid a dict lookup + mat= 0 # rare case it may be un-initialized. + me_faces= me.faces +# ALPHA= Mesh.FaceTranspModes.ALPHA + + for i, face in enumerate(faces): + if len(face[0]) < 2: + pass #raise "bad face" + elif len(face[0])==2: + if CREATE_EDGES: + edges.append(face[0]) + else: +# face_index_map= face_mapping[i] + + # since we use foreach_set to add faces, all of them are added + if 1: +# if face_index_map!=None: # None means the face wasnt added + + blender_face = me.faces[i] +# blender_face= me_faces[face_index_map] + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= face + + + + if context_smooth_group: + blender_face.smooth= True + + if context_material: + if context_material_old is not context_material: + mat= material_mapping[context_material] + if mat>15: + mat= 15 + context_material_old= context_material + + blender_face.material_index= mat +# blender_face.mat= mat + + + if verts_tex: + + blender_tface= me.uv_textures[0].data[i] + + if context_material: + image, has_data= unique_material_images[context_material] + if image: # Can be none if the material dosnt have an image. + blender_tface.image= image +# blender_face.image= image + if has_data: +# if has_data and image.depth == 32: + blender_tface.transp = 'ALPHA' +# blender_face.transp |= ALPHA + + # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. + if len(face_vert_loc_indicies)==4: + if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: + face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] + else: # length of 3 + if face_vert_loc_indicies[2]==0: + face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] + # END EEEKADOODLE FIX + + # assign material, uv's and image + blender_tface.uv1= verts_tex[face_vert_tex_indicies[0]] + blender_tface.uv2= verts_tex[face_vert_tex_indicies[1]] + blender_tface.uv3= verts_tex[face_vert_tex_indicies[2]] + + if blender_face.verts[3] != 0: + blender_tface.uv4= verts_tex[face_vert_tex_indicies[3]] + +# for ii, uv in enumerate(blender_face.uv): +# uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] + del me_faces +# del ALPHA + + if CREATE_EDGES: + + me.add_geometry(0, len(edges), 0) + + # edges should be a list of (a, b) tuples + me.edges.foreach_set("verts", unpack_list(edges)) +# me_edges.extend( edges ) + +# del me_edges + + # Add edge faces. +# me_edges= me.edges + + def edges_match(e1, e2): + return (e1[0] == e2[0] and e1[1] == e2[1]) or (e1[0] == e2[1] and e1[1] == e2[0]) + + # XXX slow +# if CREATE_FGONS and fgon_edges: +# for fgon_edge in fgon_edges.keys(): +# for ed in me.edges: +# if edges_match(fgon_edge, ed.verts): +# ed.fgon = True + +# if CREATE_FGONS and fgon_edges: +# FGON= Mesh.EdgeFlags.FGON +# for ed in me.findEdges( fgon_edges.keys() ): +# if ed!=None: +# me_edges[ed].flag |= FGON +# del FGON + + # XXX slow +# if unique_smooth_groups and sharp_edges: +# for sharp_edge in sharp_edges.keys(): +# for ed in me.edges: +# if edges_match(sharp_edge, ed.verts): +# ed.sharp = True + +# if unique_smooth_groups and sharp_edges: +# SHARP= Mesh.EdgeFlags.SHARP +# for ed in me.findEdges( sharp_edges.keys() ): +# if ed!=None: +# me_edges[ed].flag |= SHARP +# del SHARP + + me.update() +# me.calcNormals() + + ob= bpy.data.add_object("MESH", "Mesh") + ob.data= me + scn.add_object(ob) +# ob= scn.objects.new(me) + new_objects.append(ob) + + # Create the vertex groups. No need to have the flag passed here since we test for the + # content of the vertex_groups. If the user selects to NOT have vertex groups saved then + # the following test will never run + for group_name, group_indicies in vertex_groups.items(): + group= ob.add_vertex_group(group_name) +# me.addVertGroup(group_name) + for vertex_index in group_indicies: + ob.add_vertex_to_group(vertex_index, group, 1.0, 'REPLACE') +# me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE) + + +def create_nurbs(scn, context_nurbs, vert_loc, new_objects): + ''' + Add nurbs object to blender, only support one type at the moment + ''' + deg = context_nurbs.get('deg', (3,)) + curv_range = context_nurbs.get('curv_range', None) + curv_idx = context_nurbs.get('curv_idx', []) + parm_u = context_nurbs.get('parm_u', []) + parm_v = context_nurbs.get('parm_v', []) + name = context_nurbs.get('name', 'ObjNurb') + cstype = context_nurbs.get('cstype', None) + + if cstype == None: + print('\tWarning, cstype not found') + return + if cstype != 'bspline': + print('\tWarning, cstype is not supported (only bspline)') + return + if not curv_idx: + print('\tWarning, curv argument empty or not set') + return + if len(deg) > 1 or parm_v: + print('\tWarning, surfaces not supported') + return + + cu = bpy.data.curves.new(name, 'Curve') + cu.flag |= 1 # 3D curve + + nu = None + for pt in curv_idx: + + pt = vert_loc[pt] + pt = (pt[0], pt[1], pt[2], 1.0) + + if nu == None: + nu = cu.appendNurb(pt) + else: + nu.append(pt) + + nu.orderU = deg[0]+1 + + # get for endpoint flag from the weighting + if curv_range and len(parm_u) > deg[0]+1: + do_endpoints = True + for i in range(deg[0]+1): + + if abs(parm_u[i]-curv_range[0]) > 0.0001: + do_endpoints = False + break + + if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001: + do_endpoints = False + break + + else: + do_endpoints = False + + if do_endpoints: + nu.flagU |= 2 + + + # close + ''' + do_closed = False + if len(parm_u) > deg[0]+1: + for i in xrange(deg[0]+1): + #print curv_idx[i], curv_idx[-(i+1)] + + if curv_idx[i]==curv_idx[-(i+1)]: + do_closed = True + break + + if do_closed: + nu.flagU |= 1 + ''' + + ob = scn.objects.new(cu) + new_objects.append(ob) + + +def strip_slash(line_split): + if line_split[-1][-1]== '\\': + if len(line_split[-1])==1: + line_split.pop() # remove the \ item + else: + line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number + return True + return False + + + +def get_float_func(filepath): + ''' + find the float function for this obj file + - weather to replace commas or not + ''' + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + line = line.lstrip() + if line.startswith('v'): # vn vt v + if ',' in line: + return lambda f: float(f.replace(',', '.')) + elif '.' in line: + return float + + # incase all vert values were ints + return float + +def load_obj(filepath, + context, + CLAMP_SIZE= 0.0, + CREATE_FGONS= True, + CREATE_SMOOTH_GROUPS= True, + CREATE_EDGES= True, + SPLIT_OBJECTS= True, + SPLIT_GROUPS= True, + SPLIT_MATERIALS= True, + ROTATE_X90= True, + IMAGE_SEARCH=True, + POLYGROUPS=False): + ''' + Called by the user interface or another script. + load_obj(path) - should give acceptable results. + This function passes the file and sends the data off + to be split into objects and then converted into mesh objects + ''' + print('\nimporting obj "%s"' % filepath) + + if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS: + POLYGROUPS = False + + time_main= time.time() +# time_main= sys.time() + + verts_loc= [] + verts_tex= [] + faces= [] # tuples of the faces + material_libs= [] # filanems to material libs this uses + vertex_groups = {} # when POLYGROUPS is true + + # Get the string to float conversion func for this file- is 'float' for almost all files. + float_func= get_float_func(filepath) + + # Context variables + context_material= None + context_smooth_group= None + context_object= None + context_vgroup = None + + # Nurbs + context_nurbs = {} + nurbs = [] + context_parm = '' # used by nurbs too but could be used elsewhere + + has_ngons= False + # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 + + # Until we can use sets + unique_materials= {} + unique_material_images= {} + unique_smooth_groups= {} + # unique_obects= {} - no use for this variable since the objects are stored in the face. + + # when there are faces that end with \ + # it means they are multiline- + # since we use xreadline we cant skip to the next line + # so we need to know weather + context_multi_line= '' + + print('\tparsing obj file "%s"...' % filepath) + time_sub= time.time() +# time_sub= sys.time() + + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + line = line.lstrip() # rare cases there is white space at the start of the line + + if line.startswith('v '): + line_split= line.split() + # rotate X90: (x,-z,y) + verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) + + elif line.startswith('vn '): + pass + + elif line.startswith('vt '): + line_split= line.split() + verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) + + # Handel faces lines (as faces) and the second+ lines of fa multiline face here + # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) + elif line.startswith('f') or context_multi_line == 'f': + + if context_multi_line: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if strip_slash(line_split): + context_multi_line = 'f' + else: + context_multi_line = '' + + for v in line_split: + obj_vert= v.split('/') + + vert_loc_index= int(obj_vert[0])-1 + # Add the vertex to the current group + # *warning*, this wont work for files that have groups defined around verts + if POLYGROUPS and context_vgroup: + vertex_groups[context_vgroup].append(vert_loc_index) + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + if len(obj_vert)>1 and obj_vert[1]: + # formatting for faces with normals and textures us + # loc_index/tex_index/nor_index + + vert_tex_index= int(obj_vert[1])-1 + # Make relative negative vert indicies absolute + if vert_tex_index < 0: + vert_tex_index= len(verts_tex) + vert_tex_index + 1 + + face_vert_tex_indicies.append(vert_tex_index) + else: + # dummy + face_vert_tex_indicies.append(0) + + if len(face_vert_loc_indicies) > 4: + has_ngons= True + + elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'): + # very similar to the face load function above with some parts removed + + if context_multi_line: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if strip_slash(line_split): + context_multi_line = 'l' + else: + context_multi_line = '' + + isline= line.startswith('l') + + for v in line_split: + vert_loc_index= int(v)-1 + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + elif line.startswith('s'): + if CREATE_SMOOTH_GROUPS: + context_smooth_group= line_value(line.split()) + if context_smooth_group=='off': + context_smooth_group= None + elif context_smooth_group: # is not None + unique_smooth_groups[context_smooth_group]= None + + elif line.startswith('o'): + if SPLIT_OBJECTS: + context_object= line_value(line.split()) + # unique_obects[context_object]= None + + elif line.startswith('g'): + if SPLIT_GROUPS: + context_object= line_value(line.split()) + # print 'context_object', context_object + # unique_obects[context_object]= None + elif POLYGROUPS: + context_vgroup = line_value(line.split()) + if context_vgroup and context_vgroup != '(null)': + vertex_groups.setdefault(context_vgroup, []) + else: + context_vgroup = None # dont assign a vgroup + + elif line.startswith('usemtl'): + context_material= line_value(line.split()) + unique_materials[context_material]= None + elif line.startswith('mtllib'): # usemap or usemat + material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line + + + # Nurbs support + elif line.startswith('cstype '): + context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline' + elif line.startswith('curv ') or context_multi_line == 'curv': + line_split= line.split() + + curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline + + if not context_multi_line: + context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2]) + line_split[0:3] = [] # remove first 3 items + + if strip_slash(line_split): + context_multi_line = 'curv' + else: + context_multi_line = '' + + + for i in line_split: + vert_loc_index = int(i)-1 + + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + curv_idx.append(vert_loc_index) + + elif line.startswith('parm') or context_multi_line == 'parm': + line_split= line.split() + + if context_multi_line: + context_multi_line = '' + else: + context_parm = line_split[1] + line_split[0:2] = [] # remove first 2 + + if strip_slash(line_split): + context_multi_line = 'parm' + else: + context_multi_line = '' + + if context_parm.lower() == 'u': + context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] ) + elif context_parm.lower() == 'v': # surfaces not suported yet + context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] ) + # else: # may want to support other parm's ? + + elif line.startswith('deg '): + context_nurbs['deg']= [int(i) for i in line.split()[1:]] + elif line.startswith('end'): + # Add the nurbs curve + if context_object: + context_nurbs['name'] = context_object + nurbs.append(context_nurbs) + context_nurbs = {} + context_parm = '' + + ''' # How to use usemap? depricated? + elif line.startswith('usema'): # usemap or usemat + context_image= line_value(line.split()) + ''' + + file.close() + time_new= time.time() +# time_new= sys.time() + print('%.4f sec' % (time_new-time_sub)) + time_sub= time_new + + + print('\tloading materials and images...') + create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) + + time_new= time.time() +# time_new= sys.time() + print('%.4f sec' % (time_new-time_sub)) + time_sub= time_new + + if not ROTATE_X90: + verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc] + + # deselect all +# if context.selected_objects: +# bpy.ops.OBJECT_OT_select_all_toggle() + + scene = context.scene +# scn = bpy.data.scenes.active +# scn.objects.selected = [] + new_objects= [] # put new objects here + + print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) )) + # Split the mesh by objects/materials, may + if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True + else: SPLIT_OB_OR_GROUP = False + + for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + # Create meshes from the data, warning 'vertex_groups' wont support splitting + create_mesh(scene, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname) + + # nurbs support +# for context_nurbs in nurbs: +# create_nurbs(scn, context_nurbs, verts_loc, new_objects) + + + axis_min= [ 1000000000]*3 + axis_max= [-1000000000]*3 + +# if CLAMP_SIZE: +# # Get all object bounds +# for ob in new_objects: +# for v in ob.getBoundBox(): +# for axis, value in enumerate(v): +# if axis_min[axis] > value: axis_min[axis]= value +# if axis_max[axis] < value: axis_max[axis]= value + +# # Scale objects +# max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) +# scale= 1.0 + +# while CLAMP_SIZE < max_axis * scale: +# scale= scale/10.0 + +# for ob in new_objects: +# ob.setSize(scale, scale, scale) + + # Better rotate the vert locations + #if not ROTATE_X90: + # for ob in new_objects: + # ob.RotX = -1.570796326794896558 + + time_new= time.time() +# time_new= sys.time() + + print('%.4f sec' % (time_new-time_sub)) + print('finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main))) + + +DEBUG= True + + +def load_obj_ui(filepath, BATCH_LOAD= False): + if BPyMessages.Error_NoFile(filepath): + return + + global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 + + CREATE_SMOOTH_GROUPS= Draw.Create(0) + CREATE_FGONS= Draw.Create(1) + CREATE_EDGES= Draw.Create(1) + SPLIT_OBJECTS= Draw.Create(0) + SPLIT_GROUPS= Draw.Create(0) + SPLIT_MATERIALS= Draw.Create(0) + CLAMP_SIZE= Draw.Create(10.0) + IMAGE_SEARCH= Draw.Create(1) + POLYGROUPS= Draw.Create(0) + KEEP_VERT_ORDER= Draw.Create(1) + ROTATE_X90= Draw.Create(1) + + + # Get USER Options + # Note, Works but not pretty, instead use a more complicated GUI + ''' + pup_block= [\ + 'Import...',\ + ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ + ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ + ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ + 'Separate objects from obj...',\ + ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ + ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ + ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ + 'Options...',\ + ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\ + ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ + ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ + ] + + if not Draw.PupBlock('Import OBJ...', pup_block): + return + + if KEEP_VERT_ORDER.val: + SPLIT_OBJECTS.val = False + SPLIT_GROUPS.val = False + SPLIT_MATERIALS.val = False + ''' + + + + # BEGIN ALTERNATIVE UI ******************* + if True: + + EVENT_NONE = 0 + EVENT_EXIT = 1 + EVENT_REDRAW = 2 + EVENT_IMPORT = 3 + + GLOBALS = {} + GLOBALS['EVENT'] = EVENT_REDRAW + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + + def obj_ui_set_event(e,v): + GLOBALS['EVENT'] = e + + def do_split(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS + if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val: + KEEP_VERT_ORDER.val = 0 + POLYGROUPS.val = 0 + else: + KEEP_VERT_ORDER.val = 1 + + def do_vertorder(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER + if KEEP_VERT_ORDER.val: + SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 + else: + if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val): + KEEP_VERT_ORDER.val = 1 + + def do_polygroups(e,v): + global SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, KEEP_VERT_ORDER, POLYGROUPS + if POLYGROUPS.val: + SPLIT_OBJECTS.val = SPLIT_GROUPS.val = SPLIT_MATERIALS.val = 0 + + def do_help(e,v): + url = __url__[0] + print('Trying to open web browser with documentation at this address...') + print('\t' + url) + + try: + import webbrowser + webbrowser.open(url) + except: + print('...could not open a browser window.') + + def obj_ui(): + ui_x, ui_y = GLOBALS['MOUSE'] + + # Center based on overall pup size + ui_x -= 165 + ui_y -= 90 + + global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, SPLIT_MATERIALS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90 + + Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21) + Draw.BeginAlign() + CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges') + CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons') + CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges') + Draw.EndAlign() + + Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20) + Draw.BeginAlign() + SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split) + SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split) + SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split) + Draw.EndAlign() + + # Only used for user feedback + KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder) + + ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.') + + Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20) + CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)') + POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups) + IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)') + Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event) + Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event) + Draw.EndAlign() + + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT): + Draw.UIBlock(obj_ui, 0) + + if GLOBALS['EVENT'] != EVENT_IMPORT: + return + + # END ALTERNATIVE UI ********************* + + + + + + + + Window.WaitCursor(1) + + if BATCH_LOAD: # load the dir + try: + files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] + except: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|Could not open path ' + filepath) + return + + if not files: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|No files at path ' + filepath) + return + + for f in files: + scn= bpy.data.scenes.new( stripExt(f) ) + scn.makeCurrent() + + load_obj(sys.join(filepath, f),\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + ROTATE_X90.val,\ + IMAGE_SEARCH.val,\ + POLYGROUPS.val + ) + + else: # Normal load + load_obj(filepath,\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + ROTATE_X90.val,\ + IMAGE_SEARCH.val,\ + POLYGROUPS.val + ) + + Window.WaitCursor(0) + + +def load_obj_ui_batch(file): + load_obj_ui(file, True) + +DEBUG= False + +# if __name__=='__main__' and not DEBUG: +# if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: +# Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') +# else: +# Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') + + # For testing compatibility +''' +else: + # DEBUG ONLY + TIME= sys.time() + DIR = '/fe/obj' + import os + print 'Searching for files' + def fileList(path): + for dirpath, dirnames, filenames in os.walk(path): + for filename in filenames: + yield os.path.join(dirpath, filename) + + files = [f for f in fileList(DIR) if f.lower().endswith('.obj')] + files.sort() + + for i, obj_file in enumerate(files): + if 0 < i < 20: + print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files) + newScn= bpy.data.scenes.new(os.path.basename(obj_file)) + newScn.makeCurrent() + load_obj(obj_file, False, IMAGE_SEARCH=0) + + print 'TOTAL TIME: %.6f' % (sys.time() - TIME) +''' +#load_obj('/test.obj') +#load_obj('/fe/obj/mba1.obj') + + + +class IMPORT_OT_obj(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "import.obj" + __label__ = "Import 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= ""), + + bpy.props.BoolProperty(attr="CREATE_SMOOTH_GROUPS", name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True), + bpy.props.BoolProperty(attr="CREATE_FGONS", name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True), + bpy.props.BoolProperty(attr="CREATE_EDGES", name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True), + bpy.props.BoolProperty(attr="SPLIT_OBJECTS", name="Object", description="Import OBJ Objects into Blender Objects", default= True), + bpy.props.BoolProperty(attr="SPLIT_GROUPS", name="Group", description="Import OBJ Groups into Blender Objects", default= True), + bpy.props.BoolProperty(attr="SPLIT_MATERIALS", name="Material", description="Import each material into a seperate mesh (Avoids > 16 per mesh error)", default= True), + # old comment: only used for user feedback + # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj + # bpy.props.BoolProperty(attr="KEEP_VERT_ORDER", name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True), + bpy.props.BoolProperty(attr="ROTATE_X90", name="-X90", description="Rotate X 90.", default= True), + bpy.props.FloatProperty(attr="CLAMP_SIZE", name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.01, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0), + bpy.props.BoolProperty(attr="POLYGROUPS", name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True), + bpy.props.BoolProperty(attr="IMAGE_SEARCH", name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True), + ] + + ''' + def poll(self, context): + return True ''' + + def execute(self, context): + # print("Selected: " + context.active_object.name) + + if not self.filename: + raise Exception("filename not set") + + load_obj(self.filename, + context, + self.CLAMP_SIZE, + self.CREATE_FGONS, + self.CREATE_SMOOTH_GROUPS, + self.CREATE_EDGES, + self.SPLIT_OBJECTS, + self.SPLIT_GROUPS, + self.SPLIT_MATERIALS, + self.ROTATE_X90, + self.IMAGE_SEARCH, + self.POLYGROUPS) + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + + +bpy.ops.add(IMPORT_OT_obj) + + +# NOTES (all line numbers refer to 2.4x import_obj.py, not this file) +# check later: line 489 +# can convert now: edge flags, edges: lines 508-528 +# ngon (uses python module BPyMesh): 384-414 +# nurbs: 947- +# NEXT clamp size: get bound box with RNA +# get back to l 140 (here) +# search image in bpy.config.textureDir - load_image +# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load) +# bitmask won't work? - 132 +# uses operator bpy.ops.OBJECT_OT_select_all_toggle() to deselect all (not necessary?) +# uses bpy.sys.time() diff --git a/release/scripts/io/netrender/__init__.py b/release/scripts/io/netrender/__init__.py new file mode 100644 index 00000000000..4a1dd2238e3 --- /dev/null +++ b/release/scripts/io/netrender/__init__.py @@ -0,0 +1,19 @@ +# This directory is a Python package. + +import model +import operators +import client +import slave +import master +import master_html +import utils +import balancing +import ui + +# store temp data in bpy module + +import bpy + +bpy.data.netrender_jobs = [] +bpy.data.netrender_slaves = [] +bpy.data.netrender_blacklist = [] \ No newline at end of file diff --git a/release/scripts/io/netrender/balancing.py b/release/scripts/io/netrender/balancing.py new file mode 100644 index 00000000000..637dd5ff92e --- /dev/null +++ b/release/scripts/io/netrender/balancing.py @@ -0,0 +1,94 @@ +import time + +from netrender.utils import * +import netrender.model + +class RatingRule: + def rate(self, job): + return 0 + +class ExclusionRule: + def test(self, job): + return False + +class PriorityRule: + def test(self, job): + return False + +class Balancer: + def __init__(self): + self.rules = [] + self.priorities = [] + self.exceptions = [] + + def addRule(self, rule): + self.rules.append(rule) + + def addPriority(self, priority): + self.priorities.append(priority) + + def addException(self, exception): + self.exceptions.append(exception) + + def applyRules(self, job): + return sum((rule.rate(job) for rule in self.rules)) + + def applyPriorities(self, job): + for priority in self.priorities: + if priority.test(job): + return True # priorities are first + + return False + + def applyExceptions(self, job): + for exception in self.exceptions: + if exception.test(job): + return True # exceptions are last + + return False + + def sortKey(self, job): + return (1 if self.applyExceptions(job) else 0, # exceptions after + 0 if self.applyPriorities(job) else 1, # priorities first + self.applyRules(job)) + + def balance(self, jobs): + if jobs: + jobs.sort(key=self.sortKey) + return jobs[0] + else: + return None + +# ========================== + +class RatingUsage(RatingRule): + def rate(self, job): + # less usage is better + return job.usage / job.priority + +class NewJobPriority(PriorityRule): + def __init__(self, limit = 1): + self.limit = limit + + def test(self, job): + return job.countFrames(status = DONE) < self.limit + +class MinimumTimeBetweenDispatchPriority(PriorityRule): + def __init__(self, limit = 10): + self.limit = limit + + def test(self, job): + return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit + +class ExcludeQueuedEmptyJob(ExclusionRule): + def test(self, job): + return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0 + +class ExcludeSlavesLimit(ExclusionRule): + def __init__(self, count_jobs, count_slaves, limit = 0.75): + self.count_jobs = count_jobs + self.count_slaves = count_slaves + self.limit = limit + + def test(self, job): + return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit ) diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py new file mode 100644 index 00000000000..65b2937867f --- /dev/null +++ b/release/scripts/io/netrender/client.py @@ -0,0 +1,203 @@ +import bpy +import sys, os, re +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +import netrender.slave as slave +import netrender.master as master +from netrender.utils import * + + +def clientSendJob(conn, scene, anim = False, chunks = 5): + netsettings = scene.network_render + job = netrender.model.RenderJob() + + if anim: + for f in range(scene.start_frame, scene.end_frame + 1): + job.addFrame(f) + else: + job.addFrame(scene.current_frame) + + filename = bpy.data.filename + job.addFile(filename) + + job_name = netsettings.job_name + path, name = os.path.split(filename) + if job_name == "[default]": + job_name = name + + ########################### + # LIBRARIES + ########################### + for lib in bpy.data.libraries: + lib_path = lib.filename + + if lib_path.startswith("//"): + lib_path = path + os.sep + lib_path[2:] + + job.addFile(lib_path) + + ########################### + # POINT CACHES + ########################### + + root, ext = os.path.splitext(name) + cache_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that + + if os.path.exists(cache_path): + caches = {} + pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)_[0-9]+\.bphys") + for cache_file in sorted(os.listdir(cache_path)): + match = pattern.match(cache_file) + + if match: + cache_id = match.groups()[0] + cache_frame = int(match.groups()[1]) + + cache_files = caches.get(cache_id, []) + cache_files.append((cache_frame, cache_file)) + caches[cache_id] = cache_files + + for cache in caches.values(): + cache.sort() + + if len(cache) == 1: + cache_frame, cache_file = cache[0] + job.addFile(cache_path + cache_file, cache_frame, cache_frame) + else: + for i in range(len(cache)): + current_item = cache[i] + next_item = cache[i+1] if i + 1 < len(cache) else None + previous_item = cache[i - 1] if i > 0 else None + + current_frame, current_file = current_item + + if not next_item and not previous_item: + job.addFile(cache_path + current_file, current_frame, current_frame) + elif next_item and not previous_item: + next_frame = next_item[0] + job.addFile(cache_path + current_file, current_frame, next_frame - 1) + elif not next_item and previous_item: + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, current_frame) + else: + next_frame = next_item[0] + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) + + ########################### + # IMAGES + ########################### + for image in bpy.data.images: + if image.source == "FILE" and not image.packed_file: + job.addFile(image.filename) + + # print(job.files) + + job.name = job_name + + for slave in scene.network_render.slaves_blacklist: + job.blacklist.append(slave.id) + + job.chunks = netsettings.chunks + job.priority = netsettings.priority + + # try to send path first + conn.request("POST", "/job", repr(job.serialize())) + response = conn.getresponse() + + job_id = response.getheader("job-id") + + # if not ACCEPTED (but not processed), send files + if response.status == http.client.ACCEPTED: + for filepath, start, end in job.files: + f = open(filepath, "rb") + conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath}) + f.close() + response = conn.getresponse() + + # server will reply with NOT_FOUD until all files are found + + return job_id + +def requestResult(conn, job_id, frame): + conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)}) + +@rnaType +class NetworkRenderEngine(bpy.types.RenderEngine): + __idname__ = 'NET_RENDER' + __label__ = "Network Render" + def render(self, scene): + if scene.network_render.mode == "RENDER_CLIENT": + self.render_client(scene) + elif scene.network_render.mode == "RENDER_SLAVE": + self.render_slave(scene) + elif scene.network_render.mode == "RENDER_MASTER": + self.render_master(scene) + else: + print("UNKNOWN OPERATION MODE") + + def render_master(self, scene): + netsettings = scene.network_render + + address = "" if netsettings.server_address == "[default]" else netsettings.server_address + + master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break) + + + def render_slave(self, scene): + slave.render_slave(self, scene) + + def render_client(self, scene): + netsettings = scene.network_render + self.update_stats("", "Network render client initiation") + + + conn = clientConnection(scene) + + if conn: + # Sending file + + self.update_stats("", "Network render exporting") + + job_id = netsettings.job_id + + # reading back result + + self.update_stats("", "Network render waiting for results") + + requestResult(conn, job_id, scene.current_frame) + response = conn.getresponse() + + if response.status == http.client.NO_CONTENT: + netsettings.job_id = clientSendJob(conn, scene) + requestResult(conn, job_id, scene.current_frame) + + while response.status == http.client.ACCEPTED and not self.test_break(): + time.sleep(1) + requestResult(conn, job_id, scene.current_frame) + response = conn.getresponse() + + if response.status != http.client.OK: + conn.close() + return + + r = scene.render_data + x= int(r.resolution_x*r.resolution_percentage*0.01) + y= int(r.resolution_y*r.resolution_percentage*0.01) + + f = open(netsettings.path + "output.exr", "wb") + buf = response.read(1024) + + while buf: + f.write(buf) + buf = response.read(1024) + + f.close() + + result = self.begin_result(0, 0, x, y) + result.load_from_file(netsettings.path + "output.exr", 0, 0) + self.end_result(result) + + conn.close() + diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py new file mode 100644 index 00000000000..a3e186a9cfd --- /dev/null +++ b/release/scripts/io/netrender/master.py @@ -0,0 +1,752 @@ +import sys, os +import http, http.client, http.server, urllib, socket +import subprocess, shutil, time, hashlib + +from netrender.utils import * +import netrender.model +import netrender.balancing +import netrender.master_html + +class MRenderFile: + def __init__(self, filepath, start, end): + self.filepath = filepath + self.start = start + self.end = end + self.found = False + + def test(self): + self.found = os.path.exists(self.filepath) + return self.found + + +class MRenderSlave(netrender.model.RenderSlave): + def __init__(self, name, address, stats): + super().__init__() + self.id = hashlib.md5(bytes(repr(name) + repr(address), encoding='utf8')).hexdigest() + self.name = name + self.address = address + self.stats = stats + self.last_seen = time.time() + + self.job = None + self.job_frames = [] + + netrender.model.RenderSlave._slave_map[self.id] = self + + def seen(self): + self.last_seen = time.time() + + def finishedFrame(self, frame_number): + self.job_frames.remove(frame_number) + if not self.job_frames: + self.job = None + +class MRenderJob(netrender.model.RenderJob): + def __init__(self, job_id, name, files, chunks = 1, priority = 1, blacklist = []): + super().__init__() + self.id = job_id + self.name = name + self.files = files + self.frames = [] + self.chunks = chunks + self.priority = priority + self.usage = 0.0 + self.blacklist = blacklist + self.last_dispatched = time.time() + + # special server properties + self.last_update = 0 + self.save_path = "" + self.files_map = {path: MRenderFile(path, start, end) for path, start, end in files} + self.status = JOB_WAITING + + def save(self): + if self.save_path: + f = open(self.save_path + "job.txt", "w") + f.write(repr(self.serialize())) + f.close() + + def testStart(self): + for f in self.files_map.values(): + if not f.test(): + return False + + self.start() + return True + + def testFinished(self): + for f in self.frames: + if f.status == QUEUED or f.status == DISPATCHED: + break + else: + self.status = JOB_FINISHED + + def start(self): + self.status = JOB_QUEUED + + def addLog(self, frames): + log_name = "_".join(("%04d" % f for f in frames)) + ".log" + log_path = self.save_path + log_name + + for number in frames: + frame = self[number] + if frame: + frame.log_path = log_path + + def addFrame(self, frame_number): + frame = MRenderFrame(frame_number) + self.frames.append(frame) + return frame + + def reset(self, all): + for f in self.frames: + f.reset(all) + + def getFrames(self): + frames = [] + for f in self.frames: + if f.status == QUEUED: + self.last_dispatched = time.time() + frames.append(f) + if len(frames) >= self.chunks: + break + + return frames + +class MRenderFrame(netrender.model.RenderFrame): + def __init__(self, frame): + super().__init__() + self.number = frame + self.slave = None + self.time = 0 + self.status = QUEUED + self.log_path = None + + def reset(self, all): + if all or self.status == ERROR: + self.slave = None + self.time = 0 + self.status = QUEUED + + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +class RenderHandler(http.server.BaseHTTPRequestHandler): + def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"): + self.send_response(code) + self.send_header("Content-type", content) + + for key, value in headers.items(): + self.send_header(key, value) + + self.end_headers() + + def do_HEAD(self): + + if self.path == "/status": + job_id = self.headers.get('job-id', "") + job_frame = int(self.headers.get('job-frame', -1)) + + job = self.server.getJobID(job_id) + if job: + frame = job[job_frame] + + + if frame: + self.send_head(http.client.OK) + else: + # no such frame + self.send_head(http.client.NO_CONTENT) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + def do_GET(self): + + if self.path == "/version": + self.send_head() + self.server.stats("", "Version check") + self.wfile.write(VERSION) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/render": + job_id = self.headers['job-id'] + job_frame = int(self.headers['job-frame']) + + job = self.server.getJobID(job_id) + + if job: + frame = job[job_frame] + + if frame: + if frame.status in (QUEUED, DISPATCHED): + self.send_head(http.client.ACCEPTED) + elif frame.status == DONE: + self.server.stats("", "Sending result to client") + f = open(job.save_path + "%04d" % job_frame + ".exr", 'rb') + + self.send_head() + + shutil.copyfileobj(f, self.wfile) + + f.close() + elif frame.status == ERROR: + self.send_head(http.client.PARTIAL_CONTENT) + else: + # no such frame + self.send_head(http.client.NO_CONTENT) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/log": + job_id = self.headers['job-id'] + job_frame = int(self.headers['job-frame']) + + job = self.server.getJobID(job_id) + + if job: + frame = job[job_frame] + + if frame: + if not frame.log_path or frame.status in (QUEUED, DISPATCHED): + self.send_head(http.client.PROCESSING) + else: + self.server.stats("", "Sending log to client") + f = open(frame.log_path, 'rb') + + self.send_head() + + shutil.copyfileobj(f, self.wfile) + + f.close() + else: + # no such frame + self.send_head(http.client.NO_CONTENT) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/status": + job_id = self.headers.get('job-id', "") + job_frame = int(self.headers.get('job-frame', -1)) + + if job_id: + + job = self.server.getJobID(job_id) + if job: + if job_frame != -1: + frame = job[frame] + + if frame: + message = frame.serialize() + else: + # no such frame + self.send_heat(http.client.NO_CONTENT) + return + else: + message = job.serialize() + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + return + else: # status of all jobs + message = [] + + for job in self.server: + message.append(job.serialize()) + + + self.server.stats("", "Sending status") + self.send_head() + self.wfile.write(bytes(repr(message), encoding='utf8')) + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/job": + self.server.balance() + + slave_id = self.headers['slave-id'] + + slave = self.server.getSeenSlave(slave_id) + + if slave: # only if slave id is valid + job, frames = self.server.newDispatch(slave_id) + + if job and frames: + for f in frames: + print("dispatch", f.number) + f.status = DISPATCHED + f.slave = slave + + slave.job = job + slave.job_frames = [f.number for f in frames] + + self.send_head(headers={"job-id": job.id}) + + message = job.serialize(frames) + + self.wfile.write(bytes(repr(message), encoding='utf8')) + + self.server.stats("", "Sending job to slave") + else: + # no job available, return error code + slave.job = None + slave.job_frames = [] + + self.send_head(http.client.ACCEPTED) + else: # invalid slave id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/file": + slave_id = self.headers['slave-id'] + + slave = self.server.getSeenSlave(slave_id) + + if slave: # only if slave id is valid + job_id = self.headers['job-id'] + job_file = self.headers['job-file'] + + job = self.server.getJobID(job_id) + + if job: + render_file = job.files_map.get(job_file, None) + + if render_file: + self.server.stats("", "Sending file to slave") + f = open(render_file.filepath, 'rb') + + self.send_head() + shutil.copyfileobj(f, self.wfile) + + f.close() + else: + # no such file + self.send_head(http.client.NO_CONTENT) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + else: # invalid slave id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/slaves": + message = [] + + self.server.stats("", "Sending slaves status") + + for slave in self.server.slaves: + message.append(slave.serialize()) + + self.send_head() + + self.wfile.write(bytes(repr(message), encoding='utf8')) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + else: + # hand over the rest to the html section + netrender.master_html.get(self) + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + def do_POST(self): + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + if self.path == "/job": + + length = int(self.headers['content-length']) + + job_info = netrender.model.RenderJob.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) + + job_id = self.server.nextJobID() + + job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist) + + for frame in job_info.frames: + frame = job.addFrame(frame.number) + + self.server.addJob(job) + + headers={"job-id": job_id} + + if job.testStart(): + self.server.stats("", "New job, missing files") + self.send_head(headers=headers) + else: + self.server.stats("", "New job, started") + self.send_head(http.client.ACCEPTED, headers=headers) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/cancel": + job_id = self.headers.get('job-id', "") + + job = self.server.getJobID(job_id) + + if job: + self.server.stats("", "Cancelling job") + self.server.removeJob(job) + self.send_head() + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/clear": + # cancel all jobs + self.server.stats("", "Clearing jobs") + self.server.clear() + + self.send_head() + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/reset": + job_id = self.headers.get('job-id', "") + job_frame = int(self.headers.get('job-frame', "-1")) + all = bool(self.headers.get('reset-all', "False")) + + job = self.server.getJobID(job_id) + + if job: + if job_frame != -1: + + frame = job[job_frame] + if frame: + self.server.stats("", "Reset job frame") + frame.reset(all) + self.send_head() + else: + # no such frame + self.send_head(http.client.NO_CONTENT) + + else: + self.server.stats("", "Reset job") + job.reset(all) + self.send_head() + + else: # job not found + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/slave": + length = int(self.headers['content-length']) + job_frame_string = self.headers['job-frame'] + + self.server.stats("", "New slave connected") + + slave_info = netrender.model.RenderSlave.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) + + slave_id = self.server.addSlave(slave_info.name, self.client_address, slave_info.stats) + + self.send_head(headers = {"slave-id": slave_id}) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/log": + slave_id = self.headers['slave-id'] + + slave = self.server.getSeenSlave(slave_id) + + if slave: # only if slave id is valid + length = int(self.headers['content-length']) + + log_info = netrender.model.LogFile.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) + + job = self.server.getJobID(log_info.job_id) + + if job: + self.server.stats("", "Log announcement") + job.addLog(log_info.frames) + self.send_head(http.client.OK) + else: + # no such job id + self.send_head(http.client.NO_CONTENT) + else: # invalid slave id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + def do_PUT(self): + + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + if self.path == "/file": + self.server.stats("", "Receiving job") + + length = int(self.headers['content-length']) + job_id = self.headers['job-id'] + job_file = self.headers['job-file'] + + job = self.server.getJobID(job_id) + + if job: + + render_file = job.files_map.get(job_file, None) + + if render_file: + main_file = job.files[0][0] # filename of the first file + + main_path, main_name = os.path.split(main_file) + + if job_file != main_file: + file_path = prefixPath(job.save_path, job_file, main_path) + else: + file_path = job.save_path + main_name + + buf = self.rfile.read(length) + + # add same temp file + renames as slave + + f = open(file_path, "wb") + f.write(buf) + f.close() + del buf + + render_file.filepath = file_path # set the new path + + if job.testStart(): + self.server.stats("", "File upload, starting job") + self.send_head(http.client.OK) + else: + self.server.stats("", "File upload, file missings") + self.send_head(http.client.ACCEPTED) + else: # invalid file + self.send_head(http.client.NO_CONTENT) + else: # job not found + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/render": + self.server.stats("", "Receiving render result") + + slave_id = self.headers['slave-id'] + + slave = self.server.getSeenSlave(slave_id) + + if slave: # only if slave id is valid + job_id = self.headers['job-id'] + + job = self.server.getJobID(job_id) + + if job: + job_frame = int(self.headers['job-frame']) + job_result = int(self.headers['job-result']) + job_time = float(self.headers['job-time']) + + frame = job[job_frame] + + if frame: + if job_result == DONE: + length = int(self.headers['content-length']) + buf = self.rfile.read(length) + f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb') + f.write(buf) + f.close() + + del buf + elif job_result == ERROR: + # blacklist slave on this job on error + job.blacklist.append(slave.id) + + self.server.stats("", "Receiving result") + + slave.finishedFrame(job_frame) + + frame.status = job_result + frame.time = job_time + + job.testFinished() + + self.send_head() + else: # frame not found + self.send_head(http.client.NO_CONTENT) + else: # job not found + self.send_head(http.client.NO_CONTENT) + else: # invalid slave id + self.send_head(http.client.NO_CONTENT) + # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + elif self.path == "/log": + self.server.stats("", "Receiving log file") + + job_id = self.headers['job-id'] + + job = self.server.getJobID(job_id) + + if job: + job_frame = int(self.headers['job-frame']) + + frame = job[job_frame] + + if frame and frame.log_path: + length = int(self.headers['content-length']) + buf = self.rfile.read(length) + f = open(frame.log_path, 'ab') + f.write(buf) + f.close() + + del buf + + self.server.getSeenSlave(self.headers['slave-id']) + + self.send_head() + else: # frame not found + self.send_head(http.client.NO_CONTENT) + else: # job not found + self.send_head(http.client.NO_CONTENT) + +class RenderMasterServer(http.server.HTTPServer): + def __init__(self, address, handler_class, path): + super().__init__(address, handler_class) + self.jobs = [] + self.jobs_map = {} + self.slaves = [] + self.slaves_map = {} + self.job_id = 0 + self.path = path + "master_" + str(os.getpid()) + os.sep + + self.slave_timeout = 2 + + self.balancer = netrender.balancing.Balancer() + self.balancer.addRule(netrender.balancing.RatingUsage()) + self.balancer.addException(netrender.balancing.ExcludeQueuedEmptyJob()) + self.balancer.addException(netrender.balancing.ExcludeSlavesLimit(self.countJobs, self.countSlaves, limit = 0.9)) + self.balancer.addPriority(netrender.balancing.NewJobPriority()) + self.balancer.addPriority(netrender.balancing.MinimumTimeBetweenDispatchPriority(limit = 2)) + + if not os.path.exists(self.path): + os.mkdir(self.path) + + def nextJobID(self): + self.job_id += 1 + return str(self.job_id) + + def addSlave(self, name, address, stats): + slave = MRenderSlave(name, address, stats) + self.slaves.append(slave) + self.slaves_map[slave.id] = slave + + return slave.id + + def removeSlave(self, slave): + self.slaves.remove(slave) + self.slaves_map.pop(slave.id) + + def getSlave(self, slave_id): + return self.slaves_map.get(slave_id, None) + + def getSeenSlave(self, slave_id): + slave = self.getSlave(slave_id) + if slave: + slave.seen() + + return slave + + def timeoutSlaves(self): + removed = [] + + t = time.time() + + for slave in self.slaves: + if (t - slave.last_seen) / 60 > self.slave_timeout: + removed.append(slave) + + if slave.job: + for f in slave.job_frames: + slave.job[f].status = ERROR + + for slave in removed: + self.removeSlave(slave) + + def updateUsage(self): + blend = 0.5 + for job in self.jobs: + job.usage *= (1 - blend) + + if self.slaves: + slave_usage = blend / self.countSlaves() + + for slave in self.slaves: + if slave.job: + slave.job.usage += slave_usage + + + def clear(self): + removed = self.jobs[:] + + for job in removed: + self.removeJob(job) + + def balance(self): + self.balancer.balance(self.jobs) + + def countJobs(self, status = JOB_QUEUED): + total = 0 + for j in self.jobs: + if j.status == status: + total += 1 + + return total + + def countSlaves(self): + return len(self.slaves) + + def removeJob(self, job): + self.jobs.remove(job) + self.jobs_map.pop(job.id) + + for slave in self.slaves: + if slave.job == job: + slave.job = None + slave.job_frames = [] + + def addJob(self, job): + self.jobs.append(job) + self.jobs_map[job.id] = job + + # create job directory + job.save_path = self.path + "job_" + job.id + os.sep + if not os.path.exists(job.save_path): + os.mkdir(job.save_path) + + job.save() + + def getJobID(self, id): + return self.jobs_map.get(id, None) + + def __iter__(self): + for job in self.jobs: + yield job + + def newDispatch(self, slave_id): + if self.jobs: + for job in self.jobs: + if not self.balancer.applyExceptions(job) and slave_id not in job.blacklist: + return job, job.getFrames() + + return None, None + +def runMaster(address, broadcast, path, update_stats, test_break): + httpd = RenderMasterServer(address, RenderHandler, path) + httpd.timeout = 1 + httpd.stats = update_stats + + if broadcast: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + start_time = time.time() + + while not test_break(): + httpd.handle_request() + + if time.time() - start_time >= 10: # need constant here + httpd.timeoutSlaves() + + httpd.updateUsage() + + if broadcast: + print("broadcasting address") + s.sendto(bytes("%i" % address[1], encoding='utf8'), 0, ('', 8000)) + start_time = time.time() diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py new file mode 100644 index 00000000000..6a956a70e9f --- /dev/null +++ b/release/scripts/io/netrender/master_html.py @@ -0,0 +1,142 @@ +import re + +from netrender.utils import * + + +def get(handler): + def output(text): + handler.wfile.write(bytes(text, encoding='utf8')) + + def link(text, url): + return "%s" % (url, text) + + def startTable(border=1): + output("" % border) + + def headerTable(*headers): + output("") + + for c in headers: + output("") + + output("") + + def rowTable(*data): + output("") + + for c in data: + output("") + + output("") + + def endTable(): + output("
" + c + "
" + str(c) + "
") + + handler.send_head(content = "text/html") + + if handler.path == "/html" or handler.path == "/": + output("NetRender") + + output("

Master

") + + output("

Slaves

") + + startTable() + headerTable("name", "address", "last seen", "stats", "job") + + for slave in handler.server.slaves: + rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None") + + endTable() + + output("

Jobs

") + + startTable() + headerTable( + "name", + "priority", + "usage", + "wait", + "length", + "done", + "dispatched", + "error", + "first", + "exception" + ) + + handler.server.balance() + + for job in handler.server.jobs: + results = job.framesStatus() + rowTable( + link(job.name, "/html/job" + job.id), + job.priority, + "%0.1f%%" % (job.usage * 100), + "%is" % int(time.time() - job.last_dispatched), + len(job), + results[DONE], + results[DISPATCHED], + results[ERROR], + handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job) + ) + + endTable() + + output("") + + elif handler.path.startswith("/html/job"): + job_id = handler.path[9:] + + output("NetRender") + + job = handler.server.getJobID(job_id) + + if job: + output("

Frames

") + + startTable() + headerTable("no", "status", "render time", "slave", "log") + + for frame in job.frames: + rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else " ", link("view log", "/html/log%s_%i" % (job_id, frame.number)) if frame.log_path else " ") + + endTable() + else: + output("no such job") + + output("") + + elif handler.path.startswith("/html/log"): + pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)") + + output("NetRender") + + match = pattern.match(handler.path[9:]) + if match: + job_id = match.groups()[0] + frame_number = int(match.groups()[1]) + + job = handler.server.getJobID(job_id) + + if job: + frame = job[frame_number] + + if frame: + f = open(frame.log_path, 'rb') + + output("
")
+						
+						shutil.copyfileobj(f, handler.wfile)
+						
+						output("
") + + f.close() + else: + output("no such frame") + else: + output("no such job") + else: + output("malformed url") + + output("") diff --git a/release/scripts/io/netrender/model.py b/release/scripts/io/netrender/model.py new file mode 100644 index 00000000000..be97f8d0a81 --- /dev/null +++ b/release/scripts/io/netrender/model.py @@ -0,0 +1,198 @@ +import sys, os +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +from netrender.utils import * + +class LogFile: + def __init__(self, job_id = 0, frames = []): + self.job_id = job_id + self.frames = frames + + def serialize(self): + return { + "job_id": self.job_id, + "frames": self.frames + } + + @staticmethod + def materialize(data): + if not data: + return None + + logfile = LogFile() + logfile.job_id = data["job_id"] + logfile.frames = data["frames"] + + return logfile + +class RenderSlave: + _slave_map = {} + + def __init__(self): + self.id = "" + self.name = "" + self.address = ("",0) + self.stats = "" + self.total_done = 0 + self.total_error = 0 + self.last_seen = 0.0 + + def serialize(self): + return { + "id": self.id, + "name": self.name, + "address": self.address, + "stats": self.stats, + "total_done": self.total_done, + "total_error": self.total_error, + "last_seen": self.last_seen + } + + @staticmethod + def materialize(data): + if not data: + return None + + slave_id = data["id"] + + if slave_id in RenderSlave._slave_map: + return RenderSlave._slave_map[slave_id] + else: + slave = RenderSlave() + slave.id = slave_id + slave.name = data["name"] + slave.address = data["address"] + slave.stats = data["stats"] + slave.total_done = data["total_done"] + slave.total_error = data["total_error"] + slave.last_seen = data["last_seen"] + + RenderSlave._slave_map[slave_id] = slave + + return slave + +class RenderJob: + def __init__(self): + self.id = "" + self.name = "" + self.files = [] + self.frames = [] + self.chunks = 0 + self.priority = 0 + self.usage = 0.0 + self.blacklist = [] + self.last_dispatched = 0.0 + + def addFile(self, file_path, start=-1, end=-1): + self.files.append((file_path, start, end)) + + def addFrame(self, frame_number): + frame = RenderFrame(frame_number) + self.frames.append(frame) + return frame + + def __len__(self): + return len(self.frames) + + def countFrames(self, status=QUEUED): + total = 0 + for f in self.frames: + if f.status == status: + total += 1 + + return total + + def countSlaves(self): + return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED))) + + def framesStatus(self): + results = { + QUEUED: 0, + DISPATCHED: 0, + DONE: 0, + ERROR: 0 + } + + for frame in self.frames: + results[frame.status] += 1 + + return results + + def __contains__(self, frame_number): + for f in self.frames: + if f.number == frame_number: + return True + else: + return False + + def __getitem__(self, frame_number): + for f in self.frames: + if f.number == frame_number: + return f + else: + return None + + def serialize(self, frames = None): + min_frame = min((f.number for f in frames)) if frames else -1 + max_frame = max((f.number for f in frames)) if frames else -1 + return { + "id": self.id, + "name": self.name, + "files": [f for f in self.files if f[1] == -1 or not frames or (f[1] <= min_frame <= f[2] or f[1] <= max_frame <= f[2])], + "frames": [f.serialize() for f in self.frames if not frames or f in frames], + "chunks": self.chunks, + "priority": self.priority, + "usage": self.usage, + "blacklist": self.blacklist, + "last_dispatched": self.last_dispatched + } + + @staticmethod + def materialize(data): + if not data: + return None + + job = RenderJob() + job.id = data["id"] + job.name = data["name"] + job.files = data["files"] + job.frames = [RenderFrame.materialize(f) for f in data["frames"]] + job.chunks = data["chunks"] + job.priority = data["priority"] + job.usage = data["usage"] + job.blacklist = data["blacklist"] + job.last_dispatched = data["last_dispatched"] + + return job + +class RenderFrame: + def __init__(self, number = 0): + self.number = number + self.time = 0 + self.status = QUEUED + self.slave = None + + def statusText(self): + return STATUS_TEXT[self.status] + + def serialize(self): + return { + "number": self.number, + "time": self.time, + "status": self.status, + "slave": None if not self.slave else self.slave.serialize() + } + + @staticmethod + def materialize(data): + if not data: + return None + + frame = RenderFrame() + frame.number = data["number"] + frame.time = data["time"] + frame.status = data["status"] + frame.slave = RenderSlave.materialize(data["slave"]) + + return frame diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py new file mode 100644 index 00000000000..42d1f6a0b86 --- /dev/null +++ b/release/scripts/io/netrender/operators.py @@ -0,0 +1,423 @@ +import bpy +import sys, os +import http, http.client, http.server, urllib, socket +import webbrowser + +from netrender.utils import * +import netrender.client as client +import netrender.model + +@rnaOperator +class RENDER_OT_netclientanim(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "render.netclientanim" + __label__ = "Net Render Client Anim" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + scene = context.scene + + conn = clientConnection(scene) + + if conn: + # Sending file + scene.network_render.job_id = client.clientSendJob(conn, scene, True) + conn.close() + + bpy.ops.screen.render('INVOKE_AREA', animation=True) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientsend(bpy.types.Operator): + ''' + Operator documentation text, will be used for the operator tooltip and python docs. + ''' + __idname__ = "render.netclientsend" + __label__ = "Net Render Client Send" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + scene = context.scene + + conn = clientConnection(scene) + + if conn: + # Sending file + scene.network_render.job_id = client.clientSendJob(conn, scene, True) + conn.close() + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientstatus(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientstatus" + __label__ = "Net Render Client Status" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + conn = clientConnection(context.scene) + + if conn: + conn.request("GET", "/status") + + response = conn.getresponse() + print( response.status, response.reason ) + + jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8'))) + + while(len(netsettings.jobs) > 0): + netsettings.jobs.remove(0) + + bpy.data.netrender_jobs = [] + + for j in jobs: + bpy.data.netrender_jobs.append(j) + netsettings.jobs.add() + job = netsettings.jobs[-1] + + j.results = j.framesStatus() # cache frame status + + job.name = j.name + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientblacklistslave(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientblacklistslave" + __label__ = "Net Render Client Blacklist Slave" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + if netsettings.active_slave_index >= 0: + + # deal with data + slave = bpy.data.netrender_slaves.pop(netsettings.active_slave_index) + bpy.data.netrender_blacklist.append(slave) + + # deal with rna + netsettings.slaves_blacklist.add() + netsettings.slaves_blacklist[-1].name = slave.name + + netsettings.slaves.remove(netsettings.active_slave_index) + netsettings.active_slave_index = -1 + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientwhitelistslave" + __label__ = "Net Render Client Whitelist Slave" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + if netsettings.active_blacklisted_slave_index >= 0: + + # deal with data + slave = bpy.data.netrender_blacklist.pop(netsettings.active_blacklisted_slave_index) + bpy.data.netrender_slaves.append(slave) + + # deal with rna + netsettings.slaves.add() + netsettings.slaves[-1].name = slave.name + + netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index) + netsettings.active_blacklisted_slave_index = -1 + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + + +@rnaOperator +class RENDER_OT_netclientslaves(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientslaves" + __label__ = "Net Render Client Slaves" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + conn = clientConnection(context.scene) + + if conn: + conn.request("GET", "/slaves") + + response = conn.getresponse() + print( response.status, response.reason ) + + slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8'))) + + while(len(netsettings.slaves) > 0): + netsettings.slaves.remove(0) + + bpy.data.netrender_slaves = [] + + for s in slaves: + for i in range(len(bpy.data.netrender_blacklist)): + slave = bpy.data.netrender_blacklist[i] + if slave.id == s.id: + bpy.data.netrender_blacklist[i] = s + netsettings.slaves_blacklist[i].name = s.name + break + else: + bpy.data.netrender_slaves.append(s) + + netsettings.slaves.add() + slave = netsettings.slaves[-1] + slave.name = s.name + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientcancel(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientcancel" + __label__ = "Net Render Client Cancel" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + netsettings = context.scene.network_render + return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 + + def execute(self, context): + netsettings = context.scene.network_render + conn = clientConnection(context.scene) + + if conn: + job = bpy.data.netrender_jobs[netsettings.active_job_index] + + conn.request("POST", "/cancel", headers={"job-id":job.id}) + + response = conn.getresponse() + print( response.status, response.reason ) + + netsettings.jobs.remove(netsettings.active_job_index) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class RENDER_OT_netclientcancelall(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientcancelall" + __label__ = "Net Render Client Cancel All" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + conn = clientConnection(context.scene) + + if conn: + conn.request("POST", "/clear") + + response = conn.getresponse() + print( response.status, response.reason ) + + while(len(netsettings.jobs) > 0): + netsettings.jobs.remove(0) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class netclientdownload(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientdownload" + __label__ = "Net Render Client Download" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + netsettings = context.scene.network_render + return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 + + def execute(self, context): + netsettings = context.scene.network_render + rd = context.scene.render_data + + conn = clientConnection(context.scene) + + if conn: + job = bpy.data.netrender_jobs[netsettings.active_job_index] + + for frame in job.frames: + client.requestResult(conn, job.id, frame.number) + response = conn.getresponse() + + if response.status != http.client.OK: + print("missing", frame.number) + continue + + print("got back", frame.number) + + f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb") + buf = response.read(1024) + + while buf: + f.write(buf) + buf = response.read(1024) + + f.close() + + conn.close() + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class netclientscan(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientscan" + __label__ = "Net Render Client Scan" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.settimeout(30) + + s.bind(('', 8000)) + + buf, address = s.recvfrom(64) + + print("received:", buf) + + netsettings.server_address = address[0] + netsettings.server_port = int(str(buf, encoding='utf8')) + except socket.timeout: + print("no server info") + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) + +@rnaOperator +class netclientweb(bpy.types.Operator): + '''Operator documentation text, will be used for the operator tooltip and python docs.''' + __idname__ = "render.netclientweb" + __label__ = "Net Render Client Web" + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + __props__ = [] + + def poll(self, context): + return True + + def execute(self, context): + netsettings = context.scene.network_render + + + # open connection to make sure server exists + conn = clientConnection(context.scene) + + if conn: + conn.close() + + webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port)) + + return ('FINISHED',) + + def invoke(self, context, event): + return self.execute(context) diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py new file mode 100644 index 00000000000..657e31001e0 --- /dev/null +++ b/release/scripts/io/netrender/slave.py @@ -0,0 +1,207 @@ +import sys, os, platform +import http, http.client, http.server, urllib +import subprocess, time + +from netrender.utils import * +import netrender.model + +CANCEL_POLL_SPEED = 2 +MAX_TIMEOUT = 10 +INCREMENT_TIMEOUT = 1 + +if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5 + import ctypes + def SetErrorMode(): + val = ctypes.windll.kernel32.SetErrorMode(0x0002) + ctypes.windll.kernel32.SetErrorMode(val | 0x0002) + return val + + def RestoreErrorMode(val): + ctypes.windll.kernel32.SetErrorMode(val) +else: + def SetErrorMode(): + return 0 + + def RestoreErrorMode(val): + pass + +def slave_Info(): + sysname, nodename, release, version, machine, processor = platform.uname() + slave = netrender.model.RenderSlave() + slave.name = nodename + slave.stats = sysname + " " + release + " " + machine + " " + processor + return slave + +def testCancel(conn, job_id, frame_number): + conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) + response = conn.getresponse() + + # cancelled if job isn't found anymore + if response.status == http.client.NO_CONTENT: + return True + else: + return False + +def testFile(conn, job_id, slave_id, JOB_PREFIX, file_path, main_path = None): + job_full_path = prefixPath(JOB_PREFIX, file_path, main_path) + + if not os.path.exists(job_full_path): + temp_path = JOB_PREFIX + "slave.temp.blend" + conn.request("GET", "/file", headers={"job-id": job_id, "slave-id":slave_id, "job-file":file_path}) + response = conn.getresponse() + + if response.status != http.client.OK: + return None # file for job not returned by server, need to return an error code to server + + f = open(temp_path, "wb") + buf = response.read(1024) + + while buf: + f.write(buf) + buf = response.read(1024) + + f.close() + + os.renames(temp_path, job_full_path) + + return job_full_path + + +def render_slave(engine, scene): + netsettings = scene.network_render + timeout = 1 + + engine.update_stats("", "Network render node initiation") + + conn = clientConnection(scene) + + if conn: + conn.request("POST", "/slave", repr(slave_Info().serialize())) + response = conn.getresponse() + + slave_id = response.getheader("slave-id") + + NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep + if not os.path.exists(NODE_PREFIX): + os.mkdir(NODE_PREFIX) + + while not engine.test_break(): + + conn.request("GET", "/job", headers={"slave-id":slave_id}) + response = conn.getresponse() + + if response.status == http.client.OK: + timeout = 1 # reset timeout on new job + + job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8'))) + + JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep + if not os.path.exists(JOB_PREFIX): + os.mkdir(JOB_PREFIX) + + job_path = job.files[0][0] # data in files have format (path, start, end) + main_path, main_file = os.path.split(job_path) + + job_full_path = testFile(conn, job.id, slave_id, JOB_PREFIX, job_path) + print("Fullpath", job_full_path) + print("File:", main_file, "and %i other files" % (len(job.files) - 1,)) + engine.update_stats("", "Render File", main_file, "for job", job.id) + + for file_path, start, end in job.files[1:]: + print("\t", file_path) + testFile(conn, job.id, slave_id, JOB_PREFIX, file_path, main_path) + + frame_args = [] + + for frame in job.frames: + print("frame", frame.number) + frame_args += ["-f", str(frame.number)] + + # announce log to master + logfile = netrender.model.LogFile(job.id, [frame.number for frame in job.frames]) + conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'), headers={"slave-id":slave_id}) + response = conn.getresponse() + + first_frame = job.frames[0].number + + # start render + start_t = time.time() + + val = SetErrorMode() + process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + RestoreErrorMode(val) + + headers = {"job-id":job.id, "slave-id":slave_id} + + cancelled = False + stdout = bytes() + run_t = time.time() + while process.poll() == None and not cancelled: + stdout += process.stdout.read(32) + current_t = time.time() + cancelled = engine.test_break() + if current_t - run_t > CANCEL_POLL_SPEED: + + # update logs if needed + if stdout: + # (only need to update on one frame, they are linked + headers["job-frame"] = str(first_frame) + conn.request("PUT", "/log", stdout, headers=headers) + response = conn.getresponse() + + stdout = bytes() + + run_t = current_t + if testCancel(conn, job.id, first_frame): + cancelled = True + + if cancelled: + # kill process if needed + if process.poll() == None: + process.terminate() + continue # to next frame + + total_t = time.time() - start_t + + avg_t = total_t / len(job.frames) + + status = process.returncode + + print("status", status) + + # flush the rest of the logs + if stdout: + # (only need to update on one frame, they are linked + headers["job-frame"] = str(first_frame) + conn.request("PUT", "/log", stdout, headers=headers) + response = conn.getresponse() + + headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} + + if status == 0: # non zero status is error + headers["job-result"] = str(DONE) + for frame in job.frames: + headers["job-frame"] = str(frame.number) + # send result back to server + f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') + conn.request("PUT", "/render", f, headers=headers) + f.close() + response = conn.getresponse() + else: + headers["job-result"] = str(ERROR) + for frame in job.frames: + headers["job-frame"] = str(frame.number) + # send error result back to server + conn.request("PUT", "/render", headers=headers) + response = conn.getresponse() + else: + if timeout < MAX_TIMEOUT: + timeout += INCREMENT_TIMEOUT + + for i in range(timeout): + time.sleep(1) + if engine.test_break(): + conn.close() + return + + conn.close() diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py new file mode 100644 index 00000000000..7681d4865e9 --- /dev/null +++ b/release/scripts/io/netrender/ui.py @@ -0,0 +1,321 @@ +import bpy +import sys, os +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +import netrender.slave as slave +import netrender.master as master + +from netrender.utils import * + +VERSION = b"0.3" + +PATH_PREFIX = "/tmp/" + +QUEUED = 0 +DISPATCHED = 1 +DONE = 2 +ERROR = 3 + +class RenderButtonsPanel(bpy.types.Panel): + __space_type__ = "PROPERTIES" + __region_type__ = "WINDOW" + __context__ = "scene" + # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here + + def poll(self, context): + rd = context.scene.render_data + return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) + +# Setting panel, use in the scene for now. +@rnaType +class SCENE_PT_network_settings(RenderButtonsPanel): + __label__ = "Network Settings" + COMPAT_ENGINES = set(['NET_RENDER']) + + def draw_header(self, context): + layout = self.layout + scene = context.scene + + def draw(self, context): + layout = self.layout + + scene = context.scene + rd = scene.render_data + + layout.active = True + + split = layout.split() + + col = split.column() + + col.itemR(scene.network_render, "mode") + col.itemR(scene.network_render, "path") + col.itemR(scene.network_render, "server_address") + col.itemR(scene.network_render, "server_port") + + if scene.network_render.mode == "RENDER_MASTER": + col.itemR(scene.network_render, "server_broadcast") + else: + col.itemO("render.netclientscan", icon="ICON_FILE_REFRESH", text="") + +@rnaType +class SCENE_PT_network_job(RenderButtonsPanel): + __label__ = "Job Settings" + COMPAT_ENGINES = set(['NET_RENDER']) + + def poll(self, context): + scene = context.scene + return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" + + def draw(self, context): + layout = self.layout + + scene = context.scene + rd = scene.render_data + + layout.active = True + + split = layout.split() + + col = split.column() + + col.itemO("render.netclientanim", icon='ICON_RENDER_ANIMATION', text="Animaton on network") + col.itemO("render.netclientsend", icon="ICON_FILE_BLEND", text="Send job") + col.itemO("render.netclientweb", icon="ICON_QUESTION", text="Open Master Monitor") + col.itemR(scene.network_render, "job_name") + col.itemR(scene.network_render, "priority") + col.itemR(scene.network_render, "chunks") + +@rnaType +class SCENE_PT_network_slaves(RenderButtonsPanel): + __label__ = "Slaves Status" + COMPAT_ENGINES = set(['NET_RENDER']) + + def poll(self, context): + scene = context.scene + return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" + + def draw(self, context): + layout = self.layout + + scene = context.scene + netsettings = scene.network_render + + row = layout.row() + row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2) + + col = row.column() + + subcol = col.column(align=True) + subcol.itemO("render.netclientslaves", icon="ICON_FILE_REFRESH", text="") + subcol.itemO("render.netclientblacklistslave", icon="ICON_ZOOMOUT", text="") + + if len(bpy.data.netrender_slaves) == 0 and len(netsettings.slaves) > 0: + while(len(netsettings.slaves) > 0): + netsettings.slaves.remove(0) + + if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0: + layout.itemS() + + slave = bpy.data.netrender_slaves[netsettings.active_slave_index] + + layout.itemL(text="Name: " + slave.name) + layout.itemL(text="Address: " + slave.address[0]) + layout.itemL(text="Seen: " + time.ctime(slave.last_seen)) + layout.itemL(text="Stats: " + slave.stats) + +@rnaType +class SCENE_PT_network_slaves_blacklist(RenderButtonsPanel): + __label__ = "Slaves Blacklist" + COMPAT_ENGINES = set(['NET_RENDER']) + + def poll(self, context): + scene = context.scene + return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" + + def draw(self, context): + layout = self.layout + + scene = context.scene + netsettings = scene.network_render + + row = layout.row() + row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2) + + col = row.column() + + subcol = col.column(align=True) + subcol.itemO("render.netclientwhitelistslave", icon="ICON_ZOOMOUT", text="") + + if len(bpy.data.netrender_blacklist) == 0 and len(netsettings.slaves_blacklist) > 0: + while(len(netsettings.slaves_blacklist) > 0): + netsettings.slaves_blacklist.remove(0) + + if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0: + layout.itemS() + + slave = bpy.data.netrender_blacklist[netsettings.active_blacklisted_slave_index] + + layout.itemL(text="Name: " + slave.name) + layout.itemL(text="Address: " + slave.address[0]) + layout.itemL(text="Seen: " + slave.last_seen) + layout.itemL(text="Stats: " + time.ctime(slave.stats)) + +@rnaType +class SCENE_PT_network_jobs(RenderButtonsPanel): + __label__ = "Jobs" + COMPAT_ENGINES = set(['NET_RENDER']) + + def poll(self, context): + scene = context.scene + return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT" + + def draw(self, context): + layout = self.layout + + scene = context.scene + netsettings = scene.network_render + + row = layout.row() + row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2) + + col = row.column() + + subcol = col.column(align=True) + subcol.itemO("render.netclientstatus", icon="ICON_FILE_REFRESH", text="") + subcol.itemO("render.netclientcancel", icon="ICON_ZOOMOUT", text="") + subcol.itemO("render.netclientcancelall", icon="ICON_PANEL_CLOSE", text="") + subcol.itemO("render.netclientdownload", icon='ICON_RENDER_ANIMATION', text="") + + if len(bpy.data.netrender_jobs) == 0 and len(netsettings.jobs) > 0: + while(len(netsettings.jobs) > 0): + netsettings.jobs.remove(0) + + if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0: + layout.itemS() + + job = bpy.data.netrender_jobs[netsettings.active_job_index] + + layout.itemL(text="Name: %s" % job.name) + layout.itemL(text="Length: %04i" % len(job)) + layout.itemL(text="Done: %04i" % job.results[DONE]) + layout.itemL(text="Error: %04i" % job.results[ERROR]) + +@rnaType +class NetRenderSettings(bpy.types.IDPropertyGroup): + pass + +@rnaType +class NetRenderSlave(bpy.types.IDPropertyGroup): + pass + +@rnaType +class NetRenderJob(bpy.types.IDPropertyGroup): + pass + +bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") + +NetRenderSettings.StringProperty( attr="server_address", + name="Server address", + description="IP or name of the master render server", + maxlen = 128, + default = "[default]") + +NetRenderSettings.IntProperty( attr="server_port", + name="Server port", + description="port of the master render server", + default = 8000, + min=1, + max=65535) + +NetRenderSettings.BoolProperty( attr="server_broadcast", + name="Broadcast server address", + description="broadcast server address on local network", + default = True) + +if os.name == 'nt': + NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = "C:/tmp/") +else: + NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = "/tmp/") + +NetRenderSettings.StringProperty( attr="job_name", + name="Job name", + description="Name of the job", + maxlen = 128, + default = "[default]") + +NetRenderSettings.IntProperty( attr="chunks", + name="Chunks", + description="Number of frame to dispatch to each slave in one chunk", + default = 5, + min=1, + max=65535) + +NetRenderSettings.IntProperty( attr="priority", + name="Priority", + description="Priority of the job", + default = 1, + min=1, + max=10) + +NetRenderSettings.StringProperty( attr="job_id", + name="Network job id", + description="id of the last sent render job", + maxlen = 64, + default = "") + +NetRenderSettings.IntProperty( attr="active_slave_index", + name="Index of the active slave", + description="", + default = -1, + min= -1, + max=65535) + +NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", + name="Index of the active slave", + description="", + default = -1, + min= -1, + max=65535) + +NetRenderSettings.IntProperty( attr="active_job_index", + name="Index of the active job", + description="", + default = -1, + min= -1, + max=65535) + +NetRenderSettings.EnumProperty(attr="mode", + items=( + ("RENDER_CLIENT", "Client", "Act as render client"), + ("RENDER_MASTER", "Master", "Act as render master"), + ("RENDER_SLAVE", "Slave", "Act as render slave"), + ), + name="network mode", + description="mode of operation of this instance", + default="RENDER_CLIENT") + +NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") +NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") +NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") + +NetRenderSlave.StringProperty( attr="name", + name="Name of the slave", + description="", + maxlen = 64, + default = "") + +NetRenderJob.StringProperty( attr="name", + name="Name of the job", + description="", + maxlen = 128, + default = "") diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py new file mode 100644 index 00000000000..06393a738a0 --- /dev/null +++ b/release/scripts/io/netrender/utils.py @@ -0,0 +1,86 @@ +import bpy +import sys, os +import re +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +import netrender.model + +VERSION = b"0.5" + +# Jobs status +JOB_WAITING = 0 # before all data has been entered +JOB_PAUSED = 1 # paused by user +JOB_FINISHED = 2 # finished rendering +JOB_QUEUED = 3 # ready to be dispatched + +# Frames status +QUEUED = 0 +DISPATCHED = 1 +DONE = 2 +ERROR = 3 + +STATUS_TEXT = { + QUEUED: "Queued", + DISPATCHED: "Dispatched", + DONE: "Done", + ERROR: "Error" + } + +def rnaType(rna_type): + bpy.types.register(rna_type) + return rna_type + +def rnaOperator(rna_op): + bpy.ops.add(rna_op) + return rna_op + +def clientConnection(scene): + netsettings = scene.network_render + + if netsettings.server_address == "[default]": + bpy.ops.render.netclientscan() + + conn = http.client.HTTPConnection(netsettings.server_address, netsettings.server_port) + + if clientVerifyVersion(conn): + return conn + else: + conn.close() + return None + +def clientVerifyVersion(conn): + conn.request("GET", "/version") + response = conn.getresponse() + + if response.status != http.client.OK: + conn.close() + return False + + server_version = response.read() + + if server_version != VERSION: + print("Incorrect server version!") + print("expected", VERSION, "received", server_version) + return False + + return True + +def prefixPath(prefix_directory, file_path, prefix_path): + if os.path.isabs(file_path): + # if an absolute path, make sure path exists, if it doesn't, use relative local path + full_path = file_path + if not os.path.exists(full_path): + p, n = os.path.split(full_path) + + if prefix_path and p.startswith(prefix_path): + directory = prefix_directory + p[len(prefix_path):] + full_path = directory + n + if not os.path.exists(directory): + os.mkdir(directory) + else: + full_path = prefix_directory + n + else: + full_path = prefix_directory + file_path + + return full_path diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py deleted file mode 100644 index bbfb9649c69..00000000000 --- a/release/scripts/lightwave_export.py +++ /dev/null @@ -1,707 +0,0 @@ -#!BPY - -""" -Name: 'LightWave (.lwo)...' -Blender: 243 -Group: 'Export' -Tooltip: 'Export selected meshes to LightWave File Format (.lwo)' -""" - -__author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "blenderartists.org", -"Author's homepage, http://www.redrival.com/scorpius") -__version__ = "Part of IOSuite 0.5" - -__bpydoc__ = """\ -This script exports meshes to LightWave file format. - -LightWave is a full-featured commercial modeling and rendering -application. The lwo file format is composed of 'chunks,' is well -defined, and easy to read and write. It is similar in structure to the -trueSpace cob format. - -Usage:
- Select meshes to be exported and run this script from "File->Export" menu. - -Supported:
- UV Coordinates, Meshes, Materials, Material Indices, Specular -Highlights, and Vertex Colors. For added functionality, each object is -placed on its own layer. Someone added the CLIP chunk and imagename support. - -Missing:
- Not too much, I hope! :). - -Known issues:
- Empty objects crash has been fixed. - -Notes:
- For compatibility reasons, it also reads lwo files in the old LW -v5.5 format. -""" - -# $Id$ -# -# +---------------------------------------------------------+ -# | Copyright (c) 2002 Anthony D'Agostino | -# | http://www.redrival.com/scorpius | -# | scorpius@netzero.com | -# | April 21, 2002 | -# | Read and write LightWave Object File Format (*.lwo) | -# +---------------------------------------------------------+ - -# ***** 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 Blender -import BPyMesh -try: import struct -except: struct = None -try: import cStringIO -except: cStringIO = None -try: import operator -except: operator = None - -VCOL_NAME = "\251 Per-Face Vertex Colors" -DEFAULT_NAME = "\251 Blender Default" -# ============================== -# === Write LightWave Format === -# ============================== -def write(filename): - start = Blender.sys.time() - file = open(filename, "wb") - - scn = Blender.Scene.GetCurrent() - objects = list(scn.objects.context) - - if not objects: - Blender.Draw.PupMenu('Error%t|No Objects selected') - return - - try: objects.sort( key = lambda a: a.name ) - except: objects.sort(lambda a,b: cmp(a.name, b.name)) - - text = generate_text() - desc = generate_desc() - icon = "" #generate_icon() - - meshes = [] - mesh_object_name_lookup = {} # for name lookups only - - for obj in objects: - mesh = BPyMesh.getMeshFromObject(obj, None, True, False, scn) - if mesh: - mesh.transform(obj.matrixWorld) - meshes.append(mesh) - mesh_object_name_lookup[mesh] = obj.name - del obj - - material_names = get_used_material_names(meshes) - tags = generate_tags(material_names) - surfs = generate_surfs(material_names) - chunks = [text, desc, icon, tags] - - meshdata = cStringIO.StringIO() - - layer_index = 0 - - for mesh in meshes: - layr = generate_layr(mesh_object_name_lookup[mesh], layer_index) - pnts = generate_pnts(mesh) - bbox = generate_bbox(mesh) - pols = generate_pols(mesh) - ptag = generate_ptag(mesh, material_names) - clip = generate_clip(mesh, material_names) - - if mesh.faceUV: - vmad_uv = generate_vmad_uv(mesh) # per face - - if mesh.vertexColors: - #if meshtools.average_vcols: - # vmap_vc = generate_vmap_vc(mesh) # per vert - #else: - vmad_vc = generate_vmad_vc(mesh) # per face - - write_chunk(meshdata, "LAYR", layr); chunks.append(layr) - write_chunk(meshdata, "PNTS", pnts); chunks.append(pnts) - write_chunk(meshdata, "BBOX", bbox); chunks.append(bbox) - write_chunk(meshdata, "POLS", pols); chunks.append(pols) - write_chunk(meshdata, "PTAG", ptag); chunks.append(ptag) - - if mesh.vertexColors: - #if meshtools.average_vcols: - # write_chunk(meshdata, "VMAP", vmap_vc) - # chunks.append(vmap_vc) - #else: - write_chunk(meshdata, "VMAD", vmad_vc) - chunks.append(vmad_vc) - - if mesh.faceUV: - write_chunk(meshdata, "VMAD", vmad_uv) - chunks.append(vmad_uv) - write_chunk(meshdata, "CLIP", clip) - chunks.append(clip) - - layer_index += 1 - mesh.verts = None # save some ram - - del mesh_object_name_lookup - - for surf in surfs: - chunks.append(surf) - - write_header(file, chunks) - write_chunk(file, "ICON", icon) - write_chunk(file, "TEXT", text) - write_chunk(file, "DESC", desc) - write_chunk(file, "TAGS", tags) - file.write(meshdata.getvalue()); meshdata.close() - for surf in surfs: - write_chunk(file, "SURF", surf) - write_chunk(file, "DATE", "August 19, 2005") - - Blender.Window.DrawProgressBar(1.0, "") # clear progressbar - file.close() - print '\a\r', - print "Successfully exported %s in %.3f seconds" % (filename.split('\\')[-1].split('/')[-1], Blender.sys.time() - start) - - -# ======================================= -# === Generate Null-Terminated String === -# ======================================= -def generate_nstring(string): - if len(string)%2 == 0: # even - string += "\0\0" - else: # odd - string += "\0" - return string - -# =============================== -# === Get Used Material Names === -# =============================== -def get_used_material_names(meshes): - matnames = {} - for mesh in meshes: - if (not mesh.materials) and mesh.vertexColors: - # vcols only - matnames[VCOL_NAME] = None - - elif mesh.materials and (not mesh.vertexColors): - # materials only - for material in mesh.materials: - if material: - matnames[material.name] = None - elif (not mesh.materials) and (not mesh.vertexColors): - # neither - matnames[DEFAULT_NAME] = None - else: - # both - for material in mesh.materials: - if material: - matnames[material.name] = None - return matnames.keys() - -# ========================================= -# === Generate Tag Strings (TAGS Chunk) === -# ========================================= -def generate_tags(material_names): - if material_names: - material_names = map(generate_nstring, material_names) - tags_data = reduce(operator.add, material_names) - else: - tags_data = generate_nstring(''); - return tags_data - -# ======================== -# === Generate Surface === -# ======================== -def generate_surface(name): - #if name.find("\251 Per-") == 0: - # return generate_vcol_surf(mesh) - if name == DEFAULT_NAME: - return generate_default_surf() - else: - return generate_surf(name) - -# ====================== -# === Generate Surfs === -# ====================== -def generate_surfs(material_names): - return map(generate_surface, material_names) - -# =================================== -# === Generate Layer (LAYR Chunk) === -# =================================== -def generate_layr(name, idx): - data = cStringIO.StringIO() - data.write(struct.pack(">h", idx)) # layer number - data.write(struct.pack(">h", 0)) # flags - data.write(struct.pack(">fff", 0, 0, 0)) # pivot - data.write(generate_nstring(name)) # name - return data.getvalue() - -# =================================== -# === Generate Verts (PNTS Chunk) === -# =================================== -def generate_pnts(mesh): - data = cStringIO.StringIO() - for i, v in enumerate(mesh.verts): - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Writing Verts") - x, y, z = v.co - data.write(struct.pack(">fff", x, z, y)) - return data.getvalue() - -# ========================================== -# === Generate Bounding Box (BBOX Chunk) === -# ========================================== -def generate_bbox(mesh): - data = cStringIO.StringIO() - # need to transform verts here - if mesh.verts: - nv = [v.co for v in mesh.verts] - xx = [ co[0] for co in nv ] - yy = [ co[1] for co in nv ] - zz = [ co[2] for co in nv ] - else: - xx = yy = zz = [0.0,] - - data.write(struct.pack(">6f", min(xx), min(zz), min(yy), max(xx), max(zz), max(yy))) - return data.getvalue() - -# ======================================== -# === Average All Vertex Colors (Fast) === -# ======================================== -''' -def average_vertexcolors(mesh): - vertexcolors = {} - vcolor_add = lambda u, v: [u[0]+v[0], u[1]+v[1], u[2]+v[2], u[3]+v[3]] - vcolor_div = lambda u, s: [u[0]/s, u[1]/s, u[2]/s, u[3]/s] - for i, f in enumerate(mesh.faces): # get all vcolors that share this vertex - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Finding Shared VColors") - col = f.col - for j in xrange(len(f)): - index = f[j].index - color = col[j] - r,g,b = color.r, color.g, color.b - vertexcolors.setdefault(index, []).append([r,g,b,255]) - i = 0 - for index, value in vertexcolors.iteritems(): # average them - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Averaging Vertex Colors") - vcolor = [0,0,0,0] # rgba - for v in value: - vcolor = vcolor_add(vcolor, v) - shared = len(value) - value[:] = vcolor_div(vcolor, shared) - i+=1 - return vertexcolors -''' - -# ==================================================== -# === Generate Per-Vert Vertex Colors (VMAP Chunk) === -# ==================================================== -# Blender now has all vcols per face -""" -def generate_vmap_vc(mesh): - data = cStringIO.StringIO() - data.write("RGB ") # type - data.write(struct.pack(">H", 3)) # dimension - data.write(generate_nstring("Blender's Vertex Colors")) # name - vertexcolors = average_vertexcolors(mesh) - for i in xrange(len(vertexcolors)): - try: r, g, b, a = vertexcolors[i] # has a face user - except: r, g, b, a = 255,255,255,255 - data.write(struct.pack(">H", i)) # vertex index - data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) - return data.getvalue() -""" - -# ==================================================== -# === Generate Per-Face Vertex Colors (VMAD Chunk) === -# ==================================================== -def generate_vmad_vc(mesh): - data = cStringIO.StringIO() - data.write("RGB ") # type - data.write(struct.pack(">H", 3)) # dimension - data.write(generate_nstring("Blender's Vertex Colors")) # name - for i, f in enumerate(mesh.faces): - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Vertex Colors") - col = f.col - f_v = f.v - for j in xrange(len(f)-1, -1, -1): # Reverse order - r,g,b, dummy = tuple(col[j]) - data.write(struct.pack(">H", f_v[j].index)) # vertex index - data.write(struct.pack(">H", i)) # face index - data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) - return data.getvalue() - -# ================================================ -# === Generate Per-Face UV Coords (VMAD Chunk) === -# ================================================ -def generate_vmad_uv(mesh): - layers = mesh.getUVLayerNames() - org_uv = mesh.activeUVLayer - for l in layers: - mesh.activeUVLayer = l - data = cStringIO.StringIO() - data.write("TXUV") # type - data.write(struct.pack(">H", 2)) # dimension - data.write(generate_nstring(l)) # name - for i, f in enumerate(mesh.faces): - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV Coordinates") - - uv = f.uv - f_v = f.v - for j in xrange(len(f)-1, -1, -1): # Reverse order - U,V = uv[j] - v = f_v[j].index - data.write(struct.pack(">H", v)) # vertex index - data.write(struct.pack(">H", i)) # face index - data.write(struct.pack(">ff", U, V)) - - mesh.activeUVLayer = org_uv - return data.getvalue() - -# ====================================== -# === Generate Variable-Length Index === -# ====================================== -def generate_vx(index): - if index < 0xFF00: - value = struct.pack(">H", index) # 2-byte index - else: - value = struct.pack(">L", index | 0xFF000000) # 4-byte index - return value - -# =================================== -# === Generate Faces (POLS Chunk) === -# =================================== -def generate_pols(mesh): - data = cStringIO.StringIO() - data.write("FACE") # polygon type - for i,f in enumerate(mesh.faces): - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Faces") - data.write(struct.pack(">H", len(f))) # numfaceverts - numfaceverts = len(f) - f_v = f.v - for j in xrange(numfaceverts-1, -1, -1): # Reverse order - data.write(generate_vx(f_v[j].index)) - return data.getvalue() - -# ================================================= -# === Generate Polygon Tag Mapping (PTAG Chunk) === -# ================================================= -def generate_ptag(mesh, material_names): - - def surf_indicies(mat): - try: - if mat: - return material_names.index(mat.name) - except: - pass - - return 0 - - - data = cStringIO.StringIO() - data.write("SURF") # polygon tag type - mesh_materials = mesh.materials - mesh_surfindicies = [surf_indicies(mat) for mat in mesh_materials] - - try: VCOL_NAME_SURF_INDEX = material_names.index(VCOL_NAME) - except: VCOL_NAME_SURF_INDEX = 0 - - try: DEFAULT_NAME_SURF_INDEX = material_names.index(DEFAULT_NAME) - except: DEFAULT_NAME_SURF_INDEX = 0 - len_mat = len(mesh_materials) - for i, f in enumerate(mesh.faces): # numfaces - f_mat = f.mat - if f_mat >= len_mat: f_mat = 0 # Rare annoying eror - - - if not i%100: - Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Surface Indices") - - data.write(generate_vx(i)) - if (not mesh_materials) and mesh.vertexColors: # vcols only - surfidx = VCOL_NAME_SURF_INDEX - elif mesh_materials and not mesh.vertexColors: # materials only - surfidx = mesh_surfindicies[f_mat] - elif (not mesh_materials) and (not mesh.vertexColors): # neither - surfidx = DEFAULT_NAME_SURF_INDEX - else: # both - surfidx = mesh_surfindicies[f_mat] - - data.write(struct.pack(">H", surfidx)) # surface index - return data.getvalue() - -# =================================================== -# === Generate VC Surface Definition (SURF Chunk) === -# =================================================== -def generate_vcol_surf(mesh): - data = cStringIO.StringIO() - if mesh.vertexColors: - surface_name = generate_nstring(VCOL_NAME) - data.write(surface_name) - data.write("\0\0") - - data.write("COLR") - data.write(struct.pack(">H", 14)) - data.write(struct.pack(">fffH", 1, 1, 1, 0)) - - data.write("DIFF") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", 0.0, 0)) - - data.write("LUMI") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", 1.0, 0)) - - data.write("VCOL") - data.write(struct.pack(">H", 34)) - data.write(struct.pack(">fH4s", 1.0, 0, "RGB ")) # intensity, envelope, type - data.write(generate_nstring("Blender's Vertex Colors")) # name - - data.write("CMNT") # material comment - comment = "Vertex Colors: Exported from Blender\256 243" - comment = generate_nstring(comment) - data.write(struct.pack(">H", len(comment))) - data.write(comment) - return data.getvalue() - -# ================================================ -# === Generate Surface Definition (SURF Chunk) === -# ================================================ -def generate_surf(material_name): - data = cStringIO.StringIO() - data.write(generate_nstring(material_name)) - data.write("\0\0") - - try: - material = Blender.Material.Get(material_name) - R,G,B = material.R, material.G, material.B - ref = material.ref - emit = material.emit - spec = material.spec - hard = material.hard - - except: - material = None - - R=G=B = 1.0 - ref = 1.0 - emit = 0.0 - spec = 0.2 - hard = 0.0 - - - data.write("COLR") - data.write(struct.pack(">H", 14)) - data.write(struct.pack(">fffH", R, G, B, 0)) - - data.write("DIFF") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", ref, 0)) - - data.write("LUMI") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", emit, 0)) - - data.write("SPEC") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", spec, 0)) - - data.write("GLOS") - data.write(struct.pack(">H", 6)) - gloss = hard / (255/2.0) - gloss = round(gloss, 1) - data.write(struct.pack(">fH", gloss, 0)) - - data.write("CMNT") # material comment - comment = material_name + ": Exported from Blender\256 243" - comment = generate_nstring(comment) - data.write(struct.pack(">H", len(comment))) - data.write(comment) - - # Check if the material contains any image maps - if material: - mtextures = material.getTextures() # Get a list of textures linked to the material - for mtex in mtextures: - if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" - data.write("BLOK") # Surface BLOK header - data.write(struct.pack(">H", 104)) # Hardcoded and ugly! Will only handle 1 image per material - - # IMAP subchunk (image map sub header) - data.write("IMAP") - data_tmp = cStringIO.StringIO() - data_tmp.write(struct.pack(">H", 0)) # Hardcoded - not sure what it represents - data_tmp.write("CHAN") - data_tmp.write(struct.pack(">H", 4)) - data_tmp.write("COLR") - data_tmp.write("OPAC") # Hardcoded texture layer opacity - data_tmp.write(struct.pack(">H", 8)) - data_tmp.write(struct.pack(">H", 0)) - data_tmp.write(struct.pack(">f", 1.0)) - data_tmp.write(struct.pack(">H", 0)) - data_tmp.write("ENAB") - data_tmp.write(struct.pack(">HH", 2, 1)) # 1 = texture layer enabled - data_tmp.write("NEGA") - data_tmp.write(struct.pack(">HH", 2, 0)) # Disable negative image (1 = invert RGB values) - data_tmp.write("AXIS") - data_tmp.write(struct.pack(">HH", 2, 1)) - data.write(struct.pack(">H", len(data_tmp.getvalue()))) - data.write(data_tmp.getvalue()) - - # IMAG subchunk - data.write("IMAG") - data.write(struct.pack(">HH", 2, 1)) - data.write("PROJ") - data.write(struct.pack(">HH", 2, 5)) # UV projection - - data.write("VMAP") - uvname = generate_nstring("Blender's UV Coordinates") - data.write(struct.pack(">H", len(uvname))) - data.write(uvname) - - return data.getvalue() - -# ============================================= -# === Generate Default Surface (SURF Chunk) === -# ============================================= -def generate_default_surf(): - data = cStringIO.StringIO() - material_name = DEFAULT_NAME - data.write(generate_nstring(material_name)) - data.write("\0\0") - - data.write("COLR") - data.write(struct.pack(">H", 14)) - data.write(struct.pack(">fffH", 1, 1, 1, 0)) - - data.write("DIFF") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", 0.8, 0)) - - data.write("LUMI") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", 0, 0)) - - data.write("SPEC") - data.write(struct.pack(">H", 6)) - data.write(struct.pack(">fH", 0.5, 0)) - - data.write("GLOS") - data.write(struct.pack(">H", 6)) - gloss = 50 / (255/2.0) - gloss = round(gloss, 1) - data.write(struct.pack(">fH", gloss, 0)) - - data.write("CMNT") # material comment - comment = material_name + ": Exported from Blender\256 243" - - # vals = map(chr, xrange(164,255,1)) - # keys = xrange(164,255,1) - # keys = map(lambda x: `x`, keys) - # comment = map(None, keys, vals) - # comment = reduce(operator.add, comment) - # comment = reduce(operator.add, comment) - - comment = generate_nstring(comment) - data.write(struct.pack(">H", len(comment))) - data.write(comment) - return data.getvalue() - -# ============================================ -# === Generate Object Comment (TEXT Chunk) === -# ============================================ -def generate_text(): - comment = "Lightwave Export Script for Blender by Anthony D'Agostino" - return generate_nstring(comment) - -# ============================================== -# === Generate Description Line (DESC Chunk) === -# ============================================== -def generate_desc(): - comment = "Copyright 2002 Scorpius Entertainment" - return generate_nstring(comment) - -# ================================================== -# === Generate Thumbnail Icon Image (ICON Chunk) === -# ================================================== -def generate_icon(): - data = cStringIO.StringIO() - file = open("f:/obj/radiosity/lwo2_icon.tga", "rb") # 60x60 uncompressed TGA - file.read(18) - icon_data = file.read(3600) # ? - file.close() - data.write(struct.pack(">HH", 0, 60)) - data.write(icon_data) - #print len(icon_data) - return data.getvalue() - -# =============================================== -# === Generate CLIP chunk with STIL subchunks === -# =============================================== -def generate_clip(mesh, material_names): - data = cStringIO.StringIO() - clipid = 1 - for i, material in enumerate(mesh.materials): # Run through list of materials used by mesh - if material: - mtextures = material.getTextures() # Get a list of textures linked to the material - for mtex in mtextures: - if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" - pathname = mtex.tex.image.filename # If full path is needed use filename in place of name - pathname = pathname[0:2] + pathname.replace("\\", "/")[3:] # Convert to Modo standard path - imagename = generate_nstring(pathname) - data.write(struct.pack(">L", clipid)) # CLIP sequence/id - data.write("STIL") # STIL image - data.write(struct.pack(">H", len(imagename))) # Size of image name - data.write(imagename) - clipid += 1 - return data.getvalue() - -# =================== -# === Write Chunk === -# =================== -def write_chunk(file, name, data): - file.write(name) - file.write(struct.pack(">L", len(data))) - file.write(data) - -# ============================= -# === Write LWO File Header === -# ============================= -def write_header(file, chunks): - chunk_sizes = map(len, chunks) - chunk_sizes = reduce(operator.add, chunk_sizes) - form_size = chunk_sizes + len(chunks)*8 + len("FORM") - file.write("FORM") - file.write(struct.pack(">L", form_size)) - file.write("LWO2") - -def fs_callback(filename): - if not filename.lower().endswith('.lwo'): filename += '.lwo' - write(filename) - -if struct and cStringIO and operator: - Blender.Window.FileSelector(fs_callback, "Export LWO", Blender.sys.makename(ext='.lwo')) -else: - Blender.Draw.PupMenu("Error%t|This script requires a full python installation") diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py deleted file mode 100644 index 6d02467cef8..00000000000 --- a/release/scripts/lightwave_import.py +++ /dev/null @@ -1,1705 +0,0 @@ -#!BPY -""" -Name: 'LightWave (.lwo)...' -Blender: 239 -Group: 'Import' -Tooltip: 'Import LightWave Object File Format' -""" - -__author__ = ["Alessandro Pirovano, Anthony D'Agostino (Scorpius)", "Campbell Barton (ideasman42)", "ZanQdo"] -__url__ = ("www.blender.org", "blenderartist.org", -"Anthony's homepage, http://www.redrival.com/scorpius", "Alessandro's homepage, http://uaraus.altervista.org") - -importername = "lwo_import 0.4.0" - -# +---------------------------------------------------------+ -# | Save your work before and after use. | -# | Please report any useful comment to: | -# | uaraus-dem@yahoo.it | -# | Thanks | -# +---------------------------------------------------------+ -# +---------------------------------------------------------+ -# | Copyright (c) 2002 Anthony D'Agostino | -# | http://www.redrival.com/scorpius | -# | scorpius@netzero.com | -# | April 21, 2002 | -# | Import Export Suite v0.5 | -# +---------------------------------------------------------+ -# | Read and write LightWave Object File Format (*.lwo) | -# +---------------------------------------------------------+ -# +---------------------------------------------------------+ -# | Alessandro Pirovano tweaked starting on March 2005 | -# | http://uaraus.altervista.org | -# +---------------------------------------------------------+ -# +---------------------------------------------------------- -# | 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 -# +---------------------------------------------------------- -# +---------------------------------------------------------+ -# | Release log: | -# | 0.4.0 : Updated for blender 2.44 | -# | ZanQdo - made the mesh import the right way up | -# | Ideasman42 - Updated functions for the bew API | -# | as well as removing the text object class | -# | 0.2.2 : This code works with Blender 2.42 RC3 | -# | Added a new PolyFill function for BPYMesh's | -# | ngon() to use, checked compatibility | -# | lightwaves ngons are imported as fgons | -# | Checked compatibility against 1711 lwo files | -# | 0.2.1 : This code works with Blender 2.40 RC1 | -# | modified material mode assignment to deal with | -# | Python API modification | -# | Changed script license to GNU GPL | -# | 0.2.0: This code works with Blender 2.40a2 or up | -# | Major rewrite to deal with large meshes | -# | - 2 pass file parsing | -# | - lower memory foot###if DEBUG: print | -# | (as long as python gc allows) | -# | 2.40a2 - Removed subsurf settings patches=poly | -# | 2.40a2 - Edge generation instead of 2vert faces | -# | 0.1.16: fixed (try 2) texture offset calculations | -# | added hint on axis mapping | -# | added hint on texture blending mode | -# | added hint on texture transparency setting | -# | search images in original directory first | -# | fixed texture order application | -# | 0.1.15: added release log | -# | fixed texture offset calculations (non-UV) | -# | fixed reverting vertex order in face generation | -# | associate texture on game-engine settings | -# | vector math definitely based on mathutils | -# | search images in "Images" and "../Images" dir | -# | revised logging facility | -# | fixed subsurf texture and material mappings | -# | 0.1.14: patched missing mod_vector (not definitive) | -# | 0.1.13: first public release | -# +---------------------------------------------------------+ - -#blender related import -import Blender -import bpy - -# use for comprehensiveImageLoad -import BPyImage - -# Use this ngon function -import BPyMesh - -import BPyMessages - -#python specific modules import -try: - import struct, chunk, cStringIO -except: - struct= chunk= cStringIO= None - -# python 2.3 has no reversed() iterator. this will only work on lists and tuples -try: - reversed -except: - def reversed(l): return l[::-1] - -### # Debuggin disabled in release. -### # do a search replace to enabe debug prints -### DEBUG = False - -# =========================================================== -# === Utility Preamble ====================================== -# =========================================================== - -textname = None -#uncomment the following line to enable logging facility to the named text object -#textname = "lwo_log" - -TXMTX = Blender.Mathutils.Matrix(\ -[1, 0, 0, 0],\ -[0, 0, 1, 0],\ -[0, 1, 0, 0],\ -[0, 0, 0, 1]) - -# =========================================================== -# === Make sure it is a string ... deal with strange chars == -# =========================================================== -def safestring(st): - myst = "" - for ll in xrange(len(st)): - if st[ll] < " ": - myst += "#" - else: - myst += st[ll] - return myst - -# =========================================================== -# === Main read functions =================================== -# =========================================================== - -# ============================= -# === Read LightWave Format === -# ============================= -def read(filename): - if BPyMessages.Error_NoFile(filename): - return - - print "This is: %s" % importername - print "Importing file:", filename - bpy.data.scenes.active.objects.selected = [] - - start = Blender.sys.time() - file = open(filename, "rb") - - editmode = Blender.Window.EditMode() # are we in edit mode? If so ... - if editmode: Blender.Window.EditMode(0) # leave edit mode before getting the mesh # === LWO header === - - try: - form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) - except: - Blender.Draw.PupMenu('Error%t|This is not a lightwave file') - return - - if (form_type == "LWOB"): - read_lwob(file, filename) - elif (form_type == "LWO2"): - read_lwo2(file, filename) - else: - print "Can't read a file with the form_type: %s" % form_type - return - - Blender.Window.DrawProgressBar(1.0, "") # clear progressbar - file.close() - end = Blender.sys.time() - seconds = " in %.2f %s" % (end-start, "seconds") - if form_type == "LWO2": fmt = " (v6.0 Format)" - if form_type == "LWOB": fmt = " (v5.5 Format)" - print "Successfully imported " + filename.split('\\')[-1].split('/')[-1] + fmt + seconds - - if editmode: Blender.Window.EditMode(1) # optional, just being nice - Blender.Redraw() - -# enddef read - - -# ================================= -# === Read LightWave 5.5 format === -# ================================= -def read_lwob(file, filename): - #This function is directly derived from the LWO2 import routine - #dropping all the material analysis parts - - ###if DEBUG: print "LightWave 5.5 format" - - dir_part = Blender.sys.dirname(filename) - fname_part = Blender.sys.basename(filename) - #ask_weird = 1 - - #first initialization of data structures - defaultname = Blender.sys.splitext(fname_part)[0] - tag_list = [] #tag list: global for the whole file? - surf_list = [] #surf list: global for the whole file? - clip_list = [] #clip list: global for the whole file? - object_index = 0 - object_list = None - objspec_list = None - - #add default material for orphaned faces, if any - surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) - - #pass 2: effectively generate objects - ###if DEBUG: print "Pass 1: dry import" - file.seek(0) - objspec_list = ["imported", {}, [], [], {}, {}, 0, {}, {}] - # === LWO header === - form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) - if (form_type != "LWOB"): - ###if DEBUG: print "??? Inconsistent file type: %s" % form_type - return - while 1: - try: - lwochunk = chunk.Chunk(file) - except EOFError: - break - ###if DEBUG: print ' ', - if lwochunk.chunkname == "LAYR": - ###if DEBUG: print "---- LAYR", - objname = read_layr(lwochunk) - ###if DEBUG: print objname - if objspec_list != None: #create the object - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] - object_index += 1 - elif lwochunk.chunkname == "PNTS": # Verts - ###if DEBUG: print "---- PNTS", - verts = read_verts(lwochunk) - objspec_list[2] = verts - elif lwochunk.chunkname == "POLS": # Faces v5.5 - ###if DEBUG: print "-------- POLS(5.5)" - faces = read_faces_5(lwochunk) - flag = 0 - #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored - if flag<2: - if objspec_list[3] != []: - #create immediately the object - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - #update with new data - objspec_list = [objspec_list[0], #update name - {}, #init - objspec_list[2], #same vertexes - faces, #give it the new faces - {}, #no need to copy - filled at runtime - {}, #polygon tagging will follow - flag, #patch flag - objspec_list[7], #same uvcoords - {}] #no vmad mapping - object_index += 1 - #end if already has a face list - objspec_list[3] = faces - objname = objspec_list[0] - if objname == None: - objname = defaultname - #end if processing a valid poly type - else: # Misc Chunks - ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname - lwochunk.skip() - #uncomment here to log data structure as it is built - # ###if DEBUG: print object_list - #last object read - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - objspec_list = None - surf_list = None - clip_list = None - - - ###if DEBUG: print "\nFound %d objects:" % object_index - -# enddef read_lwob - - -# ============================= -# === Read LightWave Format === -# ============================= -def read_lwo2(file, filename, typ="LWO2"): - - ###if DEBUG: print "LightWave 6 (and above) format" - - dir_part = Blender.sys.dirname(filename) - fname_part = Blender.sys.basename(filename) - ask_weird = 1 - - #first initialization of data structures - defaultname = Blender.sys.splitext(fname_part)[0] - tag_list = [] #tag list: global for the whole file? - surf_list = [] #surf list: global for the whole file? - clip_list = [] #clip list: global for the whole file? - object_index = 0 - object_list = None - objspec_list = None - # init value is: object_list = [[None, {}, [], [], {}, {}, 0, {}, {}]] - #0 - objname #original name - #1 - obj_dict = {TAG} #objects created - #2 - verts = [] #object vertexes - #3 - faces = [] #object faces (associations poly -> vertexes) - #4 - obj_dim_dict = {TAG} #tuples size and pos in local object coords - used for NON-UV mappings - #5 - polytag_dict = {TAG} #tag to polygons mapping - #6 - patch_flag #0 = surf; 1 = patch (subdivision surface) - it was the image list - #7 - uvcoords_dict = {name} #uvmap coordinates (mixed mode per vertex/per face) - #8 - facesuv_dict = {name} #vmad only coordinates associations poly & vertex -> uv tuples - - #pass 1: look in advance for materials - ###if DEBUG: print "Starting Pass 1: hold on tight" - while 1: - try: - lwochunk = chunk.Chunk(file) - except EOFError: - break - ###if DEBUG: print ' ', - if lwochunk.chunkname == "TAGS": # Tags - ###if DEBUG: print "---- TAGS" - tag_list.extend(read_tags(lwochunk)) - elif lwochunk.chunkname == "SURF": # surfaces - ###if DEBUG: print "---- SURF" - surf_list.append(read_surfs(lwochunk, surf_list, tag_list)) - elif lwochunk.chunkname == "CLIP": # texture images - ###if DEBUG: print "---- CLIP" - clip_list.append(read_clip(lwochunk, dir_part)) - ###if DEBUG: print "read total %s clips up to now" % len(clip_list) - else: # Misc Chunks - if ask_weird: - ckname = safestring(lwochunk.chunkname) - if "#" in ckname: - choice = Blender.Draw.PupMenu("WARNING: file could be corrupted.%t|Import anyway|Give up") - if choice != 1: - ###if DEBUG: print "---- %s: Maybe file corrupted. Terminated by user" % lwochunk.chunkname - return - ask_weird = 0 - ###if DEBUG: print "---- %s: skipping (maybe later)" % lwochunk.chunkname - lwochunk.skip() - - #add default material for orphaned faces, if any - surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) - - #pass 2: effectively generate objects - ###if DEBUG: print "Pass 2: now for the hard part" - file.seek(0) - # === LWO header === - form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) - if (form_type != "LWO2"): - ###if DEBUG: print "??? Inconsistent file type: %s" % form_type - return - while 1: - try: - lwochunk = chunk.Chunk(file) - except EOFError: - break - ###if DEBUG: print ' ', - if lwochunk.chunkname == "LAYR": - ###if DEBUG: print "---- LAYR" - objname = read_layr(lwochunk) - ###if DEBUG: print objname - if objspec_list != None: #create the object - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] - object_index += 1 - elif lwochunk.chunkname == "PNTS": # Verts - ###if DEBUG: print "---- PNTS" - verts = read_verts(lwochunk) - objspec_list[2] = verts - elif lwochunk.chunkname == "VMAP": # MAPS (UV) - ###if DEBUG: print "---- VMAP" - #objspec_list[7] = read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) - read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) - elif lwochunk.chunkname == "VMAD": # MAPS (UV) per-face - ###if DEBUG: print "---- VMAD" - #objspec_list[7], objspec_list[8] = read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) - read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) - elif lwochunk.chunkname == "POLS": # Faces v6.0 - ###if DEBUG: print "-------- POLS(6)" - faces, flag = read_faces_6(lwochunk) - #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored - if flag<2: - if objspec_list[3] != []: - #create immediately the object - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - #update with new data - objspec_list = [objspec_list[0], #update name - {}, #init - objspec_list[2], #same vertexes - faces, #give it the new faces - {}, #no need to copy - filled at runtime - {}, #polygon tagging will follow - flag, #patch flag - objspec_list[7], #same uvcoords - {}] #no vmad mapping - object_index += 1 - #end if already has a face list - objspec_list[3] = faces - objname = objspec_list[0] - if objname == None: - objname = defaultname - #end if processing a valid poly type - elif lwochunk.chunkname == "PTAG": # PTags - ###if DEBUG: print "---- PTAG" - polytag_dict = read_ptags(lwochunk, tag_list) - for kk, polytag_dict_val in polytag_dict.iteritems(): objspec_list[5][kk] = polytag_dict_val - else: # Misc Chunks - ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname - lwochunk.skip() - #uncomment here to log data structure as it is built - - #last object read - create_objects(clip_list, objspec_list, surf_list) - update_material(clip_list, objspec_list, surf_list) #give it all the object - objspec_list = None - surf_list = None - clip_list = None - - ###if DEBUG: print "\nFound %d objects:" % object_index -# enddef read_lwo2 - - - - - - -# =========================================================== -# === File reading routines ================================= -# =========================================================== -# ================== -# === Read Verts === -# ================== -def read_verts(lwochunk): - #data = cStringIO.StringIO(lwochunk.read()) - numverts = lwochunk.chunksize/12 - return [struct.unpack(">fff", lwochunk.read(12)) for i in xrange(numverts)] -# enddef read_verts - - -# ================= -# === Read Name === -# ================= -# modified to deal with odd lenght strings -def read_name(file): - name = "" - while 1: - char = file.read(1) - if char == "\0": break - else: name += char - len_name = len(name) + 1 #count the trailing zero - if len_name%2==1: - char = file.read(1) #remove zero padding to even lenght - len_name += 1 - return name, len_name - - -# ================== -# === Read Layer === -# ================== -def read_layr(lwochunk): - data = cStringIO.StringIO(lwochunk.read()) - idx, flags = struct.unpack(">hh", data.read(4)) - pivot = struct.unpack(">fff", data.read(12)) - layer_name, discard = read_name(data) - if not layer_name: layer_name = "NoName" - return layer_name -# enddef read_layr - - -# ====================== -# === Read Faces 5.5 === -# ====================== -def read_faces_5(lwochunk): - data = cStringIO.StringIO(lwochunk.read()) - faces = [] - i = 0 - while i < lwochunk.chunksize: - #if not i%1000 and my_meshtools.show_progress: - # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") - - numfaceverts, = struct.unpack(">H", data.read(2)) - facev = [struct.unpack(">H", data.read(2))[0] for j in xrange(numfaceverts)] - facev.reverse() - faces.append(facev) - surfaceindex, = struct.unpack(">H", data.read(2)) - if surfaceindex < 0: - ###if DEBUG: print "***Error. Referencing uncorrect surface index" - return - i += (4+numfaceverts*2) - return faces - - -# ================================== -# === Read Variable-Length Index === -# ================================== -def read_vx(data): - byte1, = struct.unpack(">B", data.read(1)) - if byte1 != 0xFF: # 2-byte index - byte2, = struct.unpack(">B", data.read(1)) - index = byte1*256 + byte2 - index_size = 2 - else: # 4-byte index - byte2, byte3, byte4 = struct.unpack(">3B", data.read(3)) - index = byte2*65536 + byte3*256 + byte4 - index_size = 4 - return index, index_size - - -# ====================== -# === Read uvmapping === -# ====================== -def read_vmap(uvcoords_dict, maxvertnum, lwochunk): - - if maxvertnum == 0: - ###if DEBUG: print "Found VMAP but no vertexes to map!" - return uvcoords_dict - data = cStringIO.StringIO(lwochunk.read()) - map_type = data.read(4) - if map_type != "TXUV": - ###if DEBUG: print "Reading VMAP: No Texture UV map Were Found. Map Type: %s" % map_type - return uvcoords_dict - dimension, = struct.unpack(">H", data.read(2)) - name, i = read_name(data) #i initialized with string lenght + zeros - ###if DEBUG: print "TXUV %d %s" % (dimension, name) - #note if there is already a VMAD it will be lost - #it is assumed that VMAD will follow the corresponding VMAP - Vector = Blender.Mathutils.Vector - try: #if uvcoords_dict.has_key(name): - my_uv_dict = uvcoords_dict[name] #update existing - except: #else: - my_uv_dict = {} #start a brand new: this could be made more smart - while (i < lwochunk.chunksize - 6): #4+2 header bytes already read - vertnum, vnum_size = read_vx(data) - uv = struct.unpack(">ff", data.read(8)) - if vertnum >= maxvertnum: - ###if DEBUG: print "Hem: more uvmap than vertexes? ignoring uv data for vertex %d" % vertnum - pass - else: - my_uv_dict[vertnum] = Vector(uv) - i += 8 + vnum_size - #end loop on uv pairs - uvcoords_dict[name] = my_uv_dict - #this is a per-vertex mapping AND the uv tuple is vertex-ordered, so faces_uv is the same as faces - #return uvcoords_dict - return - -# ======================== -# === Read uvmapping 2 === -# ======================== -def read_vmad(uvcoords_dict, facesuv_dict, maxfacenum, maxvertnum, lwochunk): - if maxvertnum == 0 or maxfacenum == 0: - ###if DEBUG: print "Found VMAD but no vertexes to map!" - return uvcoords_dict, facesuv_dict - data = cStringIO.StringIO(lwochunk.read()) - map_type = data.read(4) - if map_type != "TXUV": - ###if DEBUG: print "Reading VMAD: No Texture UV map Were Found. Map Type: %s" % map_type - return uvcoords_dict, facesuv_dict - dimension, = struct.unpack(">H", data.read(2)) - name, i = read_name(data) #i initialized with string lenght + zeros - ###if DEBUG: print "TXUV %d %s" % (dimension, name) - try: #if uvcoords_dict.has_key(name): - my_uv_dict = uvcoords_dict[name] #update existing - except: #else: - my_uv_dict = {} #start a brand new: this could be made more smart - my_facesuv_list = [] - newindex = maxvertnum + 10 #why +10? Why not? - #end variable initialization - Vector = Blender.Mathutils.Vector - while (i < lwochunk.chunksize - 6): #4+2 header bytes already read - vertnum, vnum_size = read_vx(data) - i += vnum_size - polynum, vnum_size = read_vx(data) - i += vnum_size - uv = struct.unpack(">ff", data.read(8)) - if polynum >= maxfacenum or vertnum >= maxvertnum: - ###if DEBUG: print "Hem: more uvmap than vertexes? ignorig uv data for vertex %d" % vertnum - pass - else: - my_uv_dict[newindex] = Vector(uv) - my_facesuv_list.append([polynum, vertnum, newindex]) - newindex += 1 - i += 8 - #end loop on uv pairs - uvcoords_dict[name] = my_uv_dict - facesuv_dict[name] = my_facesuv_list - ###if DEBUG: print "updated %d vertexes data" % (newindex-maxvertnum-10) - return - - -# ================= -# === Read tags === -# ================= -def read_tags(lwochunk): - data = cStringIO.StringIO(lwochunk.read()) - tag_list = [] - current_tag = "" - i = 0 - while i < lwochunk.chunksize: - char = data.read(1) - if char == "\0": - tag_list.append(current_tag) - if (len(current_tag) % 2 == 0): char = data.read(1) - current_tag = "" - else: - current_tag += char - i += 1 - ###if DEBUG: print "read %d tags, list follows: %s" % (len(tag_list), tag_list) - return tag_list - - -# ================== -# === Read Ptags === -# ================== -def read_ptags(lwochunk, tag_list): - data = cStringIO.StringIO(lwochunk.read()) - polygon_type = data.read(4) - if polygon_type != "SURF": - ###if DEBUG: print "No Surf Were Found. Polygon Type: %s" % polygon_type - return {} - ptag_dict = {} - i = 0 - while(i < lwochunk.chunksize-4): #4 bytes polygon type already read - #if not i%1000 and my_meshtools.show_progress: - # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading PTAGS") - poln, poln_size = read_vx(data) - i += poln_size - tag_index, = struct.unpack(">H", data.read(2)) - if tag_index > (len(tag_list)): - ###if DEBUG: print "Reading PTAG: Surf belonging to undefined TAG: %d. Skipping" % tag_index - return {} - i += 2 - tag_key = tag_list[tag_index] - try: - ptag_dict[tag_list[tag_index]].append(poln) - except: #if not(ptag_dict.has_key(tag_key)): - ptag_dict[tag_list[tag_index]] = [poln] - - ###if DEBUG: for i, ptag_dict_val in ptag_dict.iteritems(): print "read %d polygons belonging to TAG %s" % (len(ptag_dict_val ), i) - return ptag_dict - - - -# ================== -# === Read Clips === -# ================== -def read_clip(lwochunk, dir_part): -# img, IMG, g_IMG refers to blender image objects -# ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf - clip_dict = {} - data = cStringIO.StringIO(lwochunk.read()) - data_str = data.read(4) - if len(data_str) < 4: # can be zero also??? :/ - # Should not happen but lw can import so we should too - return - - image_index, = struct.unpack(">L", data_str) - clip_dict['ID'] = image_index - i = 4 - while(i < lwochunk.chunksize): - subchunkname, = struct.unpack("4s", data.read(4)) - subchunklen, = struct.unpack(">H", data.read(2)) - if subchunkname == "STIL": - ###if DEBUG: print "-------- STIL" - clip_name, k = read_name(data) - #now split text independently from platform - #depend on the system where image was saved. NOT the one where the script is run - no_sep = "\\" - if Blender.sys.sep == no_sep: no_sep ="/" - if (no_sep in clip_name): - clip_name = clip_name.replace(no_sep, Blender.sys.sep) - short_name = Blender.sys.basename(clip_name) - if clip_name == "" or short_name == "": - ###if DEBUG: print "Reading CLIP: Empty clip name not allowed. Skipping" - discard = data.read(subchunklen-k) - clip_dict['NAME'] = clip_name - clip_dict['BASENAME'] = short_name - elif subchunkname == "XREF": #cross reference another image - ###if DEBUG: print "-------- XREF" - image_index, = struct.unpack(">L", data.read(4)) - clip_name, k = read_name(data) - clip_dict['NAME'] = clip_name - clip_dict['XREF'] = image_index - elif subchunkname == "NEGA": #negate texture effect - ###if DEBUG: print "-------- NEGA" - n, = struct.unpack(">H", data.read(2)) - clip_dict['NEGA'] = n - else: # Misc Chunks - ###if DEBUG: print "-------- CLIP:%s: skipping" % subchunkname - discard = data.read(subchunklen) - i = i + 6 + subchunklen - #end loop on surf chunks - ###if DEBUG: print "read image:%s" % clip_dict - if 'XREF' in clip_dict: # has_key - ###if DEBUG: print "Cross-reference: no image pre-allocated." - return clip_dict - #look for images - #img = load_image("",clip_dict['NAME']) - NAME= BASENAME= None - - try: - NAME= clip_dict['NAME'] - BASENAME= clip_dict['BASENAME'] - except: - clip_dict['g_IMG'] = None - return - # ###if DEBUG: print 'test', NAME, BASENAME - img = BPyImage.comprehensiveImageLoad(NAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) - if not img: - ###if DEBUG: print "***No image %s found: trying LWO file subdir" % NAME - img = BPyImage.comprehensiveImageLoad(BASENAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) - - ###if DEBUG: if not img: print "***No image %s found: giving up" % BASENAME - #lucky we are: we have an image - ###if DEBUG: print "Image pre-allocated." - clip_dict['g_IMG'] = img - - return clip_dict - - -# =========================== -# === Read Surfaces Block === -# =========================== -def read_surfblok(subchunkdata): - lenght = len(subchunkdata) - my_dict = {} - my_uvname = "" - data = cStringIO.StringIO(subchunkdata) - ############################################################## - # blok header sub-chunk - ############################################################## - subchunkname, = struct.unpack("4s", data.read(4)) - subchunklen, = struct.unpack(">h", data.read(2)) - accumulate_i = subchunklen + 6 - if subchunkname != 'IMAP': - ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname - return {}, "" - ###if DEBUG: print "---------- IMAP" - ordinal, i = read_name(data) - my_dict['ORD'] = ordinal - #my_dict['g_ORD'] = -1 - my_dict['ENAB'] = True - while(i < subchunklen): # ---------left 6------------------------- loop on header parameters - sub2chunkname, = struct.unpack("4s", data.read(4)) - sub2chunklen, = struct.unpack(">h", data.read(2)) - i = i + 6 + sub2chunklen - if sub2chunkname == "CHAN": - ###if DEBUG: print "------------ CHAN" - sub2chunkname, = struct.unpack("4s", data.read(4)) - my_dict['CHAN'] = sub2chunkname - sub2chunklen -= 4 - elif sub2chunkname == "ENAB": #only present if is to be disabled - ###if DEBUG: print "------------ ENAB" - ena, = struct.unpack(">h", data.read(2)) - my_dict['ENAB'] = ena - sub2chunklen -= 2 - elif sub2chunkname == "NEGA": #only present if is to be enabled - ###if DEBUG: print "------------ NEGA" - ena, = struct.unpack(">h", data.read(2)) - if ena == 1: - my_dict['NEGA'] = ena - sub2chunklen -= 2 - elif sub2chunkname == "OPAC": #only present if is to be disabled - ###if DEBUG: print "------------ OPAC" - opa, = struct.unpack(">h", data.read(2)) - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['OPAC'] = opa - my_dict['OPACVAL'] = s - sub2chunklen -= 6 - elif sub2chunkname == "AXIS": - ###if DEBUG: print "------------ AXIS" - ena, = struct.unpack(">h", data.read(2)) - my_dict['DISPLAXIS'] = ena - sub2chunklen -= 2 - else: # Misc Chunks - ###if DEBUG: print "------------ SURF: BLOK: IMAP: %s: skipping" % sub2chunkname - discard = data.read(sub2chunklen) - #end loop on blok header subchunks - ############################################################## - # blok attributes sub-chunk - ############################################################## - subchunkname, = struct.unpack("4s", data.read(4)) - subchunklen, = struct.unpack(">h", data.read(2)) - accumulate_i += subchunklen + 6 - if subchunkname != 'TMAP': - ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname - return {}, "" - ###if DEBUG: print "---------- TMAP" - i = 0 - while(i < subchunklen): # -----------left 6----------------------- loop on header parameters - sub2chunkname, = struct.unpack("4s", data.read(4)) - sub2chunklen, = struct.unpack(">h", data.read(2)) - i = i + 6 + sub2chunklen - if sub2chunkname == "CNTR": - ###if DEBUG: print "------------ CNTR" - x, y, z = struct.unpack(">fff", data.read(12)) - envelope, env_size = read_vx(data) - my_dict['CNTR'] = [x, y, z] - sub2chunklen -= (12+env_size) - elif sub2chunkname == "SIZE": - ###if DEBUG: print "------------ SIZE" - x, y, z = struct.unpack(">fff", data.read(12)) - envelope, env_size = read_vx(data) - my_dict['SIZE'] = [x, y, z] - sub2chunklen -= (12+env_size) - elif sub2chunkname == "ROTA": - ###if DEBUG: print "------------ ROTA" - x, y, z = struct.unpack(">fff", data.read(12)) - envelope, env_size = read_vx(data) - my_dict['ROTA'] = [x, y, z] - sub2chunklen -= (12+env_size) - elif sub2chunkname == "CSYS": - ###if DEBUG: print "------------ CSYS" - ena, = struct.unpack(">h", data.read(2)) - my_dict['CSYS'] = ena - sub2chunklen -= 2 - else: # Misc Chunks - ###if DEBUG: print "------------ SURF: BLOK: TMAP: %s: skipping" % sub2chunkname - pass - if sub2chunklen > 0: - discard = data.read(sub2chunklen) - #end loop on blok attributes subchunks - ############################################################## - # ok, now other attributes without sub_chunks - ############################################################## - while(accumulate_i < lenght): # ---------------------------------- loop on header parameters: lenght has already stripped the 6 bypes header - subchunkname, = struct.unpack("4s", data.read(4)) - subchunklen, = struct.unpack(">H", data.read(2)) - accumulate_i = accumulate_i + 6 + subchunklen - if subchunkname == "PROJ": - ###if DEBUG: print "---------- PROJ" - p, = struct.unpack(">h", data.read(2)) - my_dict['PROJ'] = p - subchunklen -= 2 - elif subchunkname == "AXIS": - ###if DEBUG: print "---------- AXIS" - a, = struct.unpack(">h", data.read(2)) - my_dict['MAJAXIS'] = a - subchunklen -= 2 - elif subchunkname == "IMAG": - ###if DEBUG: print "---------- IMAG" - i, i_size = read_vx(data) - my_dict['IMAG'] = i - subchunklen -= i_size - elif subchunkname == "WRAP": - ###if DEBUG: print "---------- WRAP" - ww, wh = struct.unpack(">hh", data.read(4)) - #reduce width and height to just 1 parameter for both - my_dict['WRAP'] = max([ww,wh]) - #my_dict['WRAPWIDTH'] = ww - #my_dict['WRAPHEIGHT'] = wh - subchunklen -= 4 - elif subchunkname == "WRPW": - ###if DEBUG: print "---------- WRPW" - w, = struct.unpack(">f", data.read(4)) - my_dict['WRPW'] = w - envelope, env_size = read_vx(data) - subchunklen -= (env_size+4) - elif subchunkname == "WRPH": - ###if DEBUG: print "---------- WRPH" - w, = struct.unpack(">f", data.read(4)) - my_dict['WRPH'] = w - envelope, env_size = read_vx(data) - subchunklen -= (env_size+4) - elif subchunkname == "VMAP": - ###if DEBUG: print "---------- VMAP" - vmp, i = read_name(data) - my_dict['VMAP'] = vmp - my_uvname = vmp - subchunklen -= i - else: # Misc Chunks - ###if DEBUG: print "---------- SURF: BLOK: %s: skipping" % subchunkname - pass - if subchunklen > 0: - discard = data.read(subchunklen) - #end loop on blok subchunks - return my_dict, my_uvname - - -# ===================== -# === Read Surfaces === -# ===================== -def read_surfs(lwochunk, surf_list, tag_list): - my_dict = {} - data = cStringIO.StringIO(lwochunk.read()) - surf_name, i = read_name(data) - parent_name, j = read_name(data) - i += j - if (surf_name == "") or not(surf_name in tag_list): - ###if DEBUG: print "Reading SURF: Actually empty surf name not allowed. Skipping" - return {} - if (parent_name != ""): - parent_index = [x['NAME'] for x in surf_list].count(parent_name) - if parent_index >0: - my_dict = surf_list[parent_index-1] - my_dict['NAME'] = surf_name - ###if DEBUG: print "Surface data for TAG %s" % surf_name - while(i < lwochunk.chunksize): - subchunkname, = struct.unpack("4s", data.read(4)) - subchunklen, = struct.unpack(">H", data.read(2)) - i = i + 6 + subchunklen #6 bytes subchunk header - if subchunkname == "COLR": #color: mapped on color - ###if DEBUG: print "-------- COLR" - r, g, b = struct.unpack(">fff", data.read(12)) - envelope, env_size = read_vx(data) - my_dict['COLR'] = [r, g, b] - subchunklen -= (12+env_size) - elif subchunkname == "DIFF": #diffusion: mapped on reflection (diffuse shader) - ###if DEBUG: print "-------- DIFF" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['DIFF'] = s - subchunklen -= (4+env_size) - elif subchunkname == "SPEC": #specularity: mapped to specularity (spec shader) - ###if DEBUG: print "-------- SPEC" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['SPEC'] = s - subchunklen -= (4+env_size) - elif subchunkname == "REFL": #reflection: mapped on raymirror - ###if DEBUG: print "-------- REFL" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['REFL'] = s - subchunklen -= (4+env_size) - elif subchunkname == "TRNL": #translucency: mapped on same param - ###if DEBUG: print "-------- TRNL" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['TRNL'] = s - subchunklen -= (4+env_size) - elif subchunkname == "GLOS": #glossiness: mapped on specularity hardness (spec shader) - ###if DEBUG: print "-------- GLOS" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['GLOS'] = s - subchunklen -= (4+env_size) - elif subchunkname == "TRAN": #transparency: inverted and mapped on alpha channel - ###if DEBUG: print "-------- TRAN" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['TRAN'] = s - subchunklen -= (4+env_size) - elif subchunkname == "LUMI": #luminosity: mapped on emit channel - ###if DEBUG: print "-------- LUMI" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['LUMI'] = s - subchunklen -= (4+env_size) - elif subchunkname == "GVAL": #glow: mapped on add channel - ###if DEBUG: print "-------- GVAL" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['GVAL'] = s - subchunklen -= (4+env_size) - elif subchunkname == "SMAN": #smoothing angle - ###if DEBUG: print "-------- SMAN" - s, = struct.unpack(">f", data.read(4)) - my_dict['SMAN'] = s - subchunklen -= 4 - elif subchunkname == "SIDE": #double sided? - ###if DEBUG: print "-------- SIDE" #if 1 side do not define key - s, = struct.unpack(">H", data.read(2)) - if s == 3: - my_dict['SIDE'] = s - subchunklen -= 2 - elif subchunkname == "RIND": #Refraction: mapped on IOR - ###if DEBUG: print "-------- RIND" - s, = struct.unpack(">f", data.read(4)) - envelope, env_size = read_vx(data) - my_dict['RIND'] = s - subchunklen -= (4+env_size) - elif subchunkname == "BLOK": #blocks - ###if DEBUG: print "-------- BLOK" - rr, uvname = read_surfblok(data.read(subchunklen)) - #paranoia setting: preventing adding an empty dict - if rr: # != {} - try: - my_dict['BLOK'].append(rr) - except: - my_dict['BLOK'] = [rr] - - if uvname: # != "": - my_dict['UVNAME'] = uvname #theoretically there could be a number of them: only one used per surf - # all are dictionaries - so testing keys - if not('g_IMAG' in my_dict) and ('CHAN' in rr) and ('OPAC' in rr) and ('IMAG' in rr): - if (rr['CHAN'] == 'COLR') and (rr['OPAC'] == 0): - my_dict['g_IMAG'] = rr['IMAG'] #do not set anything, just save image object for later assignment - subchunklen = 0 #force ending - else: # Misc Chunks - pass - ###if DEBUG: print "-------- SURF:%s: skipping" % subchunkname - if subchunklen > 0: - discard = data.read(subchunklen) - #end loop on surf chunks - try:#if my_dict.has_key('BLOK'): - my_dict['BLOK'].reverse() #texture applied in reverse order with respect to reading from lwo - except: - pass - - #uncomment this if material pre-allocated by read_surf - my_dict['g_MAT'] = bpy.data.materials.new(my_dict['NAME']) - ###if DEBUG: print "-> Material pre-allocated." - return my_dict - -# ========================= -# === Recalculate Faces === -# ========================= - -def get_uvface(complete_list, facenum): - # extract from the complete list only vertexes of the desired polygon - ''' - my_facelist = [] - for elem in complete_list: - if elem[0] == facenum: - my_facelist.append(elem) - return my_facelist - ''' - return [elem for elem in complete_list if elem[0] == facenum] - -def get_newindex(polygon_list, vertnum): - # extract from the polygon list the new index associated to a vertex - if not polygon_list: # == [] - return -1 - for elem in polygon_list: - if elem[1] == vertnum: - return elem[2] - # ###if DEBUG: print "WARNING: expected vertex %s for polygon %s. Polygon_list dump follows" % (vertnum, polygon_list[0][0]) - # ###if DEBUG: print polygon_list - return -1 - -def get_surf(surf_list, cur_tag): - for elem in surf_list: # elem can be None - if elem and elem['NAME'] == cur_tag: - return elem - return {} - - - -# ==================================== -# === Modified Create Blender Mesh === -# ==================================== -def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not_used_faces): - #take the needed faces and update the not-used face list - complete_vertlist = objspec_list[2] - complete_facelist = objspec_list[3] - uvcoords_dict = objspec_list[7] - facesuv_dict = objspec_list[8] - vertex_map = {} #implementation as dict - cur_ptag_faces = [] - cur_ptag_faces_indexes = [] - maxface = len(complete_facelist) - for ff in current_facelist: - if ff >= maxface: - ###if DEBUG: print "Non existent face addressed: Giving up with this object" - return None, not_used_faces #return the created object - cur_face = complete_facelist[ff] - cur_ptag_faces_indexes.append(ff) - if not_used_faces: # != [] - not_used_faces[ff] = -1 - for vv in cur_face: vertex_map[vv] = 1 - #end loop on faces - store_edge = 0 - - scn= bpy.data.scenes.active - msh = bpy.data.meshes.new() - obj = scn.objects.new(msh) - - mat = None - try: - msh.materials = [surf['g_MAT']] - except: - pass - - msh.mode |= Blender.Mesh.Modes.AUTOSMOOTH #smooth it anyway - if 'SMAN' in surf: # has_key - #not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle) - #only one smoothing angle will be active! => take the max one - msh.degr = min(80, int(surf['SMAN']/3.1415926535897932384626433832795*180.0)) #lwo in radians - blender in degrees - - try: - img= lookup_imag(clip_list, surf['g_IMAG'])['g_IMG'] - except: - img= None - - #uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])) and (img != None)) - uv_flag = (('UVNAME' in surf) and (surf['UVNAME'] in uvcoords_dict)) - - ###if DEBUG: print "\n#===================================================================#" - ###if DEBUG: print "Processing Object: %s" % objname - ###if DEBUG: print "#===================================================================#" - - if uv_flag: - msh.verts.extend([(0.0,0.0,0.0),]) - j = 1 - else: - j = 0 - - def tmp_get_vert(k, i): - vertex_map[k] = i+j # j is the dummy vert - # ###if DEBUG: print complete_vertlist[i] - return complete_vertlist[k] - - - - msh.verts.extend([tmp_get_vert(k, i) for i, k in enumerate(vertex_map.iterkeys())]) - msh.transform(TXMTX) # faster then applying while reading. - #end sweep over vertexes - - #append faces - FACE_TEX= Blender.Mesh.FaceModes.TEX - FACE_ALPHA= Blender.Mesh.FaceTranspModes.ALPHA - EDGE_DRAW_FLAG= Blender.Mesh.EdgeFlags.EDGEDRAW | Blender.Mesh.EdgeFlags.EDGERENDER - - - edges = [] - face_data = [] # [(indicies, material, uvs, image), ] - face_uvs = [] - edges_fgon = [] - - if uv_flag: - uvcoords_dict_context = uvcoords_dict[surf['UVNAME']] - try: current_uvdict = facesuv_dict[surf['UVNAME']] - except: current_uvdict = None - - default_uv = Blender.Mathutils.Vector(0,0) - def tmp_get_face_uvs(cur_face, i): - uvs = [] - if current_uvdict: - uvface = get_uvface(current_uvdict,i) - for vi in cur_face: - ni = get_newindex(uvface, vi) - if ni == -1: ni = vi - - try: - uvs.append(uvcoords_dict_context[ ni ]) - except: - ###if DEBUG: print '\tWarning, Corrupt UVs' - uvs.append(default_uv) - else: - for vi in cur_face: - try: - uvs.append(uvcoords_dict_context[ vi ]) - except: - ###if DEBUG: print '\tWarning, Corrupt UVs' - uvs.append(default_uv) - - return uvs - cur_face - for i in cur_ptag_faces_indexes: - cur_face = complete_facelist[i] - numfaceverts = len(cur_face) - - if numfaceverts == 2: edges.append((vertex_map[cur_face[0]], vertex_map[cur_face[1]])) - elif numfaceverts == 3 or numfaceverts == 4: - rev_face = [__i for __i in reversed(cur_face)] - face_data.append( [vertex_map[j] for j in rev_face] ) - if uv_flag: face_uvs.append(tmp_get_face_uvs(rev_face, i)) - elif numfaceverts > 4: - meta_faces= BPyMesh.ngon(complete_vertlist, cur_face, PREF_FIX_LOOPS= True) - edge_face_count = {} - for mf in meta_faces: - # These will always be tri's since they are scanfill faces - mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]] - face_data.append( [vertex_map[j] for j in mf] ) - - if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i)) - - #if USE_FGON: - if len(meta_faces) > 1: - mf = face_data[-1] # reuse mf - for j in xrange(3): - v1= mf[j] - v2= mf[j-1] - if v1!=v2: - if v1>v2: - v2,v1= v1,v2 - try: - edge_face_count[v1,v2]+= 1 - except: - edge_face_count[v1,v2]= 0 - - - - if edge_face_count: - edges_fgon.extend( [vert_key for vert_key, count in edge_face_count.iteritems() if count] ) - - if edges: - msh.edges.extend(edges) - - face_mapping_removed = msh.faces.extend(face_data, indexList=True) - if 'TRAN' in surf or (mat and mat.alpha<1.0): # incase mat is null - transp_flag = True - else: - transp_flag = False - - if uv_flag: - msh.faceUV = True - msh_faces= msh.faces - for i, uvs in enumerate(face_uvs): - i_mapped = face_mapping_removed[i] - if i_mapped != None: - f = msh_faces[i_mapped] - f.uv = uvs - if img: - f.image = img - - if transp_flag: f.transp |= FACE_ALPHA - - if edges_fgon: - msh_edges = msh.edges - FGON= Blender.Mesh.EdgeFlags.FGON - edges_fgon = msh.findEdges( edges_fgon ) - if type(edges_fgon) != list: edges_fgon = [edges_fgon] - for ed in edges_fgon: - if ed!=None: - msh_edges[ed].flag |= FGON - - if not(uv_flag): #clear eventual UV data - msh.faceUV = False - - if uv_flag: - msh.verts.delete([0,]) - - return obj, not_used_faces #return the created object - - -# ============================================ -# === Set Subsurf attributes on given mesh === -# ============================================ -def set_subsurf(obj): - mods = obj.modifiers # get the object's modifiers - mod = mods.append(Blender.Modifier.Type.SUBSURF) # add a new subsurf modifier - mod[Blender.Modifier.Settings.LEVELS] = 2 # set subsurf subdivision levels to 2 - mod[Blender.Modifier.Settings.RENDLEVELS] = 2 # set subsurf rendertime subdivision levels to 2 - obj.makeDisplayList() - - -# ================================= -# === object size and dimension === -# ================================= -def obj_size_pos(obj): - bbox = obj.getBoundBox() - bbox_min = map(lambda *row: min(row), *bbox) #transpose & get min - bbox_max = map(lambda *row: max(row), *bbox) #transpose & get max - obj_size = (bbox_max[0]-bbox_min[0], bbox_max[1]-bbox_min[1], bbox_max[2]-bbox_min[2]) - obj_pos = ( (bbox_max[0]+bbox_min[0]) / 2, (bbox_max[1]+bbox_min[1]) / 2, (bbox_max[2]+bbox_min[2]) / 2) - return (obj_size, obj_pos) - - -# ========================= -# === Create the object === -# ========================= -def create_objects(clip_list, objspec_list, surf_list): - nf = len(objspec_list[3]) - not_used_faces = range(nf) - ptag_dict = objspec_list[5] - obj_dict = {} #links tag names to object, used for material assignments - obj_dim_dict = {} - obj_list = [] #have it handy for parent association - middlechar = "+" - endchar = "" - if (objspec_list[6] == 1): - middlechar = endchar = "#" - for cur_tag, ptag_dict_val in ptag_dict.iteritems(): - if ptag_dict_val != []: - cur_surf = get_surf(surf_list, cur_tag) - cur_obj, not_used_faces= my_create_mesh(clip_list, cur_surf, objspec_list, ptag_dict_val, objspec_list[0][:9]+middlechar+cur_tag[:9], not_used_faces) - # Works now with new modifiers - if objspec_list[6] == 1: - set_subsurf(cur_obj) - if cur_obj: # != None - obj_dict[cur_tag] = cur_obj - obj_dim_dict[cur_tag] = obj_size_pos(cur_obj) - obj_list.append(cur_obj) - #end loop on current group - #and what if some faces not used in any named PTAG? get rid of unused faces - orphans = [] - for tt in not_used_faces: - if tt > -1: orphans.append(tt) - #end sweep on unused face list - not_used_faces = None - if orphans: # != [] - cur_surf = get_surf(surf_list, "_Orphans") - cur_obj, not_used_faces = my_create_mesh(clip_list, cur_surf, objspec_list, orphans, objspec_list[0][:9]+middlechar+"Orphans", []) - if cur_obj: # != None - if objspec_list[6] == 1: - set_subsurf(cur_obj) - obj_dict["_Orphans"] = cur_obj - obj_dim_dict["_Orphans"] = obj_size_pos(cur_obj) - obj_list.append(cur_obj) - objspec_list[1]= obj_dict - objspec_list[4]= obj_dim_dict - - return - - - -# =========================================== -# === Lookup for image index in clip_list === -# =========================================== -def lookup_imag(clip_list, ima_id): - for ii in clip_list: - if ii and ii['ID'] == ima_id: - if 'XREF' in ii: # has_key - #cross reference - recursively look for images - return lookup_imag(clip_list, ii['XREF']) - else: - return ii - return None - - -# =================================================== -# === Create and assign image mapping to material === -# =================================================== -def create_blok(surf, mat, clip_list, obj_size, obj_pos): - - def output_size_ofs(size, pos, blok): - #just automate repetitive task - # 0 == X, 1 == Y, 2 == Z - size_default = [1.0] * 3 - size2 = [1.0] * 3 - ofs_default = [0.0] * 3 - offset = [1.0] * 3 - axis_default = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] - axis = [1.0] * 3 - c_map_txt = [" X--", " -Y-", " --Z"] - c_map = [0,1,2] # standard, good for Z axis projection - if blok['MAJAXIS'] == 0: - c_map = [1,2,0] # X axis projection - if blok['MAJAXIS'] == 2: - c_map = [0,2,1] # Y axis projection - - ###if DEBUG: print "!!!axis mapping:" - #this is the smart way - ###if DEBUG: for mp in c_map: print c_map_txt[mp] - - if blok['SIZE'][0] != 0.0: #paranoia controls - size_default[0] = (size[0]/blok['SIZE'][0]) - ofs_default[0] = ((blok['CNTR'][0]-pos[0])/blok['SIZE'][0]) - if blok['SIZE'][1] != 0.0: - size_default[2] = (size[2]/blok['SIZE'][1]) - ofs_default[2] = ((blok['CNTR'][1]-pos[2])/blok['SIZE'][1]) - if blok['SIZE'][2] != 0.0: - size_default[1] = (size[1]/blok['SIZE'][2]) - ofs_default[1] = ((blok['CNTR'][2]-pos[1])/blok['SIZE'][2]) - - for mp in xrange(3): - axis[mp] = axis_default[c_map[mp]] - size2[mp] = size_default[c_map[mp]] - offset[mp] = ofs_default[c_map[mp]] - if offset[mp]>10.0: offset[mp]-10.0 - if offset[mp]<-10.0: offset[mp]+10.0 -# size = [size_default[mp] for mp in c_map] - - ###if DEBUG: print "!!!texture size and offsets:" - ###if DEBUG: print " sizeX = %.5f; sizeY = %.5f; sizeZ = %.5f" % (size[0],size[1],size[2]) - ###if DEBUG: print " ofsX = %.5f; ofsY = %.5f; ofsZ = %.5f" % (offset[0],offset[1],offset[2]) - return axis, size2, offset - - ti = 0 - alphaflag = 0 #switched to 1 if some tex in this block is using alpha - lastimag = 0 #experimental .... - for blok in surf['BLOK']: - ###if DEBUG: print "#...................................................................#" - ###if DEBUG: print "# Processing texture block no.%s for surf %s" % (ti,surf['NAME']) - ###if DEBUG: print "#...................................................................#" - # tobj.pdict (blok) - if ti > 9: break #only 8 channels 0..7 allowed for texture mapping - #if not blok['ENAB']: - # ###if DEBUG: print "***Image is not ENABled! Quitting this block" - # break - if not('IMAG' in blok): # has_key - ###if DEBUG: print "***No IMAGE for this block? Quitting" - break #extract out the image index within the clip_list - if blok['IMAG'] == 0: blok['IMAG'] = lastimag #experimental .... - ###if DEBUG: print "looking for image number %d" % blok['IMAG'] - ima = lookup_imag(clip_list, blok['IMAG']) - if ima == None: - ###if DEBUG: print "***Block index image not within CLIP list? Quitting Block" - break #safety check (paranoia setting) - img = ima['g_IMG'] - lastimag = blok['IMAG'] #experimental .... - if img == None: - ###if DEBUG: print "***Failed to pre-allocate image %s found: giving up" % ima['BASENAME'] - break - tname = str(ima['ID']) - if blok['ENAB']: - tname += "+" - else: - tname += "x" #let's signal when should not be enabled - if 'CHAN' in blok: # has_key - tname += blok['CHAN'] - newtex = bpy.data.textures.new(tname) - newtex.setType('Image') # make it anu image texture - newtex.image = img - #how does it extends beyond borders - if 'WRAP' in blok: # has_key - if (blok['WRAP'] == 3) or (blok['WRAP'] == 2): - newtex.setExtend('Extend') - elif (blok['WRAP'] == 1): - newtex.setExtend('Repeat') - elif (blok['WRAP'] == 0): - newtex.setExtend('Clip') - ###if DEBUG: print "generated texture %s" % tname - - #MapTo is determined by CHAN parameter - #assign some defaults - colfac = 1.0 - dvar = 1.0 - norfac = 0.5 - nega = False - mapflag = Blender.Texture.MapTo.COL #default to color - maptype = Blender.Texture.Mappings.FLAT - if 'CHAN' in blok: # has_key - if blok['CHAN'] == 'COLR' and 'OPACVAL' in blok: # has_key - colfac = blok['OPACVAL'] - # Blender needs this to be clamped - colfac = max(0.0, min(1.0, colfac)) - ###if DEBUG: print "!!!Set Texture -> MapTo -> Col = %.3f" % colfac - if blok['CHAN'] == 'BUMP': - mapflag = Blender.Texture.MapTo.NOR - if 'OPACVAL' in blok: norfac = blok['OPACVAL'] # has_key - ###if DEBUG: print "!!!Set Texture -> MapTo -> Nor = %.3f" % norfac - if blok['CHAN'] == 'LUMI': - mapflag = Blender.Texture.MapTo.EMIT - if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key - ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar - if blok['CHAN'] == 'DIFF': - mapflag = Blender.Texture.MapTo.REF - if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key - ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar - if blok['CHAN'] == 'SPEC': - mapflag = Blender.Texture.MapTo.SPEC - if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key - ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar - if blok['CHAN'] == 'TRAN': - mapflag = Blender.Texture.MapTo.ALPHA - if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key - ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar - alphaflag = 1 - nega = True - if 'NEGA' in blok: # has_key - ###if DEBUG: print "!!!Watch-out: effect of this texture channel must be INVERTED!" - nega = not nega - - blendmode_list = ['Mix', - 'Subtractive', - 'Difference', - 'Multiply', - 'Divide', - 'Mix with calculated alpha layer and stencil flag', - 'Texture Displacement', - 'Additive'] - set_blendmode = 7 #default additive - if 'OPAC' in blok: # has_key - set_blendmode = blok['OPAC'] - if set_blendmode == 5: #transparency - newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA - if nega: newtex.flags |= Blender.Texture.Flags.NEGALPHA - ###if DEBUG: print "!!!Set Texture -> MapTo -> Blending Mode = %s" % blendmode_list[set_blendmode] - - #the TexCo flag is determined by PROJ parameter - axis = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] - size = [1.0] * 3 - ofs = [0.0] * 3 - if 'PROJ' in blok: # has_key - if blok['PROJ'] == 0: #0 - Planar - ###if DEBUG: print "!!!Flat projection" - coordflag = Blender.Texture.TexCo.ORCO - maptype = Blender.Texture.Mappings.FLAT - elif blok['PROJ'] == 1: #1 - Cylindrical - ###if DEBUG: print "!!!Cylindrical projection" - coordflag = Blender.Texture.TexCo.ORCO - maptype = Blender.Texture.Mappings.TUBE - elif blok['PROJ'] == 2: #2 - Spherical - ###if DEBUG: print "!!!Spherical projection" - coordflag = Blender.Texture.TexCo.ORCO - maptype = Blender.Texture.Mappings.SPHERE - elif blok['PROJ'] == 3: #3 - Cubic - ###if DEBUG: print "!!!Cubic projection" - coordflag = Blender.Texture.TexCo.ORCO - maptype = Blender.Texture.Mappings.CUBE - elif blok['PROJ'] == 4: #4 - Front Projection - ###if DEBUG: print "!!!Front projection" - coordflag = Blender.Texture.TexCo.ORCO - maptype = Blender.Texture.Mappings.FLAT # ??? could it be a FLAT with some other TexCo type? - elif blok['PROJ'] == 5: #5 - UV - ###if DEBUG: print "UVMapped" - coordflag = Blender.Texture.TexCo.UV - maptype = Blender.Texture.Mappings.FLAT #in case of UV default to FLAT mapping => effectively not used - if blok['PROJ'] != 5: #This holds for any projection map except UV - axis, size, ofs = output_size_ofs(obj_size, obj_pos, blok) - - # Clamp ofs and size else blender will raise an error - for ii in xrange(3): - ofs[ii]= min(10.0, max(-10, ofs[ii])) - size[ii]= min(100, max(-100, size[ii])) - - mat.setTexture(ti, newtex, coordflag, mapflag) - current_mtex = mat.getTextures()[ti] - current_mtex.mapping = maptype - current_mtex.colfac = colfac - current_mtex.dvar = dvar - current_mtex.norfac = norfac - current_mtex.neg = nega - current_mtex.xproj = axis[0] - current_mtex.yproj = axis[1] - current_mtex.zproj = axis[2] - current_mtex.size = tuple(size) - current_mtex.ofs = tuple(ofs) - if (set_blendmode == 5): #transparency - current_mtex.stencil = not (nega) - - ti += 1 - #end loop over bloks - return alphaflag - - -# ======================================== -# === Create and assign a new material === -# ======================================== -#def update_material(surf_list, ptag_dict, obj, clip_list, uv_dict, dir_part): -def update_material(clip_list, objspec, surf_list): - if (surf_list == []) or (objspec[5] == {}) or (objspec[1] == {}): - ###if DEBUG: print "something getting wrong in update_material: dump follows ..." - ###if DEBUG: print surf_list - ###if DEBUG: print objspec[5] - ###if DEBUG: print objspec[1] - return - obj_dict = objspec[1] - all_faces = objspec[3] - obj_dim_dict = objspec[4] - ptag_dict = objspec[5] - uvcoords_dict = objspec[7] - facesuv_dict = objspec[8] - for surf in surf_list: - if surf and surf['NAME'] in ptag_dict: # in ptag_dict.keys() - ###if DEBUG: print "#-------------------------------------------------------------------#" - ###if DEBUG: print "Processing surface (material): %s" % surf['NAME'] - ###if DEBUG: print "#-------------------------------------------------------------------#" - #material set up - facelist = ptag_dict[surf['NAME']] - #bounding box and position - cur_obj = obj_dict[surf['NAME']] - obj_size = obj_dim_dict[surf['NAME']][0] - obj_pos = obj_dim_dict[surf['NAME']][1] - ###if DEBUG: print surf - #uncomment this if material pre-allocated by read_surf - mat = surf['g_MAT'] - if mat == None: - ###if DEBUG: print "Sorry, no pre-allocated material to update. Giving up for %s." % surf['NAME'] - break - #mat = Blender.Material.New(surf['NAME']) - #surf['g_MAT'] = mat - if 'COLR' in surf: # has_key - mat.rgbCol = surf['COLR'] - if 'LUMI' in surf: - mat.setEmit(surf['LUMI']) - if 'GVAL' in surf: # has_key - mat.setAdd(surf['GVAL']) - if 'SPEC' in surf: # has_key - mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0] - if 'DIFF' in surf: # has_key - mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0] - if 'GLOS' in surf: # has_key #lwo [0.0, 1.0] - blender [0, 255] - glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping - if glo <32: glo = 32 #clamped to 32-255 - if glo >255: glo = 255 - mat.setHardness(glo) - if 'TRNL' in surf: # has_key - mat.setTranslucency(surf['TRNL']) #NOT SURE ABOUT THIS lwo [0.0, 1.0] - blender [0.0, 1.0] - - mm = mat.mode - mm |= Blender.Material.Modes.TRANSPSHADOW - if 'REFL' in surf: # has_key - mat.setRayMirr(surf['REFL']) #lwo [0.0, 1.0] - blender [0.0, 1.0] - mm |= Blender.Material.Modes.RAYMIRROR - if 'TRAN' in surf: # has_key - mat.setAlpha(1.0-surf['TRAN']) #lwo [0.0, 1.0] - blender [1.0, 0.0] - mm |= Blender.Material.Modes.RAYTRANSP - if 'RIND' in surf: # has_key - s = surf['RIND'] - if s < 1.0: s = 1.0 - if s > 3.0: s = 3.0 - mat.setIOR(s) #clipped to blender [1.0, 3.0] - mm |= Blender.Material.Modes.RAYTRANSP - if 'BLOK' in surf and surf['BLOK'] != []: - #update the material according to texture. - alphaflag = create_blok(surf, mat, clip_list, obj_size, obj_pos) - if alphaflag: - mm |= Blender.Material.Modes.RAYTRANSP - mat.mode = mm - #finished setting up the material - #end if exist SURF - #end loop on materials (SURFs) - return - - -# ====================== -# === Read Faces 6.0 === -# ====================== -def read_faces_6(lwochunk): - data = cStringIO.StringIO(lwochunk.read()) - faces = [] - polygon_type = data.read(4) - subsurf = 0 - if polygon_type != "FACE" and polygon_type != "PTCH": - ###if DEBUG: print "No FACE/PATCH Were Found. Polygon Type: %s" % polygon_type - return "", 2 - if polygon_type == 'PTCH': subsurf = 1 - i = 0 - while(i < lwochunk.chunksize-4): - #if not i%1000 and my_meshtools.show_progress: - # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") - facev = [] - numfaceverts, = struct.unpack(">H", data.read(2)) - i += 2 - - for j in xrange(numfaceverts): - index, index_size = read_vx(data) - i += index_size - facev.append(index) - faces.append(facev) - ###if DEBUG: print "read %s faces; type of block %d (0=FACE; 1=PATCH)" % (len(faces), subsurf) - return faces, subsurf - -def main(): - if not struct: - Blender.Draw.PupMenu('This importer requires a full python install') - return - - Blender.Window.FileSelector(read, "Import LWO", '*.lwo') - -if __name__=='__main__': - main() - - -# Cams debugging lwo loader -""" -TIME= Blender.sys.time() -import os -print 'Searching for files' -os.system('find /fe/lwo/Objects/ -follow -iname "*.lwo" > /tmp/templwo_list') -# os.system('find /storage/ -iname "*.lwo" > /tmp/templwo_list') -print '...Done' -file= open('/tmp/templwo_list', 'r') -lines= file.readlines() - -# sort by filesize for faster testing -lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] -lines_size.sort() -lines = [f[1] for f in lines_size] - -file.close() - -def between(v,a,b): - if v <= max(a,b) and v >= min(a,b): - return True - - return False -size= 0.0 -for i, _lwo in enumerate(lines): - #if i==425: # SCANFILL - #if 1: - #if i==520: # SCANFILL CRASH - #if i==47: # SCANFILL CRASH - #if between(i, 525, 550): - #if i > 1635: - #if i != 1519: # 730 - if i>141: - #if 1: - # _lwo= _lwo[:-1] - print 'Importing', _lwo, '\nNUMBER', i, 'of', len(lines) - _lwo_file= _lwo.split('/')[-1].split('\\')[-1] - newScn= bpy.data.scenes.new(_lwo_file) - bpy.data.scenes.active = newScn - size += ((os.path.getsize(_lwo)/1024.0))/ 1024.0 - read(_lwo) - # Remove objects to save memory? - ''' - for ob in newScn.objects: - if ob.type=='Mesh': - me= ob.getData(mesh=1) - me.verts= None - newScn.unlink(ob) - ''' - print 'mb size so far', size - -print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -""" \ No newline at end of file diff --git a/release/scripts/md2_export.py b/release/scripts/md2_export.py deleted file mode 100644 index f0fe6b9af40..00000000000 --- a/release/scripts/md2_export.py +++ /dev/null @@ -1,1271 +0,0 @@ -#!BPY - -""" -Name: 'MD2 (.md2)' -Blender: 243 -Group: 'Export' -Tooltip: 'Export to Quake file format (.md2).' -""" - -__author__ = 'Bob Holcomb' -__version__ = '0.18.1 patch 1' -__url__ = ["Bob's site, http://bane.servebeer.com", - "Support forum, http://bane.servebeer.com", "blender", "blenderartists.org"] -__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] -__bpydoc__ = """\ -This script Exports a Quake 2 file (MD2). - - Additional help from: Shadwolf, Skandal, Rojo, Cambo
- Thanks Guys! -""" - -# This is a PATCHED VERSION, fixing the bug due to which animations would -# (almost) never work. It is now also possible to output a MD2 model without -# texture. -# On: 23 january 2008 -# By: Boris van Schooten (schooten@cs.utwente.nl) - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C): Bob Holcomb -# -# 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 Blender -from Blender import * -from Blender.Draw import * -from Blender.BGL import * -from Blender.Window import * - -import struct, string -from types import * - - - -###################################################### -# GUI Loader -###################################################### - -# Export globals -g_filename=Create("tris.md2") -g_frame_filename=Create("default") - -g_filename_search=Create("") -g_frame_search=Create("default") - -g_texture_path=Create("") - -user_frame_list=[] - -#Globals -g_scale=Create(1.0) - -# Events -EVENT_NOEVENT=1 -EVENT_SAVE_MD2=2 -EVENT_CHOOSE_FILENAME=3 -EVENT_CHOOSE_FRAME=4 -EVENT_EXIT=100 - -###################################################### -# Callbacks for Window functions -###################################################### -def filename_callback(input_filename): - global g_filename - g_filename.val=input_filename - -def frame_callback(input_frame): - global g_frame_filename - g_frame_filename.val=input_frame - -def draw_gui(): - global g_scale - global g_filename - global g_frame_filename - global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_FRAME,EVENT_EXIT - global g_texture_path - - ########## Titles - glClear(GL_COLOR_BUFFER_BIT) - glRasterPos2d(10, 120) - Text("MD2 Export") - - ######### Parameters GUI Buttons - ######### MD2 Filename text entry - g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 75, 210, 18, - g_filename.val, 255, "MD2 file to save") - ########## MD2 File Search Button - Button("Browse",EVENT_CHOOSE_FILENAME,220,75,80,18) - - ########## MD2 Frame List Text entry - g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, - g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults") - ########## Frame List Search Button - Button("Browse",EVENT_CHOOSE_FRAME,220,55,80,18) - - ########## Texture path to append - g_texture_path=String("Texture Path: ", EVENT_NOEVENT, 10,35,210,18, - g_texture_path.val,255, "Texture path to prepend") - - - ########## Scale slider-default is 1/8 which is a good scale for md2->blender - g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 95, 210, 18, - 1.0, 0.001, 10.0, 1, "Scale factor for object Model"); - - ######### Draw and Exit Buttons - Button("Export",EVENT_SAVE_MD2 , 10, 10, 80, 18) - Button("Exit",EVENT_EXIT , 170, 10, 80, 18) - -def event(evt, val): - if (evt == QKEY and not val): - Exit() - -def bevent(evt): - global g_filename - global g_frame_filename - global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_EXIT - - ######### Manages GUI events - if (evt==EVENT_EXIT): - Blender.Draw.Exit() - elif (evt==EVENT_CHOOSE_FILENAME): - FileSelector(filename_callback, "MD2 File Selection") - elif (evt==EVENT_CHOOSE_FRAME): - FileSelector(frame_callback, "Frame Selection") - elif (evt==EVENT_SAVE_MD2): - save_md2(g_filename.val) - Blender.Draw.Exit() - return - -Register(draw_gui, event, bevent) - -###################################################### -# MD2 Model Constants -###################################################### -MD2_MAX_TRIANGLES=4096 -MD2_MAX_VERTICES=2048 -MD2_MAX_TEXCOORDS=2048 -MD2_MAX_FRAMES=512 -MD2_MAX_SKINS=32 -MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) - -MD2_FRAME_NAME_LIST=(("stand",1,40), - ("run",41,46), - ("attack",47,54), - ("pain1",55,58), - ("pain2",59,62), - ("pain3",63,66), - ("jump",67,72), - ("flip",73,84), - ("salute", 85,95), - ("taunt",96,112), - ("wave",113,123), - ("point",124,135), - ("crstnd",136,154), - ("crwalk",155,160), - ("crattack",161,169), - ("crpain",170,173), - ("crdeath",174,178), - ("death1",179,184), - ("death2",185,190), - ("death3",191,198)) - #198 frames - -MD2_NORMALS=((-0.525731, 0.000000, 0.850651), - (-0.442863, 0.238856, 0.864188), - (-0.295242, 0.000000, 0.955423), - (-0.309017, 0.500000, 0.809017), - (-0.162460, 0.262866, 0.951056), - (0.000000, 0.000000, 1.000000), - (0.000000, 0.850651, 0.525731), - (-0.147621, 0.716567, 0.681718), - (0.147621, 0.716567, 0.681718), - (0.000000, 0.525731, 0.850651), - (0.309017, 0.500000, 0.809017), - (0.525731, 0.000000, 0.850651), - (0.295242, 0.000000, 0.955423), - (0.442863, 0.238856, 0.864188), - (0.162460, 0.262866, 0.951056), - (-0.681718, 0.147621, 0.716567), - (-0.809017, 0.309017, 0.500000), - (-0.587785, 0.425325, 0.688191), - (-0.850651, 0.525731, 0.000000), - (-0.864188, 0.442863, 0.238856), - (-0.716567, 0.681718, 0.147621), - (-0.688191, 0.587785, 0.425325), - (-0.500000, 0.809017, 0.309017), - (-0.238856, 0.864188, 0.442863), - (-0.425325, 0.688191, 0.587785), - (-0.716567, 0.681718, -0.147621), - (-0.500000, 0.809017, -0.309017), - (-0.525731, 0.850651, 0.000000), - (0.000000, 0.850651, -0.525731), - (-0.238856, 0.864188, -0.442863), - (0.000000, 0.955423, -0.295242), - (-0.262866, 0.951056, -0.162460), - (0.000000, 1.000000, 0.000000), - (0.000000, 0.955423, 0.295242), - (-0.262866, 0.951056, 0.162460), - (0.238856, 0.864188, 0.442863), - (0.262866, 0.951056, 0.162460), - (0.500000, 0.809017, 0.309017), - (0.238856, 0.864188, -0.442863), - (0.262866, 0.951056, -0.162460), - (0.500000, 0.809017, -0.309017), - (0.850651, 0.525731, 0.000000), - (0.716567, 0.681718, 0.147621), - (0.716567, 0.681718, -0.147621), - (0.525731, 0.850651, 0.000000), - (0.425325, 0.688191, 0.587785), - (0.864188, 0.442863, 0.238856), - (0.688191, 0.587785, 0.425325), - (0.809017, 0.309017, 0.500000), - (0.681718, 0.147621, 0.716567), - (0.587785, 0.425325, 0.688191), - (0.955423, 0.295242, 0.000000), - (1.000000, 0.000000, 0.000000), - (0.951056, 0.162460, 0.262866), - (0.850651, -0.525731, 0.000000), - (0.955423, -0.295242, 0.000000), - (0.864188, -0.442863, 0.238856), - (0.951056, -0.162460, 0.262866), - (0.809017, -0.309017, 0.500000), - (0.681718, -0.147621, 0.716567), - (0.850651, 0.000000, 0.525731), - (0.864188, 0.442863, -0.238856), - (0.809017, 0.309017, -0.500000), - (0.951056, 0.162460, -0.262866), - (0.525731, 0.000000, -0.850651), - (0.681718, 0.147621, -0.716567), - (0.681718, -0.147621, -0.716567), - (0.850651, 0.000000, -0.525731), - (0.809017, -0.309017, -0.500000), - (0.864188, -0.442863, -0.238856), - (0.951056, -0.162460, -0.262866), - (0.147621, 0.716567, -0.681718), - (0.309017, 0.500000, -0.809017), - (0.425325, 0.688191, -0.587785), - (0.442863, 0.238856, -0.864188), - (0.587785, 0.425325, -0.688191), - (0.688191, 0.587785, -0.425325), - (-0.147621, 0.716567, -0.681718), - (-0.309017, 0.500000, -0.809017), - (0.000000, 0.525731, -0.850651), - (-0.525731, 0.000000, -0.850651), - (-0.442863, 0.238856, -0.864188), - (-0.295242, 0.000000, -0.955423), - (-0.162460, 0.262866, -0.951056), - (0.000000, 0.000000, -1.000000), - (0.295242, 0.000000, -0.955423), - (0.162460, 0.262866, -0.951056), - (-0.442863, -0.238856, -0.864188), - (-0.309017, -0.500000, -0.809017), - (-0.162460, -0.262866, -0.951056), - (0.000000, -0.850651, -0.525731), - (-0.147621, -0.716567, -0.681718), - (0.147621, -0.716567, -0.681718), - (0.000000, -0.525731, -0.850651), - (0.309017, -0.500000, -0.809017), - (0.442863, -0.238856, -0.864188), - (0.162460, -0.262866, -0.951056), - (0.238856, -0.864188, -0.442863), - (0.500000, -0.809017, -0.309017), - (0.425325, -0.688191, -0.587785), - (0.716567, -0.681718, -0.147621), - (0.688191, -0.587785, -0.425325), - (0.587785, -0.425325, -0.688191), - (0.000000, -0.955423, -0.295242), - (0.000000, -1.000000, 0.000000), - (0.262866, -0.951056, -0.162460), - (0.000000, -0.850651, 0.525731), - (0.000000, -0.955423, 0.295242), - (0.238856, -0.864188, 0.442863), - (0.262866, -0.951056, 0.162460), - (0.500000, -0.809017, 0.309017), - (0.716567, -0.681718, 0.147621), - (0.525731, -0.850651, 0.000000), - (-0.238856, -0.864188, -0.442863), - (-0.500000, -0.809017, -0.309017), - (-0.262866, -0.951056, -0.162460), - (-0.850651, -0.525731, 0.000000), - (-0.716567, -0.681718, -0.147621), - (-0.716567, -0.681718, 0.147621), - (-0.525731, -0.850651, 0.000000), - (-0.500000, -0.809017, 0.309017), - (-0.238856, -0.864188, 0.442863), - (-0.262866, -0.951056, 0.162460), - (-0.864188, -0.442863, 0.238856), - (-0.809017, -0.309017, 0.500000), - (-0.688191, -0.587785, 0.425325), - (-0.681718, -0.147621, 0.716567), - (-0.442863, -0.238856, 0.864188), - (-0.587785, -0.425325, 0.688191), - (-0.309017, -0.500000, 0.809017), - (-0.147621, -0.716567, 0.681718), - (-0.425325, -0.688191, 0.587785), - (-0.162460, -0.262866, 0.951056), - (0.442863, -0.238856, 0.864188), - (0.162460, -0.262866, 0.951056), - (0.309017, -0.500000, 0.809017), - (0.147621, -0.716567, 0.681718), - (0.000000, -0.525731, 0.850651), - (0.425325, -0.688191, 0.587785), - (0.587785, -0.425325, 0.688191), - (0.688191, -0.587785, 0.425325), - (-0.955423, 0.295242, 0.000000), - (-0.951056, 0.162460, 0.262866), - (-1.000000, 0.000000, 0.000000), - (-0.850651, 0.000000, 0.525731), - (-0.955423, -0.295242, 0.000000), - (-0.951056, -0.162460, 0.262866), - (-0.864188, 0.442863, -0.238856), - (-0.951056, 0.162460, -0.262866), - (-0.809017, 0.309017, -0.500000), - (-0.864188, -0.442863, -0.238856), - (-0.951056, -0.162460, -0.262866), - (-0.809017, -0.309017, -0.500000), - (-0.681718, 0.147621, -0.716567), - (-0.681718, -0.147621, -0.716567), - (-0.850651, 0.000000, -0.525731), - (-0.688191, 0.587785, -0.425325), - (-0.587785, 0.425325, -0.688191), - (-0.425325, 0.688191, -0.587785), - (-0.425325, -0.688191, -0.587785), - (-0.587785, -0.425325, -0.688191), - (-0.688191, -0.587785, -0.425325)) - - -###################################################### -# MD2 data structures -###################################################### -class md2_point: - vertices=[] - lightnormalindex=0 - binary_format="<3BB" - def __init__(self): - self.vertices=[0]*3 - self.lightnormalindex=0 - def save(self, file): - temp_data=[0]*4 - temp_data[0]=self.vertices[0] - temp_data[1]=self.vertices[1] - temp_data[2]=self.vertices[2] - temp_data[3]=self.lightnormalindex - data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3]) - file.write(data) - def dump(self): - print "MD2 Point Structure" - print "vertex X: ", self.vertices[0] - print "vertex Y: ", self.vertices[1] - print "vertex Z: ", self.vertices[2] - print "lightnormalindex: ",self.lightnormalindex - print "" - -class md2_face: - vertex_index=[] - texture_index=[] - binary_format="<3h3h" - def __init__(self): - self.vertex_index = [ 0, 0, 0 ] - self.texture_index = [ 0, 0, 0] - def save(self, file): - temp_data=[0]*6 - #swap vertices around so they draw right - temp_data[0]=self.vertex_index[0] - temp_data[1]=self.vertex_index[2] - temp_data[2]=self.vertex_index[1] - #swap texture vertices around so they draw right - temp_data[3]=self.texture_index[0] - temp_data[4]=self.texture_index[2] - temp_data[5]=self.texture_index[1] - data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5]) - file.write(data) - def dump (self): - print "MD2 Face Structure" - print "vertex 1 index: ", self.vertex_index[0] - print "vertex 2 index: ", self.vertex_index[1] - print "vertex 3 index: ", self.vertex_index[2] - print "texture 1 index: ", self.texture_index[0] - print "texture 2 index: ", self.texture_index[1] - print "texture 3 index: ", self.texture_index[2] - print "" - -class md2_tex_coord: - u=0 - v=0 - binary_format="<2h" - def __init__(self): - self.u=0 - self.v=0 - def save(self, file): - temp_data=[0]*2 - temp_data[0]=self.u - temp_data[1]=self.v - data=struct.pack(self.binary_format, temp_data[0], temp_data[1]) - file.write(data) - def dump (self): - print "MD2 Texture Coordinate Structure" - print "texture coordinate u: ",self.u - print "texture coordinate v: ",self.v - print "" - -class md2_GL_command: - s=0.0 - t=0.0 - vert_index=0 - binary_format="<2fi" - - def __init__(self): - self.s=0.0 - self.t=0.0 - vert_index=0 - def save(self,file): - temp_data=[0]*3 - temp_data[0]=float(self.s) - temp_data[1]=float(self.t) - temp_data[2]=self.vert_index - data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2]) - file.write(data) - def dump (self): - print "MD2 OpenGL Command" - print "s: ", self.s - print "t: ", self.t - print "Vertex Index: ", self.vert_index - print "" - -class md2_GL_cmd_list: - num=0 - cmd_list=[] - binary_format="MD2_MAX_TRIANGLES: - print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES - result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO") - if(result==2): - return False - if vert_count>MD2_MAX_VERTICES: - print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES - result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO") - if(result==2): - return False - if frame_count>MD2_MAX_FRAMES: - print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES - result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO") - if(result==2): - return False - #model is OK - return True - -###################################################### -# Fill MD2 data structure -###################################################### -def fill_md2(md2, object): - #global defines - global user_frame_list - global g_texture_path - - Blender.Window.DrawProgressBar(0.25,"Filling MD2 Data") - - #get a Mesh, not NMesh - mesh=object.getData(False, True) - #don't forget to copy the data! -- Boris van Schooten - mesh=mesh.__copy__(); - #load up some intermediate data structures - tex_list={} - tex_count=0 - #create the vertex list from the first frame - Blender.Set("curframe", 1) - - has_uvs = mesh.faceUV - - #header information - md2.ident=844121161 - md2.version=8 - md2.num_vertices=len(mesh.verts) - md2.num_faces=len(mesh.faces) - - #get the skin information - #use the first faces' image for the texture information - if has_uvs: - mesh_image=mesh.faces[0].image - try: size=mesh_image.getSize() - except: size= 256,256 - - md2.skin_width=size[0] - md2.skin_height=size[1] - md2.num_skins=1 - #add a skin node to the md2 data structure - md2.skins.append(md2_skin()) - md2.skins[0].name=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename()) - if len(md2.skins[0].name)>64: - print "Texture Path and name is more than 64 characters" - result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting") - return False - - #put texture information in the md2 structure - #build UV coord dictionary (prevents double entries-saves space) - if not has_uvs: - t=(0,0) - - for face in mesh.faces: - for i in xrange(0,3): - if has_uvs: - t=(face.uv[i]) - - tex_key=(t[0],t[1]) - if not tex_list.has_key(tex_key): - tex_list[tex_key]=tex_count - tex_count+=1 - md2.num_tex_coords=tex_count #each vert has its own UV coord - - for this_tex in xrange (0, md2.num_tex_coords): - md2.tex_coords.append(md2_tex_coord()) - for coord, index in tex_list.iteritems(): - #md2.tex_coords.append(md2_tex_coord()) - md2.tex_coords[index].u=int(coord[0]*md2.skin_width) - md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height) - - #put faces in the md2 structure - #for each face in the model - - if not has_uvs: - uv_coords=[(0,0)]*3 - - for this_face in xrange(0, md2.num_faces): - md2.faces.append(md2_face()) - mf = mesh.faces[this_face] - mf_v = mf.v - if has_uvs: - uv_coords = mf.uv - - for i in xrange(0,3): - #blender uses indexed vertexes so this works very well - md2.faces[this_face].vertex_index[i] = mf_v[i].index - #lookup texture index in dictionary - if has_uvs: - uv_coord = uv_coords[i] - # otherwise we set it before - - tex_key=(uv_coord[0],uv_coord[1]) - tex_index=tex_list[tex_key] - md2.faces[this_face].texture_index[i]=tex_index - - Blender.Window.DrawProgressBar(0.5, "Computing GL Commands") - - #compute GL commands - md2.num_GL_commands=build_GL_commands(md2, mesh) - - #get the frame data - #calculate 1 frame size + (1 vert size*num_verts) - md2.frame_size=40+(md2.num_vertices*4) #in bytes - - #get the frame list - user_frame_list=get_frame_list() - if user_frame_list=="default": - md2.num_frames=198 - else: - temp=user_frame_list[len(user_frame_list)-1] #last item - md2.num_frames=temp[2] #last frame number - - - progress=0.5 - progressIncrement=0.25/md2.num_frames - - #fill in each frame with frame info and all the vertex data for that frame - for frame_counter in xrange(0,md2.num_frames): - - progress+=progressIncrement - Blender.Window.DrawProgressBar(progress, "Calculating Frame: %d of %d" % (frame_counter, md2.num_frames)) - - #add a frame - md2.frames.append(md2_frame()) - #update the mesh objects vertex positions for the animation - Blender.Set("curframe", frame_counter) #set blender to the correct frame - - - - - mesh.getFromObject(object) #update the mesh to make verts current - mesh.transform(object.matrixWorld) - -#each frame has a scale and transform value that gets the vertex value between 0-255 -#since the scale and transform are the same for the all the verts in the frame, we only need -#to figure this out once per frame - - #we need to start with the bounding box - #bounding_box=object.getBoundBox() #uses the object, not the mesh data - #initialize with the first vertex for both min and max. X and Y are swapped for MD2 format - - #initialize - frame_min_x=100000.0 - frame_max_x=-100000.0 - frame_min_y=100000.0 - frame_max_y=-100000.0 - frame_min_z=100000.0 - frame_max_z=-100000.0 - - for face in mesh.faces: - for vert in face: - co = vert.co - if frame_min_x>co[1]: frame_min_x=co[1] - if frame_max_xco[0]: frame_min_y=co[0] - if frame_max_yco[2]: frame_min_z=co[2] - if frame_max_z maxdot): - maxdot = dot; - maxdotindex = j; - - # See patch [#19206], gives good info on this line below. - md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex - - del maxdot, maxdotindex - del new_x, new_y, new_z - del frame_max_x, frame_max_y, frame_max_z, frame_min_x, frame_min_y, frame_min_z - del frame_scale_x, frame_scale_y, frame_scale_z, frame_trans_x, frame_trans_y, frame_trans_z - - - #output all the frame names-user_frame_list is loaded during the validation - for frame_set in user_frame_list: - for counter in xrange(frame_set[1]-1, frame_set[2]): - md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2) - - #compute these after everthing is loaded into a md2 structure - header_size=17*4 #17 integers, and each integer is 4 bytes - skin_size=64*md2.num_skins #64 char per skin * number of skins - tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords - face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index - frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames - GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per - - #fill in the info about offsets - md2.offset_skins=0+header_size - md2.offset_tex_coords=md2.offset_skins+skin_size - md2.offset_faces=md2.offset_tex_coords+tex_coord_size - md2.offset_frames=md2.offset_faces+face_size - md2.offset_GL_commands=md2.offset_frames+frames_size - md2.offset_end=md2.offset_GL_commands+GL_command_size - -###################################################### -# Get Frame List -###################################################### -def get_frame_list(): - global g_frame_filename - frame_list=[] - - if g_frame_filename.val=="default": - return MD2_FRAME_NAME_LIST - - else: - #check for file - if (Blender.sys.exists(g_frame_filename.val)==1): - #open file and read it in - file=open(g_frame_filename.val,"r") - lines=file.readlines() - file.close() - - #check header (first line) - if lines[0].strip() != "# MD2 Frame Name List": - print "its not a valid file" - result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK") - return MD2_FRAME_NAME_LIST - else: - #read in the data - num_frames=0 - for counter in xrange(1, len(lines)): - current_line=lines[counter].strip() - if current_line[0]=="#": - #found a comment - pass - else: - data=current_line.split() - frame_list.append([data[0],num_frames+1, num_frames+int(data[1])]) - num_frames+=int(data[1]) - return frame_list - else: - print "Cannot find file" - result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK") - return MD2_FRAME_NAME_LIST - -###################################################### -# Globals for GL command list calculations -###################################################### -used_tris=[] -edge_dict={} -strip_verts=[] -strip_st=[] -strip_tris=[] -strip_first_run=True -odd=False - -###################################################### -# Find Strip length function -###################################################### -def find_strip_length(mesh, start_tri, edge_key): - #print "Finding strip length" - - global used_tris - global edge_dict - global strip_tris - global strip_st - global strip_verts - global strip_first_run - global odd - - used_tris[start_tri]=2 - - strip_tris.append(start_tri) #add this tri to the potential list of tri-strip - - #print "I am face: ", start_tri - #print "Using edge Key: ", edge_key - - faces=edge_dict[edge_key] #get list of face indexes that share this edge - if (len(faces)==0): - #print "Cant find edge with key: ", edge_key - pass - - #print "Faces sharing this edge: ", faces - for face_index in faces: - face=mesh.faces[face_index] - if face_index==start_tri: #don't want to check myself - #print "I found myself, continuing" - pass - else: - if used_tris[face_index]!=0: #found a used tri-move along - #print "Found a used tri: ", face_index - pass - else: - #find non-shared vert - for vert_counter in xrange(0,3): - if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): - next_vert=vert_counter - - if(odd==False): - #print "Found a suitable even connecting tri: ", face_index - used_tris[face_index]=2 #mark as dirty for this rum - odd=True - - #find the new edge - if(face.verts[next_vert].index < face.verts[(next_vert+2)%3].index): - temp_key=(face.verts[next_vert].index,face.verts[(next_vert+2)%3].index) - else: - temp_key=(face.verts[(next_vert+2)%3].index, face.verts[next_vert].index) - - #print "temp key: ", temp_key - temp_faces=edge_dict[temp_key] - - if(len(temp_faces)==0): - print "Can't find any other faces with key: ", temp_key - else: - #search the new edge - #print "found other faces, searching them" - find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best - break; - else: - #print "Found a suitable odd connecting tri: ", face_index - used_tris[face_index]=2 #mark as dirty for this rum - odd=False - - #find the new edge - if(face.verts[next_vert].index < face.verts[(next_vert+1)%3].index): - temp_key=(face.verts[next_vert].index,face.verts[(next_vert+1)%3].index) - else: - temp_key=(face.verts[(next_vert+1)%3].index, face.verts[next_vert].index) - #print "temp key: ", temp_key - temp_faces=edge_dict[temp_key] - if(len(temp_faces)==0): - print "Can't find any other faces with key: ", temp_key - else: - #search the new edge - #print "found other faces, searching them" - find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best - break; - - return len(strip_tris) - - -###################################################### -# Tri-Stripify function -###################################################### -def stripify_tri_list(mesh, edge_key): - global edge_dict - global strip_tris - global strip_st - global strip_verts - - shared_edge=[] - key=[] - - #print "*****Stripify the triangle list*******" - #print "strip tris: ", strip_tris - #print "strip_tri length: ", len(strip_tris) - - for tri_counter in xrange(0, len(strip_tris)): - face=mesh.faces[strip_tris[tri_counter]] - if (tri_counter==0): #first one only - #find non-edge vert - for vert_counter in xrange(0,3): - if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): - start_vert=vert_counter - strip_verts.append(face.verts[start_vert].index) - strip_st.append(face.uv[start_vert]) - - strip_verts.append(face.verts[(start_vert+2)%3].index) - strip_st.append(face.uv[(start_vert+2)%3]) - - strip_verts.append(face.verts[(start_vert+1)%3].index) - strip_st.append(face.uv[(start_vert+1)%3]) - else: - for vert_counter in xrange(0,3): - if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]): - strip_verts.append(face.verts[vert_counter].index) - strip_st.append(face.uv[vert_counter]) - break - - - -###################################################### -# Build GL command List -###################################################### -def build_GL_commands(md2, mesh): - # we can't output gl command structure without uv - if not mesh.faceUV: - print "No UV: not building GL Commands" - return 0 - - print "Building GL Commands" - - global used_tris - global edge_dict - global strip_verts - global strip_tris - global strip_st - - #globals initialization - used_tris=[0]*len(mesh.faces) - #print "Used: ", used_tris - num_commands=0 - - #edge dictionary generation - edge_dict=dict([(ed.key,[]) for ed in mesh.edges]) - for face in (mesh.faces): - for key in face.edge_keys: - edge_dict[key].append(face.index) - - #print "edge Dict: ", edge_dict - - for tri_counter in xrange(0,len(mesh.faces)): - if used_tris[tri_counter]!=0: - #print "Found a used triangle: ", tri_counter - pass - else: - #print "Found an unused triangle: ", tri_counter - - #intialization - strip_tris=[0]*0 - strip_verts=[0]*0 - strip_st=[0]*0 - strip_first_run=True - odd=True - - #find the strip length - strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0]) - - #mark tris as used - for used_counter in xrange(0,strip_length): - used_tris[strip_tris[used_counter]]=1 - - stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0]) - - #create command list - cmd_list=md2_GL_cmd_list() - #number of commands in this list - print "strip length: ", strip_length - cmd_list.num=(len(strip_tris)+2) #positive for strips, fans would be negative, but not supported yet - num_commands+=1 - - #add s,t,vert for this command list - for command_counter in xrange(0, len(strip_tris)+2): - cmd=md2_GL_command() - cmd.s=strip_st[command_counter][0] - cmd.t=1.0-strip_st[command_counter][1] #flip upside down - cmd.vert_index=strip_verts[command_counter] - num_commands+=3 - cmd_list.cmd_list.append(cmd) - print "Cmd List length: ", len(cmd_list.cmd_list) - print "Cmd list num: ", cmd_list.num - print "Cmd List: ", cmd_list.dump() - md2.GL_commands.append(cmd_list) - - #add the null command at the end - temp_cmdlist=md2_GL_cmd_list() - temp_cmdlist.num=0 - md2.GL_commands.append(temp_cmdlist) - num_commands+=1 - - #cleanup and return - used=strip_vert=strip_st=strip_tris=0 - return num_commands - - - - -###################################################### -# Save MD2 Format -###################################################### -def save_md2(filename): - print "" - print "***********************************" - print "MD2 Export" - print "***********************************" - print "" - - Blender.Window.DrawProgressBar(0.0,"Begining MD2 Export") - - md2=md2_obj() #blank md2 object to save - - #get the object - mesh_objs = Blender.Object.GetSelected() - - #check there is a blender object selected - if len(mesh_objs)==0: - print "Fatal Error: Must select a mesh to output as MD2" - print "Found nothing" - result=Blender.Draw.PupMenu("Must select an object to export%t|OK") - return - - mesh_obj=mesh_objs[0] #this gets the first object (should be only one) - - #check if it's a mesh object - if mesh_obj.getType()!="Mesh": - print "Fatal Error: Must select a mesh to output as MD2" - print "Found: ", mesh_obj.getType() - result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK") - return - - ok=validation(mesh_obj) - if ok==False: - return - - fill_md2(md2, mesh_obj) - md2.dump() - - Blender.Window.DrawProgressBar(1.0, "Writing to Disk") - - #actually write it to disk - file=open(filename,"wb") - md2.save(file) - file.close() - - #cleanup - md2=0 - - print "Closed the file" - diff --git a/release/scripts/md2_import.py b/release/scripts/md2_import.py deleted file mode 100644 index f52746259a6..00000000000 --- a/release/scripts/md2_import.py +++ /dev/null @@ -1,600 +0,0 @@ -#!BPY - -""" -Name: 'MD2 (.md2)' -Blender: 239 -Group: 'Import' -Tooltip: 'Import from Quake file format (.md2).' -""" - -__author__ = 'Bob Holcomb' -__version__ = '0.16' -__url__ = ["Bob's site, http://bane.servebeer.com", - "Support forum, http://scourage.servebeer.com/phpbb/", "blender", "blenderartists.org"] -__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] -__bpydoc__ = """\ -This script imports a Quake 2 file (MD2), textures, -and animations into blender for editing. Loader is based on MD2 loader from www.gametutorials.com-Thanks DigiBen! and the md3 blender loader by PhaethonH
- - Additional help from: Shadwolf, Skandal, Rojo and Campbell Barton
- Thanks Guys! -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Bob Holcomb -# -# 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 Blender -from Blender import Mesh, Object, sys -from Blender.BGL import * -from Blender.Draw import * -from Blender.Window import * -from Blender.Mathutils import Vector -import struct -from types import * - - -###################################################### -# Main Body -###################################################### - -#returns the string from a null terminated string -def asciiz (s): - n = 0 - while (ord(s[n]) != 0): - n = n + 1 - return s[0:n] - - -###################################################### -# MD2 Model Constants -###################################################### -MD2_MAX_TRIANGLES=4096 -MD2_MAX_VERTICES=2048 -MD2_MAX_TEXCOORDS=2048 -MD2_MAX_FRAMES=512 -MD2_MAX_SKINS=32 -MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) - -###################################################### -# MD2 data structures -###################################################### -class md2_alias_triangle(object): - __slots__ = 'vertices', 'lightnormalindex' - binary_format="<3BB" #little-endian (<), 3 Unsigned char - - def __init__(self): - self.vertices=[0]*3 - self.lightnormalindex=0 - - def load(self, file): - temp_data = file.read(struct.calcsize(self.binary_format)) - data = struct.unpack(self.binary_format, temp_data) - self.vertices[0]=data[0] - self.vertices[1]=data[1] - self.vertices[2]=data[2] - self.lightnormalindex=data[3] - return self - - def dump(self): - print "MD2 Alias_Triangle Structure" - print "vertex: ", self.vertices[0] - print "vertex: ", self.vertices[1] - print "vertex: ", self.vertices[2] - print "lightnormalindex: ",self.lightnormalindex - print "" - -class md2_face(object): - - binary_format="<3h3h" #little-endian (<), 3 short, 3 short - - __slots__ = 'vertex_index', 'texture_index' - - def __init__(self): - self.vertex_index = [ 0, 0, 0 ] - self.texture_index = [ 0, 0, 0] - - def load (self, file): - temp_data=file.read(struct.calcsize(self.binary_format)) - data=struct.unpack(self.binary_format, temp_data) - self.vertex_index[0]=data[0] - self.vertex_index[1]=data[1] - self.vertex_index[2]=data[2] - self.texture_index[0]=data[3] - self.texture_index[1]=data[4] - self.texture_index[2]=data[5] - return self - - def dump (self): - print "MD2 Face Structure" - print "vertex index: ", self.vertex_index[0] - print "vertex index: ", self.vertex_index[1] - print "vertex index: ", self.vertex_index[2] - print "texture index: ", self.texture_index[0] - print "texture index: ", self.texture_index[1] - print "texture index: ", self.texture_index[2] - print "" - -class md2_tex_coord(object): - __slots__ = 'u', 'v' - binary_format="<2h" #little-endian (<), 2 unsigned short - - def __init__(self): - self.u=0 - self.v=0 - - def load (self, file): - temp_data=file.read(struct.calcsize(self.binary_format)) - data=struct.unpack(self.binary_format, temp_data) - self.u=data[0] - self.v=data[1] - return self - - def dump (self): - print "MD2 Texture Coordinate Structure" - print "texture coordinate u: ",self.u - print "texture coordinate v: ",self.v - print "" - - -class md2_skin(object): - __slots__ = 'name' - binary_format="<64s" #little-endian (<), char[64] - - def __init__(self): - self.name="" - - def load (self, file): - temp_data=file.read(struct.calcsize(self.binary_format)) - data=struct.unpack(self.binary_format, temp_data) - self.name=asciiz(data[0]) - return self - - def dump (self): - print "MD2 Skin" - print "skin name: ",self.name - print "" - -class md2_alias_frame(object): - __slots__ = 'scale', 'translate', 'name', 'vertices' - binary_format="<3f3f16s" #little-endian (<), 3 float, 3 float char[16] - #did not add the "3bb" to the end of the binary format - #because the alias_vertices will be read in through - #thier own loader - - def __init__(self): - self.scale=[0.0]*3 - self.translate=[0.0]*3 - self.name="" - self.vertices=[] - - - def load (self, file): - temp_data=file.read(struct.calcsize(self.binary_format)) - data=struct.unpack(self.binary_format, temp_data) - self.scale[0]=data[0] - self.scale[1]=data[1] - self.scale[2]=data[2] - self.translate[0]=data[3] - self.translate[1]=data[4] - self.translate[2]=data[5] - self.name=asciiz(data[6]) - return self - - def dump (self): - print "MD2 Alias Frame" - print "scale x: ",self.scale[0] - print "scale y: ",self.scale[1] - print "scale z: ",self.scale[2] - print "translate x: ",self.translate[0] - print "translate y: ",self.translate[1] - print "translate z: ",self.translate[2] - print "name: ",self.name - print "" - -class md2_obj(object): - __slots__ =\ - 'tex_coords', 'faces', 'frames',\ - 'skins', 'ident', 'version',\ - 'skin_width', 'skin_height',\ - 'frame_size', 'num_skins', 'num_vertices',\ - 'num_tex_coords', 'num_faces', 'num_GL_commands',\ - 'num_frames', 'offset_skins', 'offset_tex_coords',\ - 'offset_faces', 'offset_frames', 'offset_GL_commands' - - ''' - #Header Structure - ident=0 #int 0 This is used to identify the file - version=0 #int 1 The version number of the file (Must be 8) - skin_width=0 #int 2 The skin width in pixels - skin_height=0 #int 3 The skin height in pixels - frame_size=0 #int 4 The size in bytes the frames are - num_skins=0 #int 5 The number of skins associated with the model - num_vertices=0 #int 6 The number of vertices (constant for each frame) - num_tex_coords=0 #int 7 The number of texture coordinates - num_faces=0 #int 8 The number of faces (polygons) - num_GL_commands=0 #int 9 The number of gl commands - num_frames=0 #int 10 The number of animation frames - offset_skins=0 #int 11 The offset in the file for the skin data - offset_tex_coords=0 #int 12 The offset in the file for the texture data - offset_faces=0 #int 13 The offset in the file for the face data - offset_frames=0 #int 14 The offset in the file for the frames data - offset_GL_commands=0#int 15 The offset in the file for the gl commands data - offset_end=0 #int 16 The end of the file offset - ''' - binary_format="<17i" #little-endian (<), 17 integers (17i) - - #md2 data objects - - def __init__ (self): - self.tex_coords=[] - self.faces=[] - self.frames=[] - self.skins=[] - - - def load (self, file): - temp_data = file.read(struct.calcsize(self.binary_format)) - data = struct.unpack(self.binary_format, temp_data) - - self.ident=data[0] - self.version=data[1] - - if (self.ident!=844121161 or self.version!=8): - print "Not a valid MD2 file" - Exit() - - self.skin_width=data[2] - self.skin_height=data[3] - self.frame_size=data[4] - - #make the # of skin objects for model - self.num_skins=data[5] - for i in xrange(0,self.num_skins): - self.skins.append(md2_skin()) - - self.num_vertices=data[6] - - #make the # of texture coordinates for model - self.num_tex_coords=data[7] - for i in xrange(0,self.num_tex_coords): - self.tex_coords.append(md2_tex_coord()) - - #make the # of triangle faces for model - self.num_faces=data[8] - for i in xrange(0,self.num_faces): - self.faces.append(md2_face()) - - self.num_GL_commands=data[9] - - #make the # of frames for the model - self.num_frames=data[10] - for i in xrange(0,self.num_frames): - self.frames.append(md2_alias_frame()) - #make the # of vertices for each frame - for j in xrange(0,self.num_vertices): - self.frames[i].vertices.append(md2_alias_triangle()) - - self.offset_skins=data[11] - self.offset_tex_coords=data[12] - self.offset_faces=data[13] - self.offset_frames=data[14] - self.offset_GL_commands=data[15] - - #load the skin info - file.seek(self.offset_skins,0) - for i in xrange(0, self.num_skins): - self.skins[i].load(file) - #self.skins[i].dump() - - #load the texture coordinates - file.seek(self.offset_tex_coords,0) - for i in xrange(0, self.num_tex_coords): - self.tex_coords[i].load(file) - #self.tex_coords[i].dump() - - #load the face info - file.seek(self.offset_faces,0) - for i in xrange(0, self.num_faces): - self.faces[i].load(file) - #self.faces[i].dump() - - #load the frames - file.seek(self.offset_frames,0) - for i in xrange(0, self.num_frames): - self.frames[i].load(file) - #self.frames[i].dump() - for j in xrange(0,self.num_vertices): - self.frames[i].vertices[j].load(file) - #self.frames[i].vertices[j].dump() - return self - - def dump (self): - print "Header Information" - print "ident: ", self.ident - print "version: ", self.version - print "skin width: ", self.skin_width - print "skin height: ", self.skin_height - print "frame size: ", self.frame_size - print "number of skins: ", self.num_skins - print "number of texture coordinates: ", self.num_tex_coords - print "number of faces: ", self.num_faces - print "number of frames: ", self.num_frames - print "number of vertices: ", self.num_vertices - print "offset skins: ", self.offset_skins - print "offset texture coordinates: ", self.offset_tex_coords - print "offset faces: ", self.offset_faces - print "offset frames: ",self.offset_frames - print "" - -###################################################### -# Import functions -###################################################### -def load_textures(md2, texture_filename): - #did the user specify a texture they wanted to use? - if texture_filename: - if (Blender.sys.exists(texture_filename)): - try: return Blender.Image.Load(texture_filename) - except: return -1 # could not load? - - #does the model have textures specified with it? - if int(md2.num_skins) > 0: - for i in xrange(0,md2.num_skins): - #md2.skins[i].dump() - if (Blender.sys.exists(md2.skins[i].name)): - try: return Blender.Image.Load(md2.skins[i].name) - except: return -1 - - -def animate_md2(md2, mesh): - ######### Animate the verts through keyframe animation - - # Fast access to the meshes vertex coords - verts = [v.co for v in mesh.verts] - scale = g_scale.val - - for i in xrange(1, md2.num_frames): - frame = md2.frames[i] - #update the vertices - for j in xrange(md2.num_vertices): - x=(frame.scale[0] * frame.vertices[j].vertices[0] + frame.translate[0]) * scale - y=(frame.scale[1] * frame.vertices[j].vertices[1] + frame.translate[1]) * scale - z=(frame.scale[2] * frame.vertices[j].vertices[2] + frame.translate[2]) * scale - - #put the vertex in the right spot - verts[j][:] = y,-x,z - - mesh.insertKey(i,"absolute") - # mesh.insertKey(i) - - #not really necissary, but I like playing with the frame counter - Blender.Set("curframe", i) - - - # Make the keys animate in the 3d view. - key = mesh.key - key.relative = False - - # Add an IPO to teh Key - ipo = Blender.Ipo.New('Key', 'md2') - key.ipo = ipo - # Add a curve to the IPO - curve = ipo.addCurve('Basis') - - # Add 2 points to cycle through the frames. - curve.append((1, 0)) - curve.append((md2.num_frames, (md2.num_frames-1)/10.0)) - curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - - - -def load_md2(md2_filename, texture_filename): - #read the file in - file=open(md2_filename,"rb") - WaitCursor(1) - DrawProgressBar(0.0, 'Loading MD2') - md2=md2_obj() - md2.load(file) - #md2.dump() - file.close() - - ######### Creates a new mesh - mesh = Mesh.New() - - uv_coord=[] - #uv_list=[] - verts_extend = [] - #load the textures to use later - #-1 if there is no texture to load - mesh_image=load_textures(md2, texture_filename) - if mesh_image == -1 and texture_filename: - print 'MD2 Import, Warning, texture "%s" could not load' - - ######### Make the verts - DrawProgressBar(0.25,"Loading Vertex Data") - frame = md2.frames[0] - scale = g_scale.val - - def tmp_get_vertex(i): - #use the first frame for the mesh vertices - x=(frame.scale[0]*frame.vertices[i].vertices[0]+frame.translate[0])*scale - y=(frame.scale[1]*frame.vertices[i].vertices[1]+frame.translate[1])*scale - z=(frame.scale[2]*frame.vertices[i].vertices[2]+frame.translate[2])*scale - return y,-x,z - - mesh.verts.extend( [tmp_get_vertex(i) for i in xrange(0,md2.num_vertices)] ) - del tmp_get_vertex - - ######## Make the UV list - DrawProgressBar(0.50,"Loading UV Data") - - w = float(md2.skin_width) - h = float(md2.skin_height) - if w <= 0.0: w = 1.0 - if h <= 0.0: h = 1.0 - #for some reason quake2 texture maps are upside down, flip that - uv_list = [Vector(co.u/w, 1-(co.v/h)) for co in md2.tex_coords] - del w, h - - ######### Make the faces - DrawProgressBar(0.75,"Loading Face Data") - faces = [] - face_uvs = [] - for md2_face in md2.faces: - f = md2_face.vertex_index[0], md2_face.vertex_index[2], md2_face.vertex_index[1] - uv = uv_list[md2_face.texture_index[0]], uv_list[md2_face.texture_index[2]], uv_list[md2_face.texture_index[1]] - - if f[2] == 0: - # EEKADOODLE :/ - f= f[1], f[2], f[0] - uv= uv[1], uv[2], uv[0] - - #ditto in reverse order with the texture verts - faces.append(f) - face_uvs.append(uv) - - - face_mapping = mesh.faces.extend(faces, indexList=True) - print len(faces) - print len(mesh.faces) - mesh.faceUV= True #turn on face UV coordinates for this mesh - mesh_faces = mesh.faces - for i, uv in enumerate(face_uvs): - if face_mapping[i] != None: - f = mesh_faces[face_mapping[i]] - f.uv = uv - if (mesh_image!=-1): - f.image=mesh_image - - scn= Blender.Scene.GetCurrent() - mesh_obj= scn.objects.new(mesh) - animate_md2(md2, mesh) - DrawProgressBar(0.98,"Loading Animation Data") - - #locate the Object containing the mesh at the cursor location - cursor_pos=Blender.Window.GetCursorPos() - mesh_obj.setLocation(float(cursor_pos[0]),float(cursor_pos[1]),float(cursor_pos[2])) - DrawProgressBar (1.0, "") - WaitCursor(0) - -#*********************************************** -# MAIN -#*********************************************** - -# Import globals -g_md2_filename=Create("*.md2") -#g_md2_filename=Create("/d/warvet/tris.md2") -g_texture_filename=Create('') -# g_texture_filename=Create("/d/warvet/warvet.jpg") - -g_filename_search=Create("*.md2") -g_texture_search=Create('') -# g_texture_search=Create("/d/warvet/warvet.jpg") - -#Globals -g_scale=Create(1.0) - -# Events -EVENT_NOEVENT=1 -EVENT_LOAD_MD2=2 -EVENT_CHOOSE_FILENAME=3 -EVENT_CHOOSE_TEXTURE=4 -EVENT_SAVE_MD2=5 -EVENT_EXIT=100 - -###################################################### -# Callbacks for Window functions -###################################################### -def filename_callback(input_filename): - global g_md2_filename - g_md2_filename.val=input_filename - -def texture_callback(input_texture): - global g_texture_filename - g_texture_filename.val=input_texture - -###################################################### -# GUI Loader -###################################################### - - -def draw_gui(): - global g_scale - global g_md2_filename - global g_texture_filename - global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_TEXTURE,EVENT_EXIT - - ########## Titles - glClear(GL_COLOR_BUFFER_BIT) - glRasterPos2d(8, 125) - Text("MD2 loader") - - ######### Parameters GUI Buttons - BeginAlign() - g_md2_filename = String("MD2 file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, - g_md2_filename.val, 255, "MD2 file to load") - ########## MD2 File Search Button - Button("Browse",EVENT_CHOOSE_FILENAME,220,55,80,18) - EndAlign() - - BeginAlign() - g_texture_filename = String("Texture file to load: ", EVENT_NOEVENT, 10, 35, 210, 18, - g_texture_filename.val, 255, "Texture file to load-overrides MD2 file") - ########## Texture Search Button - Button("Browse",EVENT_CHOOSE_TEXTURE,220,35,80,18) - EndAlign() - - ########## Scale slider-default is 1/8 which is a good scale for md2->blender - g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 75, 210, 18, - 1.0, 0.001, 10.0, 1, "Scale factor for obj Model"); - - ######### Draw and Exit Buttons - Button("Load",EVENT_LOAD_MD2 , 10, 10, 80, 18) - Button("Exit",EVENT_EXIT , 170, 10, 80, 18) - -def event(evt, val): - if (evt == QKEY and not val): - Blender.Draw.Exit() - -def bevent(evt): - global g_md2_filename - global g_texture_filename - global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_SAVE_MD2,EVENT_EXIT - - ######### Manages GUI events - if (evt==EVENT_EXIT): - Blender.Draw.Exit() - elif (evt==EVENT_CHOOSE_FILENAME): - FileSelector(filename_callback, "MD2 File Selection") - elif (evt==EVENT_CHOOSE_TEXTURE): - FileSelector(texture_callback, "Texture Selection") - elif (evt==EVENT_LOAD_MD2): - if not Blender.sys.exists(g_md2_filename.val): - PupMenu('Model file does not exist') - return - else: - load_md2(g_md2_filename.val, g_texture_filename.val) - Blender.Redraw() - Blender.Draw.Exit() - return - -if __name__ == '__main__': - Register(draw_gui, event, bevent) diff --git a/release/scripts/mesh_boneweight_copy.py b/release/scripts/mesh_boneweight_copy.py deleted file mode 100644 index d2a477fbc0b..00000000000 --- a/release/scripts/mesh_boneweight_copy.py +++ /dev/null @@ -1,287 +0,0 @@ -#!BPY -""" -Name: 'Bone Weight Copy' -Blender: 245 -Group: 'Object' -Tooltip: 'Copy Bone Weights from 1 mesh, to all other selected meshes.' -""" - -__author__ = "Campbell Barton aka ideasman42" -__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] -__version__ = "0.1" -__bpydoc__ = """\ - -Bone Weight Copy - -This script is used to copy bone weights from 1 mesh with weights (the source mesh) to many (the target meshes). -Weights are copied from 1 mesh to another based on how close they are together. - -For normal operation, select 1 source mesh with vertex weights and any number of unweighted meshes that overlap the source mesh. -Then run this script using default options and check the new weigh. - - -A differnt way to use this script is to update the weights an an alredy weighted mesh. -this is done using the "Copy to Selected" option enabled and works a bit differently, -With the target mesh, select the verts you want to update. -since all meshes have weights we cant just use the weighted mesh as the source, -so the Active Object is used for the source mesh. -Run the script and the selected verts on all non active meshes will be updated. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 Blender -from Blender import Armature, Object, Mathutils, Window, Mesh -Vector= Mathutils.Vector -SMALL_NUM= 0.000001 -def copy_bone_influences(_from, _to, PREF_SEL_ONLY, PREF_NO_XCROSS): - ob_from, me_from, world_verts_from, from_groups= _from - ob_to, me_to, world_verts_to, dummy= _to - del dummy - - def getSnapIdx(seek_vec, vecs): - ''' - Returns the closest vec to snap_points - ''' - - # First seek the closest Z axis vert idx/v - seek_vec_x,seek_vec_y,seek_vec_z= seek_vec - - from_vec_idx= 0 - - len_vecs= len(vecs) - - upidx= len_vecs-1 - loidx= 0 - - while from_vec_idx < len_vecs and vecs[from_vec_idx][1].z < seek_vec_z: - from_vec_idx+=1 - - # Clamp if we overstepped. - if from_vec_idx >= len_vecs: - from_vec_idx-=1 - - close_dist= (vecs[from_vec_idx][1]-seek_vec).length - close_idx= vecs[from_vec_idx][0] - - upidx= from_vec_idx+1 - loidx= from_vec_idx-1 - - # Set uselo/useup. This means we can keep seeking up/down. - if upidx >= len_vecs: useup= False - else: useup= True - - if loidx < 0: uselo= False - else: uselo= True - - # Seek up/down to find the closest v to seek vec. - while uselo or useup: - if useup: - if upidx >= len_vecs: - useup= False - else: - i,v= vecs[upidx] - if (not PREF_NO_XCROSS) or ((v.x >= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing - if v.z-seek_vec_z > close_dist: - # the verticle distance is greater then the best distance sofar. we can stop looking up. - useup= False - elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: - # This is in the limit measure it. - l= (seek_vec-v).length - if l= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing - if seek_vec_z-v.z > close_dist: - # the verticle distance is greater then the best distance sofar. we can stop looking up. - uselo= False - elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: - # This is in the limit measure it. - l= (seek_vec-v).length - if l "%s" ' % (ob_from.name, ob_to.name)) - - from_idx= getSnapIdx(co, world_verts_from) - from_infs= me_from.getVertexInfluences(from_idx) - - for group, weight in from_infs: - - # Add where needed. - if PREF_SEL_ONLY and group not in to_groups: - me_to.addVertGroup(group) - to_groups.append(group) - - me_to.assignVertsToGroup(group, [i], weight, add_) - - me_to.update() - -# ZSORT return (i/co) tuples, used for fast seeking of the snapvert. -def worldspace_verts_idx(me, ob): - mat= ob.matrixWorld - verts_zsort= [ (i, v.co*mat) for i, v in enumerate(me.verts) ] - - # Sorts along the Z Axis so we can optimize the getsnap. - try: verts_zsort.sort(key = lambda a: a[1].z) - except: verts_zsort.sort(lambda a,b: cmp(a[1].z, b[1].z,)) - - return verts_zsort - - -def worldspace_verts(me, ob): - mat= ob.matrixWorld - return [ v.co*mat for v in me.verts ] - -def subdivMesh(me, subdivs): - oldmode = Mesh.Mode() - Mesh.Mode(Mesh.SelectModes['FACE']) - me.sel= 1 - for i in xrange(subdivs): - me.subdivide(0) - Mesh.Mode(oldmode) - - -def main(): - print '\nStarting BoneWeight Copy...' - scn= Blender.Scene.GetCurrent() - contextSel= Object.GetSelected() - if not contextSel: - Blender.Draw.PupMenu('Error%t|2 or more mesh objects need to be selected.|aborting.') - return - - PREF_QUALITY= Blender.Draw.Create(0) - PREF_NO_XCROSS= Blender.Draw.Create(0) - PREF_SEL_ONLY= Blender.Draw.Create(0) - - pup_block = [\ - ('Quality:', PREF_QUALITY, 0, 4, 'Generate interpolated verts for a higher quality result.'),\ - ('No X Crossing', PREF_NO_XCROSS, 'Do not snap across the zero X axis'),\ - '',\ - '"Update Selected" copies',\ - 'active object weights to',\ - 'selected verts on the other',\ - 'selected mesh objects.',\ - ('Update Selected', PREF_SEL_ONLY, 'Only copy new weights to selected verts on the target mesh. (use active object as source)'),\ - ] - - - if not Blender.Draw.PupBlock("Copy Weights for %i Meshs" % len(contextSel), pup_block): - return - - PREF_SEL_ONLY= PREF_SEL_ONLY.val - PREF_NO_XCROSS= PREF_NO_XCROSS.val - quality= PREF_QUALITY.val - - act_ob= scn.objects.active - if PREF_SEL_ONLY and act_ob==None: - Blender.Draw.PupMenu('Error%t|When dealing with 2 or more meshes with vgroups|There must be an active object|to be used as a source|aborting.') - return - - sel=[] - from_data= None - - for ob in contextSel: - if ob.type=='Mesh': - me= ob.getData(mesh=1) - groups= me.getVertGroupNames() - - # If this is the only mesh with a group OR if its one of many, but its active. - if groups and ((ob==act_ob and PREF_SEL_ONLY) or (not PREF_SEL_ONLY)): - if from_data: - Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.') - return - else: - # This uses worldspace_verts_idx which gets (idx,co) pairs, then zsorts. - if quality: - for _ob in contextSel: - _ob.sel=0 - ob.sel=1 - Object.Duplicate(mesh=1) - ob= scn.objects.active - me= ob.getData(mesh=1) - # groups will be the same - print '\tGenerating higher %ix quality weights.' % quality - subdivMesh(me, quality) - scn.unlink(ob) - from_data= (ob, me, worldspace_verts_idx(me, ob), groups) - - else: - data= (ob, me, worldspace_verts(me, ob), groups) - sel.append(data) - - if not from_data: - Blender.Draw.PupMenu('Error%t|No mesh with vertex groups found.') - return - - if not sel: - Blender.Draw.PupMenu('Error%t|Select 2 or more mesh objects, aborting.') - if quality: from_data[1].verts= None - return - - t= Blender.sys.time() - Window.WaitCursor(1) - - # Now do the copy. - print '\tCopying from "%s" to %i other mesh(es).' % (from_data[0].name, len(sel)) - for data in sel: - copy_bone_influences(from_data, data, PREF_SEL_ONLY, PREF_NO_XCROSS) - - # We cant unlink the mesh, but at least remove its data. - if quality: - from_data[1].verts= None - - print 'Copy Complete in %.6f sec' % (Blender.sys.time()-t) - Window.DrawProgressBar(1.0, '') - Window.WaitCursor(0) - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py deleted file mode 100644 index 27adca335cb..00000000000 --- a/release/scripts/mesh_cleanup.py +++ /dev/null @@ -1,456 +0,0 @@ -#!BPY -""" -Name: 'Clean Meshes' -Blender: 245 -Group: 'Mesh' -Tooltip: 'Clean unused data from all selected mesh objects.' -""" - -__author__ = "Campbell Barton aka ideasman42" -__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] -__version__ = "0.1" -__bpydoc__ = """\ -Clean Meshes - -Cleans unused data from selected meshes -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - - -from Blender import * -import bpy -from Blender.Mathutils import TriangleArea - -import Blender -import BPyMesh -dict2MeshWeight= BPyMesh.dict2MeshWeight -meshWeight2Dict= BPyMesh.meshWeight2Dict - -def rem_free_verts(me): - vert_users= [0] * len(me.verts) - for f in me.faces: - for v in f: - vert_users[v.index]+=1 - - for e in me.edges: - for v in e: # loop on edge verts - vert_users[v.index]+=1 - - verts_free= [i for i, users in enumerate(vert_users) if not users] - - if verts_free: - pass - me.verts.delete(verts_free) - return len(verts_free) - -def rem_free_edges(me, limit=None): - ''' Only remove based on limit if a limit is set, else remove all ''' - - edgeDict= {} # will use a set when python 2.4 is standard. - - for f in me.faces: - for edkey in f.edge_keys: - edgeDict[edkey] = None - - edges_free= [] - for e in me.edges: - if not edgeDict.has_key(e.key): - edges_free.append(e) - - if limit != None: - edges_free= [e for e in edges_free if e.length <= limit] - - me.edges.delete(edges_free) - return len(edges_free) - -def rem_area_faces(me, limit=0.001): - ''' Faces that have an area below the limit ''' - rem_faces= [f for f in me.faces if f.area <= limit] - if rem_faces: - me.faces.delete( 0, rem_faces ) - return len(rem_faces) - -def rem_perimeter_faces(me, limit=0.001): - ''' Faces whos combine edge length is below the limit ''' - def faceEdLen(f): - v= f.v - if len(v) == 3: - return\ - (v[0].co-v[1].co).length +\ - (v[1].co-v[2].co).length +\ - (v[2].co-v[0].co).length - else: # 4 - return\ - (v[0].co-v[1].co).length +\ - (v[1].co-v[2].co).length +\ - (v[2].co-v[3].co).length +\ - (v[3].co-v[0].co).length - rem_faces= [f for f in me.faces if faceEdLen(f) <= limit] - if rem_faces: - me.faces.delete( 0, rem_faces ) - return len(rem_faces) - -def rem_unused_materials(me): - materials= me.materials - len_materials= len(materials) - if len_materials < 2: - return 0 - - rem_materials= 0 - - material_users= dict( [(i,0) for i in xrange(len_materials)] ) - - for f in me.faces: - f_mat = f.mat - # Make sure the face index isnt too big. this happens sometimes. - if f_mat >= len_materials: - f_mat = f.mat = 0 - material_users[f_mat] += 1 - - # mat_idx_subtract= 0 - # reindex_mapping= dict( [(i,0) for i in xrange(len_materials)] ) - - reindex_mapping_ls = range(len_materials) - for i in range(len_materials-1, -1, -1): - if material_users[i] == 0: - del reindex_mapping_ls[i] - del materials[i] - rem_materials+=1 - - reindex_mapping= {} - - for i, mat in enumerate(reindex_mapping_ls): - reindex_mapping[mat] = i - - for f in me.faces: - f.mat= reindex_mapping[f.mat] - - me.materials= materials - return rem_materials - - -def rem_free_groups(me, groupNames, vWeightDict): - ''' cound how many vert users a group has and remove unused groups ''' - rem_groups = 0 - groupUserDict= dict([(group,0) for group in groupNames]) - - for vertexWeight in vWeightDict: - for group, weight in vertexWeight.iteritems(): - groupUserDict[group] += 1 - - i=len(groupNames) - while i: - i-=1 - group= groupNames[i] - if groupUserDict[group] == 0: - del groupNames[i] - print '\tremoving, vgroup', group - rem_groups+=1 - return rem_groups - -def rem_zero_weights(me, limit, groupNames, vWeightDict): - ''' remove verts from a group when their weight is zero.''' - rem_vweight_count= 0 - for vertexWeight in vWeightDict: - items= vertexWeight.items() - for group, weight in items: - if weight < limit: - del vertexWeight[group] - rem_vweight_count+= 1 - - return rem_vweight_count - - -def normalize_vweight(me, groupNames, vWeightDict): - for vertexWeight in vWeightDict: - unit= 0.0 - for group, weight in vertexWeight.iteritems(): - unit+= weight - - if unit != 1.0 and unit != 0.0: - for group, weight in vertexWeight.iteritems(): - vertexWeight[group]= weight/unit - -def isnan(f): - fstring = str(f).lower() - if 'nan' in fstring: - return True - if 'inf' in fstring: - return True - - return False - -def fix_nan_verts__internal(me): - rem_nan = 0 - for v in me.verts: - co = v.co - for i in (0,1,2): - if isnan(co[i]): - co[i] = 0.0 - rem_nan += 1 - return rem_nan - -def fix_nan_verts(me): - rem_nan = 0 - key = me.key - if key: - # Find the object, and get a mesh thats thinked to the oblink. - # this is a bit crap but needed to set the active key. - me_oblink = None - for ob in bpy.data.objects: - me_oblink = ob.getData(mesh=1) - if me_oblink == me: - me = me_oblink - break - if not me_oblink: - ob = None - - if key and ob: - blocks = key.blocks - # print blocks - orig_pin = ob.pinShape - orig_shape = ob.activeShape - orig_relative = key.relative - ob.pinShape = True - for i, block in enumerate(blocks): - ob.activeShape = i+1 - ob.makeDisplayList() - rem_nan += fix_nan_verts__internal(me) - me.update(block.name) # get the new verts - ob.pinShape = orig_pin - ob.activeShape = orig_shape - key.relative = orig_relative - - else: # No keys, simple operation - rem_nan = fix_nan_verts__internal(me) - - return rem_nan - -def fix_nan_uvs(me): - rem_nan = 0 - if me.faceUV: - orig_uvlayer = me.activeUVLayer - for uvlayer in me.getUVLayerNames(): - me.activeUVLayer = uvlayer - for f in me.faces: - for uv in f.uv: - for i in (0,1): - if isnan(uv[i]): - uv[i] = 0.0 - rem_nan += 1 - me.activeUVLayer = orig_uvlayer - return rem_nan - - -def has_vcol(me): - for f in me.faces: - for col in f.col: - if not (255 == col.r == col.g == col.b): - return True - return False - -def rem_white_vcol_layers(me): - vcols_removed = 0 - if me.vertexColors: - for col in me.getColorLayerNames(): - me.activeColorLayer = col - if not has_vcol(me): - me.removeColorLayer(col) - vcols_removed += 1 - - return vcols_removed - - -def main(): - sce= bpy.data.scenes.active - obsel= list(sce.objects.context) - actob= sce.objects.active - - is_editmode= Window.EditMode() - - # Edit mode object is not active, add it to the list. - if is_editmode and (not actob.sel): - obsel.append(actob) - - - #====================================# - # Popup menu to select the functions # - #====================================# - - CLEAN_ALL_DATA= Draw.Create(0) - CLEAN_VERTS_FREE= Draw.Create(1) - CLEAN_EDGE_NOFACE= Draw.Create(0) - CLEAN_EDGE_SMALL= Draw.Create(0) - CLEAN_FACE_PERIMETER= Draw.Create(0) - CLEAN_FACE_SMALL= Draw.Create(0) - - CLEAN_MATERIALS= Draw.Create(0) - CLEAN_WHITE_VCOL_LAYERS= Draw.Create(0) - CLEAN_GROUP= Draw.Create(0) - CLEAN_VWEIGHT= Draw.Create(0) - CLEAN_WEIGHT_NORMALIZE= Draw.Create(0) - limit= Draw.Create(0.01) - - CLEAN_NAN_VERTS= Draw.Create(0) - CLEAN_NAN_UVS= Draw.Create(0) - - # Get USER Options - - pup_block= [\ - ('Verts: free', CLEAN_VERTS_FREE, 'Remove verts that are not used by an edge or a face.'),\ - ('Edges: free', CLEAN_EDGE_NOFACE, 'Remove edges that are not in a face.'),\ - ('Edges: short', CLEAN_EDGE_SMALL, 'Remove edges that are below the length limit.'),\ - ('Faces: small perimeter', CLEAN_FACE_PERIMETER, 'Remove faces below the perimeter limit.'),\ - ('Faces: small area', CLEAN_FACE_SMALL, 'Remove faces below the area limit (may remove faces stopping T-face artifacts).'),\ - ('limit: ', limit, 0.001, 1.0, 'Limit for the area and length tests above (a higher limit will remove more data).'),\ - ('Material Clean', CLEAN_MATERIALS, 'Remove unused materials.'),\ - ('Color Layers', CLEAN_WHITE_VCOL_LAYERS, 'Remove vertex color layers that are totaly white'),\ - ('VGroup Clean', CLEAN_GROUP, 'Remove vertex groups that have no verts using them.'),\ - ('Weight Clean', CLEAN_VWEIGHT, 'Remove zero weighted verts from groups (limit is zero threshold).'),\ - ('WeightNormalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\ - 'Clean NAN values',\ - ('NAN Verts', CLEAN_NAN_VERTS, 'Make NAN or INF verts (0,0,0)'),\ - ('NAN UVs', CLEAN_NAN_UVS, 'Make NAN or INF UVs (0,0)'),\ - '',\ - ('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\ - ] - - if not Draw.PupBlock('Clean Selected Meshes...', pup_block): - return - - CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val - CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val - CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val - CLEAN_FACE_PERIMETER= CLEAN_FACE_PERIMETER.val - CLEAN_FACE_SMALL= CLEAN_FACE_SMALL.val - CLEAN_MATERIALS= CLEAN_MATERIALS.val - CLEAN_WHITE_VCOL_LAYERS= CLEAN_WHITE_VCOL_LAYERS.val - CLEAN_GROUP= CLEAN_GROUP.val - CLEAN_VWEIGHT= CLEAN_VWEIGHT.val - CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val - limit= limit.val - CLEAN_ALL_DATA= CLEAN_ALL_DATA.val - CLEAN_NAN_VERTS= CLEAN_NAN_VERTS.val - CLEAN_NAN_UVS= CLEAN_NAN_UVS.val - - if is_editmode: Window.EditMode(0) - - if CLEAN_ALL_DATA: - if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE: - # For groups we need the objects linked to the mesh - meshes= [ob.getData(mesh=1) for ob in bpy.data.objects if ob.type == 'Mesh' if not ob.lib] - else: - meshes= bpy.data.meshes - else: - meshes= [ob.getData(mesh=1) for ob in obsel if ob.type == 'Mesh'] - - tot_meshes = len(meshes) # so we can decrement libdata - rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_vcol_layer_count= rem_group_count= rem_vweight_count= fix_nan_vcount= fix_nan_uvcount= 0 - if not meshes: - if is_editmode: Window.EditMode(1) - Draw.PupMenu('No meshes to clean') - - Blender.Window.WaitCursor(1) - bpy.data.meshes.tag = False - for me in meshes: - - # Dont touch the same data twice - if me.tag: - tot_meshes -= 1 - continue - me.tag = True - - if me.lib: - tot_meshes -= 1 - continue - - if me.multires: - multires_level_orig = me.multiresDrawLevel - me.multiresDrawLevel = 1 - print 'Warning, cannot perform destructive operations on multires mesh:', me.name - else: - if CLEAN_FACE_SMALL: - rem_face_count += rem_area_faces(me, limit) - - if CLEAN_FACE_PERIMETER: - rem_face_count += rem_perimeter_faces(me, limit) - - if CLEAN_EDGE_SMALL: # for all use 2- remove all edges. - rem_edge_count += rem_free_edges(me, limit) - - if CLEAN_EDGE_NOFACE: - rem_edge_count += rem_free_edges(me) - - if CLEAN_VERTS_FREE: - rem_vert_count += rem_free_verts(me) - - if CLEAN_MATERIALS: - rem_material_count += rem_unused_materials(me) - - if CLEAN_WHITE_VCOL_LAYERS: - rem_vcol_layer_count += rem_white_vcol_layers(me) - - if CLEAN_VWEIGHT or CLEAN_GROUP or CLEAN_WEIGHT_NORMALIZE: - groupNames, vWeightDict= meshWeight2Dict(me) - - if CLEAN_VWEIGHT: - rem_vweight_count += rem_zero_weights(me, limit, groupNames, vWeightDict) - - if CLEAN_GROUP: - rem_group_count += rem_free_groups(me, groupNames, vWeightDict) - pass - - if CLEAN_WEIGHT_NORMALIZE: - normalize_vweight(me, groupNames, vWeightDict) - - # Copy back to mesh vertex groups. - dict2MeshWeight(me, groupNames, vWeightDict) - - if CLEAN_NAN_VERTS: - fix_nan_vcount = fix_nan_verts(me) - - if CLEAN_NAN_UVS: - fix_nan_uvcount = fix_nan_uvs(me) - - # restore multires. - if me.multires: - me.multiresDrawLevel = multires_level_orig - - Blender.Window.WaitCursor(0) - if is_editmode: Window.EditMode(0) - stat_string= 'Removed from ' + str(tot_meshes) + ' Mesh(es)%t|' - - if CLEAN_VERTS_FREE: stat_string+= 'Verts: %i|' % rem_vert_count - if CLEAN_EDGE_SMALL or CLEAN_EDGE_NOFACE: stat_string+= 'Edges: %i|' % rem_edge_count - if CLEAN_FACE_SMALL or CLEAN_FACE_PERIMETER: stat_string+= 'Faces: %i|' % rem_face_count - if CLEAN_MATERIALS: stat_string+= 'Materials: %i|' % rem_material_count - if CLEAN_WHITE_VCOL_LAYERS: stat_string+= 'Color Layers: %i|' % rem_vcol_layer_count - if CLEAN_VWEIGHT: stat_string+= 'VWeights: %i|' % rem_vweight_count - if CLEAN_GROUP: stat_string+= 'VGroups: %i|' % rem_group_count - if CLEAN_NAN_VERTS: stat_string+= 'Vert Nan Fix: %i|' % fix_nan_vcount - if CLEAN_NAN_UVS: stat_string+= 'UV Nan Fix: %i|' % fix_nan_uvcount - Draw.PupMenu(stat_string) - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py deleted file mode 100644 index 670165dda51..00000000000 --- a/release/scripts/mesh_edges2curves.py +++ /dev/null @@ -1,166 +0,0 @@ -#!BPY -""" Registration info for Blender menus: -Name: 'Edges to Curve' -Blender: 241 -Group: 'Mesh' -Tip: 'Edges not used by a face are converted into polyline(s)' -""" -__author__ = ("Campbell Barton") -__url__ = ("blender", "blenderartists.org") -__version__ = "1.0 2006/02/08" - -__bpydoc__ = """\ -Edges to Curves - -This script converts open and closed edge loops into curve polylines - -Supported:
- Polylines where each vert has no more then 2 edges attached to it. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - -from Blender import * - -def polysFromMesh(me): - # a polyline is 2 - #polylines are a list - polyLines = [] - - # Get edges not used by a face - edgeDict= dict([ (ed.key, ed) for ed in me.edges ]) - for f in me.faces: - for key in f.edge_keys: - try: - del edgeDict[key] - except: - pass - - edges= edgeDict.values() - - - while edges: - currentEdge= edges.pop() - startVert= currentEdge.v2 - endVert= currentEdge.v1 - polyLine= [startVert, endVert] - ok= 1 - while ok: - ok= 0 - #for i, ed in enumerate(edges): - i=len(edges) - while i: - i-=1 - ed= edges[i] - if ed.v1 == endVert: - polyLine.append(ed.v2) - endVert= polyLine[-1] - ok=1 - del edges[i] - #break - elif ed.v2 == endVert: - polyLine.append(ed.v1) - endVert= polyLine[-1] - ok=1 - del edges[i] - #break - elif ed.v1 == startVert: - polyLine.insert(0, ed.v2) - startVert= polyLine[0] - ok=1 - del edges[i] - #break - elif ed.v2 == startVert: - polyLine.insert(0, ed.v1) - startVert= polyLine[0] - ok=1 - del edges[i] - #break - polyLines.append((polyLine, polyLine[0]==polyLine[-1])) - # print len(edges), len(polyLines) - return polyLines - - -def mesh2polys(): - scn= Scene.GetCurrent() - scn.objects.selected = [] - - meshOb= scn.objects.active - if meshOb==None or meshOb.type != 'Mesh': - Draw.PupMenu( 'ERROR: No Active Mesh Selected, Aborting' ) - return - Window.WaitCursor(1) - Window.EditMode(0) - me = meshOb.getData(mesh=1) - polygons= polysFromMesh(me) - w = 1.0 - cu= Curve.New() - cu.name = me.name - cu.setFlag(1) - - ob = scn.objects.active = scn.objects.new(cu) - ob.setMatrix(meshOb.matrixWorld) - - i=0 - for poly, closed in polygons: - if closed: - vIdx= 1 - else: - vIdx= 0 - - v= poly[vIdx] - cu.appendNurb((v.co.x, v.co.y, v.co.z, w)) - vIdx += 1 - cu[i].type= 0 # Poly Line - - # Close the polyline if its closed. - if closed: - cu[i].setFlagU(1) - - # Add all the points in the polyline. - while vIdx 0] - - else: - # Use a small margin verts must be outside before we mirror them. - neg_vts = [v for v in me.verts if v.sel if v.co.x < -PREF_XZERO_THRESH] - pos_vts = [v for v in me.verts if v.sel if v.co.x > PREF_XZERO_THRESH] - - - - #*Mirror Location*********************************************************# - if PREF_MIRROR_LOCATION: - mirror_pairs= [] - # allign the negative with the positive. - flipvec= Mathutils.Vector() - len_neg_vts= float(len(neg_vts)) - for i1, nv in enumerate(neg_vts): - if nv.sel: # we may alredy be mirrored, if so well be deselected - nv_co= nv.co - for i2, pv in enumerate(pos_vts): - if pv.sel: - # Enforce edge users. - if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: - flipvec[:]= pv.co - flipvec.x= -flipvec.x - l= (nv_co-flipvec).length - - if l==0.0: # Both are alredy mirrored so we dont need to think about them. - # De-Select so we dont use again/ - pv.sel= nv.sel= 0 - - # Record a match. - elif l<=PREF_MAX_DIST: - - # We can adjust the length by the normal, now we know the length is under the limit. - # DISABLED, WASNT VERY USEFULL - ''' - if PREF_NOR_WEIGHT>0: - # Get the normal and flipm reuse flipvec - flipvec[:]= pv.no - flipvec.x= -flipvec.x - try: - ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0 - except: # on rare occasions angle between vecs will fail.- zero length vec. - ang= 0 - - l=l*(1+(ang*PREF_NOR_WEIGHT)) - ''' - # Record the pairs for sorting to see who will get joined - mirror_pairs.append((l, nv, pv)) - - # Update every 20 loops - if i1 % 10 == 0: - Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts)) - - Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations') - - # Now we have a list of the pairs we might use, lets find the best and do them first. - # de-selecting as we go. so we can makke sure not to mess it up. - try: mirror_pairs.sort(key = lambda a: a[0]) - except: mirror_pairs.sort(lambda a,b: cmp(a[0], b[0])) - - for dist, v1,v2 in mirror_pairs: # dist, neg, pos - if v1.sel and v2.sel: - if PREF_MODE==0: # Middle - flipvec[:]= v2.co # positive - flipvec.x= -flipvec.x # negatve - v2.co= v1.co= (flipvec+v1.co)*0.5 # midway - v2.co.x= -v2.co.x - elif PREF_MODE==2: # Left - v2.co= v1.co - v2.co.x= -v2.co.x - elif PREF_MODE==1: # Right - v1.co= v2.co - v1.co.x= -v1.co.x - v1.sel= v2.sel= 0 - - - #*Mirror Weights**********************************************************# - if PREF_MIRROR_WEIGHTS: - - groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) - mirror_pairs_l2r= [] # Stor a list of matches for these verts. - mirror_pairs_r2l= [] # Stor a list of matches for these verts. - - # allign the negative with the positive. - flipvec= Mathutils.Vector() - len_neg_vts= float(len(neg_vts)) - - # Here we make a tuple to look through, if were middle well need to look through both. - if PREF_MODE==0: # Middle - find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l)) - elif PREF_MODE==1: # Left - find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), ) - elif PREF_MODE==2: # Right - find_set= ((pos_vts, neg_vts, mirror_pairs_r2l), ) - - - # Do a locational lookup again :/ - This isnt that good form but if we havnt mirrored weights well need to do it anyway. - # The Difference with this is that we dont need to have 1:1 match for each vert- just get each vert to find another mirrored vert - # and use its weight. - # Use "find_set" so we can do a flipped search L>R and R>L without duplicate code. - for vtls_A, vtls_B, pair_ls in find_set: - for i1, vA in enumerate(vtls_A): - best_len=1<<30 # BIGNUM - best_idx=-1 - - # Find the BEST match - vA_co= vA.co - for i2, vB in enumerate(vtls_B): - # Enforce edge users. - if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: - flipvec[:]= vB.co - flipvec.x= -flipvec.x - l= (vA_co-flipvec).length - - if l Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc/weight.'),\ - ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc/weight.'),\ - '',\ - ('MaxDist:', PREF_MAX_DIST, 0.0, 1.0, 'Generate interpolated verts so closer vert weights can be copied.'),\ - ('XZero limit:', PREF_XZERO_THRESH, 0.0, 1.0, 'Mirror verts above this distance from the middle, else lock to X/zero.'),\ - ('Sel Verts Only', PREF_SEL_ONLY, 'Only mirror selected verts. Else try and mirror all'),\ - ('Edge Users', PREF_EDGE_USERS, 'Only match up verts that have the same number of edge users.'),\ - 'Location Prefs',\ - ('Mirror Location', PREF_MIRROR_LOCATION, 'Mirror vertex locations.'),\ - ('XMidSnap Verts', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ - 'Weight Prefs',\ - ('Mirror Weights', PREF_MIRROR_WEIGHTS, 'Mirror vertex locations.'),\ - ('Flip Groups', PREF_FLIP_NAMES, 'Mirror flip names.'),\ - ('New Flip Groups', PREF_CREATE_FLIP_NAMES, 'Make new groups for flipped names.'),\ - ] - - if not Draw.PupBlock("X Mirror mesh tool", pup_block): - return - - # WORK OUT THE MODE 0 - # PREF_MODE, 0:middle, 1: Left. 2:Right. - PREF_MODE_R2L= PREF_MODE_R2L.val - PREF_MODE_L2R= PREF_MODE_L2R.val - - if PREF_MODE_R2L and PREF_MODE_L2R: - PREF_MODE= 0 # Middle - elif not PREF_MODE_R2L and PREF_MODE_L2R: - PREF_MODE= 1 # Left to Right - elif PREF_MODE_R2L and not PREF_MODE_L2R: - PREF_MODE= 2 # Right to Left - else: # Neither Selected. Do middle anyway - PREF_MODE= 0 - - - PREF_EDITMESH_ONLY= PREF_EDITMESH_ONLY.val - PREF_MIRROR_LOCATION= PREF_MIRROR_LOCATION.val - PREF_XMID_SNAP= PREF_XMID_SNAP.val - PREF_MAX_DIST= PREF_MAX_DIST.val - PREF_XZERO_THRESH= PREF_XZERO_THRESH.val - PREF_SEL_ONLY= PREF_SEL_ONLY.val - PREF_EDGE_USERS= PREF_EDGE_USERS.val - # weights - PREF_MIRROR_WEIGHTS= PREF_MIRROR_WEIGHTS.val - PREF_FLIP_NAMES= PREF_FLIP_NAMES.val - PREF_CREATE_FLIP_NAMES= PREF_CREATE_FLIP_NAMES.val - - t= sys.time() - - is_editmode = Window.EditMode() # Exit Editmode. - if is_editmode: Window.EditMode(0) - Mesh.Mode(Mesh.SelectModes['VERTEX']) - Window.WaitCursor(1) - - if act_ob: - mesh_mirror(act_ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) - if (not PREF_EDITMESH_ONLY) and sel: - for ob in sel: - mesh_mirror(ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) - - if is_editmode: Window.EditMode(1) - Window.WaitCursor(0) - Window.DrawProgressBar(1.0, '') - Window.RedrawAll() - - print 'Mirror done in %.6f sec.' % (sys.time()-t) - -if __name__ == '__main__': - main() diff --git a/release/scripts/mesh_poly_reduce.py b/release/scripts/mesh_poly_reduce.py deleted file mode 100644 index 6dfd7a90efc..00000000000 --- a/release/scripts/mesh_poly_reduce.py +++ /dev/null @@ -1,143 +0,0 @@ -#!BPY -""" -Name: 'Poly Reducer' -Blender: 243 -Group: 'Mesh' -Tooltip: 'Removed polygons from a mesh while maintaining the shape, textures and weights.' -""" - -__author__ = "Campbell Barton" -__url__ = ("blender", "blenderartists.org") -__version__ = "1.0 2006/02/07" - -__bpydoc__ = """\ -This script simplifies the mesh by removing faces, keeping the overall shape of the mesh. -""" - -from Blender import Draw, Window, Scene, Mesh, Mathutils, sys, Object -import BPyMesh -# reload(BPyMesh) -import BPyMessages - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - - -def main(): - scn = Scene.GetCurrent() - act_ob= scn.objects.active - if not act_ob or act_ob.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - act_me= act_ob.getData(mesh=1) - - if act_me.multires: - BPyMessages.Error_NoMeshMultiresEdit() - return - - act_group= act_me.activeGroup - if not act_group: act_group= '' - - - # Defaults - PREF_REDUX= Draw.Create(0.5) - PREF_BOUNDRY_WEIGHT= Draw.Create(5.0) - PREF_REM_DOUBLES= Draw.Create(1) - PREF_FACE_AREA_WEIGHT= Draw.Create(1.0) - PREF_FACE_TRIANGULATE= Draw.Create(1) - - VGROUP_INF_ENABLE= Draw.Create(0) - VGROUP_INF_REDUX= Draw.Create(act_group) - VGROUP_INF_WEIGHT= Draw.Create(10.0) - - PREF_DO_UV= Draw.Create(1) - PREF_DO_VCOL= Draw.Create(1) - PREF_DO_WEIGHTS= Draw.Create(1) - PREF_OTHER_SEL_OBS= Draw.Create(0) - - pup_block = [\ - ('Poly Reduce:', PREF_REDUX, 0.05, 0.95, 'Scale the meshes poly count by this value.'),\ - ('Boundry Weight:', PREF_BOUNDRY_WEIGHT, 0.0, 20.0, 'Weight boundry verts by this scale, 0.0 for no boundry weighting.'),\ - ('Area Weight:', PREF_FACE_AREA_WEIGHT, 0.0, 20.0, 'Collapse edges effecting lower area faces first.'),\ - ('Triangulate', PREF_FACE_TRIANGULATE, 'Convert quads to tris before reduction, for more choices of edges to collapse.'),\ - '',\ - ('VGroup Weighting', VGROUP_INF_ENABLE, 'Use a vertex group to influence the reduction, higher weights for higher quality '),\ - ('vgroup name: ', VGROUP_INF_REDUX, 0, 32, 'The name of the vertex group to use for the weight map'),\ - ('vgroup mult: ', VGROUP_INF_WEIGHT, 0.0, 100.0, 'How much to make the weight effect the reduction'),\ - ('Other Selected Obs', PREF_OTHER_SEL_OBS, 'reduce other selected objects.'),\ - '',\ - '',\ - '',\ - ('UV Coords', PREF_DO_UV, 'Interpolate UV Coords.'),\ - ('Vert Colors', PREF_DO_VCOL, 'Interpolate Vertex Colors'),\ - ('Vert Weights', PREF_DO_WEIGHTS, 'Interpolate Vertex Weights'),\ - ('Remove Doubles', PREF_REM_DOUBLES, 'Remove doubles before reducing to avoid boundry tearing.'),\ - ] - - if not Draw.PupBlock("Poly Reducer", pup_block): - return - - PREF_REDUX= PREF_REDUX.val - PREF_BOUNDRY_WEIGHT= PREF_BOUNDRY_WEIGHT.val - PREF_REM_DOUBLES= PREF_REM_DOUBLES.val - PREF_FACE_AREA_WEIGHT= PREF_FACE_AREA_WEIGHT.val - PREF_FACE_TRIANGULATE= PREF_FACE_TRIANGULATE.val - - VGROUP_INF_ENABLE= VGROUP_INF_ENABLE.val - VGROUP_INF_WEIGHT= VGROUP_INF_WEIGHT.val - - if VGROUP_INF_ENABLE and VGROUP_INF_WEIGHT: - VGROUP_INF_REDUX= VGROUP_INF_REDUX.val - else: - VGROUP_INF_WEIGHT= 0.0 - VGROUP_INF_REDUX= None - - - PREF_DO_UV= PREF_DO_UV.val - PREF_DO_VCOL= PREF_DO_VCOL.val - PREF_DO_WEIGHTS= PREF_DO_WEIGHTS.val - PREF_OTHER_SEL_OBS= PREF_OTHER_SEL_OBS.val - - - t= sys.time() - - is_editmode = Window.EditMode() # Exit Editmode. - if is_editmode: Window.EditMode(0) - Window.WaitCursor(1) - print 'reducing:', act_ob.name, act_ob.getData(1) - BPyMesh.redux(act_ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) - - if PREF_OTHER_SEL_OBS: - for ob in scn.objects.context: - if ob.type == 'Mesh' and ob != act_ob: - print 'reducing:', ob.name, ob.getData(1) - BPyMesh.redux(ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) - Window.RedrawAll() - - if is_editmode: Window.EditMode(1) - Window.WaitCursor(0) - Window.RedrawAll() - - print 'Reduction done in %.6f sec.' % (sys.time()-t) - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/mesh_poly_reduce_grid.py b/release/scripts/mesh_poly_reduce_grid.py deleted file mode 100644 index 2903909027a..00000000000 --- a/release/scripts/mesh_poly_reduce_grid.py +++ /dev/null @@ -1,351 +0,0 @@ -#!BPY -""" -Name: 'Poly Reduce Selection (Unsubsurf)' -Blender: 245 -Group: 'Mesh' -Tooltip: 'predictable mesh simplifaction maintaining face loops' -""" - -from Blender import Scene, Mesh, Window, sys -import BPyMessages -import bpy - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell J Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - - -def my_mesh_util(me): - me_verts = me.verts - - vert_faces = [ [] for v in me_verts] - vert_faces_corner = [ [] for v in me_verts] - - - # Ignore topology where there are not 2 faces connected to an edge. - edge_count = {} - for f in me.faces: - for edkey in f.edge_keys: - try: - edge_count[edkey] += 1 - except: - edge_count[edkey] = 1 - - for edkey, count in edge_count.iteritems(): - - # Ignore verts that connect to edges with more than 2 faces. - if count != 2: - vert_faces[edkey[0]] = None - vert_faces[edkey[1]] = None - # Done - - - - def faces_set_verts(face_ls): - unique_verts = set() - for f in face_ls: - for v in f: - unique_verts.add(v.index) - return unique_verts - - for f in me.faces: - for corner, v in enumerate(f): - i = v.index - if vert_faces[i] != None: - vert_faces[i].append(f) - vert_faces_corner[i].append( corner ) - - grid_data_ls = [] - - for vi, face_ls in enumerate(vert_faces): - if face_ls != None: - if len(face_ls) == 4: - if face_ls[0].sel and face_ls[1].sel and face_ls[2].sel and face_ls[3].sel: - # Support triangles also - unique_vert_count = len(faces_set_verts(face_ls)) - quads = 0 - for f in face_ls: - if len(f) ==4: - quads += 1 - if unique_vert_count==5+quads: # yay we have a grid - grid_data_ls.append( (vi, face_ls) ) - - elif len(face_ls) == 3: - if face_ls[0].sel and face_ls[1].sel and face_ls[2].sel: - unique_vert_count = len(faces_set_verts(face_ls)) - if unique_vert_count==4: # yay we have 3 triangles to make into a bigger triangle - grid_data_ls.append( (vi, face_ls) ) - - - - # Now sort out which grid faces to use - - - # This list will be used for items we can convert, vertex is key, faces are values - grid_data_dict = {} - - if not grid_data_ls: - print "doing nothing" - return - - # quick lookup for the opposing corner of a qiad - quad_diag_mapping = 2,3,0,1 - - verts_used = [0] * len(me_verts) # 0 == untouched, 1==should touch, 2==touched - verts_used[grid_data_ls[0][0]] = 1 # start touching 1! - - # From the corner vert, get the 2 edges that are not the corner or its opposing vert, this edge will make a new face - quad_edge_mapping = (1,3), (2,0), (1,3), (0,2) # hi-low, low-hi order is intended - tri_edge_mapping = (1,2), (0,2), (0,1) - - done_somthing = True - while done_somthing: - done_somthing = False - grid_data_ls_index = -1 - - for vi, face_ls in grid_data_ls: - grid_data_ls_index += 1 - if len(face_ls) == 3: - grid_data_dict[vi] = face_ls - grid_data_ls.pop( grid_data_ls_index ) - break - elif len(face_ls) == 4: - # print vi - if verts_used[vi] == 1: - verts_used[vi] = 2 # dont look at this again. - done_somthing = True - - grid_data_dict[vi] = face_ls - - # Tag all faces verts as used - - for i, f in enumerate(face_ls): - # i == face index on vert, needed to recall which corner were on. - v_corner = vert_faces_corner[vi][i] - fv =f.v - - if len(f) == 4: - v_other = quad_diag_mapping[v_corner] - # get the 2 other corners - corner1, corner2 = quad_edge_mapping[v_corner] - if verts_used[fv[v_other].index] == 0: - verts_used[fv[v_other].index] = 1 # TAG for touching! - else: - corner1, corner2 = tri_edge_mapping[v_corner] - - verts_used[fv[corner1].index] = 2 # Dont use these, they are - verts_used[fv[corner2].index] = 2 - - - # remove this since we have used it. - grid_data_ls.pop( grid_data_ls_index ) - - break - - if done_somthing == False: - # See if there are any that have not even been tagged, (probably on a different island), then tag them. - - for vi, face_ls in grid_data_ls: - if verts_used[vi] == 0: - verts_used[vi] = 1 - done_somthing = True - break - - - # Now we have all the areas we will fill, calculate corner triangles we need to fill in. - new_faces = [] - quad_del_vt_map = (1,2,3), (0,2,3), (0,1,3), (0,1,2) - for vi, face_ls in grid_data_dict.iteritems(): - for i, f in enumerate(face_ls): - if len(f) == 4: - # i == face index on vert, needed to recall which corner were on. - v_corner = vert_faces_corner[vi][i] - v_other = quad_diag_mapping[v_corner] - fv =f.v - - #print verts_used[fv[v_other].index] - #if verts_used[fv[v_other].index] != 2: # DOSNT WORK ALWAYS - - if 1: # THIS IS LAzY - some of these faces will be removed after adding. - # Ok we are removing half of this face, add the other half - - # This is probably slower - # new_faces.append( [fv[ii].index for ii in (0,1,2,3) if ii != v_corner ] ) - - # do this instead - new_faces.append( (fv[quad_del_vt_map[v_corner][0]], fv[quad_del_vt_map[v_corner][1]], fv[quad_del_vt_map[v_corner][2]]) ) - - del grid_data_ls - - - # me.sel = 0 - def faceCombine4(vi, face_ls): - edges = [] - - for i, f in enumerate(face_ls): - fv = f.v - v_corner = vert_faces_corner[vi][i] - if len(f)==4: ed = quad_edge_mapping[v_corner] - else: ed = tri_edge_mapping[v_corner] - - edges.append( [fv[ed[0]].index, fv[ed[1]].index] ) - - # get the face from the edges - face = edges.pop() - while len(face) != 4: - # print len(edges), edges, face - for ed_idx, ed in enumerate(edges): - if face[-1] == ed[0] and (ed[1] != face[0]): - face.append(ed[1]) - elif face[-1] == ed[1] and (ed[0] != face[0]): - face.append(ed[0]) - else: - continue - - edges.pop(ed_idx) # we used the edge alredy - break - - return face - - for vi, face_ls in grid_data_dict.iteritems(): - if len(face_ls) == 4: - new_faces.append( faceCombine4(vi, face_ls) ) - #pass - if len(face_ls) == 3: # 3 triangles - face = list(faces_set_verts(face_ls)) - face.remove(vi) - new_faces.append( face ) - - - # Now remove verts surounded by 3 triangles - - - - # print new_edges - # me.faces.extend(new_faces, ignoreDups=True) - - ''' - faces_remove = [] - for vi, face_ls in grid_data_dict.iteritems(): - faces_remove.extend(face_ls) - ''' - - orig_facelen = len(me.faces) - - orig_faces = list(me.faces) - me.faces.extend(new_faces, ignoreDups=True) - new_faces = list(me.faces)[len(orig_faces):] - - - - - - if me.faceUV: - uvnames = me.getUVLayerNames() - act_uvlay = me.activeUVLayer - - vert_faces_uvs = [] - vert_faces_images = [] - - - act_uvlay = me.activeUVLayer - - for uvlay in uvnames: - me.activeUVLayer = uvlay - vert_faces_uvs[:] = [None] * len(me.verts) - vert_faces_images[:] = vert_faces_uvs[:] - - for i,f in enumerate(orig_faces): - img = f.image - fv = f.v - uv = f.uv - mat = f.mat - for i,v in enumerate(fv): - vi = v.index - vert_faces_uvs[vi] = uv[i] # no nice averaging - vert_faces_images[vi] = img - - - # Now copy UVs across - for f in new_faces: - fi = [v.index for v in f.v] - f.image = vert_faces_images[fi[0]] - uv = f.uv - for i,vi in enumerate(fi): - uv[i][:] = vert_faces_uvs[vi] - - if len(me.materials) > 1: - vert_faces_mats = [None] * len(me.verts) - for i,f in enumerate(orig_faces): - mat = f.mat - for i,v in enumerate(f.v): - vi = v.index - vert_faces_mats[vi] = mat - - # Now copy UVs across - for f in new_faces: - print vert_faces_mats[f.v[0].index] - f.mat = vert_faces_mats[f.v[0].index] - - - me.verts.delete(grid_data_dict.keys()) - - # me.faces.delete(1, faces_remove) - - if me.faceUV: - me.activeUVLayer = act_uvlay - - me.calcNormals() - -def main(): - - # Gets the current scene, there can be many scenes in 1 blend file. - sce = bpy.data.scenes.active - - # Get the active object, there can only ever be 1 - # and the active object is always the editmode object. - ob_act = sce.objects.active - - if not ob_act or ob_act.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - - Window.WaitCursor(1) - me = ob_act.getData(mesh=1) # old NMesh api is default - t = sys.time() - - # Run the mesh editing function - my_mesh_util(me) - - # Restore editmode if it was enabled - if is_editmode: Window.EditMode(1) - - # Timing the script is a good way to be aware on any speed hits when scripting - print 'My Script finished in %.2f seconds' % (sys.time()-t) - Window.WaitCursor(0) - - -# This lets you can import the script without running it -if __name__ == '__main__': - main() - diff --git a/release/scripts/mesh_skin.py b/release/scripts/mesh_skin.py deleted file mode 100644 index 4a330a516fb..00000000000 --- a/release/scripts/mesh_skin.py +++ /dev/null @@ -1,639 +0,0 @@ -#!BPY - -""" -Name: 'Skin Faces/Edge-Loops' -Blender: 243 -Group: 'MeshFaceKey' -Tooltip: 'Select 2 vert loops, then run this script.' -""" - -__author__ = "Campbell Barton AKA Ideasman" -__url__ = ["blenderartists.org", "www.blender.org"] -__version__ = "1.1 2006/12/26" - -__bpydoc__ = """\ -With this script vertex loops can be skinned: faces are created to connect the -selected loops of vertices. - -Usage: - -In mesh Edit mode select the vertices of the loops (closed paths / curves of -vertices: circles, for example) that should be skinned, then run this script. -A pop-up will provide further options, if the results of a method are not adequate try one of the others. -""" - - -# $Id$ -# -# -------------------------------------------------------------------------- -# Skin Selected edges 1.0 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 ***** -# -------------------------------------------------------------------------- - -# Made by Ideasman/Campbell 2005/06/15 - cbarton@metavr.com - -import Blender -import bpy -from Blender import Window -from Blender.Mathutils import MidpointVecs, Vector -from Blender.Mathutils import AngleBetweenVecs as _AngleBetweenVecs_ -import BPyMessages - -from Blender.Draw import PupMenu - -BIG_NUM = 1<<30 - -global CULL_METHOD -CULL_METHOD = 0 - -def AngleBetweenVecs(a1,a2): - try: - return _AngleBetweenVecs_(a1,a2) - except: - return 180.0 - -class edge(object): - __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake' - def __init__(self, v1,v2): - self.v1 = v1 - self.v2 = v2 - co1, co2= v1.co, v2.co - self.co1= co1 - self.co2= co2 - - # uv1 uv2 vcol1 vcol2 # Add later - self.length = (co1 - co2).length - self.removed = 0 # Have we been culled from the eloop - self.match = None # The other edge were making a face with - - self.cent= MidpointVecs(co1, co2) - self.angle= 0.0 - self.fake= False - -class edgeLoop(object): - __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' - def __init__(self, loop, me, closed): # Vert loop - # Use next and prev, nextDist, prevDist - - # Get Loops centre. - fac= len(loop) - verts = me.verts - self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) - - # Convert Vert loop to Edges. - self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))] - - if not closed: - self.edges[0].fake = True # fake edge option - - self.closed = closed - - - # Assign linked list - for eIdx in xrange(len(self.edges)-1): - self.edges[eIdx].next = self.edges[eIdx+1] - self.edges[eIdx].prev = self.edges[eIdx-1] - # Now last - self.edges[-1].next = self.edges[0] - self.edges[-1].prev = self.edges[-2] - - - - # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. - self.normal = Vector() - for e in self.edges: - n = (self.centre-e.co1).cross(self.centre-e.co2) - # Do we realy need tot normalize? - n.normalize() - self.normal += n - - # Generate the angle - va= e.cent - e.prev.cent - vb= e.next.cent - e.cent - - e.angle= AngleBetweenVecs(va, vb) - - # Blur the angles - #for e in self.edges: - # e.angle= (e.angle+e.next.angle)/2 - - # Blur the angles - #for e in self.edges: - # e.angle= (e.angle+e.prev.angle)/2 - - self.normal.normalize() - - # Generate a normal for each edge. - for e in self.edges: - - n1 = e.co1 - n2 = e.co2 - n3 = e.prev.co1 - - a = n1-n2 - b = n1-n3 - normal1 = a.cross(b) - normal1.normalize() - - n1 = e.co2 - n3 = e.next.co2 - n2 = e.co1 - - a = n1-n2 - b = n1-n3 - - normal2 = a.cross(b) - normal2.normalize() - - # Reuse normal1 var - normal1 += normal1 + normal2 - normal1.normalize() - - e.normal = normal1 - #print e.normal - - - - def backup(self): - # Keep a backup of the edges - self.backup_edges = self.edges[:] - - def restore(self): - self.edges = self.backup_edges[:] - for e in self.edges: - e.removed = 0 - - def reverse(self): - self.edges.reverse() - self.normal.negate() - - for e in self.edges: - e.normal.negate() - e.v1, e.v2 = e.v2, e.v1 - e.co1, e.co2 = e.co2, e.co1 - e.next, e.prev = e.prev, e.next - - - def removeSmallest(self, cullNum, otherLoopLen): - ''' - Removes N Smallest edges and backs up the loop, - this is so we can loop between 2 loops as if they are the same length, - backing up and restoring incase the loop needs to be skinned with another loop of a different length. - ''' - global CULL_METHOD - if CULL_METHOD == 1: # Shortest edge - eloopCopy = self.edges[:] - - # Length sort, smallest first - try: eloopCopy.sort(key = lambda e1: e1.length) - except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) - - # Dont use atm - #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first - #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first - - remNum = 0 - for i, e in enumerate(eloopCopy): - if not e.fake: - e.removed = 1 - self.edges.remove( e ) # Remove from own list, still in linked list. - remNum += 1 - - if not remNum < cullNum: - break - - else: # CULL METHOD is even - - culled = 0 - - step = int(otherLoopLen / float(cullNum)) * 2 - - currentEdge = self.edges[0] - while culled < cullNum: - - # Get the shortest face in the next STEP - step_count= 0 - bestAng= 360.0 - smallestEdge= None - while step_count<=step or smallestEdge==None: - step_count+=1 - if not currentEdge.removed: # 0 or -1 will not be accepted - if currentEdge.angle 2: - return None - - vert_used[i] = True - - # do an edgeloop seek - if len(sbl) == 2: - contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop - vert_used[contextVertLoop[ 0]] = True - vert_used[contextVertLoop[-1]] = True - else: - contextVertLoop= [i, sbl[0]] - vert_used[contextVertLoop[ 1]] = True - - # Always seek up - ok = True - while ok: - ok = False - closed = False - sbl = vert_siblings[contextVertLoop[-1]] - if len(sbl) == 2: - next = sbl[not sbl.index( contextVertLoop[-2] )] - if vert_used[next]: - closed = True - # break - else: - contextVertLoop.append( next ) # get the vert that isnt the second last - vert_used[next] = True - ok = True - - # Seek down as long as the starting vert was not at the edge. - if not closed and len(vert_siblings[i]) == 2: - - ok = True - while ok: - ok = False - sbl = vert_siblings[contextVertLoop[0]] - if len(sbl) == 2: - next = sbl[not sbl.index( contextVertLoop[1] )] - if vert_used[next]: - closed = True - else: - contextVertLoop.insert(0, next) # get the vert that isnt the second last - vert_used[next] = True - ok = True - - mainVertLoops.append((contextVertLoop, closed)) - - - verts = me.verts - # convert from indicies to verts - # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in mainVertLoops] - # print len(mainVertLoops) - return mainVertLoops - - - -def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE): - - new_faces= [] # - - # Make sure e1 loops is bigger then e2 - if len(eloop1.edges) != len(eloop2.edges): - if len(eloop1.edges) < len(eloop2.edges): - eloop1, eloop2 = eloop2, eloop1 - - eloop1.backup() # were about to cull faces - CULL_FACES = len(eloop1.edges) - len(eloop2.edges) - eloop1.removeSmallest(CULL_FACES, len(eloop1.edges)) - else: - CULL_FACES = 0 - # First make sure poly vert loops are in sync with eachother. - - # The vector allong which we are skinning. - skinVector = eloop1.centre - eloop2.centre - - loopDist = skinVector.length - - # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok, - if eloop1.closed or eloop2.closed: - angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal) - if angleBetweenLoopNormals > 90: - eloop2.reverse() - - - DIR= eloop1.centre - eloop2.centre - - # if eloop2.closed: - bestEloopDist = BIG_NUM - bestOffset = 0 - # Loop rotation offset to test.1 - eLoopIdxs = range(len(eloop1.edges)) - for offset in xrange(len(eloop1.edges)): - totEloopDist = 0 # Measure this total distance for thsi loop. - - offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list - - - # e1Idx is always from 0uu to N, e2Idx is offset. - for e1Idx, e2Idx in enumerate(offsetIndexLs): - e1= eloop1.edges[e1Idx] - e2= eloop2.edges[e2Idx] - - - # Include fan connections in the measurement. - OK= True - while OK or e1.removed: - OK= False - - # Measure the vloop distance =============== - diff= ((e1.cent - e2.cent).length) #/ nangle1 - - ed_dir= e1.cent-e2.cent - a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18 - - totEloopDist += (diff * (1+a_diff)) / (1+loopDist) - - # Premeture break if where no better off - if totEloopDist > bestEloopDist: - break - - e1=e1.next - - if totEloopDist < bestEloopDist: - bestOffset = offset - bestEloopDist = totEloopDist - - # Modify V2 LS for Best offset - eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset] - - else: - # Both are open loops, easier to calculate. - - - # Make sure the fake edges are at the start. - for i, edloop in enumerate((eloop1, eloop2)): - # print "LOOPO" - if edloop.edges[0].fake: - # alredy at the start - #print "A" - pass - elif edloop.edges[-1].fake: - # put the end at the start - edloop.edges.insert(0, edloop.edges.pop()) - #print "B" - - else: - for j, ed in enumerate(edloop.edges): - if ed.fake: - #print "C" - edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j] - break - # print "DONE" - ed1, ed2 = eloop1.edges[0], eloop2.edges[0] - - if not ed1.fake or not ed2.fake: - raise "Error" - - # Find the join that isnt flipped (juts like detecting a bow-tie face) - a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length - a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length - - if a1 > a2: - eloop2.reverse() - # make the first edge the start edge still - eloop2.edges.insert(0, eloop2.edges.pop()) - - - - - for loopIdx in xrange(len(eloop2.edges)): - e1 = eloop1.edges[loopIdx] - e2 = eloop2.edges[loopIdx] - - # Remember the pairs for fan filling culled edges. - e1.match = e2; e2.match = e1 - - if not (e1.fake or e2.fake): - new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1]) - - # FAN FILL MISSING FACES. - if CULL_FACES: - # Culled edges will be in eloop1. - FAN_FILLED_FACES = 0 - - contextEdge = eloop1.edges[0] # The larger of teh 2 - while FAN_FILLED_FACES < CULL_FACES: - while contextEdge.next.removed == 0: - contextEdge = contextEdge.next - - vertFanPivot = contextEdge.match.v2 - - while contextEdge.next.removed == 1: - #if not contextEdge.next.fake: - new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot]) - - # Should we use another var?, this will work for now. - contextEdge.next.removed = 1 - - contextEdge = contextEdge.next - FAN_FILLED_FACES += 1 - - # may need to fan fill backwards 1 for non closed loops. - - eloop1.restore() # Add culled back into the list. - - return new_faces - -def main(): - global CULL_METHOD - - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - ob = bpy.data.scenes.active.objects.active - if ob == None or ob.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - me = ob.getData(mesh=1) - - if me.multires: - BPyMessages.Error_NoMeshMultiresEdit() - return - - time1 = Blender.sys.time() - selEdges = getSelectedEdges(me, ob) - vertLoops = getVertLoops(selEdges, me) # list of lists of edges. - if vertLoops == None: - PupMenu('Error%t|Selection includes verts that are a part of more then 1 loop') - if is_editmode: Window.EditMode(1) - return - # print len(vertLoops) - - - if len(vertLoops) > 2: - choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment') - if choice == -1: - if is_editmode: Window.EditMode(1) - return - elif len(vertLoops) < 2: - PupMenu('Error%t|No Vertloops found!') - if is_editmode: Window.EditMode(1) - return - else: - choice = 2 - - - # The line below checks if any of the vert loops are differenyt in length. - if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]: - CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges') - if CULL_METHOD == -1: - if is_editmode: Window.EditMode(1) - return - - if CULL_METHOD ==1: # RESET CULL_METHOD - CULL_METHOD = 0 # shortest - else: - CULL_METHOD = 1 # even - - - time1 = Blender.sys.time() - # Convert to special edge data. - edgeLoops = [] - for vloop, closed in vertLoops: - edgeLoops.append(edgeLoop(vloop, me, closed)) - - - # VERT LOOP ORDERING CODE - # "Build a worm" list - grow from Both ends - edgeOrderedList = [edgeLoops.pop()] - - # Find the closest. - bestSoFar = BIG_NUM - bestIdxSoFar = None - for edLoopIdx, edLoop in enumerate(edgeLoops): - l =(edgeOrderedList[-1].centre - edLoop.centre).length - if l < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l - - edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) - - # Now we have the 2 closest, append to either end- - # Find the closest. - while edgeLoops: - bestSoFar = BIG_NUM - bestIdxSoFar = None - first_or_last = 0 # Zero is first - for edLoopIdx, edLoop in enumerate(edgeLoops): - l1 =(edgeOrderedList[-1].centre - edLoop.centre).length - - if l1 < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l1 - first_or_last = 1 # last - - l2 =(edgeOrderedList[0].centre - edLoop.centre).length - if l2 < bestSoFar: - bestIdxSoFar = edLoopIdx - bestSoFar = l2 - first_or_last = 0 # last - - if first_or_last: # add closest Last - edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) - else: # Add closest First - edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First - - faces = [] - - for i in xrange(len(edgeOrderedList)-1): - faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) ) - if choice == 1 and len(edgeOrderedList) > 2: # Loop - faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) ) - - # REMOVE SELECTED FACES. - MESH_MODE= Blender.Mesh.Mode() - if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX: pass - elif MESH_MODE & Blender.Mesh.SelectModes.FACE: - try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) - except: pass - - me.faces.extend(faces, smooth = True) - - print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1) - - - if is_editmode: Window.EditMode(1) - -if __name__ == '__main__': - main() diff --git a/release/scripts/mesh_solidify.py b/release/scripts/mesh_solidify.py deleted file mode 100644 index 9e11ed68c63..00000000000 --- a/release/scripts/mesh_solidify.py +++ /dev/null @@ -1,345 +0,0 @@ -#!BPY -""" -Name: 'Solidify Selection' -Blender: 243 -Group: 'Mesh' -Tooltip: 'Makes the mesh solid by creating a second skin.' -""" - -__author__ = "Campbell Barton" -__url__ = ("www.blender.org", "blenderartists.org") -__version__ = "1.1" - -__bpydoc__ = """\ -This script makes a skin from the selected faces. -Optionaly you can skin between the original and new faces to make a watertight solid object -""" - -# -------------------------------------------------------------------------- -# Solidify Selection 1.0 by Campbell Barton (AKA Ideasman42) -# -------------------------------------------------------------------------- -# ***** 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 ***** -# -------------------------------------------------------------------------- - -from Blender import * -import bpy -import BPyMesh -# reload(BPyMesh) -import BPyMessages -# reload(BPyMessages) - -from BPyMathutils import angleToLength - -# python 2.3 has no reversed() iterator. this will only work on lists and tuples -try: - reversed -except: - def reversed(l): return l[::-1] - -def copy_facedata_multilayer(me, from_faces, to_faces): - ''' - Tkes 2 lists of faces and copies multilayer data from 1 to another - make sure they are aligned, cant copy from a quad to a tri, used for solidify selection. - ''' - - def copy_default_face(data): - face_from, face_to = data - face_to.mat = face_from.mat - face_to.smooth = face_from.smooth - face_to.sel = True - face_from.sel = False - - def copy_tex_face(data): - face_from, face_to = data - face_to.uv = [c for c in reversed(face_from.uv)] - face_to.mode = face_from.mode - face_to.flag = face_from.flag - face_to.image = face_from.image - - def copy_col_face(data): - face_from, face_to = data - face_to.col = [c for c in reversed(face_from.col)] - - # make a list of face_from, face_to pairs - #face_pairs = zip(faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) - face_pairs = zip(from_faces, to_faces) - - # Copy properties from 1 set of faces to another. - map(copy_default_face, face_pairs) - - for uvlayer in me.getUVLayerNames(): - me.activeUVLayer = uvlayer - map(copy_tex_face, face_pairs) - - for collayer in me.getColorLayerNames(): - me.activeColorLayer = collayer - map(copy_col_face, face_pairs) - - # Now add quads between if we wants - - -Ang= Mathutils.AngleBetweenVecs -SMALL_NUM=0.00001 - -def solidify(me, PREF_THICK, PREF_SKIN_SIDES=True, PREF_REM_ORIG=False, PREF_COLLAPSE_SIDES=False): - - # Main code function - me_faces = me.faces - faces_sel= [f for f in me_faces if f.sel] - - BPyMesh.meshCalcNormals(me) - normals= [v.no for v in me.verts] - vertFaces= [[] for i in xrange(len(me.verts))] - for f in me_faces: - no=f.no - for v in f: - vertFaces[v.index].append(no) - - # Scale the normals by the face angles from the vertex Normals. - for i in xrange(len(me.verts)): - length=0.0 - if vertFaces[i]: - for fno in vertFaces[i]: - try: - a= Ang(fno, normals[i]) - except: - a= 0 - if a>=90: - length+=1 - elif a < SMALL_NUM: - length+= 1 - else: - length+= angleToLength(a) - - length= length/len(vertFaces[i]) - #print 'LENGTH %.6f' % length - # normals[i]= (normals[i] * length) * PREF_THICK - normals[i] *= length * PREF_THICK - - - - len_verts = len( me.verts ) - len_faces = len( me_faces ) - - vert_mapping= [-1] * len(me.verts) - verts= [] - for f in faces_sel: - for v in f: - i= v.index - if vert_mapping[i]==-1: - vert_mapping[i]= len_verts + len(verts) - verts.append(v.co + normals[i]) - - #verts= [v.co + normals[v.index] for v in me.verts] - - me.verts.extend( verts ) - #faces= [tuple([ me.verts[v.index+len_verts] for v in reversed(f.v)]) for f in me_faces ] - faces= [ tuple([vert_mapping[v.index] for v in reversed(f.v)]) for f in faces_sel ] - me_faces.extend( faces ) - - - - - # Old method before multi UVs - """ - has_uv = me.faceUV - has_vcol = me.vertexColors - for i, orig_f in enumerate(faces_sel): - new_f= me_faces[len_faces + i] - new_f.mat = orig_f.mat - new_f.smooth = orig_f.smooth - orig_f.sel=False - new_f.sel= True - new_f = me_faces[i+len_faces] - if has_uv: - new_f.uv = [c for c in reversed(orig_f.uv)] - new_f.mode = orig_f.mode - new_f.flag = orig_f.flag - if orig_f.image: - new_f.image = orig_f.image - if has_vcol: - new_f.col = [c for c in reversed(orig_f.col)] - """ - copy_facedata_multilayer(me, faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) - - if PREF_SKIN_SIDES or PREF_COLLAPSE_SIDES: - skin_side_faces= [] - skin_side_faces_orig= [] - # Get edges of faces that only have 1 user - so we can make walls - edges = {} - - # So we can reference indicies that wrap back to the start. - ROT_TRI_INDEX = 0,1,2,0 - ROT_QUAD_INDEX = 0,1,2,3,0 - - for f in faces_sel: - f_v= f.v - for i, edgekey in enumerate(f.edge_keys): - if edges.has_key(edgekey): - edges[edgekey]= None - else: - if len(f_v) == 3: - edges[edgekey] = f, f_v, i, ROT_TRI_INDEX[i+1] - else: - edges[edgekey] = f, f_v, i, ROT_QUAD_INDEX[i+1] - del ROT_QUAD_INDEX, ROT_TRI_INDEX - - # So we can remove doubles with edges only. - if PREF_COLLAPSE_SIDES: - me.sel = False - - # Edges are done. extrude the single user edges. - for edge_face_data in edges.itervalues(): - if edge_face_data: # != None - f, f_v, i1, i2 = edge_face_data - v1i,v2i= f_v[i1].index, f_v[i2].index - - if PREF_COLLAPSE_SIDES: - # Collapse - cv1 = me.verts[v1i] - cv2 = me.verts[vert_mapping[v1i]] - - cv3 = me.verts[v2i] - cv4 = me.verts[vert_mapping[v2i]] - - cv1.co = cv2.co = (cv1.co+cv2.co)/2 - cv3.co = cv4.co = (cv3.co+cv4.co)/2 - - cv1.sel=cv2.sel=cv3.sel=cv4.sel=True - - - - else: - # Now make a new Face - # skin_side_faces.append( (v1i, v2i, vert_mapping[v2i], vert_mapping[v1i]) ) - skin_side_faces.append( (v2i, v1i, vert_mapping[v1i], vert_mapping[v2i]) ) - skin_side_faces_orig.append((f, len(me_faces) + len(skin_side_faces_orig), i1, i2)) - - if PREF_COLLAPSE_SIDES: - me.remDoubles(0.0001) - else: - me_faces.extend(skin_side_faces) - # Now assign properties. - """ - # Before MultiUVs - for i, origfData in enumerate(skin_side_faces_orig): - orig_f, new_f_idx, i1, i2 = origfData - new_f= me_faces[new_f_idx] - - new_f.mat= orig_f.mat - new_f.smooth= orig_f.smooth - if has_uv: - new_f.mode= orig_f.mode - new_f.flag= orig_f.flag - if orig_f.image: - new_f.image= orig_f.image - - uv1= orig_f.uv[i1] - uv2= orig_f.uv[i2] - new_f.uv= (uv1, uv2, uv2, uv1) - - if has_vcol: - col1= orig_f.col[i1] - col2= orig_f.col[i2] - new_f.col= (col1, col2, col2, col1) - """ - - for i, origfData in enumerate(skin_side_faces_orig): - orig_f, new_f_idx, i2, i1 = origfData - new_f= me_faces[new_f_idx] - - new_f.mat= orig_f.mat - new_f.smooth= orig_f.smooth - - for uvlayer in me.getUVLayerNames(): - me.activeUVLayer = uvlayer - for i, origfData in enumerate(skin_side_faces_orig): - orig_f, new_f_idx, i2, i1 = origfData - new_f= me_faces[new_f_idx] - - new_f.mode= orig_f.mode - new_f.flag= orig_f.flag - new_f.image= orig_f.image - - uv1= orig_f.uv[i1] - uv2= orig_f.uv[i2] - new_f.uv= (uv1, uv2, uv2, uv1) - - for collayer in me.getColorLayerNames(): - me.activeColorLayer = collayer - for i, origfData in enumerate(skin_side_faces_orig): - orig_f, new_f_idx, i2, i1 = origfData - new_f= me_faces[new_f_idx] - - col1= orig_f.col[i1] - col2= orig_f.col[i2] - new_f.col= (col1, col2, col2, col1) - - - if PREF_REM_ORIG: - me_faces.delete(0, faces_sel) - - - - -def main(): - scn = bpy.data.scenes.active - ob = scn.objects.active - - if not ob or ob.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - me = ob.getData(mesh=1) - if me.multires: - BPyMessages.Error_NoMeshMultiresEdit() - return - - # Create the variables. - PREF_THICK = Draw.Create(-0.1) - PREF_SKIN_SIDES= Draw.Create(1) - PREF_COLLAPSE_SIDES= Draw.Create(0) - PREF_REM_ORIG= Draw.Create(0) - - pup_block = [\ - ('Thick:', PREF_THICK, -10, 10, 'Skin thickness in mesh space.'),\ - ('Skin Sides', PREF_SKIN_SIDES, 'Skin between the original and new faces.'),\ - ('Collapse Sides', PREF_COLLAPSE_SIDES, 'Skin between the original and new faces.'),\ - ('Remove Original', PREF_REM_ORIG, 'Remove the selected faces after skinning.'),\ - ] - - if not Draw.PupBlock('Solid Skin Selection', pup_block): - return - - is_editmode = Window.EditMode() - if is_editmode: Window.EditMode(0) - - Window.WaitCursor(1) - - me = ob.getData(mesh=1) - solidify(me, PREF_THICK.val, PREF_SKIN_SIDES.val, PREF_REM_ORIG.val, PREF_COLLAPSE_SIDES.val) - - - Window.WaitCursor(0) - if is_editmode: Window.EditMode(1) - - Window.RedrawAll() - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/release/scripts/mesh_unfolder.py b/release/scripts/mesh_unfolder.py deleted file mode 100644 index f5c19a92bd0..00000000000 --- a/release/scripts/mesh_unfolder.py +++ /dev/null @@ -1,1582 +0,0 @@ -#!BPY -""" -Name: 'Unfold' -Blender: 245 -Group: 'Mesh' -Tip: 'Unfold meshes to create nets' -Version: v2.5 -Author: Matthew Chadwick -""" -import Blender -from Blender import * -from Blender.Mathutils import * -try: - import sys - import traceback - import math - import re - from math import * - import sys - import random - import xml.sax, xml.sax.handler, xml.sax.saxutils - - # annoying but need so classes dont raise errors - xml_sax_handler_ContentHandler = xml.sax.handler.ContentHandler - -except: - Draw.PupMenu('Error%t|A full python installation is required to run this script.') - xml = None - xml_sax_handler_ContentHandler = type(0) - -__author__ = 'Matthew Chadwick' -__version__ = '2.5 06102007' -__url__ = ["http://celeriac.net/unfolder/", "blender", "blenderartist"] -__email__ = ["post at cele[remove this text]riac.net", "scripts"] -__bpydoc__ = """\ - -Mesh Unfolder - -Unfolds the selected mesh onto a plane to form a net - -Not all meshes can be unfolded - -Meshes must be free of holes, -isolated edges (not part of a face), twisted quads and other rubbish. -Nice clean triangulated meshes unfold best - -This program is free software; you can distribute it and/or modify it under the terms -of the GNU General Public License as published by the Free Software Foundation; version 2 -or later, currently at http://www.gnu.org/copyleft/gpl.html - -The idea came while I was riding a bike. -""" - -# ***** 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 ***** - -# Face lookup -class FacesAndEdges: - def __init__(self, mesh): - self.nfaces = 0 - # straight from the documentation - self.edgeFaces = dict([(edge.key, []) for edge in mesh.edges]) - for face in mesh.faces: - face.sel = False - for key in face.edge_keys: - self.edgeFaces[key].append(face) - def findTakenAdjacentFace(self, bface, edge): - return self.findAdjacentFace(bface, edge) - # find the first untaken (non-selected) adjacent face in the list of adjacent faces for the given edge (allows for manifold meshes too) - def findAdjacentFace(self, bface, edge): - faces = self.edgeFaces[edge.key()] - for i in xrange(len(faces)): - if faces[i] == bface: - j = (i+1) % len(faces) - while(faces[j]!=bface): - if faces[j].sel == False: - return faces[j] - j = (j+1) % len(faces) - return None - def returnFace(self, face): - face.sel = False - self.nfaces-=1 - def facesTaken(self): - return self.nfaces - def takeAdjacentFace(self, bface, edge): - if (edge==None): - return None - face = self.findAdjacentFace(bface, edge) - if(face!=None): - face.sel = True - self.nfaces+=1 - return face - def takeFace(self, bface): - if(bface!=None): - bface.sel= True - self.nfaces+=1 - - -# A fold between two faces with a common edge -class Fold: - ids = -1 - def __init__(self, parent, refPoly, poly, edge, angle=None): - Fold.ids+=1 - self.id = Fold.ids - self.refPoly = refPoly - self.poly = poly - self.srcFace = None - self.desFace = None - self.edge = edge - self.foldedEdge = edge - self.rm = None - self.parent = parent - self.tree = None - if(refPoly!=None): - self.refPolyNormal = refPoly.normal() - self.polyNormal = poly.normal() - if(angle==None): - self.angle = self.calculateAngle() - self.foldingPoly = poly.rotated(edge, self.angle) - else: - self.angle = angle - self.foldingPoly = poly - self.unfoldedEdge = self.edge - self.unfoldedNormal = None - self.animAngle = self.angle - self.cr = None - self.nancestors = None - def reset(self): - self.foldingPoly = self.poly.rotated(self.edge, self.dihedralAngle()) - def getID(self): - return self.id - def getParent(self): - return self.parent - def ancestors(self): - if(self.nancestors==None): - self.nancestors = self.computeAncestors() - return self.nancestors - def computeAncestors(self): - if(self.parent==None): - return 0 - else: - return self.parent.ancestors()+1 - def dihedralAngle(self): - return self.angle - def unfoldTo(self, f): - self.animAngle = self.angle*f - self.foldingPoly = self.poly.rotated(self.edge, self.animAngle) - def calculateAngle(self): - sangle = Mathutils.AngleBetweenVecs(self.refPolyNormal, self.polyNormal) - if(sangle!=sangle): - sangle=0.0 - ncp = self.refPolyNormal.cross(self.polyNormal) - dp = ncp.dot(self.edge.vector) - if(dp>0.0): - return +sangle - else: - return -sangle - def alignWithParent(self): - pass - def unfoldedNormal(self): - return self.unfoldedNormal - def getEdge(self): - return self.edge - def getFace(self): - return self.poly - def testFace(self): - return Poly.fromVectors([self.edge.v1, self.edge.v2, Vector([0,0,0])]) - def unfoldedFace(self): - return self.foldingPoly - def unfold(self): - if(self.parent!=None): - self.parent.foldFace(self) - def foldFace(self, child): - child.foldingPoly.rotate(self.edge, self.animAngle) - if(self.parent!=None): - self.parent.foldFace(child) - -class Cut(Fold): - pass - -# Trees build folds by traversing the mesh according to a local measure -class Tree: - def __init__(self, net, parent,fold,otherConstructor=None): - self.net = net - self.fold = fold - self.face = fold.srcFace - self.poly = Poly.fromBlenderFace(self.face) - self.generations = net.generations - self.growing = True - self.tooLong = False - self.parent = parent - self.grown = False - if not(otherConstructor): - self.edges = net.edgeIteratorClass(self) - def goodness(self): - return self.edges.goodness() - def compare(self, other): - if(self.goodness() > other.goodness()): - return +1 - else: - return -1 - def isGrowing(self): - return self.growing - def beGrowing(self): - self.growing = True - def grow(self): - self.tooLong = self.fold.ancestors()>self.generations - if(self.edges.hasNext() and self.growing): - edge = self.edges.next() - tface = self.net.facesAndEdges.takeAdjacentFace(self.face, edge) - if(tface!=None): - self.branch(tface, edge) - if(self.parent==None): - self.grow() - else: - self.grown = True - def isGrown(self): - return self.grown - def canGrow(self): - return (self.parent!=None and self.parent.grown) - def getNet(self): - return self.net - def getFold(self): - return self.fold - def getFace(self): - return self.face - def branch(self, tface, edge): - fold = Fold(self.fold, self.poly, Poly.fromBlenderFace(tface), edge) - fold.srcFace = tface - self.net.myFacesVisited+=1 - tree = Tree(self.net, self, fold) - fold.tree = tree - fold.unfold() - overlaps = self.net.checkOverlaps(fold) - nc = len(overlaps) - self.net.overlaps+=nc - if(nc>0 and self.net.avoidsOverlaps): - self.handleOverlap(fold, overlaps) - else: - self.addFace(fold) - def handleOverlap(self, fold, overlaps): - self.net.facesAndEdges.returnFace(fold.srcFace) - self.net.myFacesVisited-=1 - for cfold in overlaps: - ttree = cfold.tree - ttree.growing = True - ttree.grow() - def addFace(self, fold): - ff = fold.unfoldedFace() - fold.desFace = self.net.addFace(ff, fold.srcFace) - self.net.folds.append(fold) - self.net.addBranch(fold.tree) - fold.tree.growing = not(self.tooLong) - if(self.net.diffuse==False): - fold.tree.grow() - -# A Net is the result of the traversal of the mesh by Trees -class Net: - def __init__(self, src, des): - self.src = src - self.des = des - self.firstFace = None - self.firstPoly = None - self.refFold = None - self.edgeIteratorClass = RandomEdgeIterator - if(src!=None): - self.srcFaces = src.faces - self.facesAndEdges = FacesAndEdges(self.src) - self.myFacesVisited = 0 - self.facesAdded = 0 - self.folds = [] - self.cuts = [] - self.branches = [] - self.overlaps = 0 - self.avoidsOverlaps = True - self.frame = 1 - self.ff = 180.0 - self.firstFaceIndex = None - self.trees = 0 - self.foldIPO = None - self.perFoldIPO = None - self.IPOCurves = {} - self.generations = 128 - self.diffuse = True - self.noise = 0.0 - self.grownBranches = 0 - self.assignsUV = True - self.animates = False - self.showProgress = False - self.feedback = None - def setSelectedFaces(self, faces): - self.srcFaces = faces - self.facesAndEdges = FacesAndEdges(self.srcFaces) - def setShowProgress(self, show): - self.showProgress = show - # this method really needs work - def unfold(self): - selectedFaces = [face for face in self.src.faces if (self.src.faceUV and face.sel)] - if(self.avoidsOverlaps): - print "unfolding with overlap detection" - if(self.firstFaceIndex==None): - self.firstFaceIndex = random.randint(0, len(self.src.faces)-1) - else: - print "Using user-selected seed face ", self.firstFaceIndex - self.firstFace = self.src.faces[self.firstFaceIndex] - z = min([v.co.z for v in self.src.verts])-0.1 - ff = Poly.fromBlenderFace(self.firstFace) - if(len(ff.v)<3): - raise Exception("This mesh contains an isolated edge - it must consist only of faces") - testFace = Poly.fromVectors( [ Vector([0.0,0.0,0.0]), Vector([0.0,1.0,0.0]), Vector([1.0,1.0,0.0]) ] ) - # hmmm. I honestly can't remember why this needs to be done, but it does. - u=0 - v=1 - w=2 - if ff.v[u].x==ff.v[u+1].x and ff.v[u].y==ff.v[u+1].y: - u=1 - v=2 - w=0 - # here we make a couple of folds, not part of the net, which serve to get the net into the xy plane - xyFace = Poly.fromList( [ [ff.v[u].x,ff.v[u].y, z] , [ff.v[v].x,ff.v[v].y, z] , [ff.v[w].x+0.1,ff.v[w].y+0.1, z] ] ) - refFace = Poly.fromVectors([ ff.v[u], ff.v[v], xyFace.v[1], xyFace.v[0] ] ) - xyFold = Fold(None, xyFace, refFace, Edge(xyFace.v[0], xyFace.v[1] )) - self.refFold = Fold(xyFold, refFace, ff, Edge(refFace.v[0], refFace.v[1] )) - self.refFold.srcFace = self.firstFace - # prepare to grow the trees - trunk = Tree(self, None, self.refFold) - trunk.generations = self.generations - self.firstPoly = ff - self.facesAndEdges.takeFace(self.firstFace) - self.myFacesVisited+=1 - self.refFold.unfold() - self.refFold.tree = trunk - self.refFold.desFace = self.addFace(self.refFold.unfoldedFace(), self.refFold.srcFace) - self.folds.append(self.refFold) - trunk.grow() - i = 0 - # keep the trees growing while they can - while(self.myFacesVisited 0): - if self.edgeIteratorClass==RandomEdgeIterator: - i = random.randint(0,len(self.branches)-1) - tree = self.branches[i] - if(tree.isGrown()): - self.branches.pop(i) - else: - tree.beGrowing() - if(tree.canGrow()): - tree.grow() - i = 0 - else: - i = (i + 1) % len(self.branches) - if self.src.faceUV: - for face in self.src.faces: - face.sel = False - for face in selectedFaces: - face.sel = True - self.src.update() - Window.RedrawAll() - def assignUVs(self): - for fold in self.folds: - self.assignUV(fold.srcFace, fold.unfoldedFace()) - print " assigned uv to ", len(self.folds), len(self.src.faces) - self.src.update() - def checkOverlaps(self, fold): - #return self.getOverlapsBetween(fold, self.folds) - return self.getOverlapsBetweenGL(fold, self.folds) - def getOverlapsBetween(self, fold, folds): - if(fold.parent==None): - return [] - mf = fold.unfoldedFace() - c = [] - for afold in folds: - mdf = afold.unfoldedFace() - if(afold!=fold): - # currently need to get agreement from both polys because - # a touch by a vertex of one the other's edge is acceptable & - # they disagree on that - intersects = mf.intersects2D(mdf) and mdf.intersects2D(mf) - inside = ( mdf.containsAnyOf(mf) or mf.containsAnyOf(mdf) ) - if( intersects or inside or mdf.overlays(mf)): - c.append(afold) - return c - def getOverlapsBetweenGL(self, fold, folds): - b = fold.unfoldedFace().bounds() - polys = len(folds)*4+16 # the buffer is nhits, mindepth, maxdepth, name - buffer = BGL.Buffer(BGL.GL_INT, polys) - BGL.glSelectBuffer(polys, buffer) - BGL.glRenderMode(BGL.GL_SELECT) - BGL.glInitNames() - BGL.glPushName(0) - BGL.glPushMatrix() - BGL.glMatrixMode(BGL.GL_PROJECTION) - BGL.glLoadIdentity() - BGL.glOrtho(b[0].x, b[1].x, b[1].y, b[0].y, 0.0, 10.0) - #clip = BGL.Buffer(BGL.GL_FLOAT, 4) - #clip.list = [0,0,0,0] - #BGL.glClipPlane(BGL.GL_CLIP_PLANE1, clip) - # could use clipping planes here too - BGL.glMatrixMode(BGL.GL_MODELVIEW) - BGL.glLoadIdentity() - bx = (b[1].x - b[0].x) - by = (b[1].y - b[0].y) - cx = bx / 2.0 - cy = by / 2.0 - for f in xrange(len(folds)): - afold = folds[f] - if(fold!=afold): - BGL.glLoadName(f) - BGL.glBegin(BGL.GL_LINE_LOOP) - for v in afold.unfoldedFace().v: - BGL.glVertex2f(v.x, v.y) - BGL.glEnd() - BGL.glPopMatrix() - BGL.glFlush() - hits = BGL.glRenderMode(BGL.GL_RENDER) - buffer = [buffer[i] for i in xrange(3, 4*hits, 4)] - o = [folds[buffer[i]] for i in xrange(len(buffer))] - return self.getOverlapsBetween(fold, o) - def colourFace(self, face, cr): - for c in face.col: - c.r = int(cr[0]) - c.g = int(cr[1]) - c.b = int(cr[2]) - c.a = int(cr[3]) - self.src.update() - def setAvoidsOverlaps(self, avoids): - self.avoidsOverlaps = avoids - def addBranch(self, branch): - self.branches.append(branch) - if self.edgeIteratorClass!=RandomEdgeIterator: - self.branches.sort(lambda b1, b2: b1.compare(b2)) - def srcSize(self): - return len(self.src.faces) - def nBranches(self): - return len(self.branches) - def facesCreated(self): - return len(self.des.faces) - def facesVisited(self): - return self.myFacesVisited - def getOverlaps(self): - return self.overlaps - def sortOutIPOSource(self): - print "Sorting out IPO" - if self.foldIPO!=None: - return - o = None - try: - o = Blender.Object.Get("FoldRate") - except: - o = Blender.Object.New("Empty", "FoldRate") - Blender.Scene.GetCurrent().objects.link(o) - if(o.getIpo()==None): - ipo = Blender.Ipo.New("Object", "FoldRateIPO") - z = ipo.addCurve("RotZ") - print " added RotZ IPO curve" - z.addBezier((1,0)) - # again, why is this 10x out ? - z.addBezier((180, self.ff/10.0)) - z.addBezier((361, 0.0)) - o.setIpo(ipo) - z.recalc() - z.setInterpolation("Bezier") - z.setExtrapolation("Cyclic") - self.setIPOSource(o) - print " added IPO source" - def setIPOSource(self, object): - try: - self.foldIPO = object - for i in xrange(self.foldIPO.getIpo().getNcurves()): - self.IPOCurves[self.foldIPO.getIpo().getCurves()[i].getName()] = i - print " added ", self.foldIPO.getIpo().getCurves()[i].getName() - except: - print "Problem setting IPO object" - print sys.exc_info()[1] - traceback.print_exc(file=sys.stdout) - def setFoldFactor(self, ff): - self.ff = ff - def sayTree(self): - for fold in self.folds: - if(fold.getParent()!=None): - print fold.getID(), fold.dihedralAngle(), fold.getParent().getID() - def report(self): - p = int(float(self.myFacesVisited)/float(len(self.src.faces)) * 100) - print str(p) + "% unfolded" - print "faces created:", self.facesCreated() - print "faces visited:", self.facesVisited() - print "originalfaces:", len(self.src.faces) - n=0 - if(self.avoidsOverlaps): - print "net avoided at least ", self.getOverlaps(), " overlaps ", - n = len(self.src.faces) - self.facesCreated() - if(n>0): - print "but was unable to avoid ", n, " overlaps. Incomplete net." - else: - print "- A complete net." - else: - print "net has at least ", self.getOverlaps(), " collision(s)" - return n - # fold all my folds to a fraction of their total fold angle - def unfoldToCurrentFrame(self): - self.unfoldTo(Blender.Scene.GetCurrent().getRenderingContext().currentFrame()) - def unfoldTo(self, frame): - frames = Blender.Scene.GetCurrent().getRenderingContext().endFrame() - if(self.foldIPO!=None and self.foldIPO.getIpo()!=None): - f = self.foldIPO.getIpo().EvaluateCurveOn(self.IPOCurves["RotZ"],frame) - # err, this number seems to be 10x less than it ought to be - fff = 1.0 - (f*10.0 / self.ff) - else: - fff = 1.0-((frame)/(frames*1.0)) - for fold in self.folds: - fold.unfoldTo(fff) - for fold in self.folds: - fold.unfold() - tface = fold.unfoldedFace() - bface = fold.desFace - i = 0 - for v in bface.verts: - v.co.x = tface.v[i].x - v.co.y = tface.v[i].y - v.co.z = tface.v[i].z - i+=1 - Window.Redraw(Window.Types.VIEW3D) - return None - def addFace(self, poly, originalFace=None): - originalLength = len(self.des.verts) - self.des.verts.extend([Vector(vv.x, vv.y, vv.z) for vv in poly.v]) - self.des.faces.extend([ range(originalLength, originalLength + poly.size()) ]) - newFace = self.des.faces[len(self.des.faces)-1] - newFace.uv = [vv for vv in poly.v] - if(originalFace!=None and self.src.vertexColors): - newFace.col = [c for c in originalFace.col] - if(self.feedback!=None): - pu = str(int(self.fractionUnfolded() * 100))+"% unfolded" - howMuchDone = str(self.myFacesVisited)+" of "+str(len(self.src.faces))+" "+pu - self.feedback.say(howMuchDone) - #Window.DrawProgressBar (p, pu) - if(self.showProgress): - Window.Redraw(Window.Types.VIEW3D) - return newFace - def fractionUnfolded(self): - return float(self.myFacesVisited)/float(len(self.src.faces)) - def assignUV(self, face, uv): - face.uv = [Vector(v.x, v.y) for v in uv.v] - def unfoldAll(feedback=None): - objects = Blender.Object.Get() - for object in objects: - if(object.getType()=='Mesh' and not(object.getName().endswith("_net")) and len(object.getData(False, True).faces)>1): - net = Net.createNet(object, feedback) - net.searchForUnfolding() - svg = SVGExporter(net, object.getName()+".svg") - svg.export() - unfoldAll = staticmethod(unfoldAll) - def searchForUnfolding(self, limit=-1): - overlaps = 1 - attempts = 0 - while(overlaps > 0 or attempts=0 and (mesh.faces[mesh.activeFace].sel): - net.firstFaceIndex = mesh.activeFace - net.object = ob - net.feedback = feedback - return net - createNet = staticmethod(createNet) - def importNet(filename): - netName = filename.rstrip(".svg").replace("\\","/") - netName = netName[netName.rfind("/")+1:] - try: - netObject = Blender.Object.Get(netName) - except: - netObject = Blender.Object.New("Mesh", netName) - netObject.getData(mesh=1).name = netName - try: - Blender.Scene.GetCurrent().objects.link(netObject) - except: - pass - net = Net(None, netObject.getData(mesh=1)) - handler = NetHandler(net) - xml.sax.parse(filename, handler) - Window.Redraw(Window.Types.VIEW3D) - return net - importNet = staticmethod(importNet) - def getSourceMesh(self): - return self.src - -# determines the order in which to visit faces according to a local measure -class EdgeIterator: - def __init__(self, branch, otherConstructor=None): - self.branch = branch - self.bface = branch.getFace() - self.edge = branch.getFold().getEdge() - self.net = branch.getNet() - self.n = len(self.bface) - self.edges = [] - self.i = 0 - self.gooodness = 0 - self.createEdges() - self.computeGoodness() - if(otherConstructor==None): - self.sequenceEdges() - def createEdges(self): - edge = None - e = Edge.edgesOfBlenderFace(self.net.getSourceMesh(), self.bface) - for edge in e: - if not(edge.isBlenderSeam() and edge!=self.edge): - self.edges.append(edge) - def sequenceEdges(self): - pass - def next(self): - edge = self.edges[self.i] - self.i+=1 - return edge - def size(self): - return len(self.edges) - def reset(self): - self.i = 0 - def hasNext(self): - return (self.ilen(bface)-1): - return None - if(i==len(bface)-1): - j = 0 - else: - j = i+1 - edge = Edge( bface.v[i].co.copy(), bface.v[j].co.copy() ) - edge.bEdge = mesh.findEdge(bface.v[i], bface.v[j]) - edge.idx = i - return edge - fromBlenderFace=staticmethod(fromBlenderFace) - def edgesOfBlenderFace(mesh, bmFace): - edges = [mesh.edges[mesh.findEdges(edge[0], edge[1])] for edge in bmFace.edge_keys] - v = bmFace.verts - e = [] - vi = v[0] - i=0 - for j in xrange(1, len(bmFace)+1): - vj = v[j%len(bmFace)] - for ee in edges: - if((ee.v1.index==vi.index and ee.v2.index==vj.index) or (ee.v2.index==vi.index and ee.v1.index==vj.index)): - e.append(Edge(vi.co, vj.co, ee, i)) - i+=1 - vi = vj - return e - edgesOfBlenderFace=staticmethod(edgesOfBlenderFace) - def isBlenderSeam(self): - return (self.bmEdge.flag & Mesh.EdgeFlags.SEAM) - def isInFGon(self): - return (self.bmEdge.flag & Mesh.EdgeFlags.FGON) - def mapTo(self, poly): - if(self.idx==len(poly.v)-1): - j = 0 - else: - j = self.idx+1 - return Edge(poly.v[self.idx], poly.v[j]) - def isDegenerate(self): - return self.vector.length==0 - def vertices(s): - return [ [s.v1.x, s.v1.y, s.v1.z], [s.v2.x, s.v2.y,s.v2.z] ] - def key(self): - return self.bmEdge.key - def goodness(self): - return self.gooodness - def setGoodness(self, g): - self.gooodness = g - def compare(self, other): - if(self.goodness() > other.goodness()): - return +1 - else: - return -1 - # Does the given segment intersect this, for overlap detection. - # endpoints are allowed to touch the line segment - def intersects2D(self, s): - if(self.matches(s)): - return False - else: - i = Geometry.LineIntersect2D(self.v1, self.v2, s.v1, s.v2) - if(i!=None): - i.resize4D() - i.z = self.v1.z # hack to put the point on the same plane as this edge for comparison - return(i!=None and not(self.endsWith(i))) - def matches(self, s): - return ( (self.v1==s.v1 and self.v2==s.v2) or (self.v2==s.v1 and self.v1==s.v2) ) - # Is the given point on the end of this segment ? 10-5 seems to an acceptable limit for closeness in Blender - def endsWith(self, aPoint, e=0.0001): - return ( (self.v1-aPoint).length < e or (self.v2-aPoint).length < e ) - - -class Poly: - ids = -1 - def __init__(self): - Poly.ids+=1 - self.v = [] - self.id = Poly.ids - self.boundz = None - self.edges = None - def getID(self): - return self.id - def normal(self): - a =self.v[0] - b=self.v[1] - c=self.v[2] - p = b-a - p.resize3D() - q = a-c - q.resize3D() - return p.cross(q) - def makeEdges(self): - self.edges = [] - for i in xrange(self.nPoints()): - self.edges.append(Edge( self.v[i % self.nPoints()], self.v[ (i+1) % self.nPoints()] )) - def edgeAt(self, i): - if(self.edges==None): - self.makeEdges() - return self.edges[i] - def intersects2D(self, poly): - for i in xrange(self.nPoints()): - edge = self.edgeAt(i) - for j in xrange(poly.nPoints()): - if edge.intersects2D(poly.edgeAt(j)): - return True - return False - def isBad(self): - badness = 0 - for vv in self.v: - if(vv.x!=vv.x or vv.y!=vv.y or vv.z!=vv.z): # Nan check - badness+=1 - return (badness>0) - def midpoint(self): - x=y=z = 0.0 - n = 0 - for vv in self.v: - x+=vv.x - y+=vv.y - z+=vv.z - n+=1 - return [ x/n, y/n, z/n ] - def centerAtOrigin(self): - mp = self.midpoint() - mp = -mp - toOrigin = TranslationMatrix(mp) - self.v = [(vv * toOrigin) for vv in self.v] - def move(self, tv): - mv = TranslationMatrix(tv) - self.v = [(vv * mv) for vv in self.v] - def scale(self, s): - mp = Vector(self.midpoint()) - fromOrigin = TranslationMatrix(mp) - mp = -mp - toOrigin = TranslationMatrix(mp) - sm = ScaleMatrix(s, 4) - # Todo, the 3 lines below in 1 LC - self.v = [(vv * toOrigin) for vv in self.v] - self.v = [(sm * vv) for vv in self.v] - self.v = [(vv * fromOrigin) for vv in self.v] - def nPoints(self): - return len(self.v) - def size(self): - return len(self.v) - def rotated(self, axis, angle): - p = self.clone() - p.rotate(axis, angle) - return p - def rotate(self, axis, angle): - rotation = RotationMatrix(angle, 4, "r", axis.vector) - toOrigin = TranslationMatrix(axis.v1n) - fromOrigin = TranslationMatrix(axis.v1) - # Todo, the 3 lines below in 1 LC - self.v = [(vv * toOrigin) for vv in self.v] - self.v = [(rotation * vv) for vv in self.v] - self.v = [(vv * fromOrigin) for vv in self.v] - def moveAlong(self, vector, distance): - t = TranslationMatrix(vector) - s = ScaleMatrix(distance, 4) - ts = t*s - self.v = [(vv * ts) for vv in self.v] - def bounds(self): - if(self.boundz == None): - vv = [vv for vv in self.v] - vv.sort(key=lambda v: v.x) - minx = vv[0].x - maxx = vv[len(vv)-1].x - vv.sort(key=lambda v: v.y) - miny = vv[0].y - maxy = vv[len(vv)-1].y - self.boundz = [Vector(minx, miny, 0), Vector(maxx, maxy, 0)] - return self.boundz - def fromBlenderFace(bface): - p = Poly() - for vv in bface.v: - vec = Vector([vv.co[0], vv.co[1], vv.co[2] , 1.0]) - p.v.append(vec) - return p - fromBlenderFace = staticmethod(fromBlenderFace) - def fromList(list): - p = Poly() - for vv in list: - vec = Vector( [vvv for vvv in vv] ) - vec.resize4D() - p.v.append(vec) - return p - fromList = staticmethod(fromList) - def fromVectors(vectors): - p = Poly() - p.v.extend([v.copy().resize4D() for v in vectors]) - return p - fromVectors = staticmethod(fromVectors) - def clone(self): - p = Poly() - p.v.extend(self.v) - return p - def hasVertex(self, ttv): - v = Mathutils.Vector(ttv) - v.normalize() - for tv in self.v: - vv = Mathutils.Vector(tv) - vv.normalize() - t = 0.00001 - if abs(vv.x-v.x)0): j=i-1 - cv = self.v[i] - nv = self.v[j] - if ((((cv.y<=tp.y) and (tp.y") - self.e.endElement("style") - self.e.endElement("defs") - #self.addClipPath() - self.addMeta() - def addMeta(self): - self.e.startElement("metadata", xml.sax.xmlreader.AttributesImpl({})) - self.e.startElement("nets:net", xml.sax.xmlreader.AttributesImpl({})) - for i in xrange(1, len(self.net.folds)): - fold = self.net.folds[i] - # AttributesNSImpl - documentation is rubbish. using this hack. - atts = {} - atts["nets:id"] = "fold"+str(fold.getID()) - if(fold.parent!=None): - atts["nets:parent"] = "fold"+str(fold.parent.getID()) - else: - atts["nets:parent"] = "null" - atts["nets:da"] = str(fold.dihedralAngle()) - if(fold.parent!=None): - atts["nets:ofPoly"] = "poly"+str(fold.parent.foldingPoly.getID()) - else: - atts["nets:ofPoly"] = "" - atts["nets:toPoly"] = "poly"+str(fold.foldingPoly.getID()) - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("nets:fold", a) - self.e.endElement("nets:fold") - self.e.endElement("nets:net") - self.e.endElement("metadata") - def end(self): - self.e.endElement("svg") - self.e.endDocument() - print "grown." - def export(self): - self.net.unfoldTo(1) - bb = self.object.getBoundBox() - print bb - self.vxmin = bb[0][0] - self.vymin = bb[0][1] - self.vxmax = bb[7][0] - self.vymax = bb[7][1] - self.start() - atts = {} - atts["id"] = self.object.getName() - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("g", a) - #self.addUVImage() - self.addPolys() - self.addFoldLines() - #self.addCutLines() - self.e.endElement("g") - self.end() - def addClipPath(self): - atts = {} - atts["id"] = "netClip" - atts["clipPathUnits"] = "userSpaceOnUse" - atts["x"] = str(self.vxmin) - atts["y"] = str(self.vymin) - atts["width"] = "100%" - atts["height"] = "100%" - self.e.startElement("clipPath", atts) - self.addPolys() - self.e.endElement("clipPath") - def addUVImage(self): - image = Blender.Image.GetCurrent() #hmm - how to determine the desired image ? - if image==None: - return - ifn = image.getFilename() - ifn = self.filename.replace(".svg", ".jpg") - image.setFilename(ifn) - ifn = ifn[ifn.rfind("/")+1:] - image.save() - atts = {} - atts["clip-path"] = "url(#netClip)" - atts["xlink:href"] = ifn - self.e.startElement("image", atts) - self.e.endElement("image") - def addPolys(self): - atts = {} - atts["id"] = "polys" - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("g", a) - for i in xrange(len(self.net.folds)): - self.addPoly(self.net.folds[i]) - self.e.endElement("g") - def addFoldLines(self): - atts = {} - atts["id"] = "foldLines" - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("g", a) - for i in xrange( 1, len(self.net.folds)): - self.addFoldLine(self.net.folds[i]) - self.e.endElement("g") - def addFoldLine(self, fold): - edge = fold.edge.mapTo(fold.parent.foldingPoly) - if fold.dihedralAngle()>0: - foldType="valley" - else: - foldType="mountain" - atts={} - atts["x1"] = str(edge.v1.x) - atts["y1"] = str(edge.v1.y) - atts["x2"] = str(edge.v2.x) - atts["y2"] = str(edge.v2.y) - atts["id"] = "fold"+str(fold.getID()) - atts["class"] = foldType - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("line", a) - self.e.endElement("line") - def addCutLines(self): - atts = {} - atts["id"] = "cutLines" - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("g", a) - for i in xrange( 1, len(self.net.cuts)): - self.addCutLine(self.net.cuts[i]) - self.e.endElement("g") - def addCutLine(self, cut): - edge = cut.edge.mapTo(cut.parent.foldingPoly) - if cut.dihedralAngle()>0: - foldType="valley" - else: - foldType="mountain" - atts={} - atts["x1"] = str(edge.v1.x) - atts["y1"] = str(edge.v1.y) - atts["x2"] = str(edge.v2.x) - atts["y2"] = str(edge.v2.y) - atts["id"] = "cut"+str(cut.getID()) - atts["class"] = foldType - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("line", a) - self.e.endElement("line") - def addPoly(self, fold): - face = fold.foldingPoly - atts = {} - if fold.desFace.col: - col = fold.desFace.col[0] - rgb = "rgb("+str(col.r)+","+str(col.g)+","+str(col.b)+")" - atts["fill"] = rgb - atts["class"] = "poly" - atts["id"] = "poly"+str(face.getID()) - points = "" - first = True - for vv in face.v: - if(not(first)): - points+=',' - first = False - points+=str(vv[0]) - points+=' ' - points+=str(vv[1]) - atts["points"] = points - a = xml.sax.xmlreader.AttributesImpl(atts) - self.e.startElement("polygon", a) - self.e.endElement("polygon") - def fileSelected(filename): - try: - net = Registry.GetKey('unfolder')['net'] - exporter = SVGExporter(net, filename) - exporter.export() - except: - print "Problem exporting SVG" - traceback.print_exc(file=sys.stdout) - fileSelected = staticmethod(fileSelected) - -# for importing nets saved by the above exporter -class NetHandler(xml.sax.handler.ContentHandler): - def __init__(self, net): - self.net = net - self.first = (41==41) - self.currentElement = None - self.chars = None - self.currentAction = None - self.foldsPending = {} - self.polys = {} - self.actions = {} - self.actions["nets:fold"] = self.foldInfo - self.actions["line"] = self.cutOrFold - self.actions["polygon"] = self.createPoly - def setDocumentLocator(self, locator): - pass - def startDocument(self): - pass - def endDocument(self): - for fold in self.foldsPending.values(): - face = self.net.addFace(fold.unfoldedFace()) - fold.desFace = face - self.net.folds.append(fold) - self.net.addFace(self.first) - self.foldsPending = None - self.polys = None - def startPrefixMapping(self, prefix, uri): - pass - def endPrefixMapping(self, prefix): - pass - def startElement(self, name, attributes): - self.currentAction = None - try: - self.currentAction = self.actions[name] - except: - pass - if(self.currentAction!=None): - self.currentAction(attributes) - def endElement(self, name): - pass - def startElementNS(self, name, qname, attrs): - self.currentAction = self.actions[name] - if(self.currentAction!=None): - self.currentAction(attributes) - def endElementNS(self, name, qname): - pass - def characters(self, content): - pass - def ignorableWhitespace(self): - pass - def processingInstruction(self, target, data): - pass - def skippedEntity(self, name): - pass - def foldInfo(self, atts): - self.foldsPending[atts["nets:id"]] = atts - def createPoly(self, atts): - xy = re.split('[, ]' , atts["points"]) - vectors = [] - for i in xrange(0, len(xy)-1, 2): - v = Vector([float(xy[i]), float(xy[i+1]), 0.0]) - vectors.append(v) - poly = Poly.fromVectors(vectors) - if(self.first==True): - self.first = poly - self.polys[atts["id"]] = poly - def cutOrFold(self, atts): - fid = atts["id"] - try: - fi = self.foldsPending[fid] - except: - pass - p1 = Vector([float(atts["x1"]), float(atts["y1"]), 0.0]) - p2 = Vector([float(atts["x2"]), float(atts["y2"]), 0.0]) - edge = Edge(p1, p2) - parent = None - ofPoly = None - toPoly = None - try: - parent = self.foldsPending[fi["nets:parent"]] - except: - pass - try: - ofPoly = self.polys[fi["nets:ofPoly"]] - except: - pass - try: - toPoly = self.polys[fi["nets:toPoly"]] - except: - pass - fold = Fold(parent, ofPoly , toPoly, edge, float(fi["nets:da"])) - self.foldsPending[fid] = fold - def fileSelected(filename): - try: - net = Net.importNet(filename) - try: - Registry.GetKey('unfolder')['net'] = net - except: - Registry.SetKey('unfolder', {}) - Registry.GetKey('unfolder')['net'] = net - Registry.GetKey('unfolder')['lastpath'] = filename - except: - print "Problem importing SVG" - traceback.print_exc(file=sys.stdout) - fileSelected = staticmethod(fileSelected) - - -class GUI: - def __init__(self): - self.overlaps = Draw.Create(0) - self.ani = Draw.Create(0) - self.selectedFaces =0 - self.search = Draw.Create(0) - self.diffuse = True - self.ancestors = Draw.Create(0) - self.noise = Draw.Create(0.0) - self.shape = Draw.Create(0) - self.nOverlaps = 1==2 - self.iterators = [RandomEdgeIterator,Brightest,Curvature,EdgeIterator,OddEven,Largest] - self.iterator = RandomEdgeIterator - self.overlapsText = "*" - self.message = " " - def makePopupGUI(self): - useRandom = Draw.Create(0) - pub = [] - pub.append(("Search", self.search, "Search for non-overlapping net (maybe forever)")) - pub.append(("Random", useRandom, "Random style net")) - ok = True - while ok: - ok = Blender.Draw.PupBlock("Unfold", pub) - if ok: - if useRandom.val: - self.iterator = RandomEdgeIterator - else: - self.iterator = Curvature - self.unfold() - def makeStandardGUI(self): - Draw.Register(self.draw, self.keyOrMouseEvent, self.buttonEvent) - def installScriptLink(self): - print "Adding script link for animation" - s = Blender.Scene.GetCurrent().getScriptLinks("FrameChanged") - if(s!=None and s.count("frameChanged.py")>0): - return - try: - script = Blender.Text.Get("frameChanged.py") - except: - script = Blender.Text.New("frameChanged.py") - script.write("import Blender\n") - script.write("import mesh_unfolder as Unfolder\n") - script.write("u = Blender.Registry.GetKey('unfolder')\n") - script.write("if u!=None:\n") - script.write("\tn = u['net']\n") - script.write("\tif(n!=None and n.animates):\n") - script.write("\t\tn.unfoldToCurrentFrame()\n") - Blender.Scene.GetCurrent().addScriptLink("frameChanged.py", "FrameChanged") - def unfold(self): - anc = self.ancestors.val - n = 0.0 - s = True - self.nOverlaps = 0 - searchLimit = 10 - search = 1 - Draw.Redraw(1) - net = None - name = None - try: - self.say("Unfolding...") - Draw.Redraw(1) - while(s):# and search < searchLimit): - if(net!=None): - name = net.des.name - net = Net.fromSelected(self, name) - net.setAvoidsOverlaps(not(self.overlaps.val)) - print - print "Unfolding selected object" - net.edgeIteratorClass = self.iterator - print "Using ", net.edgeIteratorClass - net.animates = self.ani.val - self.diffuse = (self.ancestors.val==0) - net.diffuse = self.diffuse - net.generations = self.ancestors.val - net.noise = self.noise.val - print "even:", net.diffuse, " depth:", net.generations - net.unfold() - n = net.report() - t = "." - if(n<1.0): - t = "Overlaps>="+str(n) - else: - t = "A complete net." - self.nOverlaps = (n>=1) - if(self.nOverlaps): - self.say(self.message+" - unfolding failed - try again ") - elif(not(self.overlaps.val)): - self.say("Success. Complete net - no overlaps ") - else: - self.say("Unfolding complete") - self.ancestors.val = anc - s = (self.search.val and n>=1.0) - dict = Registry.GetKey('unfolder') - if(not(dict)): - dict = {} - dict['net'] = net - Registry.SetKey('unfolder', dict) - if(s): - net = net.clone() - search += 1 - except(IndexError): - self.say("Please select an object to unfold") - except: - self.say("Problem unfolding selected object - see console for details") - print "Problem unfolding selected object:" - print sys.exc_info()[1] - traceback.print_exc(file=sys.stdout) - if(self.ani): - if Registry.GetKey('unfolder')==None: - print "no net!" - return - Registry.GetKey('unfolder')['net'].sortOutIPOSource() - self.installScriptLink() - Draw.Redraw(1) - def keyOrMouseEvent(self, evt, val): - if (evt == Draw.ESCKEY and not val): - Draw.Exit() - def buttonEvent(self, evt): - if (evt == 1): - self.unfold() - if (evt == 5): - try: - Registry.GetKey('unfolder')['net'].setAvoidsOverlaps(self.overlaps.val) - except: - pass - if (evt == 2): - print "Trying to set IPO curve" - try: - s = Blender.Object.GetSelected() - if(s!=None): - Registry.GetKey('unfolder')['net'].setIPOSource( s[0] ) - print "Set IPO curve" - else: - print "Please select an object to use the IPO of" - except: - print "Problem setting IPO source" - Draw.Redraw(1) - if (evt == 6): - Draw.Exit() - if (evt == 7): - try: - if (Registry.GetKey('unfolder')['net']!=None): - Registry.GetKey('unfolder')['net'].animates = self.ani.val - if(self.ani): - Registry.GetKey('unfolder')['net'].sortOutIPOSource() - self.installScriptLink() - except: - print sys.exc_info()[1] - traceback.print_exc(file=sys.stdout) - Draw.Redraw(1) - if (evt == 19): - pass - if (evt == 87): - try: - if (Registry.GetKey('unfolder')['net']!=None): - Registry.GetKey('unfolder')['net'].assignUVs() - self.say("Assigned UVs") - except: - print sys.exc_info()[1] - traceback.print_exc(file=sys.stdout) - Draw.Redraw(1) - if(evt==91): - if( testOverlap() == True): - self.nOverlaps = 1 - else: - self.nOverlaps = 0 - Draw.Redraw(1) - if(evt==233): - f1 = Poly.fromBlenderFace(Blender.Object.GetSelected()[0].getData().faces[0]) - f2 = Poly.fromBlenderFace(Blender.Object.GetSelected()[1].getData().faces[0]) - print - print Blender.Object.GetSelected()[0].getName() - print Blender.Object.GetSelected()[1].getName() - print f1.intersects2D(f2) - print f2.intersects2D(f1) - if(evt==714): - Net.unfoldAll(self) - Draw.Redraw(1) - if(evt==713): - self.iterator = self.iterators[self.shape.val] - Draw.Redraw(1) - if(evt==92): - if( testContains() == True): - self.nOverlaps = 1 - else: - self.nOverlaps = 0 - Draw.Redraw(1) - if(evt==104): - try: - filename = "net.svg" - s = Blender.Object.GetSelected() - if(s!=None and len(s)>0): - filename = s[0].getName()+".svg" - else: - if (Registry.GetKey('unfolder')['net']!=None): - filename = Registry.GetKey('unfolder')['net'].des.name - if(filename==None): - filename="net.svg" - else: - filename=filename+".svg" - Window.FileSelector(SVGExporter.fileSelected, "Select filename", filename) - except: - print "Problem exporting SVG" - traceback.print_exc(file=sys.stdout) - if(evt==107): - try: - Window.FileSelector(NetHandler.fileSelected, "Select file") - except: - print "Problem importing SVG" - traceback.print_exc(file=sys.stdout) - def say(self, m): - self.message = m - Draw.Redraw(1) - Window.Redraw(Window.Types.SCRIPT) - def draw(self): - cw = 64 - ch = 16 - l = FlowLayout(32, cw, ch, 350, 64) - l.y = 70 - self.search = Draw.Toggle("search", 19, l.nx(), l.ny(), l.cw, l.ch, self.search.val, "Search for non-overlapping mesh (potentially indefinitely)") - self.overlaps = Draw.Toggle("overlaps", 5, l.nx(), l.ny(), l.cw, l.ch, self.overlaps.val, "Allow overlaps / avoid overlaps - if off, will not place overlapping faces") - self.ani = Draw.Toggle("ani", 7, l.nx(), l.ny(), l.cw, l.ch, self.ani.val, "Animate net") - Draw.Button("uv", 87, l.nx(), l.ny(), l.cw, l.ch, "Assign net as UV to source mesh (overwriting existing UV)") - Draw.Button("Unfold", 1, l.nx(), l.ny(), l.cw, l.ch, "Unfold selected mesh to net") - Draw.Button("save", 104, l.nx(), l.ny(), l.cw, l.ch, "Save net as SVG") - Draw.Button("load", 107, l.nx(), l.ny(), l.cw, l.ch, "Load net from SVG") - #Draw.Button("test", 233, l.nx(), l.ny(), l.cw, l.ch, "test") - # unfolding enthusiasts - try uncommenting this - self.ancestors = Draw.Number("depth", 654, l.nx(), l.ny(), cw, ch, self.ancestors.val, 0, 9999, "depth of branching 0=diffuse") - #self.noise = Draw.Number("noise", 631, l.nx(), l.ny(), cw, ch, self.noise.val, 0.0, 1.0, "noisyness of branching") - #Draw.Button("UnfoldAll", 714, l.nx(), l.ny(), l.cw, l.ch, "Unfold all meshes and save their nets") - options = "order %t|random %x0|brightest %x1|curvature %x2|winding %x3| 1010 %x4|largest %x5" - self.shape = Draw.Menu(options, 713, l.nx(), l.ny(), cw, ch, self.shape.val, "shape of net") - Draw.Button("exit", 6, l.nx(), l.ny(), l.cw, l.ch, "exit") - BGL.glClearColor(0.3, 0.3, 0.3, 1) - BGL.glColor3f(0.3,0.3,0.3) - l.newLine() - BGL.glRasterPos2i(32, 100) - Draw.Text(self.message) - -class FlowLayout: - def __init__(self, margin, cw, ch, w, h): - self.x = margin-cw-4 - self.y = margin - self.cw = cw - self.ch = ch - self.width = w - self.height = h - self.margin = margin - def nx(self): - self.x+=(self.cw+4) - if(self.x>self.width): - self.x = self.margin - self.y-=self.ch+4 - return self.x - def ny(self): - return self.y - def newLine(self): - self.y-=self.ch+self.margin - self.x = self.margin - -# if xml is None, then dont bother running the script -if xml: - try: - sys.setrecursionlimit(10000) - gui = GUI() - gui.makeStandardGUI() - #gui.makePopupGUI() - except: - traceback.print_exc(file=sys.stdout) diff --git a/release/scripts/mesh_wire.py b/release/scripts/mesh_wire.py deleted file mode 100644 index bd38c47a9b9..00000000000 --- a/release/scripts/mesh_wire.py +++ /dev/null @@ -1,290 +0,0 @@ -#!BPY -""" -Name: 'Solid Wireframe' -Blender: 243 -Group: 'Mesh' -Tooltip: 'Make a solid wireframe copy of this mesh' -""" - -# -------------------------------------------------------------------------- -# Solid Wireframe1.0 by Campbell Barton (AKA Ideasman42) -# -------------------------------------------------------------------------- -# ***** 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 Blender -from Blender import Scene, Mesh, Window, sys -from Blender.Mathutils import AngleBetweenVecs, TriangleNormal -from BPyMesh import faceAngles # get angles for face cornders -#import BPyMesh -#reload(BPyMesh) -#faceAngles = BPyMesh.faceAngles - -# works out the distanbce to inset the corners based on angles -from BPyMathutils import angleToLength -#import BPyMathutils -#reload(BPyMathutils) -#angleToLength = BPyMathutils.angleToLength - -import mesh_solidify - -import BPyMessages -reload(BPyMessages) -import bpy - - -def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PREF_XSHARP): - if not PREF_SHARP and PREF_XSHARP: - PREF_XSHARP = False - - # This function runs out of editmode with a mesh - # error cases are alredy checked for - - inset_half = PREF_THICKNESS / 2 - del PREF_THICKNESS - - ob = ob_orig.copy() - me = me_orig.copy() - ob.link(me) - sce.objects.selected = [] - sce.objects.link(ob) - ob.sel = True - sce.objects.active = ob - - # Modify the object, should be a set - FGON= Mesh.EdgeFlags.FGON - edges_fgon = dict([(ed.key,None) for ed in me.edges if ed.flag & FGON]) - # edges_fgon.fromkeys([ed.key for ed in me.edges if ed.flag & FGON]) - - del FGON - - - - # each face needs its own verts - # orig_vert_count =len(me.verts) - new_vert_count = len(me.faces) * 4 - for f in me.faces: - if len(f) == 3: - new_vert_count -= 1 - - if PREF_SHARP == 0: - new_faces_edge= {} - - def add_edge(i1,i2, ni1, ni2): - - if i1>i2: - i1,i2 = i2,i1 - flip = True - else: - flip = False - new_faces_edge.setdefault((i1,i2), []).append((ni1, ni2, flip)) - - - new_verts = [] - new_faces = [] - vert_index = len(me.verts) - - for f in me.faces: - f_v_co = [v.co for v in f] - angles = faceAngles(f_v_co) - f_v_idx = [v.index for v in f] - - def new_vert(fi): - co = f_v_co[fi] - a = angles[fi] - if a > 180: - vert_inset = 1 * inset_half - else: - vert_inset = inset_half * angleToLength( abs((180-a) / 2) ) - - # Calculate the inset direction - co1 = f_v_co[fi-1] - co2 = fi+1 # Wrap this index back to the start - if co2 == len(f_v_co): co2 = 0 - co2 = f_v_co[co2] - - co1 = co1 - co - co2 = co2 - co - co1.normalize() - co2.normalize() - d = co1+co2 - # Done with inset direction - - d.length = vert_inset - return co+d - - new_verts.extend([new_vert(i) for i in xrange(len(f_v_co))]) - - if len(f_v_idx) == 4: - faces = [\ - (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ - (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ - (f_v_idx[3], f_v_idx[2], vert_index+2, vert_index+3),\ - (f_v_idx[0], f_v_idx[3], vert_index+3, vert_index),\ - ] - else: - faces = [\ - (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ - (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ - (f_v_idx[0], f_v_idx[2], vert_index+2, vert_index),\ - ] - - - if PREF_SHARP == 1: - if not edges_fgon: - new_faces.extend(faces) - else: - for nf in faces: - i1,i2 = nf[0], nf[1] - if i1>i2: i1,i2 = i2,i1 - - if edges_fgon and (i1,i2) not in edges_fgon: - new_faces.append(nf) - - - - elif PREF_SHARP == 0: - for nf in faces: - add_edge(*nf) - - vert_index += len(f_v_co) - - me.verts.extend(new_verts) - - if PREF_SHARP == 0: - def add_tri_flipped(i1,i2,i3): - try: - if AngleBetweenVecs(me.verts[i1].no, TriangleNormal(me.verts[i1].co, me.verts[i2].co, me.verts[i3].co)) < 90: - return i3,i2,i1 - else: - return i1,i2,i3 - except: - return i1,i2,i3 - - # This stores new verts that use this vert - # used for re-averaging this verts location - # based on surrounding verts. looks better but not needed. - vert_users = [set() for i in xrange(vert_index)] - - for (i1,i2), nf in new_faces_edge.iteritems(): - - if len(nf) == 2: - # Add the main face - if edges_fgon and (i1,i2) not in edges_fgon: - new_faces.append((nf[0][0], nf[0][1], nf[1][0], nf[1][1])) - - - if nf[0][2]: key1 = nf[0][1],nf[0][0] - else: key1 = nf[0][0],nf[0][1] - if nf[1][2]: key2 = nf[1][1],nf[1][0] - else: key2 = nf[1][0],nf[1][1] - - # CRAP, cont work out which way to flip so make it oppisite the verts normal. - - ###new_faces.append((i2, key1[0], key2[0])) # NO FLIPPING, WORKS THOUGH - ###new_faces.append((i1, key1[1], key2[1])) - new_faces.append(add_tri_flipped(i2, key1[0], key2[0])) - new_faces.append(add_tri_flipped(i1, key1[1], key2[1])) - - # Average vert loction so its not tooo pointy - # not realy needed but looks better - vert_users[i2].update((key1[0], key2[0])) - vert_users[i1].update((key1[1], key2[1])) - - if len(nf) == 1: - if nf[0][2]: new_faces.append((nf[0][0], nf[0][1], i2, i1)) # flipped - else: new_faces.append((i1,i2, nf[0][0], nf[0][1])) - - - # average points now. - for i, vusers in enumerate(vert_users): - if vusers: - co = me.verts[i].co - co.zero() - - for ii in vusers: - co += me.verts[ii].co - co /= len(vusers) - - me.faces.delete(1, range(len(me.faces))) - - me.faces.extend(new_faces) - - # External function, solidify - me.sel = True - if PREF_SOLID: - mesh_solidify.solidify(me, -inset_half*2, True, False, PREF_XSHARP) - - -def main(): - - # Gets the current scene, there can be many scenes in 1 blend file. - sce = bpy.data.scenes.active - - # Get the active object, there can only ever be 1 - # and the active object is always the editmode object. - ob_act = sce.objects.active - - if not ob_act or ob_act.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - # Saves the editmode state and go's out of - # editmode if its enabled, we cant make - # changes to the mesh data while in editmode. - is_editmode = Window.EditMode() - Window.EditMode(0) - - me = ob_act.getData(mesh=1) # old NMesh api is default - if len(me.faces)==0: - BPyMessages.Error_NoMeshFaces() - if is_editmode: Window.EditMode(1) - return - - # Create the variables. - PREF_THICK = Blender.Draw.Create(0.005) - PREF_SOLID = Blender.Draw.Create(1) - PREF_SHARP = Blender.Draw.Create(1) - PREF_XSHARP = Blender.Draw.Create(0) - - pup_block = [\ - ('Thick:', PREF_THICK, 0.0001, 2.0, 'Skin thickness in mesh space.'),\ - ('Solid Wire', PREF_SOLID, 'If Disabled, will use 6 sided wire segments'),\ - ('Sharp Wire', PREF_SHARP, 'Use the original mesh topology for more accurate sharp wire.'),\ - ('Extra Sharp', PREF_XSHARP, 'Use less geometry to create a sharper looking wire'),\ - ] - - if not Blender.Draw.PupBlock('Solid Wireframe', pup_block): - if is_editmode: Window.EditMode(1) - return - - Window.WaitCursor(1) - t = sys.time() - - # Run the mesh editing function - solid_wire(ob_act, me, sce, PREF_THICK.val, PREF_SOLID.val, PREF_SHARP.val, PREF_XSHARP.val) - - # Timing the script is a good way to be aware on any speed hits when scripting - print 'Solid Wireframe finished in %.2f seconds' % (sys.time()-t) - Window.WaitCursor(0) - if is_editmode: Window.EditMode(1) - - -# This lets you can import the script without running it -if __name__ == '__main__': - main() diff --git a/release/scripts/ms3d_import.py b/release/scripts/ms3d_import.py deleted file mode 100644 index c1438cbfc97..00000000000 --- a/release/scripts/ms3d_import.py +++ /dev/null @@ -1,487 +0,0 @@ -#!BPY -""" -Name: 'MilkShape3D (.ms3d)...' -Blender: 245 -Group: 'Import' -Tooltip: 'Import from MilkShape3D file format (.ms3d)' -""" -# -# Author: Markus Ilmola -# Email: markus.ilmola@pp.inet.fi -# -# 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. -# - -# import needed stuff -import os.path -import math -from math import * -import struct -import Blender -from Blender import Mathutils -from Blender.Mathutils import * - - -# trims a string by removing ending 0 and everything after it -def uku(s): - try: - return s[:s.index('\0')] - except: - return s - - -# Converts ms3d euler angles to a rotation matrix -def RM(a): - sy = sin(a[2]) - cy = cos(a[2]) - sp = sin(a[1]) - cp = cos(a[1]) - sr = sin(a[0]) - cr = cos(a[0]) - return Matrix([cp*cy, cp*sy, -sp], [sr*sp*cy+cr*-sy, sr*sp*sy+cr*cy, sr*cp],[cr*sp*cy+-sr*-sy, cr*sp*sy+-sr*cy, cr*cp]) - - -# Converts ms3d euler angles to a quaternion -def RQ(a): - angle = a[2] * 0.5; - sy = sin(angle); - cy = cos(angle); - angle = a[1] * 0.5; - sp = sin(angle); - cp = cos(angle); - angle = a[0] * 0.5; - sr = sin(angle); - cr = cos(angle); - return Quaternion(cr*cp*cy+sr*sp*sy, sr*cp*cy-cr*sp*sy, cr*sp*cy+sr*cp*sy, cr*cp*sy-sr*sp*cy) - - -# takes a texture filename and tries to load it -def loadImage(path, filename): - image = None - try: - image = Blender.Image.Load(os.path.abspath(filename)) - except IOError: - print "Warning: Failed to load image: " + filename + ". Trying short path instead...\n" - try: - image = Blender.Image.Load(os.path.dirname(path) + "/" + os.path.basename(filename)) - except IOError: - print "Warning: Failed to load image: " + os.path.basename(filename) + "!\n" - return image - - -# imports a ms3d file to the current scene -def import_ms3d(path): - # get scene - scn = Blender.Scene.GetCurrent() - if scn == None: - return "No scene to import to!" - - # open the file - try: - file = open(path, 'rb') - except IOError: - return "Failed to open the file!" - - # get the file size - file.seek(0, os.SEEK_END); - fileSize = file.tell(); - file.seek(0, os.SEEK_SET); - - # read id to check if the file is a MilkShape3D file - id = file.read(10) - if id!="MS3D000000": - return "The file is not a MS3D file!" - - # read version - version = struct.unpack("i", file.read(4))[0] - if version!=4: - return "The file has invalid version!" - - # Create the mesh - scn.objects.selected = [] - mesh = Blender.Mesh.New("MilkShape3D Mesh") - meshOb = scn.objects.new(mesh) - - # read the number of vertices - numVertices = struct.unpack("H", file.read(2))[0] - - # read vertices - coords = [] - boneIds = [] - for i in xrange(numVertices): - # skip flags - file.read(1) - - # read coords - coords.append(struct.unpack("fff", file.read(3*4))) - - # read bone ids - boneIds.append(struct.unpack("b", file.read(1))[0]) - - # skip refcount - file.read(1) - - # add the vertices to the mesh - mesh.verts.extend(coords) - - # read number of triangles - numTriangles = struct.unpack("H", file.read(2))[0] - - # read triangles - faces = [] - uvs = [] - for i in xrange(numTriangles): - # skip flags - file.read(2) - - # read indices (faces) - faces.append(struct.unpack("HHH", file.read(3*2))) - - # read normals - normals = struct.unpack("fffffffff", file.read(3*3*4)) - - # read texture coordinates - s = struct.unpack("fff", file.read(3*4)) - t = struct.unpack("fff", file.read(3*4)) - - # store texture coordinates - uvs.append([[s[0], 1-t[0]], [s[1], 1-t[1]], [s[2], 1-t[2]]]) - - if faces[-1][2] == 0: # Cant have zero at the third index - faces[-1] = faces[-1][1], faces[-1][2], faces[-1][0] - uvs[-1] = uvs[-1][1], uvs[-1][2], uvs[-1][0] - - # skip smooth group - file.read(1) - - # skip group - file.read(1) - - # add the faces to the mesh - mesh.faces.extend(faces) - - # set texture coordinates - for i in xrange(numTriangles): - mesh.faces[i].uv = [Vector(uvs[i][0]), Vector(uvs[i][1]), Vector(uvs[i][2])] - - # read number of groups - numGroups = struct.unpack("H", file.read(2))[0] - - # read groups - for i in xrange(numGroups): - # skip flags - file.read(1) - - # skip name - file.read(32) - - # read the number of triangles in the group - numGroupTriangles = struct.unpack("H", file.read(2))[0] - - # read the group triangles - if numGroupTriangles > 0: - triangleIndices = struct.unpack(str(numGroupTriangles) + "H", file.read(2*numGroupTriangles)); - - # read material - material = struct.unpack("b", file.read(1))[0] - if material>=0: - for j in xrange(numGroupTriangles): - mesh.faces[triangleIndices[j]].mat = material - - # read the number of materials - numMaterials = struct.unpack("H", file.read(2))[0] - - # read materials - for i in xrange(numMaterials): - # read name - name = uku(file.read(32)) - - # create the material - mat = Blender.Material.New(name) - mesh.materials += [mat] - - # read ambient color - ambient = struct.unpack("ffff", file.read(4*4))[0:3] - mat.setAmb((ambient[0]+ambient[1]+ambient[2])/3) - - # read diffuse color - diffuse = struct.unpack("ffff", file.read(4*4))[0:3] - mat.setRGBCol(diffuse) - - # read specular color - specular = struct.unpack("ffff", file.read(4*4))[0:3] - mat.setSpecCol(specular) - - # read emissive color - emissive = struct.unpack("ffff", file.read(4*4))[0:3] - mat.setEmit((emissive[0]+emissive[1]+emissive[2])/3) - - # read shininess - shininess = struct.unpack("f", file.read(4))[0] - - # read transparency - transparency = struct.unpack("f", file.read(4))[0] - mat.setAlpha(transparency) - if transparency < 1: - mat.mode |= Blender.Material.Modes.ZTRANSP - - # read mode - mode = struct.unpack("B", file.read(1))[0] - - # read texturemap - texturemap = uku(file.read(128)) - if len(texturemap)>0: - colorTexture = Blender.Texture.New(name + "_texture") - colorTexture.setType('Image') - colorTexture.setImage(loadImage(path, texturemap)) - mat.setTexture(0, colorTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) - - # read alphamap - alphamap = uku(file.read(128)) - if len(alphamap)>0: - alphaTexture = Blender.Texture.New(name + "_alpha") - alphaTexture.setType('Image') - alphaTexture.setImage(loadImage(path, alphamap)) - mat.setTexture(1, alphaTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.ALPHA) - - # read animation - fps = struct.unpack("f", file.read(4))[0] - time = struct.unpack("f", file.read(4))[0] - frames = struct.unpack("i", file.read(4))[0] - - # read the number of joints - numJoints = struct.unpack("H", file.read(2))[0] - - # create the armature - armature = 0 - armOb = 0 - if numJoints > 0: - armOb = Blender.Object.New('Armature', "MilkShape3D Skeleton") - armature = Blender.Armature.New("MilkShape3D Skeleton") - armature.drawType = Blender.Armature.STICK - armOb.link(armature) - scn.objects.link(armOb) - armOb.makeParentDeform([meshOb]) - armature.makeEditable() - - # read joints - joints = [] - rotKeys = {} - posKeys = {} - for i in xrange(numJoints): - # skip flags - file.read(1) - - # read name - name = uku(file.read(32)) - joints.append(name) - - # create the bone - bone = Blender.Armature.Editbone() - armature.bones[name] = bone - - # read parent - parent = uku(file.read(32)) - if len(parent)>0: - bone.parent = armature.bones[parent] - - # read orientation - rot = struct.unpack("fff", file.read(3*4)) - - # read position - pos = struct.unpack("fff", file.read(3*4)) - - # set head - if bone.hasParent(): - bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head - tempM = RM(rot) * bone.parent.matrix - tempM.transpose; - bone.matrix = tempM - else: - bone.head = Vector(pos) - bone.matrix = RM(rot) - - # set tail - bvec = bone.tail - bone.head - bvec.normalize() - bone.tail = bone.head + 0.01 * bvec - - # Create vertex group for this bone - mesh.addVertGroup(name) - vgroup = [] - for index, v in enumerate(boneIds): - if v==i: - vgroup.append(index) - mesh.assignVertsToGroup(name, vgroup, 1.0, 1) - - # read the number of rotation keys - numKeyFramesRot = struct.unpack("H", file.read(2))[0] - - # read the number of postions keys - numKeyFramesPos = struct.unpack("H", file.read(2))[0] - - # read rotation keys - rotKeys[name] = [] - for j in xrange(numKeyFramesRot): - # read time - time = fps * struct.unpack("f", file.read(4))[0] - # read data - rotKeys[name].append([time, struct.unpack("fff", file.read(3*4))]) - - # read position keys - posKeys[name] = [] - for j in xrange(numKeyFramesPos): - # read time - time = fps * struct.unpack("f", file.read(4))[0] - # read data - posKeys[name].append([time, struct.unpack("fff", file.read(3*4))]) - - # create action and pose - action = 0 - pose = 0 - if armature!=0: - armature.update() - pose = armOb.getPose() - action = armOb.getAction() - if not action: - action = Blender.Armature.NLA.NewAction() - action.setActive(armOb) - - # create animation key frames - for name, pbone in pose.bones.items(): - # create position keys - for key in posKeys[name]: - pbone.loc = Vector(key[1]) - pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.LOC, True) - - # create rotation keys - for key in rotKeys[name]: - pbone.quat = RQ(key[1]) - pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.ROT, True) - - # The old format ends here. If there is more data then the file is newer version - - # check to see if there are any comments - if file.tell()0: - print "Group comment: " + file.read(size) - - # Material comments - numComments = struct.unpack("i", file.read(4))[0] - for i in range(numComments): - file.read(4) # index - size = struct.unpack("i", file.read(4))[0] # comment size - if size>0: - print "Material comment: " + file.read(size) - - # Joint comments - numComments = struct.unpack("i", file.read(4))[0] - for i in range(numComments): - file.read(4) # index - size = struct.unpack("i", file.read(4))[0] # comment size - if size>0: - print "Joint comment: " + file.read(size) - - # Model comments - numComments = struct.unpack("i", file.read(4))[0] - for i in range(numComments): - file.read(4) # index - size = struct.unpack("i", file.read(4))[0] # comment size - if size>0: - print "Model comment: " + file.read(size) - - # Unknown version give a warning - else: - print "Warning: Unknown version!" - - - # check to see if there is any extra vertex data - if file.tell()=0 or ids[1]>=0 or ids[2]>=0: - mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1) - if ids[0]>=0: - mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1) - if ids[1]>=0: - mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1) - if ids[2]>=0: - mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1) - - elif subVersion==1: - # read extra data for each vertex - for i in xrange(numVertices): - # bone ids - ids = struct.unpack("bbb", file.read(3)) - # weights - weights = struct.unpack("BBB", file.read(3)) - # add extra vertices with weights to deform groups - if ids[0]>=0 or ids[1]>=0 or ids[2]>=0: - mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1) - if ids[0]>=0: - mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1) - if ids[1]>=0: - mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1) - if ids[2]>=0: - mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1) - - # non supported subversion give a warning - else: - print "Warning: Unknown subversion!" - - # rest of the extra data in the file is not imported/used - - # refresh the view - Blender.Redraw() - - # close the file - file.close() - - # succes return empty error string - return "" - - -# load the model -def fileCallback(filename): - error = import_ms3d(filename) - if error!="": - Blender.Draw.PupMenu("An error occured during import: " + error + "|Not all data might have been imported succesfully.", 2) - -Blender.Window.FileSelector(fileCallback, 'Import') diff --git a/release/scripts/ms3d_import_ascii.py b/release/scripts/ms3d_import_ascii.py deleted file mode 100644 index d8c22a1ec99..00000000000 --- a/release/scripts/ms3d_import_ascii.py +++ /dev/null @@ -1,479 +0,0 @@ -#!BPY -""" -Name: 'MilkShape3D ASCII (.txt)...' -Blender: 245 -Group: 'Import' -Tooltip: 'Import from a MilkShape3D ASCII file format (.txt)' -""" -# -# Author: Markus Ilmola -# Email: markus.ilmola@pp.inet.fi -# -# 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. -# - -# import needed stuff -import os.path -import re -import math -from math import * -import Blender -from Blender import Mathutils -from Blender.Mathutils import * - - - -# Converts ms3d euler angles to a rotation matrix -def RM(a): - sy = sin(a[2]) - cy = cos(a[2]) - sp = sin(a[1]) - cp = cos(a[1]) - sr = sin(a[0]) - cr = cos(a[0]) - return Matrix([cp*cy, cp*sy, -sp], [sr*sp*cy+cr*-sy, sr*sp*sy+cr*cy, sr*cp],[cr*sp*cy+-sr*-sy, cr*sp*sy+-sr*cy, cr*cp]) - - -# Converts ms3d euler angles to a quaternion -def RQ(a): - angle = a[2] * 0.5; - sy = sin(angle); - cy = cos(angle); - angle = a[1] * 0.5; - sp = sin(angle); - cp = cos(angle); - angle = a[0] * 0.5; - sr = sin(angle); - cr = cos(angle); - return Quaternion(cr*cp*cy+sr*sp*sy, sr*cp*cy-cr*sp*sy, cr*sp*cy+sr*cp*sy, cr*cp*sy-sr*sp*cy) - - -# takes a texture filename and tries to load it -def loadImage(path, filename): - image = None - try: - image = Blender.Image.Load(os.path.abspath(filename)) - except IOError: - print "Warning: Failed to load image: " + filename + ". Trying short path instead...\n" - try: - image = Blender.Image.Load(os.path.dirname(path) + "/" + os.path.basename(filename)) - except IOError: - print "Warning: Failed to load image: " + os.path.basename(filename) + "!\n" - return image - - - -# returns the next non-empty, non-comment line from the file -def getNextLine(file): - ready = False - while ready==False: - line = file.readline() - if len(line)==0: - print "Warning: End of file reached." - return line - ready = True - line = line.strip() - if len(line)==0 or line.isspace(): - ready = False - if len(line)>=2 and line[0]=='/' and line[1]=='/': - ready = False - return line - - - -# imports a MilkShape3D ascii file to the current scene -def import_ms3d_ascii(path): - # limits - MAX_NUMMESHES = 1000 - MAX_NUMVERTS = 100000 - MAX_NUMNORMALS = 100000 - MAX_NUMTRIS = 100000 - MAX_NUMMATS = 16 - MAX_NUMBONES = 100 - MAX_NUMPOSKEYS = 1000 - MAX_NUMROTKEYS = 1000 - - # get scene - scn = Blender.Scene.GetCurrent() - if scn==None: - return "No scene to import to!" - - # open the file - try: - file = open(path, 'r') - except IOError: - return "Failed to open the file!" - - # Read frame info - try: - lines = getNextLine(file).split() - if len(lines) != 2 or lines[0] != "Frames:": - raise ValueError - lines = getNextLine(file).split() - if len(lines) != 2 or lines[0] != "Frame:": - raise ValueError - except ValueError: - return "Frame information is invalid!" - - # Create the mesh - meshOb = Blender.Object.New('Mesh', "MilkShape3D Object") - mesh = Blender.Mesh.New("MilkShape3D Mesh") - meshOb.link(mesh) - scn.objects.link(meshOb) - - # read the number of meshes - try: - lines = getNextLine(file).split() - if len(lines)!=2 or lines[0]!="Meshes:": - raise ValueError - numMeshes = int(lines[1]) - if numMeshes < 0 or numMeshes > MAX_NUMMESHES: - raise ValueError - except ValueError: - return "Number of meshes is invalid!" - - # read meshes - vertBase = 0 - faceBase = 0 - boneIds = [] - for i in range(numMeshes): - # read name, flags and material - try: - lines = re.findall(r'\".*\"|[^ ]+', getNextLine(file)) - if len(lines)!=3: - raise ValueError - material = int(lines[2]) - except ValueError: - return "Name, flags or material in mesh " + str(i+1) + " are invalid!" - - # read the number of vertices - try: - numVerts = int(getNextLine(file)) - if numVerts < 0 or numVerts > MAX_NUMVERTS: - raise ValueError - except ValueError: - return "Number of vertices in mesh " + str(i+1) + " is invalid!" - - # read vertices - coords = [] - uvs = [] - for j in xrange(numVerts): - try: - lines = getNextLine(file).split() - if len(lines)!=7: - raise ValueError - coords.append([float(lines[1]), float(lines[2]), float(lines[3])]) - uvs.append([float(lines[4]), 1-float(lines[5])]) - boneIds.append(int(lines[6])) - except ValueError: - return "Vertex " + str(j+1) + " in mesh " + str(i+1) + " is invalid!" - mesh.verts.extend(coords) - - # read number of normals - try: - numNormals = int(getNextLine(file)) - if numNormals < 0 or numNormals > MAX_NUMNORMALS: - raise ValueError - except ValueError: - return "Number of normals in mesh " + str(i+1) + " is invalid!" - - # read normals - normals = [] - for j in xrange(numNormals): - try: - lines = getNextLine(file).split() - if len(lines)!=3: - raise ValueError - normals.append([float(lines[0]), float(lines[1]), float(lines[2])]) - except ValueError: - return "Normal " + str(j+1) + " in mesh " + str(i+1) + " is invalid!" - - # read the number of triangles - try: - numTris = int(getNextLine(file)) - if numTris < 0 or numTris > MAX_NUMTRIS: - raise ValueError - except ValueError: - return "Number of triangles in mesh " + str(i+1) + " is invalid!" - - # read triangles - faces = [] - for j in xrange(numTris): - # read the triangle - try: - lines = getNextLine(file).split() - if len(lines)!=8: - raise ValueError - v1 = int(lines[1]) - v2 = int(lines[2]) - v3 = int(lines[3]) - faces.append([v1+vertBase, v2+vertBase, v3+vertBase]) - except ValueError: - return "Triangle " + str(j+1) + " in mesh " + str(i+1) + " is invalid!" - mesh.faces.extend(faces) - - # set texture coordinates and material - for j in xrange(faceBase, len(mesh.faces)): - face = mesh.faces[j] - face.uv = [Vector(uvs[face.verts[0].index-vertBase]), Vector(uvs[face.verts[1].index-vertBase]), Vector(uvs[face.verts[2].index-vertBase])] - if material>=0: - face.mat = material - - # increase vertex and face base - vertBase = len(mesh.verts) - faceBase = len(mesh.faces) - - # read the number of materials - try: - lines = getNextLine(file).split() - if len(lines)!=2 or lines[0]!="Materials:": - raise ValueError - numMats = int(lines[1]) - if numMats < 0 or numMats > MAX_NUMMATS: - raise ValueError - except ValueError: - return "Number of materials is invalid!" - - # read the materials - for i in range(numMats): - # read name - name = getNextLine(file)[1:-1] - - # create the material - mat = Blender.Material.New(name) - mesh.materials += [mat] - - # read ambient color - try: - lines = getNextLine(file).split() - if len(lines)!=4: - raise ValueError - amb = (float(lines[0])+float(lines[1])+float(lines[2]))/3 - mat.setAmb(amb) - except ValueError: - return "Ambient color in material " + str(i+1) + " is invalid!" - - # read diffuse color - try: - lines = getNextLine(file).split() - if len(lines)!=4: - raise ValueError - mat.setRGBCol([float(lines[0]), float(lines[1]), float(lines[2])]) - except ValueError: - return "Diffuse color in material " + str(i+1) + " is invalid!" - - # read specular color - try: - lines = getNextLine(file).split() - if len(lines)!=4: - raise ValueError - mat.setSpecCol([float(lines[0]), float(lines[1]), float(lines[2])]) - except ValueError: - return "Specular color in material " + str(i+1) + " is invalid!" - - # read emissive color - try: - lines = getNextLine(file).split() - if len(lines)!=4: - raise ValueError - emit = (float(lines[0])+float(lines[1])+float(lines[2]))/3 - mat.setEmit(emit) - except ValueError: - return "Emissive color in material " + str(i+1) + " is invalid!" - - # read shininess - try: - shi = float(getNextLine(file)) - #mat.setHardness(int(shi)) - except ValueError: - return "Shininess in material " + str(i+1) + " is invalid!" - - # read transparency - try: - alpha = float(getNextLine(file)) - mat.setAlpha(alpha) - if alpha < 1: - mat.mode |= Blender.Material.Modes.ZTRANSP - except ValueError: - return "Transparency in material " + str(i+1) + " is invalid!" - - # read texturemap - texturemap = getNextLine(file)[1:-1] - if len(texturemap)>0: - colorTexture = Blender.Texture.New(name + "_texture") - colorTexture.setType('Image') - colorTexture.setImage(loadImage(path, texturemap)) - mat.setTexture(0, colorTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) - - # read alphamap - alphamap = getNextLine(file)[1:-1] - if len(alphamap)>0: - alphaTexture = Blender.Texture.New(name + "_alpha") - alphaTexture.setType('Image') - alphaTexture.setImage(loadImage(path, alphamap)) - mat.setTexture(1, alphaTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.ALPHA) - - # read the number of bones - try: - lines = getNextLine(file).split() - if len(lines)!=2 or lines[0]!="Bones:": - raise ValueError - numBones = int(lines[1]) - if numBones < 0 or numBones > MAX_NUMBONES: - raise ValueError - except: - return "Number of bones is invalid!" - - # create the armature - armature = None - armOb = None - if numBones > 0: - armOb = Blender.Object.New('Armature', "MilkShape3D Skeleton") - armature = Blender.Armature.New("MilkShape3D Skeleton") - armature.drawType = Blender.Armature.STICK - armOb.link(armature) - scn.objects.link(armOb) - armOb.makeParentDeform([meshOb]) - armature.makeEditable() - - # read bones - posKeys = {} - rotKeys = {} - for i in range(numBones): - # read name - name = getNextLine(file)[1:-1] - - # create the bone - bone = Blender.Armature.Editbone() - armature.bones[name] = bone - - # read parent - parent = getNextLine(file)[1:-1] - if len(parent)>0: - bone.parent = armature.bones[parent] - - # read position and rotation - try: - lines = getNextLine(file).split() - if len(lines) != 7: - raise ValueError - pos = [float(lines[1]), float(lines[2]), float(lines[3])] - rot = [float(lines[4]), float(lines[5]), float(lines[6])] - except ValueError: - return "Invalid position or orientation in a bone!" - - # set position and orientation - if bone.hasParent(): - bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head - bone.tail = bone.head + Vector([1,0,0]) - tempM = RM(rot) * bone.parent.matrix - tempM.transpose; - bone.matrix = tempM - else: - bone.head = Vector(pos) - bone.tail = bone.head + Vector([1,0,0]) - bone.matrix = RM(rot) - - # Create vertex group for this bone - mesh.addVertGroup(name) - vgroup = [] - for index, v in enumerate(boneIds): - if v==i: - vgroup.append(index) - mesh.assignVertsToGroup(name, vgroup, 1.0, 1) - - # read the number of position key frames - try: - numPosKeys = int(getNextLine(file)) - if numPosKeys < 0 or numPosKeys > MAX_NUMPOSKEYS: - raise ValueError - except ValueError: - return "Invalid number of position key frames!" - - # read position key frames - posKeys[name] = [] - for j in range(numPosKeys): - # read time and position - try: - lines = getNextLine(file).split() - if len(lines) != 4: - raise ValueError - time = float(lines[0]) - pos = [float(lines[1]), float(lines[2]), float(lines[3])] - posKeys[name].append([time, pos]) - except ValueError: - return "Invalid position key frame!" - - # read the number of rotation key frames - try: - numRotKeys = int(getNextLine(file)) - if numRotKeys < 0 or numRotKeys > MAX_NUMROTKEYS: - raise ValueError - except ValueError: - return "Invalid number of rotation key frames!" - - # read rotation key frames - rotKeys[name] = [] - for j in range(numRotKeys): - # read time and rotation - try: - lines = getNextLine(file).split() - if len(lines) != 4: - raise ValueError - time = float(lines[0]) - rot = [float(lines[1]), float(lines[2]), float(lines[3])] - rotKeys[name].append([time, rot]) - except ValueError: - return "Invalid rotation key frame!" - - # create action and pose - action = None - pose = None - if armature != None: - armature.update() - pose = armOb.getPose() - action = armOb.getAction() - if not action: - action = Blender.Armature.NLA.NewAction() - action.setActive(armOb) - - # create animation key frames - for name, pbone in pose.bones.items(): - # create position keys - for key in posKeys[name]: - pbone.loc = Vector(key[1]) - pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.LOC, True) - - # create rotation keys - for key in rotKeys[name]: - pbone.quat = RQ(key[1]) - pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.ROT, True) - - # set the imported object to be the selected one - scn.objects.selected = [] - meshOb.sel= 1 - Blender.Redraw() - - # The import was a succes! - return "" - - -# load the model -def fileCallback(filename): - error = import_ms3d_ascii(filename) - if error!="": - Blender.Draw.PupMenu("An error occured during import: " + error + "|Not all data might have been imported succesfully.", 2) - -Blender.Window.FileSelector(fileCallback, 'Import') diff --git a/release/scripts/obdatacopier.py b/release/scripts/obdatacopier.py deleted file mode 100644 index 2f5617951de..00000000000 --- a/release/scripts/obdatacopier.py +++ /dev/null @@ -1,215 +0,0 @@ -#!BPY - -""" Registration info for Blender menus: <- these words are ignored -Name: 'Data Copier' -Blender: 232 -Group: 'Object' -Tip: 'Copy data from active object to other selected ones.' -""" - -__author__ = "Jean-Michel Soler (jms), Campbell Barton (Ideasman42)" -__url__ = ("blender", "blenderartists.org", -"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm", -"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "0.1.2" - -__bpydoc__ = """\ -Use "Data Copier" to copy attributes from the active object to other selected ones of -its same type. - -This script is still in an early version but is already useful for copying -attributes for some types of objects like lamps and cameras. - -Usage: - -Select the objects that will be updated, select the object whose data will -be copied (they must all be of the same type, of course), then run this script. -Toggle the buttons representing the attributes to be copied and press "Copy". -""" - -# ---------------------------------------------------------- -# Object DATA copier 0.1.2 -# (c) 2004 jean-michel soler -# ----------------------------------------------------------- -#---------------------------------------------- -# Page officielle/official page du blender python Object DATA copier: -# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm -# Communiquer les problemes et erreurs sur: -# To Communicate problems and errors on: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender -#--------------------------------------------- -# Blender Artistic License -# http://download.blender.org/documentation/html/x21254.html -#--------------------------------------------- - -import Blender -from Blender import * -from Blender.Draw import * -from Blender.BGL import * - - -scn= Blender.Scene.GetCurrent() - -type_func_method= type(dir) -type_func= type(lambda:i) -type_dict= type({}) -# type_list= type([]) - -IGNORE_VARS = 'users', 'fakeUser', 'edges', 'faces', 'verts', 'elements' - -def renew(): - scn= Blender.Scene.GetCurrent() - act_ob= scn.objects.active - if act_ob==None: - return {} - - act_ob_type= act_ob.getType() - act_ob_data= act_ob.getData(mesh=1) - - if act_ob_data==None: # Surf? - return {} - - PARAM={} - evt=4 - doc='doc' - - for prop_name in dir(act_ob_data): - if not prop_name.startswith('__') and prop_name not in IGNORE_VARS: - # Get the type - try: exec 'prop_type= type(act_ob_data.%s)' % prop_name - except: prop_type= None - - if prop_type != None and prop_type not in (type_func_method, type_func, type_dict): - - # Now we know that the attribute can be listed in the UI Create a button and tooltip. - - # Tooltip - try: - if prop_name=='mode': - try: - exec "doc=str(%s.Modes)+' ; value : %s'"%( act_ob_type, str(act_ob_data.mode) ) - except: - exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) - elif prop_name=='type': - try: - exec "doc=str(%s.Types)+' ; value : %s'"%( act_ob_type, str(act_ob_data.type) ) - except: - exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) - else: - exec """doc= '%s'+' value = '+ str(act_ob_data.%s)"""%(prop_name, prop_name) - if doc.find('built-in')!=-1: - exec """doc= 'This is a function ! Doc = '+ str(act_ob_data.%s.__doc__)"""% prop_name - except: - doc='Doc...' - - # Button - PARAM[prop_name]= [Create(0), evt, doc] - evt+=1 - - return PARAM - -def copy(): - global PARAM - - scn= Blender.Scene.GetCurrent() - act_ob= scn.getActiveObject() - if act_ob==None: - Blender.Draw.PupMenu('Error|No Active Object.') - return - - act_ob_type= act_ob.getType() - - if act_ob_type in ('Empty', 'Surf'): - Blender.Draw.PupMenu('Error|Copying Empty or Surf object data isnt supported.') - return - - act_ob_data= act_ob.getData(mesh=1) - - print '\n\nStarting copy for object "%s"' % act_ob.name - some_errors= False - for ob in scn.objects.context: - if ob != act_ob and ob.getType() == act_ob_type: - ob_data= None - for prop_name, value in PARAM.iteritems(): - if value[0].val==1: - - # Init the object data if we havnt alredy - if ob_data==None: - ob_data= ob.getData(mesh=1) - - try: - exec "ob_data.%s = act_ob_data.%s"%(prop_name, prop_name) - except: - some_errors= True - print 'Cant copy property "%s" for type "%s"' % (prop_name, act_ob_type) - if some_errors: - Blender.Draw.PupMenu('Some attributes could not be copied, see console for details.') - -PARAM= renew() - -def EVENT(evt,val): - pass - -def BUTTON(evt): - global PARAM - if (evt==1): - Exit() - - if (evt==2): - copy() - Blender.Redraw() - - if (evt==3): - PARAM= renew() - Blender.Redraw() - -def DRAW(): - global PARAM - - scn= Blender.Scene.GetCurrent() - act_ob= scn.objects.active - - glColor3f(0.7, 0.7, 0.7) - glClear(GL_COLOR_BUFFER_BIT) - glColor3f(0.1, 0.1, 0.15) - - size=Buffer(GL_FLOAT, 4) - glGetFloatv(GL_SCISSOR_BOX, size) - size= size.list - for s in [0,1,2,3]: size[s]=int(size[s]) - ligne=20 - - Button("Exit",1,20,4,80,ligne) - Button("Copy",2,102,4,80,ligne) - Button("Renew",3,184,4,80,ligne) - - glRasterPos2f(20, ligne*2-8) - if act_ob: - Text(act_ob.getType()+" DATA copier") - else: - Text("Please select an object") - - - max=size[3] / 22 -2 - pos = 0 - decal = 20 - key=PARAM.keys() - key.sort() - for p in key: - if pos==max: - decal+=102 - pos=1 - else: - pos+=1 - - PARAM[p][0]=Toggle(p, - PARAM[p][1], - decal, - pos*22+22, - 100, - 20, - PARAM[p][0].val, - str(PARAM[p][2])) - - -Register(DRAW,EVENT,BUTTON) diff --git a/release/scripts/object_active_to_other.py b/release/scripts/object_active_to_other.py deleted file mode 100644 index 68aa6a3a039..00000000000 --- a/release/scripts/object_active_to_other.py +++ /dev/null @@ -1,58 +0,0 @@ -#!BPY -""" -Name: 'Copy Active to Selected' -Blender: 249 -Group: 'Object' -Tooltip: 'For every selected object, copy the active to their loc/size/rot' -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell Barton -# -# 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 ***** -# -------------------------------------------------------------------------- - - -from Blender import Window, sys, Draw -import bpy - -def my_object_util(sce): - ob_act = sce.objects.active - - if not ob_act: - Draw.PupMenu('Error%t|No active object selected') - return - - mats = [(ob, ob.matrixWorld) for ob in sce.objects.context if ob != ob_act] - - for ob, m in mats: - ob_copy = ob_act.copy() - sce.objects.link(ob_copy) - ob_copy.setMatrix(m) - ob_copy.Layers = ob.Layers & (1<<20)-1 - - -def main(): - sce = bpy.data.scenes.active - - Window.WaitCursor(1) - my_object_util(sce) - Window.WaitCursor(0) - -if __name__ == '__main__': - main() diff --git a/release/scripts/object_apply_def.py b/release/scripts/object_apply_def.py deleted file mode 100644 index 006e97463d8..00000000000 --- a/release/scripts/object_apply_def.py +++ /dev/null @@ -1,178 +0,0 @@ -#!BPY - -""" -Name: 'Apply Deformation' -Blender: 242 -Group: 'Object' -Tooltip: 'Make copys of all the selected objects with modifiers, softbodies and fluid baked into a mesh' -""" - -__author__ = "Martin Poirier (theeth), Jean-Michel Soler (jms), Campbell Barton (ideasman)" -# This script is the result of merging the functionalities of two other: -# Martin Poirier's Apply_Def.py and -# Jean-Michel Soler's Fix From Everything - -__url__ = ("http://www.blender.org", "http://blenderartists.org", "http://jmsoler.free.fr") -__version__ = "1.6 07/07/2006" - -__bpydoc__ = """\ -This script creates "raw" copies of deformed meshes. - -Usage: - -Select any number of Objects and run this script. A fixed copy of each selected object -will be created, with the word "_def" appended to its name. If an object with -the same name already exists, it appends a number at the end as Blender itself does. - -Objects in Blender can be deformed by armatures, lattices, curve objects and subdivision, -but this will only change its appearance on screen and rendered -images -- the actual mesh data is still simpler, with vertices in an original -"rest" position and less vertices than the subdivided version. - -Use this script if you want a "real" version of the deformed mesh, so you can -directly manipulate or export its data. - -This script will work with object types: Mesh, Metaballs, Text3d, Curves and Nurbs Surface. -""" - - -# $Id$ -# -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2003: Martin Poirier, theeth@yahoo.com -# -# Thanks to Jonathan Hudson for help with the vertex groups part -# -# 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 Blender -import bpy -import BPyMesh - -def copy_vgroups(source_ob, target_ob): - - source_me = source_ob.getData(mesh=1) - - vgroups= source_me.getVertGroupNames() - if vgroups: - ADD= Blender.Mesh.AssignModes.ADD - target_me = target_ob.getData(mesh=1) - for vgroupname in vgroups: - target_me.addVertGroup(vgroupname) - if len(target_me.verts) == len(source_me.verts): - try: # in rare cases this can raise an 'no deform groups assigned to mesh' error - vlist = source_me.getVertsFromGroup(vgroupname, True) - except: - vlist = [] - - try: - for vpair in vlist: - target_me.assignVertsToGroup(vgroupname, [vpair[0]], vpair[1], ADD) - except: - pass - - -def apply_deform(): - scn= bpy.data.scenes.active - #Blender.Window.EditMode(0) - - NAME_LENGTH = 19 - SUFFIX = "_def" - SUFFIX_LENGTH = len(SUFFIX) - # Get all object and mesh names - - - ob_list = list(scn.objects.context) - ob_act = scn.objects.active - - # Assume no soft body - has_sb= False - - # reverse loop so we can remove objects (metaballs in this case) - for ob_idx in xrange(len(ob_list)-1, -1, -1): - ob= ob_list[ob_idx] - - ob.sel = 0 # deselect while where checking the metaballs - - # Test for a softbody - if not has_sb and ob.isSB(): - has_sb= True - - # Remove all numbered metaballs because their disp list is only on the main metaball (un numbered) - if ob.type == 'MBall': - name= ob.name - # is this metaball numbered? - dot_idx= name.rfind('.') + 1 - if name[dot_idx:].isdigit(): - # Not the motherball, ignore it. - del ob_list[ob_idx] - - - if not ob_list: - Blender.Draw.PupMenu('No objects selected, nothing to do.') - return - - - if has_sb: - curframe=Blender.Get('curframe') - for f in xrange(curframe): - Blender.Set('curframe',f+1) - Blender.Window.RedrawAll() - - used_names = [ob.name for ob in Blender.Object.Get()] - used_names.extend(Blender.NMesh.GetNames()) - - - deformedList = [] - for ob in ob_list: - - # Get the mesh data - new_me= BPyMesh.getMeshFromObject(ob, vgroups=False) - - if not new_me: - continue # Object has no display list - - - name = ob.name - new_name = "%s_def" % name[:NAME_LENGTH-SUFFIX_LENGTH] - num = 0 - - while new_name in used_names: - new_name = "%s_def.%.3i" % (name[:NAME_LENGTH-(SUFFIX_LENGTH+SUFFIX_LENGTH)], num) - num += 1 - used_names.append(new_name) - - new_me.name= new_name - - new_ob= scn.objects.new(new_me) - new_ob.setMatrix(ob.matrixWorld) - - # Make the active duplicate also active - if ob == ob_act: - scn.objects.active = new_ob - - # Original object was a mesh? see if we can copy any vert groups. - if ob.type =='Mesh': - copy_vgroups(ob, new_ob) - - Blender.Window.RedrawAll() - -if __name__=='__main__': - apply_deform() diff --git a/release/scripts/object_batch_name_edit.py b/release/scripts/object_batch_name_edit.py deleted file mode 100644 index 4db3a6210db..00000000000 --- a/release/scripts/object_batch_name_edit.py +++ /dev/null @@ -1,274 +0,0 @@ -#!BPY -""" -Name: 'Batch Object Name Edit' -Blender: 240 -Group: 'Object' -Tooltip: 'Apply the chosen rule to rename all selected objects at once.' -""" -__author__ = "Campbell Barton" -__url__ = ("blender", "blenderartists.org") -__version__ = "1.0" - -__bpydoc__ = """\ -"Batch Object Name Edit" allows you to change multiple names of Blender -objects at once. It provides options to define if you want to: replace text -in the current names, truncate their beginnings or endings or prepend / append -strings to them. - -Usage: -Select the objects to be renamed and run this script from the Object->Scripts -menu of the 3d View. -""" -# $Id$ -# -# -------------------------------------------------------------------------- -# Batch Name Edit 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 ***** -# -------------------------------------------------------------------------- -from Blender import * -import bpy - -global renameCount -renameCount = 0 -obsel = [ob for ob in bpy.data.scenes.active.objects.context if not ob.lib] - -def setDataNameWrapper(ob, newname): - if ob.getData(name_only=1) == newname: - return False - - data= ob.getData(mesh=1) - - if data and not data.lib: - data.name= newname - return True - return False - -def main(): - global renameCount - # Rename the datablocks that are used by the object. - def renameLinkedDataFromObject(): - - # Result 1, we want to rename data - for ob in obsel: - if ob.name == ob.getData(name_only=1): - return # Alredy the same name, dont bother. - - data = ob.getData(mesh=1) # use mesh so we dont have to update the nmesh. - if data and not data.lib: - data.name = ob.name - - - def new(): - global renameCount - NEW_NAME_STRING = Draw.Create('') - RENAME_LINKED = Draw.Create(0) - pup_block = [\ - ('New Name: ', NEW_NAME_STRING, 19, 19, 'New Name'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Replace in name...', pup_block): - return 0 - - NEW_NAME_STRING= NEW_NAME_STRING.val - - Window.WaitCursor(1) - for ob in obsel: - if ob.name != NEW_NAME_STRING: - ob.name = NEW_NAME_STRING - renameCount+=1 - - return RENAME_LINKED.val - - def replace(): - global renameCount - REPLACE_STRING = Draw.Create('') - WITH_STRING = Draw.Create('') - RENAME_LINKED = Draw.Create(0) - - pup_block = [\ - ('Replace: ', REPLACE_STRING, 19, 19, 'Text to find'),\ - ('With:', WITH_STRING, 19, 19, 'Text to replace with'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Replace in name...', pup_block) or\ - ((not REPLACE_STRING.val) and (not WITH_STRING)): - return 0 - - REPLACE_STRING = REPLACE_STRING.val - WITH_STRING = WITH_STRING.val - - Window.WaitCursor(1) - for ob in obsel: - newname = ob.name.replace(REPLACE_STRING, WITH_STRING) - if ob.name != newname: - ob.name = newname - renameCount+=1 - return RENAME_LINKED.val - - - def prefix(): - global renameCount - PREFIX_STRING = Draw.Create('') - RENAME_LINKED = Draw.Create(0) - - pup_block = [\ - ('Prefix: ', PREFIX_STRING, 19, 19, 'Name prefix'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Prefix...', pup_block) or\ - not PREFIX_STRING.val: - return 0 - - PREFIX_STRING = PREFIX_STRING.val - - Window.WaitCursor(1) - for ob in obsel: - ob.name = PREFIX_STRING + ob.name - renameCount+=1 # we knows these are different. - return RENAME_LINKED.val - - def suffix(): - global renameCount - SUFFIX_STRING = Draw.Create('') - RENAME_LINKED = Draw.Create(0) - - pup_block = [\ - ('Suffix: ', SUFFIX_STRING, 19, 19, 'Name suffix'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Suffix...', pup_block) or\ - not SUFFIX_STRING.val: - return 0 - - SUFFIX_STRING = SUFFIX_STRING.val - - Window.WaitCursor(1) - for ob in obsel: - ob.name = ob.name + SUFFIX_STRING - renameCount+=1 # we knows these are different. - return RENAME_LINKED.val - - def truncate_start(): - global renameCount - TRUNCATE_START = Draw.Create(0) - RENAME_LINKED = Draw.Create(0) - - pup_block = [\ - ('Truncate Start: ', TRUNCATE_START, 0, 19, 'Truncate chars from the start of the name'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Truncate Start...', pup_block) or\ - not TRUNCATE_START.val: - return 0 - - Window.WaitCursor(1) - TRUNCATE_START = TRUNCATE_START.val - for ob in obsel: - newname = ob.name[TRUNCATE_START: ] - ob.name = newname - renameCount+=1 - - return RENAME_LINKED.val - - def truncate_end(): - global renameCount - TRUNCATE_END = Draw.Create(0) - RENAME_LINKED = Draw.Create(0) - - pup_block = [\ - ('Truncate End: ', TRUNCATE_END, 0, 19, 'Truncate chars from the end of the name'),\ - ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ - ] - - if not Draw.PupBlock('Truncate End...', pup_block) or\ - not TRUNCATE_END.val: - return 0 - - Window.WaitCursor(1) - TRUNCATE_END = TRUNCATE_END.val - for ob in obsel: - newname = ob.name[: -TRUNCATE_END] - ob.name = newname - renameCount+=1 - - return RENAME_LINKED.val - - def renameObjectFromLinkedData(): - global renameCount - Window.WaitCursor(1) - - for ob in obsel: - newname = ob.getData(name_only=1) - if newname != None and ob.name != newname: - ob.name = newname - renameCount+=1 - return 0 - - def renameObjectFromDupGroup(): - global renameCount - Window.WaitCursor(1) - - for ob in obsel: - group= ob.DupGroup - if group != None: - newname= group.name - if newname != ob.name: - ob.name = newname - renameCount+=1 - return 0 - - def renameLinkedDataFromObject(): - global renameCount - Window.WaitCursor(1) - - for ob in obsel: - if setDataNameWrapper(ob, ob.name): - renameCount+=1 - return 0 - - name = "Selected Object Names%t|New Name|Replace Text|Add Prefix|Add Suffix|Truncate Start|Truncate End|Rename Objects to Data Names|Rename Objects to DupGroup Names|Rename Data to Object Names" - result = Draw.PupMenu(name) - renLinked = 0 # Rename linked data to the object name? - if result == -1: - return - elif result == 1: renLinked= new() - elif result == 2: renLinked= replace() - elif result == 3: renLinked= prefix() - elif result == 4: renLinked= suffix() - elif result == 5: renLinked= truncate_start() - elif result == 6: renLinked= truncate_end() - elif result == 7: renameObjectFromLinkedData() - elif result == 8: renameObjectFromDupGroup() - elif result == 9: renameLinkedDataFromObject() - - if renLinked: - renameLinkedDataFromObject() - - Window.WaitCursor(0) - - Draw.PupMenu('renamed: %d objects.' % renameCount) - -if __name__=='__main__': - main() diff --git a/release/scripts/object_cookie_cutter.py b/release/scripts/object_cookie_cutter.py deleted file mode 100644 index 4950c18c0f4..00000000000 --- a/release/scripts/object_cookie_cutter.py +++ /dev/null @@ -1,667 +0,0 @@ -#!BPY -""" -Name: 'Cookie Cut from View' -Blender: 234 -Group: 'Object' -Tooltip: 'Cut from the view axis, (Sel 3d Curves and Meshes (only edges) into other meshes with faces)' -""" -__author__= "Campbell Barton" -__url__= ["blender", "blenderartist"] -__version__= "1.0" - -__bpydoc__= """\ -This script takes the selected mesh objects, divides them into 2 groups -Cutters and The objects to be cut. - -Cutters are meshes with no faces, just edge loops. and any meshes with faces will be cut. - -Usage: - -Select 2 or more meshes, one with no faces (a closed polyline) and one with faces to cut. - -Align the view on the axis you want to cut. -For shapes that have overlapping faces (from the view), hide any backfacing faces so they will be ignored during the cut. -Run the script. - -You can choose to make the cut verts lie on the face that they were cut from or on the edge that cut them. -This script supports UV coordinates and images. -""" - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Script copyright (C) Campbell Barton -# -# 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 Blender -from math import sqrt -import BPyMesh -Vector= Blender.Mathutils.Vector -LineIntersect2D= Blender.Geometry.LineIntersect2D -PointInTriangle2D= Blender.Geometry.PointInTriangle2D - -# Auto class -def auto_class(slots): - exec('class container_class(object): __slots__=%s' % slots) - return container_class - - -bignum= 1<<30 -def bounds_xy(iter_item): - ''' - Works with types - MMesh.verts - MFace - MEdge - ''' - xmin= ymin= bignum - xmax= ymax= -bignum - for v in iter_item: - x= v.co.x - y= v.co.y - if xxmax: xmax= x - if y>ymax: ymax= y - - return xmin, ymin, xmax, ymax - -def bounds_intersect(a,b): - ''' - each tuple is - xmin, ymin, xmax, ymax - ''' - if\ - a[0]>b[2] or\ - a[1]>b[3] or\ - a[2]i2: - i1,i2= i2,i1 - return i1, i2 - -def sorted_indicies(i1, i2): - if i1>i2: - i1,i2= i2,i1 - return i1, i2 - -def fake_length2d(pt1, pt2): - ''' - Only used for comparison so don't sqrt - ''' - #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) - return pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2) - -def length2d(pt1, pt2): - ''' - Only used for comparison so don't sqrt - ''' - #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) - return sqrt(pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2)) - - - -def tri_area_2d(v1, v2, v3): - e1 = length2d(v1, v2) - e2 = length2d(v2, v3) - e3 = length2d(v3, v1) - p = e1+e2+e3 - return 0.25 * sqrt(abs(p*(p-2*e1)*(p-2*e2)*(p-2*e3))) - -def tri_pt_find_z_2d(pt, tri): - """ Takes a face and 3d vector and assigns the vectors Z to its on the face""" - - l1= tri_area_2d(tri[1], tri[2], pt) - l2= tri_area_2d(tri[0], tri[2], pt) - l3= tri_area_2d(tri[0], tri[1], pt) - - tot= l1+l2+l3 - # Normalize - l1=l1/tot - l2=l2/tot - l3=l3/tot - - z1= tri[0].z*l1 - z2= tri[1].z*l2 - z3= tri[2].z*l3 - - return z1+z2+z3 - - -def tri_pt_find_uv_2d(pt, tri, uvs): - """ Takes a face and 3d vector and assigns the vectors Z to its on the face""" - - l1= tri_area_2d(tri[1], tri[2], pt) - l2= tri_area_2d(tri[0], tri[2], pt) - l3= tri_area_2d(tri[0], tri[1], pt) - - tot= l1+l2+l3 - if not tot: # No area, just return the first uv - return Vector(uvs[0]) - - # Normalize - l1=l1/tot - l2=l2/tot - l3=l3/tot - - uv1= uvs[0]*l1 - uv2= uvs[1]*l2 - uv3= uvs[2]*l3 - - return uv1+uv2+uv3 - - - - -def mesh_edge_dict(me): - ed_dict= {} - for f in me.faces: - if not f.hide: - for edkey in f.edge_keys: - ed_dict.setdefault(edkey, []).append(f) - - return ed_dict - - - -def terrain_cut_2d(t, c, PREF_Z_LOC): - ''' - t is the terrain - c is the cutter - - PREF_Z_LOC: 0 - from terrain face - 1 - from cutter edge - - returns nothing - ''' - - # do we have a 2d intersection - if not bounds_intersect(t.bounds, c.bounds): - return - - # Local vars - me_t= t.mesh - me_c= c.mesh - - has_uv= me_t.faceUV - - Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) - ''' - first assign a face terrain face for each cutter verticie - ''' - cut_verts_temp= list(me_c.verts) - cut_vert_terrain_faces= [None] * len(me_c.verts) - vert_z_level= [-10.0] * len(me_c.verts) - - for v in me_c.verts: - v_index= v.index - v_co= v.co - for fidx, f in enumerate(me_t.faces): - if not f.hide: - if point_in_bounds(v_co, t.face_bounds[fidx]): - f_v= [vv.co for vv in f] - if point_in_poly2d(v_co, f_v): - - - if PREF_Z_LOC==0: - ''' - Get the z location from the face. - ''' - - if len(f_v)==3: - vert_z_level[v_index]= tri_pt_find_z_2d(v_co, (f_v[0], f_v[1], f_v[2]) ) - else: - # Quad, which side are we on? - a1= tri_area_2d(f_v[0], f_v[1], v_co) - a2= tri_area_2d(f_v[1], f_v[2], v_co) - - a3= tri_area_2d(f_v[0], f_v[1], f_v[2]) - - if a1+a2