diff options
Diffstat (limited to 'release/scripts')
124 files changed, 16132 insertions, 5778 deletions
diff --git a/release/scripts/3ds_export.py b/release/scripts/3ds_export.py index 0209b04844a..54e1ea3db33 100644 --- a/release/scripts/3ds_export.py +++ b/release/scripts/3ds_export.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Name: '3D Studio (.3ds)...' Blender: 243 diff --git a/release/scripts/3ds_import.py b/release/scripts/3ds_import.py index 07da4df1603..028b9633606 100644 --- a/release/scripts/3ds_import.py +++ b/release/scripts/3ds_import.py @@ -6,9 +6,9 @@ Group: 'Import' Tooltip: 'Import from 3DS file format (.3ds)' """ -__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton'] +__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.995' +__version__= '0.996' __bpydoc__= '''\ 3ds Importer @@ -17,6 +17,15 @@ 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 <br> + - 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<br> - workaround for buggy mesh vert delete @@ -319,6 +328,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): contextMesh_vertls= None contextMesh_facels= None contextMeshMaterials= {} # matname:[face_idxs] + contextMeshUV= None TEXTURE_DICT={} MATDICT={} @@ -409,7 +419,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): ob.setMatrix(contextMatrix_rot) importedObjects.append(ob) - + bmesh.calcNormals() for matName, faces in myContextMeshMaterials.iteritems(): makeMeshMaterialCopy(matName, faces) @@ -422,6 +432,8 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): #a spare chunk new_chunk= chunk() temp_chunk= chunk() + + CreateBlenderObject = False #loop through all the data for this chunk (previous chunk) and see what it is while (previous_chunk.bytes_read<previous_chunk.length): @@ -454,6 +466,20 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): #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 @@ -637,21 +663,9 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH): #contextMatrix_tx= None #print contextLamp.name, - elif (new_chunk.ID==OBJECT_MESH): # print 'Found an OBJECT_MESH chunk' - if contextMesh_facels != None: # Write context mesh if we have one. - putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials) - - contextMesh_vertls= []; contextMesh_facels= [] - - contextMeshMaterials= {} # matname:[face_idxs] - contextMeshUV= None - #contextMesh.vertexUV= 1 # Make sticky coords. - # Reset matrix - contextMatrix_rot= None - #contextMatrix_tx= None - + pass elif (new_chunk.ID==OBJECT_VERTICES): ''' Worldspace vertex locations @@ -979,4 +993,4 @@ else: print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -'''
\ No newline at end of file +''' diff --git a/release/scripts/DirectX8Exporter.py b/release/scripts/DirectX8Exporter.py index 3dbd8d9d539..b8bdae4de2b 100644 --- a/release/scripts/DirectX8Exporter.py +++ b/release/scripts/DirectX8Exporter.py @@ -6,9 +6,9 @@ # Group: 'Export' # Tooltip: 'Export to DirectX text file format format for XNA Animation Component Library.' """ -__author__ = "minahito (original:Arben (Ben) Omari)" -__url__ = ("blender", "elysiun", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it") -__version__ = "3.0" +__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 @@ -444,6 +444,7 @@ class xExport: 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)) @@ -464,6 +465,7 @@ class xExport: 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) @@ -1047,6 +1049,32 @@ template SkinWeights {\n\ 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 diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py index bccb7978f5f..57f27c7e3a2 100644 --- a/release/scripts/ac3d_export.py +++ b/release/scripts/ac3d_export.py @@ -8,7 +8,7 @@ Tip: 'Export selected meshes to AC3D (.ac) format' """ __author__ = "Willian P. Germano" -__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", +__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" diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py index 9a7004e4b4d..6a2b290e010 100644 --- a/release/scripts/ac3d_import.py +++ b/release/scripts/ac3d_import.py @@ -8,7 +8,7 @@ Tip: 'Import an AC3D (.ac) file.' """ __author__ = "Willian P. Germano" -__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", +__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org", "PLib 3d gaming lib, http://plib.sf.net") __version__ = "2.43.1 2007-02-21" diff --git a/release/scripts/add_mesh_torus.py b/release/scripts/add_mesh_torus.py index de2db42d482..4f759256497 100644 --- a/release/scripts/add_mesh_torus.py +++ b/release/scripts/add_mesh_torus.py @@ -51,9 +51,9 @@ def main(): 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, 'Radius for the main ring of the torus'),\ - ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\ + ('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 @@ -61,4 +61,5 @@ def main(): BPyAddMesh.add_mesh_simple('Torus', verts, [], faces) -main()
\ No newline at end of file +main() + diff --git a/release/scripts/animation_bake_constraints.py b/release/scripts/animation_bake_constraints.py new file mode 100644 index 00000000000..58e9e2b1d02 --- /dev/null +++ b/release/scripts/animation_bake_constraints.py @@ -0,0 +1,792 @@ +#!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<objname> +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 <br> + +Usage: <br> + - Select the reference Object(s) you want to bake <br> + - Set the frame range to bake in the Anim Panel <br> + - Set the test code (if you want a self-test) in the RT field in the Anim Panel <br> + -- Set RT:1 to create a test armature <br> + -- Set RT: up to 100 for more debug messages and status updates <br> +<br> + - Run the script <br> + - The clone copy of the object is created and it has an IPO curve assigned to it. <br> + - The clone shadows the object by an offset locrot (see usrDelta) <br> + - That Object has Ipo Location and Rotation curves that make the clone mimic the movement <br> + of the selected object, but without using constraints. <br> + - If the object was an Armature, the clone's bones move identically in relation to the <br> + original armature, and an Action is created that drives the bone movements. <br> + +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.1415 # 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<staframe: endframe=staframe + curframe = Blender.Get(CURFRAME) + debug(90,'Scene is on frame %i and frame range is %i to %i' % (curframe,staframe,endframe)) + return (staframe,endframe,curframe) + +######################################## +def sortObjects(obs): #returns a list of objects sorted based on parent dependency + obClones= [] + while len(obClones) < len(obs): + for ob in obs: + if not ob in obClones: + par= ob.getParent() + #if no parent, or the parent is not scheduled to be cloned + if par==None: + obClones.append(ob) # add the independent + elif par not in obs: # parent will not be cloned + obClones.append(ob) # add the child + elif par in obClones: # is it on the list? + obClones.append(ob) # add the child + # parent may be a child, so it will be caught next time thru + debug(100,'clone object order: \n%s' % obClones) + return obClones # ordered list of (ob, par) tuples + +######################################## +def sortBones(xbones): #returns a sorted list of bones that should be added,sorted based on parent dependency +# while there are bones to add, +# look thru the list of bones we need to add +# if we have not already added this bone +# if it does not have a parent +# add it +# else, it has a parent +# if we already added it's parent +# add it now. +# else #we need to keep cycling and catch its parent +# else it is a root bone +# add it +# else skip it, it's already in there +# endfor +# endwhile + xboneNames=[] + for xbone in xbones: xboneNames.append(xbone.name) + debug (80,'reference bone order: \n%s' % xboneNames) + eboneNames=[] + while len(eboneNames) < len(xboneNames): + for xbone in xbones: + if not xbone.name in eboneNames: + if not xbone.parent: + eboneNames.append(xbone.name) + else: + if xbone.parent.name in eboneNames: + eboneNames.append(xbone.name) + #else skip it + #endif + #else prego + #endfor + #endwhile + debug (80,'clone bone order: \n%s' % eboneNames) + return eboneNames + +######################################## +def dupliArmature(ob): #makes a copy in current scn of the armature used by ob and its bones + ob_mat = ob.matrixWorld + ob_data = ob.getData() + debug(49,'Reference object uses %s' % ob_data) + arm_ob = Armature.Get(ob_data.name) #the armature used by the passed object + + arm = Blender.Armature.New() + debug(20,'Cloning Armature %s to create %s' % (arm_ob.name, arm.name)) + arm.drawType = Armature.STICK #set the draw type + + arm.makeEditable() #enter editmode + + # for each bone in the object's armature, + xbones=ob.data.bones.values() + usrSpace = 0 #0=armature, 1=local + space=[BONE_SPACES[usrSpace]][0] + + #we have to make a list of bones, then figure out our parents, then add to the arm + #when creating a child, we cannot link to a parent if it does not yet exist in our armature + ebones = [] #list of the bones I want to create for my arm + + eboneNames = sortBones(xbones) + + i=0 + # error('bones sorted. continue?') + for abone in eboneNames: #set all editable attributes to fully define the bone. + for bone in xbones: + if bone.name == abone: break # get the reference bone + ebone = Armature.Editbone() #throw me a bone, bone-man! + ebones.append(ebone) #you're on my list, buddy + + ebone.name = bone.name + ebone.headRadius = bone.headRadius + ebone.tailRadius = bone.tailRadius + ebone.weight = bone.weight + ebone.options = bone.options + + ebone.head = bone.head[space] #dictionary lookups + ebone.tail = bone.tail[space] + ebone.matrix = bone.matrix[space] + ebone.roll = bone.roll[space] + + debug(30,'Generating new %s as child of %s' % (bone,bone.parent)) + if bone.hasParent(): +# parent=bone.parent.name +# debug(100,'looking for %s' % parent) +# for parbone in xbones: if parbone.name == parent: break # get the parent bone +# ebone.parent = arm.bones[ebones[j].name] + ebone.parent = arm.bones[bone.parent.name] +# else: +# ebone.parent = None + debug(30,'Generating new editbone %s as child of %s' % (ebone,ebone.parent)) + arm.bones[ebone.name] = ebone # i would have expected an append or add function, but this works + + debug (100,'arm.bones: \n%s' % arm.bones) + debug (20,'Cloned %i bones now in armature %s' %(len(arm.bones),arm.name)) + + myob = scn.objects.new(arm) #interestingly, object must be created before + arm.update() #armature can be saved + debug(40,'dupArm finished %s instanced as object %s' % (arm.name,myob.getName())) + print ob.matrix + print myob.matrix + + return myob +######################################## +def scrub(): # scrubs to startframe + staFrame,endFrame,curFrame = getRenderInfo() + + # eye-candy, go from current to start, fwd or back + if not BATCH: + debug(100, "Positioning to start...") + frameinc=(staFrame-curFrame)/10 + if abs(frameinc) >= 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/bevel_center.py b/release/scripts/bevel_center.py index 0ea305a0120..063c6380483 100644 --- a/release/scripts/bevel_center.py +++ b/release/scripts/bevel_center.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Registration info for Blender menus Name: 'Bevel Center' Blender: 243 @@ -8,7 +8,7 @@ Tip: 'Bevel selected faces, edges, and vertices' """ __author__ = "Loic BERTHE" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "2.0" __bpydoc__ = """\ diff --git a/release/scripts/blenderLipSynchro.py b/release/scripts/blenderLipSynchro.py index ef765086e25..c4815811512 100644 --- a/release/scripts/blenderLipSynchro.py +++ b/release/scripts/blenderLipSynchro.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Name: 'BlenderLipSynchro' Blender: 242 diff --git a/release/scripts/bpymodules/BPyAddMesh.py b/release/scripts/bpymodules/BPyAddMesh.py index 6ffb394320a..901e68866cc 100644 --- a/release/scripts/bpymodules/BPyAddMesh.py +++ b/release/scripts/bpymodules/BPyAddMesh.py @@ -16,13 +16,17 @@ def add_mesh_simple(name, verts, edges, faces): scn = bpy.data.scenes.active if scn.lib: return ob_act = scn.objects.active - + + is_editmode = EditMode() + cursor = GetCursorPos() - try: quat = Blender.Mathutils.Quaternion(GetViewQuat()) - except: quat = None + 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 EditMode(): + if ob_act and ob_act.type != 'Mesh' and is_editmode: EditMode(0) # We are in mesh editmode @@ -64,10 +68,7 @@ def add_mesh_simple(name, verts, edges, faces): else: # Mesh with no data, unlikely me.edges.extend(edges) - me.faces.extend(faces) - - EditMode(1) - + me.faces.extend(faces) else: # Object mode add new @@ -90,8 +91,14 @@ def add_mesh_simple(name, verts, edges, faces): 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): @@ -106,7 +113,7 @@ def write_mesh_script(filepath, me): file.write('#!BPY\n') file.write('"""\n') file.write('Name: \'%s\'\n' % name) - file.write('Blender: 243\n') + file.write('Blender: 245\n') file.write('Group: \'AddMesh\'\n') file.write('"""\n\n') file.write('import BPyAddMesh\n') diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py index d0b41dc35c5..63df02d080c 100644 --- a/release/scripts/bpymodules/BPyArmature.py +++ b/release/scripts/bpymodules/BPyArmature.py @@ -11,13 +11,19 @@ # 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): +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 - return a list of frame aligned bone dictionary's + 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 @@ -77,7 +83,13 @@ def getBakedPoseData(ob_arm, start_frame, end_frame): # --------------------------------- 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) @@ -88,9 +100,7 @@ def getBakedPoseData(ob_arm, start_frame, end_frame): 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] @@ -98,40 +108,45 @@ def getBakedPoseData(ob_arm, start_frame, end_frame): rest_matrix= rest_matrix * parent_bone_matrix_inv matrix=matrix * rest_matrix.copy().invert() - pose_bone.quat= matrix.toQuat() pose_bone.loc= matrix.translationPart() - 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 + 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) + # 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() + 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 + 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 - - + 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 - Blender.Set('curframe', backup_frame) - return bake_data + 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/BPyRegistry.py b/release/scripts/bpymodules/BPyRegistry.py index f0d6da82d52..4d681e15937 100644 --- a/release/scripts/bpymodules/BPyRegistry.py +++ b/release/scripts/bpymodules/BPyRegistry.py @@ -193,14 +193,17 @@ def LoadConfigData (key = None): if bsys.exists(fname): files.append(fname) for p in files: - 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)) + 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): @@ -223,8 +226,11 @@ def RemoveConfigData (key = None): import os - for p in files: - os.remove(p) # remove the file(s) + 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): @@ -250,9 +256,12 @@ def SaveConfigData (key = None): if not cfgdict: continue - 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() + 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 index e335ee7f6a8..951e1ae6300 100644 --- a/release/scripts/bpymodules/BPyRender.py +++ b/release/scripts/bpymodules/BPyRender.py @@ -125,14 +125,14 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam # camera is wider then image res. # to make the image wider, reduce the aspy asp_diff= asp_image_res/asp_cam_mat - min_asp= int(round(asp_diff * 200)) + 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= int(round(asp_diff * 200)) + min_asp= asp_diff * 200 #print 'Y', min_asp else: min_asp= 200 @@ -181,7 +181,6 @@ def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, cam Blender.Window.RedrawAll() - render_context.threads= 2 # good for dual core cpu's render_context.render() render_context.saveRenderedImage(path) Render.CloseRenderWindow() @@ -496,3 +495,139 @@ def vcol2image(me_s,\ 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/BPyTextPlugin.py b/release/scripts/bpymodules/BPyTextPlugin.py new file mode 100644 index 00000000000..cd5a085de37 --- /dev/null +++ b/release/scripts/bpymodules/BPyTextPlugin.py @@ -0,0 +1,814 @@ +"""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' : <module 'Blender.Text' (built-in)> + + 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/blend2renderinfo.py b/release/scripts/bpymodules/blend2renderinfo.py new file mode 100644 index 00000000000..1b9dec58d55 --- /dev/null +++ b/release/scripts/bpymodules/blend2renderinfo.py @@ -0,0 +1,95 @@ +#!/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('<i', file.read(4))[0] + + sizeof_bhead_left -= 4 + + # We dont care about the rest of the bhead struct + file.read(sizeof_bhead_left) + + # Now we want the scene name, start and end frame. this is 32bites long + + if isBigEndian: start_frame, end_frame = 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/dxfImportObjects.py b/release/scripts/bpymodules/dxfImportObjects.py deleted file mode 100644 index 960c4c1ac15..00000000000 --- a/release/scripts/bpymodules/dxfImportObjects.py +++ /dev/null @@ -1,1326 +0,0 @@ -"""This module provides wrapper objects for dxf entities. - - The wrappers expect a "dxf object" as input. The dxf object is - an object with a type and a data attribute. Type is a lowercase - string matching the 0 code of a dxf entity. Data is a list containing - dxf objects or lists of [code, data] pairs. - - This module is not general, and is only for dxf import. -""" - -# -------------------------------------------------------------------------- -# DXF Import Objects v0.8 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 ***** -# -------------------------------------------------------------------------- -from math import * - - -# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) -#---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 -class Object: - """Empty container class for dxf objects""" - - def __init__(self, _type=''): - """_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 Layer: - """Class for objects representing dxf layers.""" - - def __init__(self, obj): - """Expects an entity object of type line as input.""" - self.type = obj.type - self.data = obj.data[:] - - self.name = obj.get_type(2)[0] - self.color = obj.get_type(62)[0] - 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) - - - -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 = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - - self.points = self.get_points(obj.data) - - - - - 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 - sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0 - for item in data: - if item[0] == 10: # 10 = x - sx = item[1] - elif item[0] == 20: # 20 = y - sy = item[1] - elif item[0] == 30: # 30 = z - sz = item[1] - elif item[0] == 11: # 11 = x - ex = item[1] - elif item[0] == 21: # 21 = y - ey = item[1] - elif item[0] == 31: # 31 = z - ez = item[1] - return [[sx, sy, sz], [ex, ey, ez]] - - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class LWpolyline: - """Class for objects representing dxf LWpolylines.""" - - def __init__(self, obj): - """Expects an entity object of type lwpolyline as input.""" - 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 = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.elevation = obj.get_type(38) - if self.elevation: - self.elevation = self.elevation[0] - else: - self.elevation = 0 - - self.flags = obj.get_type(70) - if self.flags: - self.flags = self.flags[0] - else: - self.flags = 0 - - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.points = self.get_points(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - - def get_points(self, data): - """Gets points for a polyline type object. - - 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] - 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 get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class Polyline: - """Class for objects representing dxf LWpolylines.""" - - def __init__(self, obj): - """Expects an entity object of type polyline as input.""" - if not obj.type == 'polyline': - raise TypeError, "Wrong type %s for polyline object!" %obj.type - self.type = obj.type - self.data = obj.data[:] - self.points = [] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.elevation = obj.get_type(30) - if self.elevation: - self.elevation = self.elevation[0] - else: - self.elevation = 0 - - self.flags = obj.get_type(70) - if self.flags: - self.flags = self.flags[0] - else: - self.flags = 0 - - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - - -class Vertex(object): - """Generic vertex object used by polylines (and maybe others).""" - - def __init__(self, obj=None): - """Initializes vertex data. - - The optional obj arg is an entity object of type vertex. - """ - self.loc = [0,0,0] - self.bulge = 0 - self.swidth = 0 - self.ewidth = 0 - self.flags = 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.data) - - - 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 - """ - for item in data: - if item[0] == 10: # 10 = x - self.x = item[1] - elif item[0] == 20: # 20 = y - self.y = item[1] - elif item[0] == 30: # 30 = z - self.z = item[1] - elif item[0] == 40: # 40 = start width - self.swidth = item[1] - elif item[0] == 41: # 41 = end width - self.ewidth = item[1] - elif item[0] == 42: # 42 = bulge - self.bulge = item[1] - elif item[0] == 70: # 70 = vert flags - self.flags = item[1] - - - 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" %(self.loc, self.swidth, self.ewidth, self.bulge) - - - 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 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 = obj.get_type(40)[0] - self.value = obj.get_type(1)[0] # The text string value - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.rotation = obj.get_type(50) # radians? - if not self.rotation: - self.rotation = 0 - else: - self.rotation = self.rotation[0] - - self.width_factor = obj.get_type(41) # Scaling factor along local x axis - if not self.width_factor: - self.width_factor = 1 - else: - self.width_factor = self.width_factor[0] - - self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90 - if not self.oblique: - self.oblique = 0 - else: - self.oblique = self.oblique[0] - - self.halignment = obj.get_type(72) # horiz. alignment - if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit - self.halignment = 0 - else: - self.halignment = self.halignment[0] - - self.valignment = obj.get_type(73) # vert. alignment - if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top - self.valignment = 0 - else: - self.valignment = self.valignment[0] - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data, self.halignment, self.valignment) - self.extrusion = self.get_extrusion(obj.data) - - - - - def get_loc(self, data, halign, valign): - """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 - for item in data: - if item[0] == 10: # 10 = x - x = item[1] - elif item[0] == 20: # 20 = y - y = item[1] - elif item[0] == 30: # 30 = z - z = item[1] - elif item[0] == 11: # 11 = x - jx = item[1] - elif item[0] == 21: # 21 = y - jy = item[1] - elif item[0] == 31: # 31 = z - jz = item[1] - - if halign or valign: - x, y, z = jx, jy, jz - return [x, y, z] - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - -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.data) # The text string value - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - self.rotation = obj.get_type(50) # radians - if not self.rotation: - self.rotation = 0 - else: - self.rotation = self.rotation[0] - - self.width_factor = obj.get_type(42) # Scaling factor along local x axis - if not self.width_factor: - self.width_factor = 1 - else: - self.width_factor = self.width_factor[0] - - self.line_space = obj.get_type(44) # percentage of default - if not self.line_space: - self.line_space = 1 - else: - self.line_space = self.line_space[0] - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - 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 location. - """ - loc = [0,0,0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) - - - -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 = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for circle type objects. - - Circles have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -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 = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -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 = obj.get_type(2)[0] - - # optional data (with defaults) - self.insertion_units = obj.get_type(70) - if not self.insertion_units: - self.insertion_units = None - else: - self.insertion_units = self.insertion_units[0] - - self.insert_units = obj.get_type(1070) - if not self.insert_units: - self.insert_units = None - else: - self.insert_units = self.insert_units[0] - - - - - - - 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.data = obj.data[:] - - # required data - self.flags = obj.get_type(70)[0] - self.entities = Object('block_contents') - self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) - - # optional data (with defaults) - self.name = obj.get_type(3) - if self.name: - self.name = self.name[0] - else: - self.name = '' - - self.path = obj.get_type(1) - if self.path: - self.path = self.path[0] - else: - self.path = '' - - self.discription = obj.get_type(4) - if self.discription: - self.discription = self.discription[0] - else: - self.discription = '' - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - - - - - - def get_loc(self, data): - """Gets the insert point of the block.""" - loc = [0, 0, 0] - for item in data: - if type(item) != list: - continue - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - 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[:] - - # required data - self.block = obj.get_type(2)[0] - - # optional data (with defaults) - self.rotation = obj.get_type(50) - if self.rotation: - self.rotation = self.rotation[0] - else: - self.rotation = 0 - - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.scale = self.get_scale(obj.data) - self.rows, self.columns = self.get_array(obj.data) - self.extrusion = self.get_extrusion(obj.data) - - - - - - def get_loc(self, data): - """Gets the center location for circle type objects. - - Circles have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - return loc - - - - def get_scale(self, data): - """Gets the x/y/z scale factor for the block. - """ - scale = [1, 1, 1] - for item in data: - if item[0] == 41: # 41 = x scale - scale[0] = item[1] - elif item[0] == 42: # 42 = y scale - scale[1] = item[1] - elif item[0] == 43: # 43 = z scale - scale[2] = item[1] - return scale - - - - def get_array(self, data): - """Returns the pair (row number, row spacing), (column number, column spacing).""" - columns = 1 - rows = 1 - cspace = 0 - rspace = 0 - for item in data: - if item[0] == 70: # 70 = columns - columns = item[1] - elif item[0] == 71: # 71 = rows - rows = item[1] - if item[0] == 44: # 44 = columns - cspace = item[1] - elif item[0] == 45: # 45 = rows - rspace = item[1] - return (rows, rspace), (columns, cspace) - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block) - - - - -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] - self.start_angle = obj.get_type(41)[0] - self.end_angle = obj.get_type(42)[0] - - # optional data (with defaults) - self.space = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.loc = self.get_loc(obj.data) - self.major = self.get_major(obj.data) - self.extrusion = self.get_extrusion(obj.data) - self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) - - - - - def get_loc(self, data): - """Gets the center location for arc type objects. - - Arcs have a single coord location. - """ - loc = [0, 0, 0] - for item in data: - if item[0] == 10: # 10 = x - loc[0] = item[1] - elif item[0] == 20: # 20 = y - loc[1] = item[1] - elif item[0] == 30: # 30 = z - loc[2] = item[1] - 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] - for item in data: - if item[0] == 11: # 11 = x - loc[0] = item[1] - elif item[0] == 21: # 21 = y - loc[1] = item[1] - elif item[0] == 31: # 31 = z - loc[2] = item[1] - return loc - - - - def get_extrusion(self, data): - """Find the axis of extrusion. - - Used to get the objects Object Coordinate System (ocs). - """ - vec = [0,0,1] - for item in data: - if item[0] == 210: # 210 = x - vec[0] = item[1] - elif item[0] == 220: # 220 = y - vec[1] = item[1] - elif item[0] == 230: # 230 = z - vec[2] = item[1] - return vec - - - def __repr__(self): - return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) - - - -class Face: - """Class for objects representing dxf 3d faces.""" - - 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 = obj.get_type(67) - if self.space: - self.space = self.space[0] - else: - self.space = 0 - - self.color_index = obj.get_type(62) - if self.color_index: - self.color_index = self.color_index[0] - else: - self.color_index = BYLAYER - - discard, self.layer, discard_index = get_layer(obj.data) - del obj.data[discard_index] - self.points = self.get_points(obj.data) - - - - - 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 = False - for item in data: - # ----------- a ------------- - if item[0] == 10: # 10 = x - a[0] = item[1] - elif item[0] == 20: # 20 = y - a[1] = item[1] - elif item[0] == 30: # 30 = z - a[2] = item[1] - # ----------- b ------------- - elif item[0] == 11: # 11 = x - b[0] = item[1] - elif item[0] == 21: # 21 = y - b[1] = item[1] - elif item[0] == 31: # 31 = z - b[2] = item[1] - # ----------- c ------------- - elif item[0] == 12: # 12 = x - c[0] = item[1] - elif item[0] == 22: # 22 = y - c[1] = item[1] - elif item[0] == 32: # 32 = z - c[2] = item[1] - # ----------- d ------------- - elif item[0] == 13: # 13 = x - d = [0, 0, 0] - d[0] = item[1] - elif item[0] == 23: # 23 = y - d[1] = item[1] - elif item[0] == 33: # 33 = z - d[2] = item[1] - out = [a,b,c] - if d: - out.append(d) - return out - - - def __repr__(self): - return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) - - -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 i, item in enumerate(data): - if item[0] == 2: - value = item[1] - break - return item, value, i - -def get_layer(data): - """Expects object data as input. - - Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name. - """ - value = None - for i, item in enumerate(data): - if item[0] == 8: - value = item[1] - break - return item, value, i - - -# type to object map -type_map = { - 'line':Line, - 'lwpolyline':LWpolyline, - 'text':Text, - 'mtext':Mtext, - 'circle':Circle, - 'arc':Arc, - 'layer':Layer, - 'block_record':BlockRecord, - 'block':Block, - 'insert':Insert, - 'ellipse':Ellipse, - '3dface':Face -} - -def objectify(data): - """Expects a section type object's data as input. - - Maps object data to the correct object type. - """ - objects = [] # colector for finished objects - known_types = type_map.keys() # so we don't have to call foo.keys() every iteration - index = 0 - while index < len(data): - item = data[index] - if type(item) != list and item.type in known_types: - # proccess the object and append the resulting object - objects.append(type_map[item.type](item)) - elif 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': - pline = Polyline(item) - while 1: - index += 1 - item = data[index] - if item.type == 'vertex': - v = Vertex(item) - pline.points.append(v) - elif item.type == 'seqend': - break - else: - print "Error: non-vertex found before seqend!" - index -= 1 - break - objects.append(pline) - else: - # we will just let the data pass un-harrased - objects.append(item) - index += 1 - return objects -if __name__ == "__main__": - print "No example yet!"
\ No newline at end of file diff --git a/release/scripts/bpymodules/dxfLibrary.py b/release/scripts/bpymodules/dxfLibrary.py new file mode 100644 index 00000000000..5c63e7f5bf5 --- /dev/null +++ b/release/scripts/bpymodules/dxfLibrary.py @@ -0,0 +1,708 @@ +#dxfLibrary.py : provides functions for generating DXF files +# -------------------------------------------------------------------------- +__version__ = "v1.27beta - 2008.10.05" +__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" +__license__ = "GPL" +__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" +__bpydoc__ ="""The script exports geometry data to DXF format r12 version. + +Copyright %s +Version %s +License %s +Homepage %s + +See the homepage for documentation. +url: + +IDEAs: +- + +TODO: +- + +History +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 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,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))]) + #print 'deb: points=\n', out #------------------- + 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,color=None,extrusion=None,layer='0', + lineType=None,lineTypeScale=None,lineWeight=None, + thickness=None,parent=None): + """None values will be omitted.""" + self.color = color + self.extrusion = extrusion + self.layer = layer + self.lineType = lineType + self.lineTypeScale = lineTypeScale + self.lineWeight = lineWeight + self.thickness = thickness + 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.layer!=None: result+=' 8\n%s\n'%parent.layer + if parent.color!=None: result+=' 62\n%s\n'%parent.color + if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) + if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType + #TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight + if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale + if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness + 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) + if 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\n%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): + _Entity.__init__(self,**common) + self.points=points + self.org_point=org_point + self.flag=flag + if self.flag==64: + self.points=points[0] + self.faces=points[1] + self.p_count=len(self.points) + self.f_count=len(self.faces) + self.width=width + + def __str__(self): + result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag) + #print 'deb: self._common()', self._common() #---------- + result+=' 66\n1\n' + result+='%s\n' %_point(self.org_point) + if self.flag==64: + result+=' 71\n%s\n' %self.p_count + result+=' 72\n%s\n' %self.f_count + for point in self.points: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + result+='%s\n' %_point(point) + if self.flag==64: result+=' 70\n192\n' + if self.width: result+=' 40\n%s\n 41\n%s\n' %(self.width,self.width) + if self.flag==64: + 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): + """Colored solid fill.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=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 + #TODO: 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): + 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=[],flag=64): + # TODO: Implement lineType elements + self.name=name + self.description=description + self.elements=copy.copy(elements) + self.flag=flag + def __str__(self): + return ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n 73\n%s\n 40\n0.0\n'%\ + (self.name.upper(),self.flag,self.description,len(self.elements)) + +#----------------------------------------------- +class Style(_Call): + """Text style""" + def __init__(self,name='standard',flag=0,height=0,widthFactor=40,obliqueAngle=50, + 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 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=width + self.height=height + self.center=center + self.direction=direction + self.target=target + self.lens=lens + self.frontClipping=frontClipping + self.backClipping=backClipping + self.twist=twist + self.mode=mode + def __str__(self): + return ' 0\nVIEW\n 2\n%s\n 70\n%s\n 40\n%s\n%s\n 41\n%s\n%s\n%s\n 42\n%s\n 43\n%s\n 44\n%s\n 50\n%s\n 71\n%s\n'%\ + (self.name,self.flag,self.height,_point(self.center),self.width, + _point(self.direction,1),_point(self.target,2),self.lens, + self.frontClipping,self.backClipping,self.twist,self.mode) + +#----------------------------------------------- +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),extmax=(0.0,0.0), + layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], + views=[],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.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('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)],closed=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') + main() +
\ No newline at end of file diff --git a/release/scripts/bpymodules/dxfReader.py b/release/scripts/bpymodules/dxfReader.py index d4a39cf63d6..df4ebc309e4 100644 --- a/release/scripts/bpymodules/dxfReader.py +++ b/release/scripts/bpymodules/dxfReader.py @@ -1,11 +1,12 @@ """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. + 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 ***** # @@ -30,215 +31,215 @@ #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 - + """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 + """(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 + """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 + """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(value) - elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: - value = long(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 + """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 + """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 = [] + """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) - - - + """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) - - - + """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: @@ -250,133 +251,131 @@ states: """ 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!") + """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 = [] + """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) + """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 + """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 + """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 + """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/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py index dcf56853184..6eb5023a8d4 100644 --- a/release/scripts/bpymodules/paths_ai2obj.py +++ b/release/scripts/bpymodules/paths_ai2obj.py @@ -1,3 +1,4 @@ +# -*- coding: latin-1 -*- """ paths_ai2obj.py # --------------------------------------------------------------- @@ -42,10 +43,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Communiquer les problemes et erreurs sur: # http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender #---------------------------------------------- + +#Changelog #---------------------------------------------- -#Chagelog -#---------------------------------------------- -# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative +# 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 @@ -57,6 +58,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # 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 diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py index 8b31c5d7294..c2ce9718c71 100644 --- a/release/scripts/bpymodules/paths_gimp2obj.py +++ b/release/scripts/bpymodules/paths_gimp2obj.py @@ -1,3 +1,4 @@ +# -*- coding: latin-1 -*- """ #---------------------------------------------- # (c) jm soler juillet 2004, @@ -43,6 +44,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # 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 diff --git a/release/scripts/bpymodules/paths_svg2obj.py b/release/scripts/bpymodules/paths_svg2obj.py index e535af705df..de40bea3191 100644 --- a/release/scripts/bpymodules/paths_svg2obj.py +++ b/release/scripts/bpymodules/paths_svg2obj.py @@ -1309,8 +1309,9 @@ def curve_FILL(Courbe,proprietes): if not 'fill:none' in pr: Courbe[n].fill=1 if USE_COLORS: - if '#' in pr: - i= pr.find('fill:#')+6 + 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: diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py index 2093ac109f7..5cdd8a71231 100644 --- a/release/scripts/bvh_import.py +++ b/release/scripts/bvh_import.py @@ -231,7 +231,7 @@ def read_bvh(file_path, GLOBAL_SCALE=1.0): bvh_nodes_list= bvh_nodes.values() - while lineIdx < len(file_lines) -1: + while lineIdx < len(file_lines): line= file_lines[lineIdx] for bvh_node in bvh_nodes_list: #for bvh_node in bvh_nodes_serial: @@ -726,7 +726,7 @@ def load_bvh_ui(file, PREF_UI= True): Blender.Window.WaitCursor(1) # Get the BVH data and act on it. t1= Blender.sys.time() - print '\tpassing bvh...', + print '\tparsing bvh...', bvh_nodes= read_bvh(file, IMPORT_SCALE) print '%.4f' % (Blender.sys.time()-t1) t1= Blender.sys.time() diff --git a/release/scripts/c3d_import.py b/release/scripts/c3d_import.py new file mode 100644 index 00000000000..bfe691c394c --- /dev/null +++ b/release/scripts/c3d_import.py @@ -0,0 +1,1243 @@ +#!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:<br> + - Run the script <br> + - Choose the file to open<br> + - Press Import C3D button<br> + +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.startFrame(StartFrame) + context.endFrame(EndFrame) + context.framesPerSec(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)<Nmarkers: + for i in range(len(markerList),Nmarkers): markerList.append("mark."+str(i)) + #note that they may supply more markers than Nmarkers, extras are usually null or ignored + #an idea here to winnow down the marker List is to go through the nodes and see if there are markers + # in the list that are not used in constraining the armature, and discard them or set them debug(0, + # so that later on in processing we don't bother saving their location, possibly speeding up processing + # because we can just skip over their data block. + # put this on TODO list since it gets pretty complicated going throuch each marker set and all constraints etc. + + ## ############################################### + ## ## ## + ## ## Initalize Arrays and Allocate Memory + ## ## ## + ## ############################################### + ## Get the coordinate and analog data + # + + content = content_memory + content = content[(NrecordDataBlock-1)*512:] + debug(20,"Allocating memory for %i floats" %NvideoFrames*(Nmarkers*3+2)) + for i in range (NvideoFrames): + Markers.append([]) + ResidualError.append([]) + CameraInfo.append([]) + for j in range (Nmarkers): + Markers[i].append(Marker(0.0,0.0,0.0)) + ResidualError[i].append(0) + CameraInfo[i].append(0) + + #print Markers + # + #if Scale < 0 + # for i=1:NvideoFrames + # for j=1:Nmarkers + # Markers(i,j,1:3)=fread(fid,3,'float32')'; + # a=fix(fread(fid,1,'float32')); + # highbyte=fix(a/256); + # lowbyte=a-highbyte*256; + # CameraInfo(i,j)=highbyte; + # ResidualError(i,j)=lowbyte*abs(Scale); + # end + # waitbar(i/NvideoFrames) + # for j=1:NanalogFramesPerVideoFrame, + # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=... + # fread(fid,NanalogChannels,'int16')'; + # end + # end + + debug(10, "***************************") + debug(00, "**** Reading DataBlock of %i Frames...." % NvideoFrames) + debug(10, "***************************") + residuals= NanalogFramesPerVideoFrame*NanalogChannels*2 + err=0 #keep track of errors or serious data issues + ptr_read = 0 + + if Scale < 0.0: # 3D Data - 4-byte Floating-point Format + 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,ptr_read = parseFloat(content, ptr_read, proctype) + y,ptr_read = parseFloat(content, ptr_read, proctype) + z,ptr_read = parseFloat(content, ptr_read, proctype) + myx= x * -Scale + myy= y * -Scale + myz= z * -Scale + + if abs(myx)>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]<Markers[i][j].x: minmax[3]=Markers[i][j].x + if minmax[4]<Markers[i][j].y: minmax[4]=Markers[i][j].y + if minmax[5]<Markers[i][j].z: minmax[5]=Markers[i][j].z + debug(0,"Markers move in 3D space from (%i,%i,%i) to (%i,%i,%i). "%(minmax[0],minmax[1],minmax[2],minmax[3],minmax[4],minmax[5])) + debug(0,"Set your 3D View Properties Clip End and zoom out your display.") +def my_callback(filename): + # processing options UI goes here, eventually + Window.WaitCursor(1) + t = sys.time() + load_c3d(filename) + # Timing the script is a good way to be aware on any speed hits when scripting + debug(0, '%s file processed in %.2f sec.' % (filename,sys.time()-t)) + Window.WaitCursor(0) + +def processFile(): + # select file and pass a handle to the processor + Blender.Window.FileSelector(my_callback, "Import C3D") # makes a window a file selector and processes it + #processing contiues while file is being worked + +def main(): + # Display the GUI + + # Run the function + processFile() + + #Close files, display stats, cleanup, advice on next steps + +# This lets you import the script without running it +if __name__ == '__main__': + debug(00, "------------------------------------") + debug(00, '%s %s script began at %.0f' % (__script__,__version__,sys.time())) + main() + + + diff --git a/release/scripts/config.py b/release/scripts/config.py index 69f929dab97..cbf8e272b91 100644 --- a/release/scripts/config.py +++ b/release/scripts/config.py @@ -10,7 +10,7 @@ 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', 'elysiun') +__url__ = ('blender', 'blenderartists.org') __bpydoc__ ="""\ This script can be used to view and edit configuration data stored @@ -246,6 +246,10 @@ information about how to fix this. 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 diff --git a/release/scripts/console.py b/release/scripts/console.py index 7d9d8be5e9e..0e46f41f581 100644 --- a/release/scripts/console.py +++ b/release/scripts/console.py @@ -1,14 +1,14 @@ #!BPY """ -Name: 'Interactive Console' -Blender: 237 +Name: 'Interactive Python Console' +Blender: 245 Group: 'System' Tooltip: 'Interactive Python Console' """ -__author__ = "Campbell Barton AKA Ideasman" -__url__ = ["Author's homepage, http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] +__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. @@ -26,8 +26,6 @@ Usage:<br> - Ctrl + Enter: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;<br> - Shift + Enter: multiline functions -- delays executing code until only Enter is pressed. """ -__author__ = "Campbell Barton AKA Ideasman" -__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"] # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** @@ -63,12 +61,14 @@ __LINE_HISTORY__ = 500 global __FONT_SIZE__ -__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normal', 14), ('large', 16) ) +__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(): @@ -161,19 +161,13 @@ def include(filename): return compile(filedata, filename, 'exec') # Writes command line data to a blender text file. -def writeCmdData(cmdLineList, type): - if type == 3: - typeList = [0,1,2, 3, None] # all - else: - typeList = [type] # so we can use athe lists 'in' methiod - +def writeCmdData(type): newText = Text.New('command_output.py', 1) - for myCmd in cmdLineList: - if myCmd.type in typeList: # user input - newText.write('%s\n' % myCmd.cmd) + 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(cmdBuffer): +def insertCmdData(): texts = list(bpy.data.texts) textNames = [tex.name for tex in texts] if textNames: @@ -339,7 +333,6 @@ def handle_event(evt, val): # Insert Char into the cammand line def insCh(ch): # Instert a char - global cmdBuffer global cursor # Later account for a cursor variable cmdBuffer[-1].cmd = ('%s%s%s' % ( cmdBuffer[-1].cmd[:cursor], ch, cmdBuffer[-1].cmd[cursor:])) @@ -348,7 +341,7 @@ def handle_event(evt, val): # Define Complex Key Actions # #------------------------------------------------------------------------------# def actionEnterKey(): - global histIndex, cursor, cmdBuffer + global histIndex, cursor def getIndent(string): # Gather white space to add in the previous line @@ -414,44 +407,64 @@ def handle_event(evt, val): # Clear the output based on __LINE_HISTORY__ if len(cmdBuffer) > __LINE_HISTORY__: - cmdBuffer = cmdBuffer[-__LINE_HISTORY__:] + cmdBuffer[:__LINE_HISTORY__] = [] histIndex = cursor = -1 # Reset cursor and history def actionUpKey(): - global histIndex, cmdBuffer + 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): + + 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, cmdBuffer + 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: + 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|Quit') + 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(cmdBuffer, 0) # type 0 user + writeCmdData(0) # type 0 user elif choice == 2: - writeCmdData(cmdBuffer, 1) # type 1 user output + writeCmdData(1) # type 1 user output elif choice == 3: - writeCmdData(cmdBuffer, 2) # type 2 errors + writeCmdData(2) # type 2 errors elif choice == 4: - writeCmdData(cmdBuffer, 3) # All + writeCmdData(3) # All elif choice == 6: - insertCmdData(cmdBuffer) # Insert text from Blender and run it. + insertCmdData() # Insert text from Blender and run it. elif choice == 8: # Fontsize. font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny') @@ -465,8 +478,10 @@ def handle_event(evt, val): elif font_choice == 4: __FONT_SIZE__ = 0 Draw.Redraw() - - elif choice == 10: # Exit + 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() @@ -777,7 +792,6 @@ __CONSOLE_VAR_DICT__ = {} # Initialize var dict # Print Startup lines, add __bpydoc__ to the console startup. -cmdBuffer = [] for l in __bpydoc__.split('<br>'): cmdBuffer.append( cmdLine(l, 1, None) ) @@ -821,12 +835,19 @@ def include_console(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__)) - exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy')) + # 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 diff --git a/release/scripts/envelope_symmetry.py b/release/scripts/envelope_symmetry.py index 935dae9aabe..a52e622a65b 100644 --- a/release/scripts/envelope_symmetry.py +++ b/release/scripts/envelope_symmetry.py @@ -8,7 +8,7 @@ Tooltip: 'Make envelope symetrical' """ __author__ = "Jonas Petersen" -__url__ = ("blender", "elysiun", "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 ") +__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 diff --git a/release/scripts/export_cal3d.py b/release/scripts/export_cal3d.py deleted file mode 100644 index 990ac480e3d..00000000000 --- a/release/scripts/export_cal3d.py +++ /dev/null @@ -1,1112 +0,0 @@ -#!BPY -""" -Name: 'Cal3D (.cfg .xaf .xsf .xmf .xrf)...' -Blender: 243 -Group: 'Export' -Tip: 'Export armature/bone/mesh/action data to the Cal3D format.' -""" - -# export_cal3d.py -# Copyright (C) 2003-2004 Jean-Baptiste LAMY -- jibalamy@free.fr -# Copyright (C) 2004 Matthias Braun -- matze@braunis.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 - - -__version__ = '0.9f' -__author__ = 'Jean-Baptiste, Jiba, Lamy, Campbell Barton (Ideasman42)' -__email__ = ['Authors email, jibalamy:free*fr'] -__url__ = ['Soya3ds homepage, http://home.gna.org/oomadness/en/soya/', 'Cal3d, http://cal3d.sourceforge.net'] -__bpydoc__ =\ -'''This script is a Blender => Cal3D converter. -(See http://blender.org and http://cal3d.sourceforge.net) - -USAGE: - -To install it, place the script in your $HOME/.blender/scripts directory. - -Then open the File->Export->Cal3d v0.9 menu. And select the filename of the .cfg file. -The exporter will create a set of other files with same prefix (ie. bla.cfg, bla.xsf, -bla_Action1.xaf, bla_Action2.xaf, ...). - -You should be able to open the .cfg file in cal3d_miniviewer. - - -NOT (YET) SUPPORTED: - - - Rotation, translation, or stretching Blender objects is still quite -buggy, so AVOID MOVING / ROTATING / RESIZE OBJECTS (either mesh or armature) ! -Instead, edit the object (with tab), select all points / bones (with "a"), -and move / rotate / resize them.<br> - - no support for exporting springs yet<br> - - no support for exporting material colors (most games should only use images -I think...) - - -KNOWN ISSUES: - - - Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone -is not animated;<br> - - Cal3D versions <=0.9.1 have a bug where objects that aren't influenced by any bones -are not drawn (fixed in Cal3D CVS). - - -NOTES: - -It requires a very recent version of Blender (>= 2.44). - -Build a model following a few rules:<br> - - Use only a single armature;<br> - - Use only a single rootbone (Cal3D doesn't support floating bones);<br> - - Use only locrot keys (Cal3D doesn't support bone's size change);<br> - - Don't try to create child/parent constructs in blender object, that gets exported -incorrectly at the moment;<br> - - Objects or animations whose names start by "_" are not exported (hidden object). - -You can pass as many parameters as you want at the end, "EXPORT_FOR_SOYA=1" is just an -example. The parameters are the same as below. -''' - -# True (=1) to export for the Soya 3D engine -# (http://oomadness.tuxfamily.org/en/soya). -# (=> rotate meshes and skeletons so as X is right, Y is top and -Z is front) -# EXPORT_FOR_SOYA = 0 - -# Enables LODs computation. LODs computation is quite slow, and the algo is -# surely not optimal :-( -LODS = 0 - -# Scale the model (not supported by Soya). - -# See also BASE_MATRIX below, if you want to rotate/scale/translate the model at -# the exportation. - -######################################################################################### -# Code starts here. -# The script should be quite re-useable for writing another Blender animation exporter. -# Most of the hell of it is to deal with Blender's head-tail-roll bone's definition. - -import math -import Blender -import BPyMesh -import BPySys -import BPyArmature -import BPyObject -import bpy - -def best_armature_root(armature): - ''' - Find the armature root bone with the most children, return that bone - ''' - - bones = [bone for bone in armature.bones.values() if bone.hasChildren() == True] - if len(bones) == 1: - return bones[0] - - # Get the best root since we have more then 1 - bones = [(len(bone.getAllChildren()), bone) for bone in bones] - bones.sort() - return bones[-1][1] # bone with most children - - -Vector = Blender.Mathutils.Vector -Quaternion = Blender.Mathutils.Quaternion -Matrix = Blender.Mathutils.Matrix - -# HACK -- it seems that some Blender versions don't define sys.argv, -# which may crash Python if a warning occurs. -# if not hasattr(sys, 'argv'): sys.argv = ['???'] - -def matrix_multiply(b, a): - return [ [ - a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0], - a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1], - a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2], - 0.0, - ], [ - a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0], - a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1], - a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2], - 0.0, - ], [ - a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0], - a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1], - a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2], - 0.0, - ], [ - a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + b[3][0], - a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + b[3][1], - a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + b[3][2], - 1.0, - ] ] - -# multiplies 2 quaternions in x,y,z,w notation -def quaternion_multiply(q1, q2): - return Quaternion(\ - q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1], - q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2], - q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0], - q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2],\ - ) - -def matrix_translate(m, v): - m[3][0] += v[0] - m[3][1] += v[1] - m[3][2] += v[2] - return m - -def matrix2quaternion(m): - s = math.sqrt(abs(m[0][0] + m[1][1] + m[2][2] + m[3][3])) - if s == 0.0: - x = abs(m[2][1] - m[1][2]) - y = abs(m[0][2] - m[2][0]) - z = abs(m[1][0] - m[0][1]) - if (x >= y) and (x >= z): return Quaternion(1.0, 0.0, 0.0, 0.0) - elif (y >= x) and (y >= z): return Quaternion(0.0, 1.0, 0.0, 0.0) - else: return Quaternion(0.0, 0.0, 1.0, 0.0) - - q = Quaternion([ - -(m[2][1] - m[1][2]) / (2.0 * s), - -(m[0][2] - m[2][0]) / (2.0 * s), - -(m[1][0] - m[0][1]) / (2.0 * s), - 0.5 * s, - ]) - q.normalize() - #print q - return q - -def vector_by_matrix_3x3(p, m): - return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0], - p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1], - p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2]] - -def vector_add(v1, v2): - return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]] - -def vector_sub(v1, v2): - return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]] - -def quaternion2matrix(q): - xx = q[0] * q[0] - yy = q[1] * q[1] - zz = q[2] * q[2] - xy = q[0] * q[1] - xz = q[0] * q[2] - yz = q[1] * q[2] - wx = q[3] * q[0] - wy = q[3] * q[1] - wz = q[3] * q[2] - return Matrix([1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0], - [ 2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0], - [ 2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0], - [0.0 , 0.0 , 0.0 , 1.0]) - -def matrix_invert(m): - det = (m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) - + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])) - if det == 0.0: return None - det = 1.0 / det - r = [ [ - det * (m[1][1] * m[2][2] - m[2][1] * m[1][2]), - - det * (m[0][1] * m[2][2] - m[2][1] * m[0][2]), - det * (m[0][1] * m[1][2] - m[1][1] * m[0][2]), - 0.0, - ], [ - - det * (m[1][0] * m[2][2] - m[2][0] * m[1][2]), - det * (m[0][0] * m[2][2] - m[2][0] * m[0][2]), - - det * (m[0][0] * m[1][2] - m[1][0] * m[0][2]), - 0.0 - ], [ - det * (m[1][0] * m[2][1] - m[2][0] * m[1][1]), - - det * (m[0][0] * m[2][1] - m[2][0] * m[0][1]), - det * (m[0][0] * m[1][1] - m[1][0] * m[0][1]), - 0.0, - ] ] - r.append([ - -(m[3][0] * r[0][0] + m[3][1] * r[1][0] + m[3][2] * r[2][0]), - -(m[3][0] * r[0][1] + m[3][1] * r[1][1] + m[3][2] * r[2][1]), - -(m[3][0] * r[0][2] + m[3][1] * r[1][2] + m[3][2] * r[2][2]), - 1.0, - ]) - return r - - -def point_by_matrix(p, m): - return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0], - p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1], - p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]] - -# Hack for having the model rotated right. -# Put in BASE_MATRIX your own rotation if you need some. - -BASE_MATRIX = None - - -# Cal3D data structures - -CAL3D_VERSION = 910 -MATERIALS = {} # keys are (mat.name, img.name) - -class Cal3DMaterial(object): - __slots__ = 'amb', 'diff', 'spec', 'shininess', 'maps_filenames', 'id' - def __init__(self, blend_world, blend_material, blend_images): - - # Material Settings - if blend_world: amb = [ int(c*255) for c in blend_world.amb ] - else: amb = [0,0,0] # Default value - - if blend_material: - self.amb = tuple([int(c*blend_material.amb) for c in amb] + [255]) - self.diff = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) - self.spec = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) - self.shininess = (float(blend_material.hard)-1)/5.10 - else: - self.amb = tuple(amb + [255]) - self.diff = (255,255,255,255) - self.spec = (255,255,255,255) - self.shininess = 1.0 - - self.maps_filenames = [] - for image in blend_images: - if image: - self.maps_filenames.append( image.filename.split('\\')[-1].split('/')[-1] ) - - self.id = len(MATERIALS) - MATERIALS[blend_material, blend_images] = self - - # new xml format - def writeCal3D(self, file): - file.write('<?xml version="1.0"?>\n') - file.write('<HEADER MAGIC="XRF" VERSION="%i"/>\n' % CAL3D_VERSION) - file.write('<MATERIAL NUMMAPS="%s">\n' % len(self.maps_filenames)) - file.write('\t<AMBIENT>%i %i %i %i</AMBIENT>\n' % self.amb) - file.write('\t<DIFFUSE>%i %i %i %i</DIFFUSE>\n' % self.diff) - file.write('\t<SPECULAR>%i %i %i %i</SPECULAR>\n' % self.spec) - file.write('\t<SHININESS>%.6f</SHININESS>\n' % self.shininess) - - for map_filename in self.maps_filenames: - file.write('\t<MAP>%s</MAP>\n' % map_filename) - - file.write('</MATERIAL>\n') - - -class Cal3DMesh(object): - __slots__ = 'name', 'submeshes', 'matrix', 'matrix_normal' - def __init__(self, ob, blend_mesh, blend_world): - self.name = ob.name - self.submeshes = [] - - BPyMesh.meshCalcNormals(blend_mesh) - - self.matrix = ob.matrixWorld - self.matrix_normal = self.matrix.copy().rotationPart() - - #if BASE_MATRIX: - # matrix = matrix_multiply(BASE_MATRIX, matrix) - - face_groups = {} - blend_materials = blend_mesh.materials - uvlayers = () - mat = None # incase we have no materials - if blend_mesh.faceUV: - uvlayers = blend_mesh.getUVLayerNames() - if len(uvlayers) == 1: - for f in blend_mesh.faces: - image = (f.image,) # bit in a tuple so we can match multi UV code - if blend_materials: mat = blend_materials[f.mat] # if no materials, mat will always be None - face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) - else: - # Multi UV's - face_multi_images = [[] for i in xrange(len(blend_mesh.faces))] - face_multi_uvs = [[[] for i in xrange(len(f)) ] for f in blend_mesh.faces] - for uvlayer in uvlayers: - blend_mesh.activeUVLayer = uvlayer - for i, f in enumerate(blend_mesh.faces): - face_multi_images[i].append(f.image) - if f.image: - for j, uv in enumerate(f.uv): - face_multi_uvs[i][j].append( tuple(uv) ) - - # Convert UV's to tuples so they can be compared with eachother - # when creating new verts - for fuv in face_multi_uvs: - for i, uv in enumerate(fuv): - fuv[i] = tuple(uv) - - for i, f in enumerate(blend_mesh.faces): - image = tuple(face_multi_images[i]) - if blend_materials: mat = blend_materials[f.mat] - face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) - else: - # No UV's - for f in blend_mesh.faces: - if blend_materials: mat = blend_materials[f.mat] - face_groups.setdefault( (mat,()), (mat,(),[]) )[2].append( f ) - - for blend_material, blend_images, faces in face_groups.itervalues(): - - try: material = MATERIALS[blend_material, blend_images] - except: material = MATERIALS[blend_material, blend_images] = Cal3DMaterial(blend_world, blend_material, blend_images) - - submesh = Cal3DSubMesh(self, material, len(self.submeshes)) - self.submeshes.append(submesh) - - # Check weather we need to write UVs, dont do it if theres no image - # Multilayer UV's have alredy checked that they have images when - # building face_multi_uvs - if len(uvlayers) == 1: - if blend_images == (None,): - write_single_layer_uvs = False - else: - write_single_layer_uvs = True - - - for face in faces: - - if not face.smooth: - normal = face.no - - face_vertices = [] - face_v = face.v - - - if len(uvlayers)>1: - for i, blend_vert in enumerate(face_v): - if face.smooth: normal = blend_vert.no - vertex = submesh.getVertex(blend_mesh, blend_vert, normal, face_multi_uvs[face.index][i]) - face_vertices.append(vertex) - - elif len(uvlayers)==1: - if write_single_layer_uvs: - face_uv = face.uv - - for i, blend_vert in enumerate(face_v): - if face.smooth: normal = blend_vert.no - if write_single_layer_uvs: uvs = (tuple(face_uv[i]),) - else: uvs = () - - vertex = submesh.getVertex(blend_mesh, blend_vert, normal, uvs ) - face_vertices.append(vertex) - else: - # No UVs - for i, blend_vert in enumerate(face_v): - if face.smooth: normal = blend_vert.no - vertex = submesh.getVertex(blend_mesh, blend_vert, normal, () ) - face_vertices.append(vertex) - - - # Split faces with more than 3 vertices - for i in xrange(1, len(face) - 1): - submesh.faces.append(Cal3DFace(face_vertices[0], face_vertices[i], face_vertices[i + 1])) - - def writeCal3D(self, file): - file.write('<?xml version="1.0"?>\n') - file.write('<HEADER MAGIC="XMF" VERSION="%i"/>\n' % CAL3D_VERSION) - file.write('<MESH NUMSUBMESH="%i">\n' % len(self.submeshes)) - for submesh in self.submeshes: - submesh.writeCal3D(file, self.matrix, self.matrix_normal) - file.write('</MESH>\n') - - -class Cal3DSubMesh(object): - __slots__ = 'material', 'vertices', 'vert_mapping', 'vert_count', 'faces', 'nb_lodsteps', 'springs', 'id' - def __init__(self, mesh, material, id): - self.material = material - self.vertices = [] - self.vert_mapping = {} # map original indicies to local - self.vert_count = 0 - self.faces = [] - self.nb_lodsteps = 0 - self.springs = [] - self.id = id - - def getVertex(self, blend_mesh, blend_vert, normal, maps): - ''' - Request a vertex, and create a new one or return a matching vertex - ''' - blend_index = blend_vert.index - index_map = self.vert_mapping.get(blend_index) - - if index_map == None: - vertex = Cal3DVertex(blend_vert.co, normal, maps, blend_mesh.getVertexInfluences(blend_index)) - self.vertices.append([vertex]) - self.vert_mapping[blend_index] = len(self.vert_mapping) - self.vert_count +=1 - return vertex - else: - vertex_list = self.vertices[index_map] - - for v in vertex_list: - if v.normal == normal and\ - v.maps == maps: - return v # reusing - - # No match, add a new vert - # Use the first verts influences - vertex = Cal3DVertex(blend_vert.co, normal, maps, vertex_list[0].influences) - vertex_list.append(vertex) - # self.vert_mapping[blend_index] = len(self.vert_mapping) - self.vert_count +=1 - return vertex - - - def compute_lods(self): - '''Computes LODs info for Cal3D (there's no Blender related stuff here).''' - - print 'Start LODs computation...' - vertex2faces = {} - for face in self.faces: - for vertex in (face.vertex1, face.vertex2, face.vertex3): - l = vertex2faces.get(vertex) - if not l: vertex2faces[vertex] = [face] - else: l.append(face) - - couple_treated = {} - couple_collapse_factor = [] - for face in self.faces: - for a, b in ((face.vertex1, face.vertex2), (face.vertex1, face.vertex3), (face.vertex2, face.vertex3)): - a = a.cloned_from or a - b = b.cloned_from or b - if a.id > b.id: a, b = b, a - if not couple_treated.has_key((a, b)): - # The collapse factor is simply the distance between the 2 points :-( - # This should be improved !! - if vector_dotproduct(a.normal, b.normal) < 0.9: continue - couple_collapse_factor.append((point_distance(a.loc, b.loc), a, b)) - couple_treated[a, b] = 1 - - couple_collapse_factor.sort() - - collapsed = {} - new_vertices = [] - new_faces = [] - for factor, v1, v2 in couple_collapse_factor: - # Determines if v1 collapses to v2 or v2 to v1. - # We choose to keep the vertex which is on the smaller number of faces, since - # this one has more chance of being in an extrimity of the body. - # Though heuristic, this rule yields very good results in practice. - if len(vertex2faces[v1]) < len(vertex2faces[v2]): v2, v1 = v1, v2 - elif len(vertex2faces[v1]) == len(vertex2faces[v2]): - if collapsed.get(v1, 0): v2, v1 = v1, v2 # v1 already collapsed, try v2 - - if (not collapsed.get(v1, 0)) and (not collapsed.get(v2, 0)): - collapsed[v1] = 1 - collapsed[v2] = 1 - - # Check if v2 is already colapsed - while v2.collapse_to: v2 = v2.collapse_to - - common_faces = filter(vertex2faces[v1].__contains__, vertex2faces[v2]) - - v1.collapse_to = v2 - v1.face_collapse_count = len(common_faces) - - for clone in v1.clones: - # Find the clone of v2 that correspond to this clone of v1 - possibles = [] - for face in vertex2faces[clone]: - possibles.append(face.vertex1) - possibles.append(face.vertex2) - possibles.append(face.vertex3) - clone.collapse_to = v2 - for vertex in v2.clones: - if vertex in possibles: - clone.collapse_to = vertex - break - - clone.face_collapse_count = 0 - new_vertices.append(clone) - - # HACK -- all faces get collapsed with v1 (and no faces are collapsed with v1's - # clones). This is why we add v1 in new_vertices after v1's clones. - # This hack has no other incidence that consuming a little few memory for the - # extra faces if some v1's clone are collapsed but v1 is not. - new_vertices.append(v1) - - self.nb_lodsteps += 1 + len(v1.clones) - - new_faces.extend(common_faces) - for face in common_faces: - face.can_collapse = 1 - - # Updates vertex2faces - vertex2faces[face.vertex1].remove(face) - vertex2faces[face.vertex2].remove(face) - vertex2faces[face.vertex3].remove(face) - vertex2faces[v2].extend(vertex2faces[v1]) - - new_vertices.extend(filter(lambda vertex: not vertex.collapse_to, self.vertices)) - new_vertices.reverse() # Cal3D want LODed vertices at the end - for i in xrange(len(new_vertices)): new_vertices[i].id = i - self.vertices = new_vertices - - new_faces.extend(filter(lambda face: not face.can_collapse, self.faces)) - new_faces.reverse() # Cal3D want LODed faces at the end - self.faces = new_faces - - print 'LODs computed : %s vertices can be removed (from a total of %s).' % (self.nb_lodsteps, len(self.vertices)) - - - def writeCal3D(self, file, matrix, matrix_normal): - - file.write('\t<SUBMESH NUMVERTICES="%i" NUMFACES="%i" MATERIAL="%i" ' % \ - (self.vert_count, len(self.faces), self.material.id)) - file.write('NUMLODSTEPS="%i" NUMSPRINGS="%i" NUMTEXCOORDS="%i">\n' % \ - (self.nb_lodsteps, len(self.springs), - len(self.material.maps_filenames))) - - i = 0 - for v in self.vertices: - for item in v: - item.id = i - item.writeCal3D(file, matrix, matrix_normal) - i += 1 - - for item in self.springs: - item.writeCal3D(file) - for item in self.faces: - item.writeCal3D(file) - - file.write('\t</SUBMESH>\n') - -class Cal3DVertex(object): - __slots__ = 'loc','normal','collapse_to','face_collapse_count','maps','influences','weight','cloned_from','clones','id' - def __init__(self, loc, normal, maps, blend_influences): - self.loc = loc - self.normal = normal - self.collapse_to = None - self.face_collapse_count = 0 - self.maps = maps - self.weight = None - - self.cloned_from = None - self.clones = [] - - self.id = -1 - - if len(blend_influences) == 0 or isinstance(blend_influences[0], Cal3DInfluence): - # This is a copy from another vert - self.influences = blend_influences - else: - # Pass the blender influences - - self.influences = [] - # should this really be a warning? (well currently enabled, - # because blender has some bugs where it doesn't return - # influences in python api though they are set, and because - # cal3d<=0.9.1 had bugs where objects without influences - # aren't drawn. - #if not blend_influences: - # print 'A vertex of object "%s" has no influences.\n(This occurs on objects placed in an invisible layer, you can fix it by using a single layer)' % ob.name - - # sum of influences is not always 1.0 in Blender ?!?! - sum = 0.0 - - for bone_name, weight in blend_influences: - sum += weight - - for bone_name, weight in blend_influences: - bone = BONES.get(bone_name) - if not bone: # keys - # print 'Couldnt find bone "%s" which influences object "%s"' % (bone_name, ob.name) - continue - - if weight: - self.influences.append(Cal3DInfluence(bone, weight / sum)) - - - def writeCal3D(self, file, matrix, matrix_normal): - if self.collapse_to: - collapse_id = self.collapse_to.id - else: - collapse_id = -1 - file.write('\t\t<VERTEX ID="%i" NUMINFLUENCES="%i">\n' % \ - (self.id, len(self.influences))) - file.write('\t\t\t<POS>%.6f %.6f %.6f</POS>\n' % tuple(self.loc*matrix)) - file.write('\t\t\t<NORM>%.6f %.6f %.6f</NORM>\n' % tuple( (self.normal*matrix_normal).normalize() )) - if collapse_id != -1: - file.write('\t\t\t<COLLAPSEID>%i</COLLAPSEID>\n' % collapse_id) - file.write('\t\t\t<COLLAPSECOUNT>%i</COLLAPSECOUNT>\n' % \ - self.face_collapse_count) - - for uv in self.maps: - # we cant have more UV's then our materials image maps - # check for this - file.write('\t\t\t<TEXCOORD>%.6f %.6f</TEXCOORD>\n' % uv) - - for item in self.influences: - item.writeCal3D(file) - - if self.weight != None: - file.write('\t\t\t<PHYSIQUE>%.6f</PHYSIQUE>\n' % len(self.weight)) - file.write('\t\t</VERTEX>\n') - -class Cal3DInfluence(object): - __slots__ = 'bone', 'weight' - def __init__(self, bone, weight): - self.bone = bone - self.weight = weight - - def writeCal3D(self, file): - file.write('\t\t\t<INFLUENCE ID="%i">%.6f</INFLUENCE>\n' % \ - (self.bone.id, self.weight)) - -class Cal3DSpring(object): - __slots__ = 'vertex1', 'vertex2', 'spring_coefficient', 'idlelength' - def __init__(self, vertex1, vertex2): - self.vertex1 = vertex1 - self.vertex2 = vertex2 - self.spring_coefficient = 0.0 - self.idlelength = 0.0 - - def writeCal3D(self, file): - file.write('\t\t<SPRING VERTEXID="%i %i" COEF="%.6f" LENGTH="%.6f"/>\n' % \ - (self.vertex1.id, self.vertex2.id, self.spring_coefficient, self.idlelength)) - -class Cal3DFace(object): - __slots__ = 'vertex1', 'vertex2', 'vertex3', 'can_collapse', - def __init__(self, vertex1, vertex2, vertex3): - self.vertex1 = vertex1 - self.vertex2 = vertex2 - self.vertex3 = vertex3 - self.can_collapse = 0 - - def writeCal3D(self, file): - file.write('\t\t<FACE VERTEXID="%i %i %i"/>\n' % \ - (self.vertex1.id, self.vertex2.id, self.vertex3.id)) - -class Cal3DSkeleton(object): - __slots__ = 'bones' - def __init__(self): - self.bones = [] - - def writeCal3D(self, file): - file.write('<?xml version="1.0"?>\n') - file.write('<HEADER MAGIC="XSF" VERSION="%i"/>\n' % CAL3D_VERSION) - file.write('<SKELETON NUMBONES="%i">\n' % len(self.bones)) - for item in self.bones: - item.writeCal3D(file) - - file.write('</SKELETON>\n') - -BONES = {} -POSEBONES= {} -class Cal3DBone(object): - __slots__ = 'head', 'tail', 'name', 'cal3d_parent', 'loc', 'quat', 'children', 'matrix', 'lloc', 'lquat', 'id' - def __init__(self, skeleton, blend_bone, arm_matrix, cal3d_parent=None): - - # def treat_bone(b, parent = None): - head = blend_bone.head['BONESPACE'] - tail = blend_bone.tail['BONESPACE'] - #print parent.quat - # Turns the Blender's head-tail-roll notation into a quaternion - #quat = matrix2quaternion(blender_bone2matrix(head, tail, blend_bone.roll['BONESPACE'])) - quat = matrix2quaternion(blend_bone.matrix['BONESPACE'].copy().resize4x4()) - - # Pose location - ploc = POSEBONES[blend_bone.name].loc - - if cal3d_parent: - # Compute the translation from the parent bone's head to the child - # bone's head, in the parent bone coordinate system. - # The translation is parent_tail - parent_head + child_head, - # but parent_tail and parent_head must be converted from the parent's parent - # system coordinate into the parent system coordinate. - - parent_invert_transform = matrix_invert(quaternion2matrix(cal3d_parent.quat)) - parent_head = vector_by_matrix_3x3(cal3d_parent.head, parent_invert_transform) - parent_tail = vector_by_matrix_3x3(cal3d_parent.tail, parent_invert_transform) - ploc = vector_add(ploc, blend_bone.head['BONESPACE']) - - # EDIT!!! FIX BONE OFFSET BE CAREFULL OF THIS PART!!! ?? - #diff = vector_by_matrix_3x3(head, parent_invert_transform) - parent_tail= vector_add(parent_tail, head) - # DONE!!! - - parentheadtotail = vector_sub(parent_tail, parent_head) - # hmm this should be handled by the IPos, but isn't for non-animated - # bones which are transformed in the pose mode... - loc = parentheadtotail - - else: - # Apply the armature's matrix to the root bones - head = point_by_matrix(head, arm_matrix) - tail = point_by_matrix(tail, arm_matrix) - - loc = head - quat = matrix2quaternion(matrix_multiply(arm_matrix, quaternion2matrix(quat))) # Probably not optimal - - self.head = head - self.tail = tail - - self.cal3d_parent = cal3d_parent - self.name = blend_bone.name - self.loc = loc - self.quat = quat - self.children = [] - - self.matrix = matrix_translate(quaternion2matrix(quat), loc) - if cal3d_parent: - self.matrix = matrix_multiply(cal3d_parent.matrix, self.matrix) - - # lloc and lquat are the bone => model space transformation (translation and rotation). - # They are probably specific to Cal3D. - m = matrix_invert(self.matrix) - self.lloc = m[3][0], m[3][1], m[3][2] - self.lquat = matrix2quaternion(m) - - self.id = len(skeleton.bones) - skeleton.bones.append(self) - BONES[self.name] = self - - if not blend_bone.hasChildren(): return - for blend_child in blend_bone.children: - self.children.append(Cal3DBone(skeleton, blend_child, arm_matrix, self)) - - - def writeCal3D(self, file): - file.write('\t<BONE ID="%i" NAME="%s" NUMCHILD="%i">\n' % \ - (self.id, self.name, len(self.children))) - # We need to negate quaternion W value, but why ? - file.write('\t\t<TRANSLATION>%.6f %.6f %.6f</TRANSLATION>\n' % \ - (self.loc[0], self.loc[1], self.loc[2])) - file.write('\t\t<ROTATION>%.6f %.6f %.6f %.6f</ROTATION>\n' % \ - (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) - file.write('\t\t<LOCALTRANSLATION>%.6f %.6f %.6f</LOCALTRANSLATION>\n' % \ - (self.lloc[0], self.lloc[1], self.lloc[2])) - file.write('\t\t<LOCALROTATION>%.6f %.6f %.6f %.6f</LOCALROTATION>\n' % \ - (self.lquat[0], self.lquat[1], self.lquat[2], -self.lquat[3])) - if self.cal3d_parent: - file.write('\t\t<PARENTID>%i</PARENTID>\n' % self.cal3d_parent.id) - else: - file.write('\t\t<PARENTID>%i</PARENTID>\n' % -1) - - for item in self.children: - file.write('\t\t<CHILDID>%i</CHILDID>\n' % item.id) - - file.write('\t</BONE>\n') - -class Cal3DAnimation: - def __init__(self, name, duration = 0.0): - self.name = name - self.duration = duration - self.tracks = {} # Map bone names to tracks - - def writeCal3D(self, file): - file.write('<?xml version="1.0"?>\n') - file.write('<HEADER MAGIC="XAF" VERSION="%i"/>\n' % CAL3D_VERSION) - file.write('<ANIMATION DURATION="%.6f" NUMTRACKS="%i">\n' % \ - (self.duration, len(self.tracks))) - - for item in self.tracks.itervalues(): - item.writeCal3D(file) - - file.write('</ANIMATION>\n') - -class Cal3DTrack(object): - __slots__ = 'bone', 'keyframes' - def __init__(self, bone): - self.bone = bone - self.keyframes = [] - - def writeCal3D(self, file): - file.write('\t<TRACK BONEID="%i" NUMKEYFRAMES="%i">\n' % - (self.bone.id, len(self.keyframes))) - for item in self.keyframes: - item.writeCal3D(file) - file.write('\t</TRACK>\n') - -class Cal3DKeyFrame(object): - __slots__ = 'time', 'loc', 'quat' - def __init__(self, time, loc, quat): - self.time = time - self.loc = loc - self.quat = quat - - def writeCal3D(self, file): - file.write('\t\t<KEYFRAME TIME="%.6f">\n' % self.time) - file.write('\t\t\t<TRANSLATION>%.6f %.6f %.6f</TRANSLATION>\n' % \ - (self.loc[0], self.loc[1], self.loc[2])) - # We need to negate quaternion W value, but why ? - file.write('\t\t\t<ROTATION>%.6f %.6f %.6f %.6f</ROTATION>\n' % \ - (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) - file.write('\t\t</KEYFRAME>\n') - -def export_cal3d(filename, PREF_SCALE=0.1, PREF_BAKE_MOTION = True, PREF_ACT_ACTION_ONLY=True, PREF_SCENE_FRAMES=False): - if not filename.endswith('.cfg'): - filename += '.cfg' - - file_only = filename.split('/')[-1].split('\\')[-1] - file_only_noext = file_only.split('.')[0] - base_only = filename[:-len(file_only)] - - def new_name(dataname, ext): - return file_only_noext + '_' + BPySys.cleanName(dataname) + ext - - #if EXPORT_FOR_SOYA: - # global BASE_MATRIX - # BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0) - # Get the sce - - sce = bpy.data.scenes.active - blend_world = sce.world - # ---- Export skeleton (armature) ---------------------------------------- - - skeleton = Cal3DSkeleton() - blender_armature = [ob for ob in sce.objects.context if ob.type == 'Armature'] - if len(blender_armature) > 1: print "Found multiple armatures! using ",armatures[0].name - if blender_armature: blender_armature = blender_armature[0] - else: - # Try find a meshes armature - for ob in sce.objects.context: - blender_armature = BPyObject.getObjectArmature(ob) - if blender_armature: - break - - if not blender_armature: - Blender.Draw.PupMenu('Aborting%t|No Armature in selection') - return - - # we need pose bone locations - for pbone in blender_armature.getPose().bones.values(): - POSEBONES[pbone.name] = pbone - - Cal3DBone(skeleton, best_armature_root(blender_armature.getData()), blender_armature.matrixWorld) - - # ---- Export Mesh data --------------------------------------------------- - meshes = [] - for ob in sce.objects.context: - if ob.type != 'Mesh': continue - blend_mesh = ob.getData(mesh=1) - - if not blend_mesh.faces: continue - meshes.append( Cal3DMesh(ob, blend_mesh, blend_world) ) - - # ---- Export animations -------------------------------------------------- - backup_action = blender_armature.action - - ANIMATIONS = [] - SUPPORTED_IPOS = 'QuatW', 'QuatX', 'QuatY', 'QuatZ', 'LocX', 'LocY', 'LocZ' - - if PREF_ACT_ACTION_ONLY: action_items = [(blender_armature.action.name, blender_armature.action)] - else: action_items = Blender.Armature.NLA.GetActions().items() - - print len(action_items), 'action_items' - - for animation_name, blend_action in action_items: - - # get frame range - if PREF_SCENE_FRAMES: - action_start= Blender.Get('staframe') - action_end= Blender.Get('endframe') - else: - _frames = blend_action.getFrameNumbers() - action_start= min(_frames); - action_end= max(_frames); - del _frames - - blender_armature.action = blend_action - - if PREF_BAKE_MOTION: - # We need to set the action active if we are getting baked data - pose_data = BPyArmature.getBakedPoseData(blender_armature, action_start, action_end) - - # Fake, all we need is bone names - blend_action_ipos_items = [(pbone, True) for pbone in POSEBONES.iterkeys()] - else: - # real (bone_name, ipo) pairs - blend_action_ipos_items = blend_action.getAllChannelIpos().items() - - # Now we mau have some bones with no channels, easiest to add their names and an empty list here - # this way they are exported with dummy keyfraames at teh first used frame - action_bone_names = [name for name, ipo in blend_action_ipos_items] - for bone_name in BONES: # iterkeys - if bone_name not in action_bone_names: - blend_action_ipos_items.append( (bone_name, []) ) - - animation = Cal3DAnimation(animation_name) - # ---------------------------- - ANIMATIONS.append(animation) - animation.duration = 0.0 - - for bone_name, ipo in blend_action_ipos_items: - # Baked bones may have no IPO's width motion still - if bone_name not in BONES: - print '\tNo Bone "' + bone_name + '" in (from Animation "' + animation_name + '") ?!?' - continue - - # So we can loop without errors - if ipo==None: ipo = [] - - bone = BONES[bone_name] - track = animation.tracks[bone_name] = Cal3DTrack(bone) - - if PREF_BAKE_MOTION: - for i in xrange(action_end - action_start): - cal3dtime = i / 25.0 # assume 25FPS by default - - if cal3dtime > animation.duration: - animation.duration = cal3dtime - - #print pose_data[i][bone_name], i - loc, quat = pose_data[i][bone_name] - - loc = vector_by_matrix_3x3(loc, bone.matrix) - loc = vector_add(bone.loc, loc) - quat = quaternion_multiply(quat, bone.quat) - quat = Quaternion(quat) - - quat.normalize() - quat = tuple(quat) - - track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) - - else: - #run 1: we need to find all time values where we need to produce keyframes - times = set() - for curve in ipo: - curve_name = curve.name - if curve_name in SUPPORTED_IPOS: - for p in curve.bezierPoints: - times.add( p.pt[0] ) - - times = list(times) - times.sort() - - # Incase we have no keys here or ipo==None - if not times: times.append(action_start) - - # run2: now create keyframes - for time in times: - cal3dtime = (time-1) / 25.0 # assume 25FPS by default - if cal3dtime > animation.duration: - animation.duration = cal3dtime - - trans = Vector() - quat = Quaternion() - - for curve in ipo: - val = curve.evaluate(time) - # val = 0.0 - curve_name= curve.name - if curve_name == 'LocX': trans[0] = val - elif curve_name == 'LocY': trans[1] = val - elif curve_name == 'LocZ': trans[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 - - transt = vector_by_matrix_3x3(trans, bone.matrix) - loc = vector_add(bone.loc, transt) - quat = quaternion_multiply(quat, bone.quat) - quat = Quaternion(quat) - - quat.normalize() - quat = tuple(quat) - - track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) - - - if animation.duration <= 0: - print 'Ignoring Animation "' + animation_name + '": duration is 0.\n' - continue - - # Restore the original armature - blender_armature.action = backup_action - # ------------------------------------- End Animation - - - - cfg = open((filename), 'wb') - cfg.write('# Cal3D model exported from Blender with export_cal3d.py\n# from %s\n' % Blender.Get('filename')) - - if PREF_SCALE != 1.0: cfg.write('scale=%.6f\n' % PREF_SCALE) - - fname = file_only_noext + '.xsf' - file = open( base_only + fname, 'wb') - skeleton.writeCal3D(file) - file.close() - - cfg.write('skeleton=%s\n' % fname) - - for animation in ANIMATIONS: - if not animation.name.startswith('_'): - if animation.duration > 0.1: # Cal3D does not support animation with only one state - fname = new_name(animation.name, '.xaf') - file = open(base_only + fname, 'wb') - animation.writeCal3D(file) - file.close() - cfg.write('animation=%s\n' % fname) - - for mesh in meshes: - if not mesh.name.startswith('_'): - fname = new_name(mesh.name, '.xmf') - file = open(base_only + fname, 'wb') - mesh.writeCal3D(file) - file.close() - - cfg.write('mesh=%s\n' % fname) - - materials = MATERIALS.values() - materials.sort(key = lambda a: a.id) - for material in materials: - # Just number materials, its less trouble - fname = new_name(str(material.id), '.xrf') - - file = open(base_only + fname, 'wb') - material.writeCal3D(file) - file.close() - - cfg.write('material=%s\n' % fname) - - print 'Cal3D Saved to "%s.cfg"' % file_only_noext - - # Warnings - if len(animation.tracks) < 2: - Blender.Draw.PupMenu('Warning, the armature has less then 2 tracks, file may not load in Cal3d') - - -def export_cal3d_ui(filename): - - PREF_SCALE= Blender.Draw.Create(1.0) - PREF_BAKE_MOTION = Blender.Draw.Create(1) - PREF_ACT_ACTION_ONLY= Blender.Draw.Create(1) - PREF_SCENE_FRAMES= Blender.Draw.Create(0) - - block = [\ - ('Scale: ', PREF_SCALE, 0.01, 100, 'The scale to set in the Cal3d .cfg file (unsupported by soya)'),\ - ('Baked Motion', PREF_BAKE_MOTION, 'use final pose position instead of ipo keyframes (IK and constraint support)'),\ - ('Active Action', PREF_ACT_ACTION_ONLY, 'Only export action applied to this armature, else export all actions.'),\ - ('Scene Frames', PREF_SCENE_FRAMES, 'Use scene frame range, else the actions start/end'),\ - ] - - if not Blender.Draw.PupBlock('Cal3D Options', block): - return - - Blender.Window.WaitCursor(1) - export_cal3d(filename, 1.0/PREF_SCALE.val, PREF_BAKE_MOTION.val, PREF_ACT_ACTION_ONLY.val, PREF_SCENE_FRAMES.val) - Blender.Window.WaitCursor(0) - - -#import os -if __name__ == '__main__': - Blender.Window.FileSelector(export_cal3d_ui, 'Cal3D Export', Blender.Get('filename').replace('.blend', '.cfg')) - #export_cal3d('/cally/data/skeleton/skeleton' + '.cfg', 1.0, True, False, False) - #export_cal3d('/test' + '.cfg') - #export_cal3d_ui('/test' + '.cfg') - #os.system('cd /; wine /cal3d_miniviewer.exe /skeleton.cfg') - #os.system('cd /cally/;wine cally') diff --git a/release/scripts/export_dxf.py b/release/scripts/export_dxf.py new file mode 100644 index 00000000000..061e29b81c7 --- /dev/null +++ b/release/scripts/export_dxf.py @@ -0,0 +1,407 @@ +#!BPY + +""" + Name: 'Autodesk DXF (.dxf)' + Blender: 247 + Group: 'Export' + Tooltip: 'Export geometry to DXF-r12 (Drawing eXchange Format).' +""" + +__version__ = "v1.27beta - 2008.10.07" +__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 + +See the homepage for documentation. +url: %s + +IDEAs: + - correct normals for POLYLINE-POLYFACE via proper point-order + - HPGL output for 2d and flattened 3d content + +TODO: +- optimize back-faces removal (probably needs matrix transform) +- optimize POLYFACE routine: remove double-vertices +- optimize POLYFACE routine: remove unused vertices +- support hierarchies: groups, instances, parented structures +- support 210-code (3d orientation vector) +- presets for architectural scales +- write drawing extends for automatic view positioning in CAD + +History +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, sys, Draw +import BPyMessages + +#import dxfLibrary +#reload(dxfLibrary) +from dxfLibrary import * + + +#----------------------------------------------------- +def hidden_status(faces, mx_n): + #print 'HIDDEN_MODE: caution! not full implemented yet' + ok_faces = [] + ok_edges = [] + #sort out back-faces = with normals pointed away from camera + for f in faces: + #print 'deb: face=', 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' #------------------ + + # normal must point the Z direction-hemisphere + if vec_normal[2] > 0.0 : + ok_faces.append(f.index) + for key in f.edge_keys: + #this test can be done faster with set() + if key not in ok_edges: + ok_edges.append(key) + #print 'deb: amount of visible faces=', len(ok_faces) #--------- + #print 'deb: visible faces=', ok_faces #--------- + #print 'deb: amount of visible edges=', len(ok_edges) #--------- + #print 'deb: visible edges=', ok_edges #--------- + return ok_faces, ok_edges + + +#----------------------------------------------------- +def projected_co(vec, mw): + # convert the world coordinates of vector to screen coordinates + #co = vec.co.copy().resize4D() + co = vec.copy().resize4D() + co[3] = 1.0 + sc = co * mw + #print 'deb: viewprojection=', sc #--------- + return [sc[0],sc[1],0.0] + + +#--------not used--------------------------------------------- +def flatten(points, mw): + for i,v in enumerate(points): + v = projected_co(v, mw) + points[i]=v + #print 'deb: flatten points=', points #--------- + return points + +#----------------------------------------------------- +def exportMesh(ob, mx, mx_n): + entities = [] + me = ob.getData(mesh=1) + #me.transform(mx) + # above is eventualy faster, but bad, cause + # directly transforms origin geometry and write back rounding errors + me_verts = me.verts[:] #we dont want manipulate origin data + #print 'deb: me_verts=', me_verts #--------- + #me.transform(mx_inv) #counterpart to - back to the origin state + for v in me_verts: + v.co *= mx + faces=[] + edges=[] + if HIDDEN_MODE: + ok_faces, ok_edges = hidden_status(me.faces, mx_n) + + #if (not FLATTEN) and len(me.faces)>0 and ONLYFACES: + if ONLYFACES: + if POLYFACES: #export 3D as POLYFACEs + allpoints = [] + allfaces = [] + allpoints = [v.co[:3] for v in me_verts] + for f in me.faces: + #print 'deb: face=', f #--------- + if not HIDDEN_MODE or \ + (HIDDEN_MODE and f.index in ok_faces): + if 1: + points = f.verts + face = [p.index+1 for p in points] + #print 'deb: face=', face #--------- + allfaces.append(face) + else: #bad, cause create multiple vertex instances + points = f.verts + points = [ me_verts[p.index].co[:3] for p in points] + #points = [p.co[:3] for p in points] + #print 'deb: points=', points #--------- + index = len(allpoints)+1 + face = [index+i for i in range(len(points))] + allpoints.extend(points) + allfaces.append(face) + if allpoints and allfaces: + #print 'deb: allpoints=', allpoints #--------- + #print 'deb: allfaces=', allfaces #--------- + dxfPOLYFACE = PolyLine([allpoints, allfaces], flag=64) + entities.append(dxfPOLYFACE) + else: #export 3D as 3DFACEs + for f in me.faces: + #print 'deb: face=', f #--------- + if not HIDDEN_MODE or \ + (HIDDEN_MODE and f.index in ok_faces): + points = f.verts + points = [ me_verts[p.index].co[:3] for p in points] + #points = [p.co[:3] for p in points] + #print 'deb: points=', points #--------- + dxfFACE = Face(points) + entities.append(dxfFACE) + + else: #export 3D as LINEs + if HIDDEN_MODE and len(me.faces)!=0: + for e in ok_edges: + points = [ me_verts[key].co[:3] for key in e] + dxfLINE = Line(points) + entities.append(dxfLINE) + + else: + for e in me.edges: + #print 'deb: edge=', e #--------- + points=[] + #points = [e.v1.co*mx, e.v2.co*mx] + points = [ me_verts[key].co[:3] for key in e.key] + #print 'deb: points=', points #--------- + dxfLINE = Line(points) + entities.append(dxfLINE) + return entities + + +#----------------------------------------------------- +def exportCurve(ob, mx): + entities = [] + curve = ob.getData() + for cur in curve: + #print 'deb: START cur=', cur #-------------- + if 1: #not cur.isNurb(): + #print 'deb: START points' #-------------- + points = [] + org_point = [0.0,0.0,0.0] + for point in cur: + #print 'deb: point=', point #--------- + if cur.isNurb(): + vec = point[0:3] + else: + point = point.getTriple() + #print 'deb: point=', point #--------- + vec = point[1] + #print 'deb: vec=', vec #--------- + pkt = Mathutils.Vector(vec) * mx + #print 'deb: pkt=', pkt #--------- + #pkt *= SCALE_FACTOR + if 0: #FLATTEN: + pkt = projected_co(pkt, mw) + points.append(pkt) + if cur.isCyclic(): closed = 1 + else: closed = 0 + if len(points)>1: + #print 'deb: points', points #-------------- + if POLYLINES: dxfPLINE = PolyLine(points,org_point,closed) + else: dxfPLINE = LineList(points,org_point,closed) + entities.append(dxfPLINE) + return entities + +#----------------------------------------------------- +def do_export(sel_group, filepath): + Window.WaitCursor(1) + t = sys.time() + + #init Drawing --------------------- + d=Drawing() + #add 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 + + #add Entities -------------------- + something_ready = False + #ViewVector = Mathutils.Vector(Window.GetViewVector()) + #print 'deb: ViewVector=', ViewVector #------------------ + mw0 = Window.GetViewMatrix() + #mw0 = Window.GetPerspMatrix() #TODO: how get it working? + mw = mw0.copy() + if FLATTEN: + m0 = Mathutils.Matrix() + m0[2][2]=0.0 + mw *= m0 #flatten ViewMatrix + + for ob in sel_group: + entities = [] + mx = ob.matrix.copy() + mb = mx.copy() + #print 'deb: mb =\n', mb #--------- + #print 'deb: mw0 =\n', mw0 #--------- + mx_n = mx.rotationPart() * mw0.rotationPart() #trans-matrix for normal_vectors + if SCALE_FACTOR!=1.0: mx *= SCALE_FACTOR + if FLATTEN: mx *= mw + + #mx_inv = mx.copy().invert() + #print 'deb: mx =\n', mx #--------- + #print 'deb: mx_inv=\n', mx_inv #--------- + + if (ob.type == 'Mesh'): + entities = exportMesh(ob, mx, mx_n) + elif (ob.type == 'Curve'): + entities = exportCurve(ob, mx) + + for e in entities: + d.append(e) + something_ready = True + + if something_ready: + d.saveas(filepath) + Window.WaitCursor(0) + #Draw.PupMenu('DXF Exporter: job finished') + print 'exported to %s' % filepath + print 'finished in %.2f seconds' % (sys.time()-t) + else: + Window.WaitCursor(0) + print "Abort: selected objects dont mach choosen export option, nothing exported!" + Draw.PupMenu('DXF Exporter: nothing exported!|selected objects dont mach choosen export option!') + +#----globals------------------------------------------ +ONLYSELECTED = True +POLYLINES = True +ONLYFACES = False +POLYFACES = 1 +FLATTEN = 0 +HIDDEN_MODE = False #filter out hidden lines +SCALE_FACTOR = 1.0 #optional, can be done later in CAD too + + + +#----------------------------------------------------- +def dxf_export_ui(filepath): + global ONLYSELECTED,\ + POLYLINES,\ + ONLYFACES,\ + POLYFACES,\ + FLATTEN,\ + HIDDEN_MODE,\ + SCALE_FACTOR + + print '\n\nDXF-Export %s -----------------------' %__version__ + #filepath = 'blend_test.dxf' + # Dont overwrite + if not BPyMessages.Warning_SaveOver(filepath): + print 'Aborted by user: nothing exported' + return + #test():return + + + PREF_ONLYSELECTED= Draw.Create(ONLYSELECTED) + PREF_POLYLINES= Draw.Create(POLYLINES) + PREF_ONLYFACES= Draw.Create(ONLYFACES) + PREF_POLYFACES= Draw.Create(POLYFACES) + PREF_FLATTEN= Draw.Create(FLATTEN) + PREF_HIDDEN_MODE= Draw.Create(HIDDEN_MODE) + PREF_SCALE_FACTOR= Draw.Create(SCALE_FACTOR) + PREF_HELP= Draw.Create(0) + block = [\ + ("only selected", PREF_ONLYSELECTED, "export only selected geometry"),\ + ("global Scale:", PREF_SCALE_FACTOR, 0.001, 1000, "set global Scale factor for exporting geometry"),\ + ("only faces", PREF_ONLYFACES, "from mesh-objects export only faces, otherwise only edges"),\ + ("write POLYFACE", PREF_POLYFACES, "export mesh to POLYFACE, otherwise to 3DFACEs"),\ + ("write POLYLINEs", PREF_POLYLINES, "export curve to POLYLINE, otherwise to LINEs"),\ + ("3D-View to Flat", PREF_FLATTEN, "flatten geometry according current 3d-View"),\ + ("Hidden Mode", PREF_HIDDEN_MODE, "filter out hidden lines"),\ + #(''),\ + ("online Help", PREF_HELP, "calls DXF-Exporter Manual Page on Wiki.Blender.org"),\ + ] + + if not Draw.PupBlock("DXF-Exporter %s" %__version__[:10], block): return + + if PREF_HELP.val!=0: + try: + import webbrowser + webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf') + except: + Draw.PupMenu('DXF Exporter: %t|no connection to manual-page on Blender-Wiki! try:|\ +http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf') + return + + ONLYSELECTED = PREF_ONLYSELECTED.val + POLYLINES = PREF_POLYLINES.val + ONLYFACES = PREF_ONLYFACES.val + POLYFACES = PREF_POLYFACES.val + FLATTEN = PREF_FLATTEN.val + HIDDEN_MODE = PREF_HIDDEN_MODE.val + SCALE_FACTOR = PREF_SCALE_FACTOR.val + + sce = Scene.GetCurrent() + if ONLYSELECTED: sel_group = sce.objects.selected + else: sel_group = sce.objects + + if sel_group: do_export(sel_group, filepath) + else: + print "Abort: selection was empty, no object to export!" + Draw.PupMenu('DXF Exporter: nothing exported!|empty selection!') + # Timing the script is a good way to be aware on any speed hits when scripting + + + +#----------------------------------------------------- +if __name__=='__main__': + #main() + if not copy: + Draw.PupMenu('Error%t|This script requires a full python install') + Window.FileSelector(dxf_export_ui, 'EXPORT DXF', sys.makename(ext='.dxf')) + + +
\ No newline at end of file diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py index 99d036b38bc..3f02a71f951 100644 --- a/release/scripts/export_fbx.py +++ b/release/scripts/export_fbx.py @@ -1101,12 +1101,12 @@ def write(filename, batch_objects = None, \ 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_dif) + 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_emit) + 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)) @@ -2887,7 +2887,7 @@ def fbx_ui(): def write_ui(): # globals - GLOBALS['EVENT'] = 2 + GLOBALS['EVENT'] = EVENT_REDRAW #GLOBALS['MOUSE'] = Window.GetMouseCoords() GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] GLOBALS['FILENAME'] = '' @@ -2929,13 +2929,6 @@ def write_ui(): GLOBALS['_YROT90'] = Draw.Create(False) GLOBALS['_ZROT90'] = Draw.Create(False) - # horrible ugly hack so tooltips draw, dosnt always work even - # Fixed in Draw.UIBlock for 2.45rc2, but keep this until 2.45 is released - Window.SetKeyQualifiers(0) - while Window.GetMouseButtons(): Blender.sys.sleep(10) - for i in xrange(100): Window.QHandle(i) - # END HORRID HACK - # best not do move the cursor # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) @@ -2959,7 +2952,7 @@ def write_ui(): #fbx_ui_write('/test.fbx') break - Draw.UIBlock(fbx_ui) + Draw.UIBlock(fbx_ui, 0) # GLOBALS.clear() diff --git a/release/scripts/export_lightwave_motion.py b/release/scripts/export_lightwave_motion.py index cabc4cf5fc6..562e44f3a2b 100644 --- a/release/scripts/export_lightwave_motion.py +++ b/release/scripts/export_lightwave_motion.py @@ -8,13 +8,13 @@ Tip: 'Export Loc Rot Size chanels to a Lightwave .mot file' """ __author__ = "Daniel Salazar (ZanQdo)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "e-mail: zanqdo@gmail.com") -__version__ = "24/03/06" +__version__ = "16/04/08" __bpydoc__ = """\ -This script exports the selected object's motion channels to a Lightwave -motion file (.mot). +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 @@ -45,6 +45,7 @@ are between Start and End frames in Render buttons. # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- import Blender as B +import math as M #------------------------------------ #Declarados: TotalCanales = 9 @@ -116,11 +117,11 @@ def FuncionPrincipal (Dir): elif NumCanal == 2: Val = mat.translationPart().y elif NumCanal == 3: - Val = -mat.toEuler().z + Val = M.radians (-mat.toEuler().z) elif NumCanal == 4: - Val = -mat.toEuler().x + Val = M.radians (-mat.toEuler().x) elif NumCanal == 5: - Val = -mat.toEuler().y + Val = M.radians (-mat.toEuler().y) elif NumCanal == 6: Val = mat.scalePart().x elif NumCanal == 7: @@ -153,4 +154,4 @@ def main(): B.Window.FileSelector(FuncionPrincipal, "Write .mot File", B.sys.makename(ext='.mot')) if __name__=='__main__': - main()
\ No newline at end of file + main() diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py index afb019fcc1e..c74e7acbcd3 100644 --- a/release/scripts/export_m3g.py +++ b/release/scripts/export_m3g.py @@ -1,4 +1,5 @@ #!BPY +# coding: utf-8 """ Registration info for Blender menus: Name: 'M3G (.m3g, .java)...' Blender: 244 @@ -10,7 +11,7 @@ Tooltip: 'Export to M3G' # # Source: http://www.nelson-games.de/bl2m3g/source # -# $Id: m3g_export.py,v 0.1 2005/04/19 12:25 gerhardv Exp gerhardv $ +# $Id$ # # Author: Gerhard Völkl # @@ -234,6 +235,19 @@ Tooltip: 'Export to M3G' # # * 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 @@ -1213,7 +1227,7 @@ class M3GVertexArray(M3GObject3D): # 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]= int(self.components[i]*(-1)) + 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!") @@ -1284,7 +1298,7 @@ class M3GVertexArray(M3GObject3D): self.blenderIndexes[key]=index #print"blenderIndexes",self.blenderIndexes else: - # print "VertexArray.append: element=",element + print "VertexArray.append: element=",element self.components.append(element) class M3GVertexBuffer(M3GObject3D): @@ -2001,7 +2015,7 @@ class M3GTranslator: self.scene = Blender.Scene.GetCurrent() self.world = self.translateWorld(self.scene) - for obj in self.scene.objects: + for obj in self.scene.objects : if obj.getType()=='Camera': # older Version: isinstance(obj.getData(),Types.CameraType) self.translateCamera(obj) elif obj.getType()=='Mesh': @@ -2176,7 +2190,7 @@ class M3GTranslator: if mOptions.createAmbientLight & mOptions.lightingEnabled: lLight = M3GLight() lLight.mode = lLight.modes['AMBIENT'] - lLight.color = self.translateRGB(AllWorlds[0].getAmb()) + lLight.color = self.translateRGB(blWorld.getAmb()) self.nodes.append(lLight) #TODO: Set background picture from world @@ -2550,7 +2564,7 @@ class M3GTranslator: mLight.intensity = lamp.energy #SpotAngle, SpotExponent (SPOT) if lampType == Lamp.Types.Spot: - mLight.spotAngle = lamp.spotSize + mLight.spotAngle = lamp.spotSize/2 mLight.spotExponent = lamp.spotBlend self.translateToNode(obj,mLight) @@ -2945,6 +2959,8 @@ class OptionMgr: self.perspectiveCorrection = rdict['perspectiveCorrection'] self.smoothShading = rdict['smoothShading'] self.exportAsJava = rdict['exportAsJava'] + self.exportVersion2 = rdict['exportVersion2'] + self.exportGamePhysics = rdict['exportGamePhysics'] except: self.save() # if data isn't valid, rewrite it @@ -2958,6 +2974,8 @@ class OptionMgr: self.perspectiveCorrection = False self.smoothShading = True self.exportAsJava = False + self.exportVersion2 = False + self.exportGamePhysics = False def save(self): d = {} @@ -2970,7 +2988,9 @@ class OptionMgr: d['perspectiveCorrection'] = self.perspectiveCorrection d['smoothShading'] = self.smoothShading d['exportAsJava'] = self.exportAsJava - + d['exportVersion2'] = self.exportVersion2 + d['exportGamePhysics'] = self.exportGamePhysics + Blender.Registry.SetKey('M3GExport', d, True) @@ -2993,6 +3013,8 @@ def gui(): perspectiveCorrection = Draw.Create(mOptions.perspectiveCorrection) smoothShading = Draw.Create(mOptions.smoothShading) exportAsJava = Draw.Create(mOptions.exportAsJava) + exportVersion2 = Draw.Create(mOptions.exportVersion2) + exportGamePhysics = Draw.Create(mOptions.exportGamePhysics) pupBlock = [\ ('Texturing'),\ @@ -3008,7 +3030,9 @@ def gui(): ('Posing'),\ ('All Armature Actions', exportAllActions, 'Exports all actions for armatures'),\ ('Export'),\ - ('As Java Source', exportAsJava, 'Exports scene as Java source code') + ('As Java Source', exportAsJava, 'Exports scene as Java source code'),\ + ('M3G Version 2.0', exportVersion2, 'Exports M3G Version 2.0 File'),\ + ('Game Physics', exportGamePhysics, 'Includes Game Physics infos for NOPE in export') ] # Only execute if use didn't quit (ESC). @@ -3022,6 +3046,8 @@ def gui(): mOptions.perspectiveCorrection = perspectiveCorrection.val mOptions.smoothShading = smoothShading.val mOptions.exportAsJava = exportAsJava.val + mOptions.exportVersion2 = exportVersion2.val + mOptions.exportGamePhysics = exportGamePhysics.val mOptions.save() if mOptions.exportAsJava: @@ -3044,4 +3070,5 @@ def file_callback_m3g(filename): Window.RedrawAll() if __name__ == '__main__': - gui()
\ No newline at end of file + gui() + diff --git a/release/scripts/export_mdd.py b/release/scripts/export_mdd.py index 42a85029505..4f99c9175fd 100644 --- a/release/scripts/export_mdd.py +++ b/release/scripts/export_mdd.py @@ -45,7 +45,7 @@ try: except: pack = None - + def zero_file(filepath): ''' If a file fails, this replaces it with 1 char, better not remove it? @@ -54,11 +54,24 @@ def zero_file(filepath): 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 = ob.getData(mesh=1) + mesh_orig = Mesh.New() + mesh_orig.getFromObject(ob.name) #Flip y and z ''' @@ -83,23 +96,25 @@ def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): f = open(filepath, 'wb') #no Errors yet:Safe to create file # Write the header - f.write(pack(">2i", numframes-1, numverts)) + f.write(pack(">2i", numframes, numverts)) # Write the frame times (should we use the time IPO??) - f.write( pack(">%df" % (numframes-1), *[frame/PREF_FPS for frame in xrange(numframes-1)]) ) # seconds + 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) - # Blender.Window.RedrawAll() # not needed + me_tmp.getFromObject(ob.name) - if len(me_tmp.verts) != numverts: - Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export') - Blender.Window.WaitCursor(0) - f.close() # should we zero? - zero_file(filepath) - return + check_vertcount(me_tmp,numverts) me_tmp.transform(ob.matrixWorld * mat_flip) @@ -150,4 +165,4 @@ 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')) + 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 index 101a1ab1e84..9feb02638c3 100644 --- a/release/scripts/export_obj.py +++ b/release/scripts/export_obj.py @@ -2,14 +2,14 @@ """ Name: 'Wavefront (.obj)...' -Blender: 243 +Blender: 248 Group: 'Export' Tooltip: 'Save a Wavefront OBJ File' """ __author__ = "Campbell Barton, Jiri Hnidek" -__url__ = ['www.blender.org', 'blenderartists.org'] -__version__ = "1.1" +__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. @@ -185,7 +185,7 @@ 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_MORPH_TARGET=False): +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 @@ -195,9 +195,9 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) 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 veckey2d(v): + return round(v.x, 6), round(v.y, 6) print 'OBJ Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' @@ -235,7 +235,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # Initialize totals, these are updated each object totverts = totuvco = totno = 1 - face_vert_index = 1 # used for uvs now + face_vert_index = 1 globalNormals = {} @@ -247,7 +247,11 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: continue - faceuv= me.faceUV + + if EXPORT_UV: + faceuv= me.faceUV + else: + faceuv = False # We have a valid mesh if EXPORT_TRI and me.faces: @@ -318,9 +322,9 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # Sort by Material, then images # so we dont over context switch in the obj file. - if EXPORT_MORPH_TARGET: + if EXPORT_KEEP_VERT_ORDER: pass - elif faceuv and EXPORT_UV: + 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: @@ -354,10 +358,23 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) # UV - if faceuv and EXPORT_UV: - for f in faces: - for uv in f.uv: - file.write('vt %.6f %.6f 0.0\n' % tuple(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: @@ -376,10 +393,11 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) + if not faceuv: f_image = None - for f in faces: + for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth f_mat = min(f.mat, len(materialNames)-1) @@ -388,7 +406,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) f_uv= f.uv # MAKE KEY - if EXPORT_UV and faceuv and f_image: # Object is always true. + 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. @@ -432,13 +450,13 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) contextSmooth = f_smooth file.write('f') - if faceuv and EXPORT_UV: + 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,\ - face_vert_index + vi,\ + totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals @@ -446,14 +464,14 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ - face_vert_index + vi,\ + 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,\ - face_vert_index + vi)) # vert, uv + totuvco + uv_face_mapping[f_index][vi])) # vert, uv face_vert_index += len(f_v) @@ -486,6 +504,8 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # Make the indicies global rather then per mesh totverts += len(me.verts) + if faceuv: + totuvco += uv_unique_count me.verts= None file.close() @@ -515,23 +535,31 @@ def write_ui(filename): if not BPyMessages.Warning_SaveOver(filename): return - EXPORT_APPLY_MODIFIERS = Draw.Create(1) + 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(1) + 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(1) + EXPORT_BLEN_OBS = Draw.Create(0) EXPORT_GROUP_BY_OB = Draw.Create(0) EXPORT_GROUP_BY_MAT = Draw.Create(0) - EXPORT_MORPH_TARGET = Draw.Create(0) + EXPORT_KEEP_VERT_ORDER = Draw.Create(1) + # Old UI + ''' # removed too many options are bad! # Get USER Options @@ -543,7 +571,7 @@ def write_ui(filename): ('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'),\ - ('Morph Target', EXPORT_MORPH_TARGET, 'Keep vert and face order, disables some other options.'),\ + ('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).'),\ @@ -560,12 +588,124 @@ def write_ui(filename): if not Draw.PupBlock('Export...', pup_block): return + ''' - if EXPORT_MORPH_TARGET.val: + # 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_GROUP_BY_MAT.val = False EXPORT_APPLY_MODIFIERS.val = False Window.EditMode(0) @@ -586,7 +726,7 @@ def write_ui(filename): 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_MORPH_TARGET = EXPORT_MORPH_TARGET.val + EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val @@ -636,7 +776,7 @@ def write_ui(filename): 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_MORPH_TARGET) + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER) Blender.Set('curframe', orig_frame) diff --git a/release/scripts/faceselect_same_weights.py b/release/scripts/faceselect_same_weights.py index b8d50cf09b6..967aedec363 100644 --- a/release/scripts/faceselect_same_weights.py +++ b/release/scripts/faceselect_same_weights.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Same Weights...' -Blender: 241 +Blender: 245 Group: 'FaceSelect' Tooltip: 'Select same faces with teh same weight for the active group.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = ["Campbell Barton aka ideasman42"] +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py index 5dca8ba63d7..5c44fe29a6f 100644 --- a/release/scripts/flt_defaultp.py +++ b/release/scripts/flt_defaultp.py @@ -1 +1 @@ -pal = [-256,0,16711680,-16777216,-19529984,-19726592,-19923200,-20119808,-20316416,-20578560,-20840704,-21102848,-21364992,-21692672,-22020352,-22413568,-22806784,-23200000,-23658752,-24117504,-24641792,-25166080,-25755904,-26411264,-27066624,-27787520,-28573952,-29425920,-30343424,-31326464,-32375040,-33489152,-354550016,-371458304,-388366592,-405274880,-422183168,-439156992,-456130816,-473104640,-506855680,-540672256,-574488832,-608305408,-642121984,-676004096,-709886208,-760611072,-811335936,-862060800,-912851200,-980418816,-1048051968,-1115685120,-1183383808,-1267925248,-1352466688,-1453850880,-1555300608,-1656815872,-1775173888,-1893597440,-2028863744,2130771712,-1010376448,-1043996416,-1077681920,-1111367424,-1145052928,-1178738432,-1229201152,-1279663872,-1330126592,-1380654848,-1431183104,-1498488576,-1565794048,-1633165056,-1700536064,-1784684288,-1868832512,-1969823488,-2070814464,2123096320,2005262592,1887428864,1752752384,1601298688,1449779456,1281417472,1096278272,911073536,709026048,490201344,254533888,2023680,-1380857856,-1397700608,-1431320576,-1464940544,-1498560512,-1532180480,-1565865984,-1599551488,-1650014208,-1700476928,-1750939648,-1801402368,-1851865088,-1919170560,-1986476032,-2053781504,-2121086976,2089797632,2005649408,1904723968,1803798528,1686030336,1568262144,1450493952,1315883008,1164494848,1013041152,844810240,659736576,457885696,239192064,3655680,-1767919872,-1784762624,-1801605376,-1818448128,-1852068096,-1885688064,-1919308032,-1952928000,-1986547968,-2020167936,-2070565120,-2120962304,2123542272,2073079552,2022616832,1955376896,1888136960,1820897024,1736879872,1652797184,1568714496,1467854592,1366994688,1249357568,1131654912,997175040,862695168,711372544,560049920,391950080,207007488,5287680,2139657728,2122880512,2106103296,2089326080,2072548864,2055771648,2022217216,1988662784,1955108352,1921553920,1887933952,1854313984,1803916800,1753519616,1703122432,1652725248,1602328064,1535153664,1467979264,1400804864,1316853248,1232901632,1148950016,1048221184,947426816,846632448,729060864,611489280,477140480,326014464,174888448,6919680,1837268224,1820491008,1803713792,1786936576,1770159360,1753382144,1736604928,1719827712,1686273280,1652718848,1619164416,1585609984,1552055552,1518501120,1468169472,1417837824,1367506176,1317174528,1266842880,1199734016,1132625152,1065516288,998407424,914521344,830635264,729971968,629308672,528645376,411204864,293764352,159546624,8551680,-2086957824,-2103735040,-2120512256,-2137289472,2140900608,2107346176,2073791744,2040237056,2006682368,1973127680,1939572992,1906018304,1855686400,1805354496,1755022592,1704690688,1654358784,1587249664,1520140544,1453031424,1369145088,1285258496,1201371904,1100708096,1000044288,882603264,765162240,630943744,496725248,345729536,177956608,10183680,-1699438080,-1716215552,-1732993024,-1766547712,-1800102400,-1833657088,-1867211776,-1900766464,-1934321152,-1967875840,-2018207744,-2068539904,-2118872064,2125763072,2058653696,1991544320,1924434944,1857325568,1773438720,1689551872,1588887808,1488223744,1387559424,1270117888,1152676352,1018457600,884238592,733242368,565468672,397694976,213144064,11815680,-1311918848,-1345473536,-1379028224,-1412582912,-1446137600,-1479692544,-1513247488,-1546802432,-1597134592,-1647466752,-1697798912,-1748131072,-1798463488,-1865573120,-1932682752,-1999792384,-2083679232,2127400960,2043513856,1942849536,1842184960,1724743168,1607301376,1473082112,1338862848,1187866112,1020092160,852317952,667766528,466437632,248331264,13447680,-924399104,-957954048,-991508992,-1025063936,-1058618880,-1092173824,-1142505984,-1192838144,-1243170560,-1293502976,-1343835392,-1410945024,-1478054656,-1545164544,-1629051648,-1712938752,-1796826112,-1897490688,-1998155264,-2098820096,2078705152,1961262848,1827043328,1676046336,1525049344,1357274880,1172722944,971393792,753287168,518403072,283518720,15079680,-570434304,-603989248,-637544192,-671099136,-704654080,-754986496,-805318912,-855651328,-905983744,-973093632,-1040203520,-1107313408,-1174423296,-1258310656,-1342198016,-1442862848,-1543527680,-1644192512,-1761634816,-1879077120,-2013296896,2147450624,1996453376,1828678656,1660903936,1476351744,1275022080,1056914944,822030336,570368256,301928704,16711680,-503325440,-536880384,-570435328,-603990272,-637545216,-671100416,-721432832,-771765248,-822097664,-872430336,-922763008,-989872896,-1056982784,-1124092928,-1191203072,-1275090688,-1358978304,-1459643136,-1560308224,-1660973312,-1778415872,-1895858432,-2030078464,2113891328,1962893824,1795118848,1610566400,1426013696,1224683520,1006575872,771690752,520028160,-452993792,-469771520,-503326464,-536881408,-570436352,-603991552,-637546752,-671101952,-721434368,-771767040,-822099712,-872432384,-922765056,-989875200,-1056985344,-1124095744,-1191206144,-1275093760,-1358981632,-1459646720,-1560312064,-1677754624,-1795197440,-1912640512,-2046860800,2097108736,1946110720,1778335232,1593782272,1392451840,1174343936,939458560,-419439360,-436217088,-452994816,-469772544,-503327488,-536882688,-570437888,-603993088,-637548288,-671103744,-721436416,-771769088,-822101760,-872434688,-922767616,-989878016,-1056988416,-1124098816,-1207986688,-1291874560,-1375762688,-1476428032,-1577093632,-1694536704,-1811979776,-1946200320,-2080421120,2063547904,1912549376,1744773376,1560219904,1358888960,-385884928,-402662656,-419440384,-436218112,-452995840,-469773824,-503329024,-536884224,-570439424,-603994880,-637550336,-671105792,-721438464,-771771392,-822104320,-872437504,-922770688,-989881088,-1056991744,-1124102400,-1191213312,-1275101440,-1358989824,-1459655680,-1560321536,-1677764864,-1795208448,-1912652288,-2046873600,2097094912,1946095872,1778319360,-335553280,-352331008,-369108736,-385886464,-402664192,-419442176,-436220160,-452998144,-486553344,-520108800,-553664256,-587219712,-620775168,-654330880,-687886592,-738219776,-788552960,-838886144,-889219584,-939553024,-1006663936,-1073774848,-1140886016,-1224774656,-1308663296,-1392552192,-1493218560,-1593885184,-1711329280,-1828773632,-1962995456,-2097217536,-285221632,-301999360,-318777088,-335554816,-352332544,-369110528,-385888512,-402666496,-419444480,-436222720,-453000960,-469779200,-503334656,-536890368,-570446080,-604002048,-637558016,-671113984,-721447424,-771780864,-822114560,-872448256,-922782208,-989893632,-1057005056,-1124116736,-1191228672,-1275118080,-1359007744,-1459674880,-1560342272,-1677787136,-234889984,-234890496,-251668224,-268445952,-285223680,-302001664,-318779648,-335557632,-352335616,-369113856,-385892096,-402670336,-419448576,-436227072,-453005568,-469784320,-503340288,-536896256,-570452480,-604008704,-637565184,-671121664,-704678400,-755012608,-805346816,-855681280,-906016000,-973128192,-1040240640,-1107353344,-1174466304,-1258356736,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-251673344,-268451584,-285229824,-302008064,-318786560,-335565056,-352343808,-369122560,-385901312,-402680320,-419459328,-436238592,-453017856,-486574592,-520131584,-553688576,-587245824,-620803328,-654361088,-687919104,-738254592,-788590336,-838926336,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-234896128,-234897152,-234898176,-234899200,-234900480,-234901760,-234903296,-234904832,-234906368,-234908160,-234909952,-234912000,-251691264,-268470784,-285250560,-302030336,-318810368,-335590656,-352371200,-369152000,-385933056,-402714368,-419495936,-8960,-9472,-9984,-10496,-11008,-11776,-12544,-13312,-14080,-15104,-16128,-17152,-18176,-19456,-20736,-22272,-23808,-25344,-27136,-28928,-30976,-33024,-35328,-37888,-40448,-43264,-46336,-49664,-53248,-57088,-61184,-65536,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-930816,-931584,-932608,-933632,-934656,-935680,-936960,-938240,-939776,-941312,-1008384,-1075712,-1143040,-1210624,-1278208,-1346048,-1414144,-1482240,-1550592,-1619200,-1688064,-1757184,-1826560,-1896192,-2031616,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-996352,-1062656,-1129216,-1195776,-1262336,-1328896,-1395712,-1462528,-1529600,-1596672,-1663744,-1731072,-1798400,-1865984,-1999104,-2132480,-2266112,-2399744,-2533632,-2667776,-2867712,-3067904,-3268352,-3469056,-3670016,-926464,-992512,-1058560,-1124608,-1190656,-1256960,-1323264,-1389568,-1455872,-1522432,-1588992,-1655552,-1722112,-1788928,-1855744,-1988352,-2120960,-2253568,-2386432,-2519296,-2652416,-2785536,-2984448,-3183616,-3382784,-3582208,-3847424,-4112896,-4378624,-4644608,-4976384,-5308416,-1188608,-1254656,-1320704,-1386752,-1452800,-1519104,-1585408,-1651712,-1718016,-1784576,-1851136,-1983232,-2115328,-2247680,-2380032,-2512640,-2645248,-2777856,-2976256,-3174656,-3373312,-3571968,-3836416,-4101120,-4365824,-4630784,-4961536,-5292544,-5689344,-6086400,-6483712,-6946816,-1385216,-1451264,-1517312,-1583360,-1649408,-1715712,-1782016,-1848320,-1980160,-2112256,-2244352,-2376448,-2508544,-2640896,-2838784,-3036928,-3235072,-3433216,-3631616,-3895552,-4159744,-4423936,-4688384,-5018624,-5348864,-5744896,-6141184,-6537728,-7000064,-7462656,-7991040,-8585216,-1581824,-1647872,-1713920,-1779968,-1846016,-1977856,-2109696,-2241536,-2373376,-2505472,-2637568,-2769664,-2967296,-3165184,-3363072,-3561216,-3759360,-4023040,-4286976,-4550912,-4880640,-5210368,-5540352,-5936128,-6331904,-6793472,-7255296,-7782912,-8310784,-8904448,-9563904,-10223616,-1712896,-1778944,-1844992,-1976576,-2108160,-2240000,-2371840,-2503680,-2635520,-2767616,-2965248,-3162880,-3360512,-3558400,-3821824,-4085504,-4349184,-4612864,-4942336,-5271808,-5667072,-6062336,-6457856,-6919168,-7380480,-7907584,-8434944,-9028096,-9687040,-10346240,-11071232,-11862016,-1843968,-1975552,-2107136,-2238720,-2370304,-2502144,-2633984,-2765824,-2963200,-3160832,-3358464,-3556096,-3753728,-4017152,-4280576,-4544256,-4873472,-5202688,-5532160,-5927168,-6322432,-6783232,-7244288,-7771136,-8297984,-8890624,-9549056,-10207744,-10932224,-11722496,-12578560,-13500416,-1975040,-2106624,-2238208,-2369792,-2501376,-2633216,-2830592,-3027968,-3225344,-3422976,-3620608,-3883776,-4146944,-4410368,-4673792,-5003008,-5332224,-5726976,-6121984,-6582528,-7043328,-7504128,-8030720,-8623104,-9215488,-9873664,-10597632,-11387392,-12242944,-13164288,-14085888,-15138816,-2237184,-2368768,-2500352,-2631936,-2763520,-2960896,-3158272,-3355648,-3553024,-3816192,-4079360,-4342528,-4605696,-4934656,-5263616,-5658368,-6053120,-6447872,-6908416,-7368960,-7895296,-8421632,-9013760,-9671680,-10329600,-11053312,-11842816,-12698112,-13619200,-14606080,-15658752,-16777216]
\ No newline at end of file +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 new file mode 100644 index 00000000000..36e8e4d2501 --- /dev/null +++ b/release/scripts/flt_dofedit.py @@ -0,0 +1,835 @@ +#!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 index 033a03f1163..c099c8e62d1 100644 --- a/release/scripts/flt_export.py +++ b/release/scripts/flt_export.py @@ -8,7 +8,7 @@ Tip: 'Export to OpenFlight v16.0 (.flt)' __author__ = "Greg MacDonald, Geoffrey Bantle" __version__ = "2.0 11/21/07" -__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__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. @@ -44,48 +44,56 @@ 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 - #new stuff - self.export_shading = 0 - self.shading_default = 45.0 - self.basepath = os.path.dirname(Blender.Get('filename')) - self.scale = 1.0 - - #set externals path - if(os.path.exists(os.path.join(self.basepath,'externals'))): - self.externalspath = os.path.join(self.basepath,'externals') + 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.externalspath = self.basepath - - self.doxrefs = 1 + self.state['externalspath'] = self.state['basepath'] - #texture options - if(os.path.exists(os.path.join(self.basepath,'textures'))): - self.texturespath = os.path.join(self.basepath,'textures') + if(os.path.exists(os.path.join(self.state['basepath'],'textures'))): + self.state['texturespath'] = os.path.join(self.state['basepath'],'textures') else: - self.texturespath = self.basepath + self.state['texturespath'] = self.state['basepath'] + + self.state['xappath'] = '' + self.read_state() #read from registry - #misc - self.write_attrib_files = 0 - self.copy_textures = 0 - self.export_transform = 0 - self.flattenmesh = False - self.xapp = 1 - reg = Blender.Registry.GetKey('flt_export',1) - if(reg and 'xappath' in reg.keys()): - self.xappath = reg['xappath'] - else: - self.xappath = '' options = ExporterOptions() tex_files = dict() #a list of (possibly) modified texture path names @@ -100,7 +108,7 @@ 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,11,73,63,111] +alltypes = [2,4,14,11,73,63,111] childtypes = { 2 : [111,2,73,4,14,63], 4 : [111], @@ -196,11 +204,14 @@ class GlobalResourceRepository: 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)) == "<type " + "'Blender MVert'>": vertex = face + vno = Blender.Mathutils.Vector(0.0,0.0,1.0) elif str(type(face)) == "<type " + "'Blender MEdge'>": if vfindex == 1: vertex = face.v1 @@ -218,12 +229,15 @@ class GlobalResourceRepository: indexhash = self.namehash[object.name] #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME - if not options.export_transform: + 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: @@ -385,6 +399,7 @@ class Node: print '\t' * level[0], self.name, self.object.type level[0] += 1 + self.children.reverse() for child in self.children: child.blender_export() @@ -409,14 +424,26 @@ class Node: 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: @@ -444,9 +471,9 @@ class Node: self.object = object if object: self.name = self.object.name - if not options.export_transform: + if not options.state['transform']: oloc = Blender.Mathutils.Vector(object.getLocation('worldspace')) - vec = Blender.Mathutils.Vector(oloc[0] * options.scale, oloc[1] * options.scale, oloc[2] * options.scale) #scale + 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. @@ -467,43 +494,44 @@ class Node: for child in self.child_objects: if(not child.restrictDisplay): childprops = None - type = None + ftype = None if not child.properties.has_key('FLT'): if child.type == 'Empty': if child.DupGroup: childprops = FLTXRef.copy() - type = 63 + ftype = 63 else: childprops = FLTGroup.copy() - type = 2 + ftype = 2 elif child.type == 'Mesh': if self.header.childhash[child.name] or not child.parent: childprops = FLTGroup.copy() - type = 2 + ftype = 2 else: childprops = FLTObject.copy() - type = 4 + ftype = 4 else: childprops = dict() for prop in child.properties['FLT']: childprops[prop] = child.properties['FLT'][prop] - type = child.properties['FLT']['type'] + ftype = child.properties['FLT']['type'] - if type in self.childtypes and type in alltypes: - Newnode = FLTNode(self,header,child,childprops,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 = -1 - self.material_index = -1 + 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. @@ -613,33 +641,52 @@ class FLTNode(Node): #first pass: do open faces for vert in wireverts: if not visited[vert] and vertuse[vert.index][1] == 1: - visited[vert] = True - loop = [vert] - othervert = edge_get_othervert(vert, disk[vert][0]) - self.vertwalk(othervert, loop, disk, visited) + 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]: - visited[vert] = True - loop = [vert] - othervert = edge_get_othervert(vert,disk[vert][0]) - self.vertwalk(othervert, loop, disk, visited) + 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: - (type, loop) = l + (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 type == 'closed': + 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") @@ -716,6 +763,9 @@ class FLTNode(Node): 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 @@ -779,13 +829,13 @@ class FLTNode(Node): self.exportmesh.getFromObject(self.object.name) for vert in self.exportmesh.verts: - if not options.export_transform: + if not options.state['transform']: vec = vert.co - vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + 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.scale != 1.0: - vert.co = vert.co * options.scale + 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: @@ -802,7 +852,7 @@ class FLTNode(Node): default = None - if options.export_shading: + if options.state['export_shading']: mods = self.object.modifiers hasedsplit = False for mod in mods: @@ -811,7 +861,7 @@ class FLTNode(Node): break if not hasedsplit: default = mods.append(Modifier.Types.EDGESPLIT) - default[Modifier.Settings.EDGESPLIT_ANGLE] = options.shading_default + 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() @@ -820,17 +870,17 @@ class FLTNode(Node): #recalculate vertex positions for vert in self.exportmesh.verts: - if not options.export_transform: + if not options.state['transform']: vec = vert.co - vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + 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.scale != 1.0: - vert.co = vert.co * options.scale + if options.state['scale'] != 1.0: + vert.co = vert.co * options.state['scale'] flipped = self.object.getMatrix('worldspace').determinant() - if not options.export_transform: + if not options.state['transform']: self.exportmesh.calcNormals() @@ -862,7 +912,7 @@ class FLTNode(Node): self.buildNormFaces() self.buildTexData() - if not options.export_transform: + if not options.state['transform']: if flipped < 0: for vdesc in self.header.GRR.vertex_lst: vdesc.accum = 0 @@ -904,6 +954,9 @@ class FLTNode(Node): alpha = 1 except: pass + + if face_desc.billboard: + alpha = 2 if face_desc.subface: if face_desc.subface == 'Push': @@ -926,8 +979,14 @@ class FLTNode(Node): self.header.fw.write_char(0) # Reserved self.header.fw.write_char(alpha) # Template self.header.fw.write_short(-1) # Detail tex pat index - self.header.fw.write_short(face_desc.texture_index) # Tex pattern index - self.header.fw.write_short(face_desc.material_index) # material 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 @@ -962,7 +1021,10 @@ class FLTNode(Node): self.header.fw.write_ushort(8 + (mtex * 8)) # Length self.header.fw.write_uint(uvmask) # UV mask for i in xrange(mtex): - self.header.fw.write_ushort(face_desc.images[i]) # Tex pattern index + 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 @@ -1009,27 +1071,43 @@ class FLTNode(Node): 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.externalspath: + if self.opcode == 63 and options.state['externalspath']: try: - exportdict['3t200!filename'] = os.path.join(options.externalspath,self.object.DupGroup.name+'.flt') + 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]: - (type,length,propname) = records[self.opcode][key] - write_prop(self.header.fw,type,exportdict[propname],length) + (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.export_transform or self.opcode == 63: + if options.state['transform'] or self.opcode == 63: #writing transform matrix.... self.write_matrix() @@ -1049,8 +1127,8 @@ class FLTNode(Node): #self.write_pop() self.write_pop() - def __init__(self, parent, header, object,props,type): - self.opcode = type #both these next two lines need to be in the node class.... + 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 = [] @@ -1111,8 +1189,8 @@ class Database(Node): 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(0x20000000) # Flags + 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) @@ -1176,7 +1254,7 @@ class Database(Node): cpalette = defaultp.pal count = len(cpalette) for i in xrange(count): - color = struct.unpack('>BBBB',struct.pack('>I',cpalette[i])) + 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 @@ -1192,21 +1270,16 @@ class Database(Node): self.write_push() - if options.flattenmesh: - self.mnodes.reverse() - for mnode in self.mnodes: - mnode.write_faces() - else: - for child in self.children: - child.write() + 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.copy_textures: - filename = os.path.normpath(os.path.join(options.texturespath, os.path.basename(self.GRR.request_texture_filename(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)) @@ -1280,8 +1353,8 @@ def write_attribute_files(): fw.write_int(size[0]) fw.write_int(size[1]) for key in records['Image']: - (type,length,propname) = records['Image'][key] - write_prop(fw,type,exportdict[propname],length) + (ftype,length,propname) = records['Image'][key] + write_prop(fw,ftype,exportdict[propname],length) fw.close_file() #globals used by the scene export function @@ -1293,10 +1366,10 @@ def dbexport_internal(scene): global xrefsdone global options - if exportlevel == 0 or not options.externalspath: - fname = os.path.join(options.basepath,scene.name + '.flt') + if exportlevel == 0 or not options.state['externalspath']: + fname = os.path.join(options.state['basepath'],scene.name + '.flt') else: - fname = os.path.join(options.externalspath,scene.name + '.flt') + fname = os.path.join(options.state['externalspath'],scene.name + '.flt') fw = FltOut(fname) db = Database(scene,fw) @@ -1310,7 +1383,7 @@ def dbexport_internal(scene): db.write() fw.close_file() - if options.doxrefs: + if options.state['doxrefs']: for xname in xreflist: try: xrefscene = Blender.Scene.Get(xname) @@ -1345,7 +1418,7 @@ def dbexport(): Blender.Window.WaitCursor(False) #optional: Copy textures - if options.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]): @@ -1356,11 +1429,11 @@ def dbexport(): shutil.copyfile(origpath,tex_files[imgname]) #optional: Write attribute files - if options.write_attrib_files: + if options.state['attrib']: write_attribute_files() - if options.xapp: - cmd= options.xappath + " " + fname + if options.state['xapp']: + cmd= options.state['xappath'] + " " + fname status = os.system(cmd) @@ -1398,33 +1471,33 @@ FLTXAPPChooser = None FLTAttrib = None + +FLTWarn = None + def setshadingangle(ID,val): global options - options.shading_default = val + options.state['shading_default'] = val def setBpath(fname): global options - options.basepath = os.path.dirname(fname) + options.state['basepath'] = os.path.dirname(fname) #update xref and textures path too.... - if(os.path.exists(os.path.join(options.basepath,'externals'))): - options.externalspath = os.path.join(options.basepath,'externals') - if(os.path.exists(os.path.join(options.texturespath,'textures'))): - options.texturespath = os.path.join(options.basepath,'textures') + 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.scale = val + options.state['scale'] = val def setTpath(fname): global options - options.texturespath = os.path.dirname(fname) + options.state['texturespath'] = os.path.dirname(fname) def setXpath(fname): global options - options.externalspath = os.path.dirname(fname) + options.state['externalspath'] = os.path.dirname(fname) def setXApath(fname): global options - options.xappath = fname - d = dict() - d['xappath'] = options.xappath - Blender.Registry.SetKey('flt_export', d, 1) + options.state['xappath'] = fname def event(evt, val): x = 1 def but_event(evt): @@ -1464,48 +1537,55 @@ def but_event(evt): global FLTAttrib - + global FLTWarn #choose base path for export if evt == 4: - Blender.Window.FileSelector(setBpath, "DB Root", options.basepath) + Blender.Window.FileSelector(setBpath, "DB Root", options.state['basepath']) #choose XREF path if evt == 6: - Blender.Window.FileSelector(setXpath,"DB Externals",options.externalspath) + Blender.Window.FileSelector(setXpath,"DB Externals",options.state['externalspath']) #choose texture path if evt == 8: - Blender.Window.FileSelector(setTpath,"DB Textures",options.texturespath) + Blender.Window.FileSelector(setTpath,"DB Textures",options.state['texturespath']) #export shading toggle if evt == 9: - options.export_shading = FLTShadeExport.val + options.state['export_shading'] = FLTShadeExport.val #export Textures if evt == 11: - options.copy_textures = FLTCopyTex.val + options.state['copytex']= FLTCopyTex.val #export XRefs if evt == 13: - options.doxrefs = FLTDoXRef.val + options.state['doxrefs'] = FLTDoXRef.val #export Transforms if evt == 12: - options.export_transform = FLTGlobal.val + options.state['transform'] = FLTGlobal.val if evt == 14: - options.xapp = FLTXAPP.val + options.state['xapp'] = FLTXAPP.val if evt == 16: - Blender.Window.FileSelector(setXApath,"External Application",options.xappath) + Blender.Window.FileSelector(setXApath,"External Application",options.state['xappath']) if evt == 20: - options.write_attrib_files = FLTAttrib.val + options.state['attrib'] = FLTAttrib.val #Export DB if evt == 1: - dbexport() - + 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(): @@ -1566,47 +1646,46 @@ def gui(): #FLTLabel = Draw.Text("FLT Exporter V2.0",'large') cy = height - 80 - #base path FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20) - FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.basepath,255,"Folder to export to") + 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.externalspath,255,"Folder for external references") + 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.texturespath,255,"Folder for texture files") + 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.xappath,255,"External application to launch when done") + 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.export_shading,"Turn on export of custom shading") - FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.shading_default,0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle) + 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.scale,0.0,100.0,"Export scaling factor",setexportscale) + 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.copy_textures,"Copy textures to folder indicated above") + 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.export_transform,"If unchecked, Global coordinates are used (recommended)") + 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.doxrefs,"Export External references (only those below current scene!)") + 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.xapp,"Launch External Application on export") + 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.write_attrib_files, "Write Texture Attribute files") + 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") diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py index 220fc9f355c..f8d31f7bb57 100644 --- a/release/scripts/flt_import.py +++ b/release/scripts/flt_import.py @@ -6,15 +6,17 @@ Group: 'Import' Tip: 'Import OpenFlight (.flt)' """ + + __author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle" __version__ = "2.0 11/21/07" -__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__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_flt +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. """ @@ -42,6 +44,7 @@ import BPyMesh import BPyImage import flt_filewalker import flt_properties +import sys reload(flt_properties) from flt_properties import * @@ -59,6 +62,7 @@ FLTDoXRef = None FLTScale = None FLTShadeImport = None FLTAttrib = None +FLTWarn = None Vector= Blender.Mathutils.Vector FLOAT_TOLERANCE = 0.01 @@ -83,8 +87,16 @@ 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, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] +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: @@ -486,6 +498,20 @@ class Node: 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] @@ -618,10 +644,12 @@ class VertexPalette(Node): 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 @@ -630,12 +658,307 @@ class InterNode(Node): 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): @@ -714,8 +1037,9 @@ class InterNode(Node): else: # fgon mesh_face_indicies = [i+vert_index for i in xrange(face_len)] tri_ngons= ngon(self.mesh, mesh_face_indicies) - 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 ]) + 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 @@ -742,9 +1066,15 @@ class InterNode(Node): self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"]) for i, f in enumerate(self.mesh.faces): - f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] #fix this! - f.mode |= Blender.Mesh.FaceModes["LIGHT"] 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] @@ -789,6 +1119,8 @@ class InterNode(Node): 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] @@ -842,10 +1174,13 @@ class InterNode(Node): #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier. Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) - self.mesh.verts.delete(0) # remove the dummy vert self.mesh.sel= 1 self.header.scene.update(1) #slow! - self.mesh.remDoubles(0.0001) + + #self.mesh.remDoubles(0.0001) + weldmesh = self.buildWeldMesh() + welded = self.weldFuseFaces(weldmesh) + self.mesh.verts.delete(0) # remove the dummy vert edgeHash = dict() @@ -924,10 +1259,11 @@ class InterNode(Node): self.mesh.activeUVLayer = actuvlayer def blender_import(self): - if self.vis and self.parent: + 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' @@ -948,9 +1284,18 @@ class InterNode(Node): 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]) + 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 @@ -959,24 +1304,24 @@ class InterNode(Node): lodlist = list() for child in self.children: if child.props.has_key('type') and child.props['type'] == 73: - 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 + 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 - if self.matrix: - self.object.setMatrix(self.matrix) Node.blender_import(self) # Attach faces to self.faceLs @@ -1215,9 +1560,10 @@ class Object(InterNode): 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, + 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, @@ -1226,7 +1572,10 @@ class Object(InterNode): 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() @@ -1239,7 +1588,8 @@ class Group(InterNode): self.root_handler.set_handler({33: self.parse_long_id, 31: self.parse_comment, 10: self.parse_push, - 49: self.parse_matrix}) + 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, @@ -1256,6 +1606,10 @@ class Group(InterNode): 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']) @@ -1283,7 +1637,8 @@ class DOF(InterNode): self.root_handler.set_handler({33: self.parse_long_id, 31: self.parse_comment, 10: self.parse_push, - 49: self.parse_matrix}) + 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, @@ -1298,6 +1653,8 @@ class DOF(InterNode): 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() @@ -1320,11 +1677,17 @@ class XRef(InterNode): self.props['comment'] = '' self.parse_record() - xref_filename = self.props['3t200!filename'] + 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(xref_filename) and not self.header.grr.xrefs.has_key(xref_filename): - self.xref = Database(xref_filename, self.header.grr, self) + 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 @@ -1344,8 +1707,15 @@ class XRef(InterNode): except: pass + + + if self.parent and self.parent.object: - self.parent.object.makeParent([self.object]) + self.parent.object.makeParent([self.object],1) + + if self.matrix: + self.object.setMatrix(self.matrix) + #id props import self.object.properties['FLT'] = dict() @@ -1357,8 +1727,7 @@ class XRef(InterNode): self.object.Layer = current_layer self.object.sel = 1 - if self.matrix: - self.object.setMatrix(self.matrix) + Node.blender_import(self) @@ -1375,7 +1744,8 @@ class LOD(InterNode): self.root_handler.set_handler({33: self.parse_long_id, 31: self.parse_comment, 10: self.parse_push, - 49: self.parse_matrix}) + 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, @@ -1389,6 +1759,9 @@ class LOD(InterNode): 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'] = '' @@ -1401,13 +1774,16 @@ class InlineLightPoint(InterNode): 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'] = '' @@ -1433,6 +1809,11 @@ class InlineLightPoint(InterNode): 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]) @@ -1635,6 +2016,11 @@ class Database(InterNode): 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: @@ -1839,6 +2225,9 @@ class Database(InterNode): 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] @@ -1898,7 +2287,7 @@ def fixscale(root,childhash): for child in childhash[root]: fixscale(child,childhash) location = Blender.Mathutils.Vector(root.getLocation('worldspace')) - if location[0] != 0.0 and location[1] != 0.0 and location[2] != 0.0: + 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) @@ -1909,7 +2298,6 @@ def fixscale(root,childhash): for v in rmesh.verts: v.co = v.co * smat - def reparent(root,childhash,sce): for child in childhash[root]: reparent(child,childhash,sce) @@ -2023,9 +2411,17 @@ def setimportscale(ID,val): 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 @@ -2039,6 +2435,8 @@ def but_event(evt): global FLTShadeImport global FLTAttrib + global FLTWarn + #Import DB if evt == 1: if global_prefs['verbose'] >= 1: @@ -2050,7 +2448,14 @@ def but_event(evt): print GRR = GlobalResourceRepository() - select_file(global_prefs['fltfile'], GRR) + + 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']) @@ -2067,11 +2472,11 @@ def but_event(evt): if evt == 2: Draw.Exit() + d = dict() + for key in global_prefs: + d[key] = global_prefs[key] + Blender.Registry.SetKey('flt_import', d, 1) - - -from Blender.BGL import * -from Blender import Draw def gui(): global FLTBaseLabel diff --git a/release/scripts/flt_lodedit.py b/release/scripts/flt_lodedit.py new file mode 100644 index 00000000000..58319b9e525 --- /dev/null +++ b/release/scripts/flt_lodedit.py @@ -0,0 +1,502 @@ +#!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 index c641a0a4f08..c2f1380a6fa 100644 --- a/release/scripts/flt_palettemanager.py +++ b/release/scripts/flt_palettemanager.py @@ -10,7 +10,7 @@ Tooltip: 'Manage FLT colors' __author__ = "Geoffrey Bantle" __version__ = "1.0 11/21/2007" __email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'elysiun') +__url__ = ('blender', 'blenderartists.org') __bpydoc__ ="""\ @@ -25,7 +25,7 @@ http://wiki.blender.org/index.php/Scripts/Manual/FLTools """ # -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 +# flt_palettemanager.py version 1.0 2005/04/08 # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -55,6 +55,75 @@ 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 @@ -68,6 +137,14 @@ 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 @@ -128,7 +205,7 @@ def event(evt,val): Draw.Redraw(1) #copy current color and intensity to selected faces. - elif evt == Draw.CKEY: + elif evt == Draw.VKEY: if Blender.Window.EditMode(): Blender.Window.EditMode(0) @@ -136,7 +213,7 @@ def event(evt,val): state = update_state() #retrieve color from palette - color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + color = struct.unpack('>BBBB',struct.pack('>i',colors[curswatch])) actmesh = state["activeMesh"] if actmesh: if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]): @@ -182,7 +259,7 @@ def event(evt,val): Blender.Window.RedrawAll() #grab color and intensity from active face - elif evt == Draw.VKEY: + elif evt == Draw.CKEY: if Blender.Window.EditMode(): Blender.Window.EditMode(0) editmode = 1 @@ -211,6 +288,23 @@ def event(evt,val): 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() @@ -225,11 +319,11 @@ def update_all(): for object in state["activeScene"].objects: if object.type == "Mesh": mesh = object.getData(mesh=True) - if 'FLT_COL' in mesh.faces.properties: + 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])) + 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) @@ -284,8 +378,13 @@ def draw_palette(): global colors global curint global curswatch - global picker - + global picker + global ts1 + global ts2 + global ts3 + global ts4 + global ts5 + state = update_state() init_pal() @@ -297,7 +396,7 @@ def draw_palette(): for x in xrange(32): ypos = palette_y for y in xrange(32): - color = struct.unpack('>BBBB',struct.pack('>I',colors[cid])) + 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) @@ -328,7 +427,7 @@ def draw_palette(): xpos = xpos + ssize #draw intensity gradient - color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + 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 @@ -355,15 +454,15 @@ def draw_palette(): xpos = ((palette_size*32) * (1.0 - curint)) + palette_x glColor3f(1.0,1.0,1.0) glBegin(GL_LINE_LOOP) - glVertex2i(xpos-6,grady-1) - glVertex2i(xpos+6,grady-1) - glVertex2i(xpos+6,grady+palette_size+1) - glVertex2i(xpos-6,grady+palette_size+1) + 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])) + 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) @@ -377,6 +476,24 @@ def draw_palette(): 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) @@ -385,4 +502,4 @@ def gui(): 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 index 07bcc8def1d..4c841e9c0c0 100644 --- a/release/scripts/flt_properties.py +++ b/release/scripts/flt_properties.py @@ -197,7 +197,10 @@ def write_prop(fw,type,value,length): elif type == 'i': fw.write_int(value) elif type == 'I': - fw.write_uint(value) + #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': @@ -227,6 +230,14 @@ def read_prop(fw,type,length): 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, @@ -259,16 +270,16 @@ FLTObjectDisplay = [10] FLTLOD = { '3t8!id' : 'L', '4i!reserved' : 0, - '5d!switch in' : 0, - '6d!switch out' : 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, - '11d!Y co' : 0, - '12d!Z co' : 0, - '13d!Transition' : 0, - '14d!Sig Size' : 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] @@ -280,7 +291,7 @@ FLTInlineLP = { '7C!back color: b' : 255, '8C!back color: g' : 255, '9C!back color: r' : 255, - '10i!display mode' : 255, + '10i!display mode' : 0, '11f!intensity' : 1.0, '12f!back intensity' : 0.0, '13f!minimum defocus' : 0.0, @@ -305,15 +316,15 @@ FLTInlineLP = { '32f!lobe roll angle' : 0.0, '33f!dir falloff exponent' : 1.0, '34f!dir ambient intensity' : 0.1, - '35f!anim period' : 0, + '35f!anim period' : 2, '36f!anim phase' : 0, - '37f!anim enabled' : 0, + '37f!anim enabled' : 1.0, '38f!significance' : 0.0, '39i!draw order' : 0, - '40I!flags' : 813875616, + '40I!flags' : 277004288, '41f!roti' : 0, '42f!rotj' : 0, - '43f!rotk' : 0 + '43f!rotk' : 1.0 } FLTInlineLPDisplay = [35,36,37,41,42,43] @@ -388,7 +399,7 @@ FLTImage = { '5i!UpX' : 0, '6i!UpY' : 0, '7i!File Format' : 0, - '8i!Min Filter' : 1, + '8i!Min Filter' : 6, '9i!Mag Filter' : 1, '10i!Wrap' : 0, '11i!WrapU' : 0, @@ -587,6 +598,7 @@ FLT_Records = { 14 : FLTDOF, 1 : FLTHeader, 111 : FLTInlineLP, + 100 : FLTExt, 'Image' : FLTImage } diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py index d8a4aa8b4a0..a707b87f846 100644 --- a/release/scripts/flt_toolbar.py +++ b/release/scripts/flt_toolbar.py @@ -10,7 +10,7 @@ Tooltip: 'Tools for working with FLT databases' __author__ = "Geoffrey Bantle" __version__ = "1.0 11/21/07" __email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'elysiun') +__url__ = ('blender', 'blenderartists.org') __bpydoc__ ="""\ This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a @@ -75,7 +75,9 @@ evcode = { "SCENE_UPDATE" : 303, "IDPROP_COPY" : 501, "IDPROP_KILL" : 502, - "CLIGHT_MAKE" : 700 + "CLIGHT_MAKE" : 700, + "DFROMACT" : 701, + "FIXCOL" : 702 } XREF_PREFIX = None @@ -90,11 +92,50 @@ 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"].getActiveObject() + 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 @@ -139,24 +180,130 @@ def idprops_copy(source): for key in source.properties['FLT']: object.properties['FLT'][key] = source.properties['FLT'][key] -def update_all(): +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() - #update the baked FLT colors for all meshes. - for object in state["activeScene"].objects: - if object.type == "Mesh": + + 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: - 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',state["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 + 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(): @@ -231,7 +378,19 @@ def xref_create(): 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 @@ -424,12 +583,56 @@ def clight_make(): actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"]) for v in actmesh.verts: - v.setProperty("FLT_VCOL", 67295) + 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 @@ -447,7 +650,7 @@ def but_event(evt): if evt == evcode["XREF_EDIT"]: xref_edit() if evt == evcode["XREF_SELECT"]: - select_by_typecode(63) + xref_select() if evt == evcode["XREF_MAKE"]: xref_create() #do scene buttons @@ -471,6 +674,10 @@ def but_event(evt): 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() @@ -525,17 +732,20 @@ def draw_postcommon(x,y,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 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 @@ -583,12 +793,17 @@ def draw_propsheet(x,y): #General tools y = y-20 SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors") - draw_postcommon(origx, origy,y) + + 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 = 256 + 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_browser.py b/release/scripts/help_browser.py index d321ffa6256..b27e266f368 100644 --- a/release/scripts/help_browser.py +++ b/release/scripts/help_browser.py @@ -10,7 +10,7 @@ Tooltip: 'Show help information about a chosen installed script.' __author__ = "Willian P. Germano" __version__ = "0.1 11/02/04" __email__ = ('scripts', 'Author, wgermano:ig*com*br') -__url__ = ('blender', 'elysiun') +__url__ = ('blender', 'blenderartists.org') __bpydoc__ ="""\ This script shows help information for scripts registered in the menus. @@ -84,8 +84,7 @@ DEFAULT_EMAILS = { } DEFAULT_LINKS = { - 'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"], - 'elysiun': ["elYsiun\'s Python and Plugins forum", "http://www.elysiun.com/forum/viewforum.php?f=5"] + 'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"] } PADDING = 15 @@ -449,11 +448,19 @@ def parse_help_info(script): def parse_script_line(l): + tip = 'No tooltip' try: pieces = l.split("'") name = pieces[1].replace('...','') - version, fname, userdir = pieces[2].strip().split() - tip = pieces[3] + 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 diff --git a/release/scripts/help_getting_started.py b/release/scripts/help_getting_started.py index 19eac9e2e20..81b002da4e4 100644 --- a/release/scripts/help_getting_started.py +++ b/release/scripts/help_getting_started.py @@ -7,7 +7,7 @@ Tooltip: 'Help for new users' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/help_manual.py b/release/scripts/help_manual.py index 75d93522c31..cf293bf7c2c 100644 --- a/release/scripts/help_manual.py +++ b/release/scripts/help_manual.py @@ -7,7 +7,7 @@ Tooltip: 'The Blender reference manual' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/help_release_notes.py b/release/scripts/help_release_notes.py index 49382755163..af7a7042489 100644 --- a/release/scripts/help_release_notes.py +++ b/release/scripts/help_release_notes.py @@ -7,7 +7,7 @@ Tooltip: 'Information about the changes in this version of Blender' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/help_tutorials.py b/release/scripts/help_tutorials.py index 1fbabc43eb6..04d6c799455 100644 --- a/release/scripts/help_tutorials.py +++ b/release/scripts/help_tutorials.py @@ -8,7 +8,7 @@ Tooltip: 'Tutorials for learning to use Blender' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/help_web_blender.py b/release/scripts/help_web_blender.py index 999746c1f9c..0f9e32dea0e 100644 --- a/release/scripts/help_web_blender.py +++ b/release/scripts/help_web_blender.py @@ -8,7 +8,7 @@ Tooltip: 'The official Blender website' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at Blender's main site, diff --git a/release/scripts/help_web_devcomm.py b/release/scripts/help_web_devcomm.py index afe9ef064d9..344622cc113 100644 --- a/release/scripts/help_web_devcomm.py +++ b/release/scripts/help_web_devcomm.py @@ -8,7 +8,7 @@ Tooltip: 'Get involved with Blender development' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender.org, the diff --git a/release/scripts/help_web_eshop.py b/release/scripts/help_web_eshop.py index 997d07ca255..451fd735150 100644 --- a/release/scripts/help_web_eshop.py +++ b/release/scripts/help_web_eshop.py @@ -8,7 +8,7 @@ Tooltip: 'Buy official Blender resources and merchandise online' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/help_web_usercomm.py b/release/scripts/help_web_usercomm.py index 56f64764ac7..fbe19956eb7 100644 --- a/release/scripts/help_web_usercomm.py +++ b/release/scripts/help_web_usercomm.py @@ -8,7 +8,7 @@ Tooltip: 'Get involved with other Blender users' """ __author__ = "Matt Ebb" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ This script opens the user's default web browser at www.blender3d.org's diff --git a/release/scripts/hotkeys.py b/release/scripts/hotkeys.py index bfaac252b21..187cba964bc 100644 --- a/release/scripts/hotkeys.py +++ b/release/scripts/hotkeys.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Registration info for Blender menus: Name: 'HotKey and MouseAction Reference' Blender: 242 @@ -128,17 +128,21 @@ hotkeys={ ['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'], +['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+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'], ['.', '...'] ], @@ -228,7 +232,7 @@ hotkeys={ ['Home', 'OutLiner Windows, Show hierarchy'], ['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'], ['PgUp', 'Strip Editor, Move Down'], -['PgUn', 'TimeLine: Jump to next marker'], +['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'], @@ -246,7 +250,6 @@ hotkeys={ ['Alt-Up', 'Blender in Fullscreen mode'], ['Ctrl-Left', 'Previous screen'], ['Ctrl-Right', 'Next screen'], -['Ctrl-Alt-C', 'Object Mode : Add Constraint'], ['Ctrl-Down', 'Maximize window toggle'], ['Ctrl-Up', 'Maximize window toggle'], ['Shift-Arrow', 'Toggle first frame/ last frame'], @@ -264,8 +267,10 @@ hotkeys={ ['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 '], @@ -275,13 +280,13 @@ hotkeys={ "B":[ ['B', 'Border select'], ['BB', 'Circle select'], -['Alt+B', 'Object Mode: Select visible view section in 3D space'], +['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 +['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 ['.', '...'] ], @@ -295,11 +300,12 @@ hotkeys={ ['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.'], +['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'], ['.', '...'] @@ -393,9 +399,11 @@ hotkeys={ ], "I":[ -['I', 'Keyframe menu'], -['Alt-I','ARMATURE : posemode, remove IK constraints.'], -['Ctrl-I','ARMATURE : add IK constraint'], +['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.'], ['.', '...'] ], @@ -433,6 +441,10 @@ hotkeys={ ['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'], ['.', '...'] ], @@ -483,8 +495,8 @@ hotkeys={ "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'], +['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'], @@ -493,6 +505,7 @@ hotkeys={ ['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'], ['.', '...'] ], @@ -541,6 +554,7 @@ hotkeys={ ['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 '], ['.', '...'] ], @@ -556,7 +570,7 @@ hotkeys={ ['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'], +['Ctrl-Alt-T', 'Benchmark'], ['.', '...'] ], @@ -594,9 +608,18 @@ hotkeys={ "W":[ ['W', 'Edit Mode: Specials menu'], ['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'], -['W', 'Edit Mode: Specials menu, ARMATURE 2 Flip Left-Right Name'], +['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'], @@ -624,7 +647,6 @@ hotkeys={ ['WY', 'UV Image Editor: Weld/Align Y axis'], ['Ctrl-W', 'Save current file'] , ['Shift-W', 'Warp/bend selected vertices around cursor'], -['alt-W', 'Export in videoscape format'], ['.', '...'] ], @@ -635,6 +657,7 @@ hotkeys={ ['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)'], ['.', '...'] ], @@ -918,4 +941,4 @@ def bevent(evt): Blender.Window.Redraw() if __name__ == '__main__': - Register(draw, event, bevent)
\ No newline at end of file + Register(draw, event, bevent) diff --git a/release/scripts/image_auto_layout.py b/release/scripts/image_auto_layout.py index 19ee396c3b1..c6f97a25434 100644 --- a/release/scripts/image_auto_layout.py +++ b/release/scripts/image_auto_layout.py @@ -265,8 +265,8 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR render_context.setRenderWinSize(100) render_context.setImageType(Render.PNG) render_context.enableExtensions(True) - render_context.enableSky() # No alpha needed. - render_context.enableRGBColor() + render_context.enablePremultiply() # No alpha needed. + render_context.enableRGBAColor() render_context.threads = 2 #Render.EnableDispView() # Broken?? @@ -275,8 +275,9 @@ def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PR render_mat= B.Material.New() render_mat.mode |= B.Material.Modes.SHADELESS render_mat.mode |= B.Material.Modes.TEXFACE - - + render_mat.mode |= 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') diff --git a/release/scripts/image_billboard.py b/release/scripts/image_billboard.py index b1cd9d38891..54f0f7c5c55 100644 --- a/release/scripts/image_billboard.py +++ b/release/scripts/image_billboard.py @@ -46,44 +46,37 @@ Usage # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- -import Blender as B +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= B.Mathutils.Vector +Vector= Blender.Mathutils.Vector def alpha_mat(image): # returns a material useable for mtl= bpy.data.materials.new() - mtl.mode |= (B.Material.Modes.SHADELESS | B.Material.Modes.ZTRANSP | B.Material.Modes.FULLOSA ) - mtl.alpha= 0.0 # so image sets the alpha - - tex= bpy.data.textures.new() - tex.type= B.Texture.Types.IMAGE - image.antialias = True - tex.setImageFlags('InterPol', 'UseAlpha') - tex.setExtend('Clip') - tex.image= image - - mtl.setTexture(0, tex, B.Texture.TexCo.UV, B.Texture.MapTo.COL | B.Texture.MapTo.ALPHA) - + 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= B.Draw.Create(512) -PREF_TILE_RES= B.Draw.Create(256) -PREF_AA = B.Draw.Create(1) -PREF_ALPHA= B.Draw.Create(1) -PREF_Z_OFFSET = B.Draw.Create(10.0) -PREF_IMG_PACK= B.Draw.Create(1) +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): - B.Window.WaitCursor(1) + Blender.Window.WaitCursor(1) # remove png, add it later PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '') @@ -91,7 +84,7 @@ def save_billboard(PREF_IMAGE_PATH): me_ob = GLOBALS['me_ob'] me_data = GLOBALS['me_data'] - time= B.sys.time() + time= Blender.sys.time() me_mat= me_ob.matrixWorld @@ -99,9 +92,10 @@ def save_billboard(PREF_IMAGE_PATH): 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] @@ -114,9 +108,7 @@ def save_billboard(PREF_IMAGE_PATH): else: rot90= False - - #plane.reverse() - no= B.Mathutils.QuadNormal(*plane) + 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 @@ -127,39 +119,43 @@ def save_billboard(PREF_IMAGE_PATH): #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 |= B.Mesh.FaceModes.TEX + f.mode |= Mesh.FaceModes.TEX f.image = img - f.uv=Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1) if PREF_ALPHA.val: - f.transp |= B.Mesh.FaceTranspModes.ALPHA + 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, rot90) ) + 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 = B.Geometry.BoxPack2D(boxes2Pack) + 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, rot90= face_data[i] + orig_f, img= face_data[i] # New Mesh and Object - render_mat= alpha_mat(img) render_me= bpy.data.meshes.new() - render_ob= B.Object.New('Mesh') + render_ob= Blender.Object.New('Mesh') render_me.materials= [render_mat] render_ob.link(render_me) @@ -178,47 +174,39 @@ def save_billboard(PREF_IMAGE_PATH): Vector(_x + _w, _y +_h, 0),\ Vector(_x + _w, _y, 0),\ ]) - + render_me.faces.extend(list(render_me.verts)) render_me.faceUV= True - # target_face= render_me.faces[-1] - # TEXFACE isnt used because of the renderign engine cant to alpha's for texdface. - #target_face.image= img - #target_face.mode |= B.Mesh.FaceModes.TEX + 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? - uv1, uv2, uv3, uv4= orig_f.uv - uv3.x= uv4.x= _x+_w - uv1.x= uv2.x= _x - - uv2.y= uv3.y= _y+_h - uv1.y= uv4.y= _y - - if rot90: - orig_f.uv= Vector(uv4), Vector(uv1), Vector(uv2), Vector(uv3) - + 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 |= B.Mesh.FaceTranspModes.ALPHA + 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() - B.Window.WaitCursor(0) - print '%.2f secs taken' % (B.sys.time()-time) - - + Blender.Window.WaitCursor(0) + print '%.2f secs taken' % (Blender.sys.time()-time) def main(): @@ -229,13 +217,13 @@ def main(): # Error Checking if len(ob_sel) < 2: - B.Draw.PupMenu("Error%t|Select 2 mesh objects") + Draw.PupMenu("Error%t|Select 2 mesh objects") return me_ob= scn.objects.active if not me_ob: - B.Draw.PupMenu("Error%t|No active mesh selected.") + Draw.PupMenu("Error%t|No active mesh selected.") try: ob_sel.remove(me_ob) @@ -243,14 +231,14 @@ def main(): pass if me_ob.type != 'Mesh': - B.Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too") + 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: - B.Draw.PupMenu("Error%t|Active mesh must have only quads") + Draw.PupMenu("Error%t|Active mesh must have only quads") return @@ -260,13 +248,13 @@ def main(): ("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 all images into 1 image"),\ + ("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 B.Draw.PupBlock("Billboard Render", block): + if not Draw.PupBlock("Billboard Render", block): return # Set globals @@ -274,7 +262,8 @@ def main(): GLOBALS['me_ob'] = me_ob GLOBALS['me_data'] = me_data - B.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', B.sys.makename(ext='.png')) + 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 index 14ab57515ba..cae40b74097 100644 --- a/release/scripts/image_edit.py +++ b/release/scripts/image_edit.py @@ -1,30 +1,31 @@ #!BPY """ -Name: 'Edit Externaly' +Name: 'Edit Externally' Blender: 242a Group: 'Image' Tooltip: 'Open in an application for editing. (hold Shift to configure)' """ __author__ = "Campbell Barton" -__url__ = ["blender", "elysiun"] +__url__ = ["blender", "blenderartists.org"] __version__ = "1.0" - __bpydoc__ = """\ This script opens the current image in an external application for editing. -Useage: +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. +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. +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 assosiated application. +* 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 ***** @@ -48,17 +49,36 @@ This will use the system default assosiated application. # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- +import Blender +from Blender import Image, sys, Draw, Registry try: - import os + import subprocess import sys as py_sys platform = py_sys.platform except: - Draw.PupMenu('Error, python not installed') - os=None + Draw.PupMenu('Error: Recent version of Python not installed.') + subprocess=None -import Blender -from Blender import Image, sys, Draw, Registry +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): @@ -66,7 +86,7 @@ def edit_extern(image=None): image = Image.GetCurrent() if not image: # Image is None - Draw.PupMenu('ERROR: You must select an active Image.') + Draw.PupMenu('ERROR: Please select active Image.') return if image.packed: Draw.PupMenu('ERROR: Image is packed, unpack before editing.') @@ -94,16 +114,19 @@ def edit_extern(image=None): if new_text: pupblock.append('first time, set path.') if platform == 'win32': - appstring = 'start "" /B "%f"' + # 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-remote "%f"' + appstring = 'gimp %f' appstring_but = Draw.Create(appstring) save_default_but = Draw.Create(0) - pupblock.append(('editor: ', appstring_but, 0, 48, 'Path to application, %f will be replaced with the image path.')) + 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, @@ -118,19 +141,18 @@ def edit_extern(image=None): Registry.SetKey('ExternalImageEditor', {'path':appstring}, True) if appstring.find('%f') == -1: - Draw.PupMenu('ERROR: The comment you entered did not contain the filename ("%f")') + Draw.PupMenu('ERROR: No filename specified! ("%f")') return # ------------------------------- - appstring = appstring.replace('%f', imageFileName) - print '\tediting image with command "%s"' % appstring - os.system(appstring) + os_run(appstring, imageFileName) + def main(): edit_extern() -if __name__ == '__main__' and os != None: - main()
\ No newline at end of file +if __name__ == '__main__' and subprocess: + main() diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py index 2a1081420e4..bb0119a9a81 100644 --- a/release/scripts/import_dxf.py +++ b/release/scripts/import_dxf.py @@ -2,88 +2,166 @@ """ Name: 'Autodesk DXF (.dxf)' -Blender: 244 +Blender: 246 Group: 'Import' Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).' """ __author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' -__version__ = '1.0.11 - 2007.11.17 by migius' +__version__ = '1.12 - 2008.08.03 by migius' __url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] -__email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"] +__email__ = ["migius(at)4d-vectors.de","Kitsune_e(at)yahoo.com"] __bpydoc__ = """\ -This script imports DXF objects (2d/3d) into Blender. +This script imports objects from DXF (2d/3d) into Blender. -This script imports 2d and 3d Geometery from DXFr12 format files. -This version is focused on import of 3d-objects. +This script imports 2d and 3d geometery from DXF files. +Supported DXF format versions: from (r2.5) r12 up to 2008. +Enhanced features are: +- configurable object filtering and geometry manipulation, +- configurable material pre-processing, +- DXF-code analyze and reporting. -Supported DXF Objects: +Supported DXF r12 objects: LINE, POINT, SOLID, TRACE, TEXT, INSERT (=block), -MINSERT (=arrays of blocks), +MINSERT (=array of blocks), CIRCLE, ARC, 3DFACE, 2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline), -3d-POLYLINE (=non-plane polylines), +3d-POLYLINE (=non-plane), 3d-POLYMESH, -3d-POLYFACE - -under construction, partly supported DXF>r12 Objects: -LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE - -Unsupported DXF Objects: -DXF r12: DIMENSION, XREF (External Reference), -DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK - -Supported Properties: -Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender -visibility, frozen, -COLOR, LAYER, -thickness, width, -(todo: grouped, XDATA) -It is recommended to use DXF-object properties for coding Blender materials. +3d-POLYFACE, +VIEW, VPORT +XREF (External Reference). + +Supported DXF>r12 objects: +ELLIPSE, +LWPOLYLINE (LightWeight Polyline), +SPLINE, +(wip v1.13) MLINE, +(wip 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 objescts 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, +(wip 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. -- Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem. - -TODO: -- the new style object visibility -- support for real 3d-solids (ACIS) -- (to see more, search for "-todo-" in script) +- 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.11. by migius: "full 3d"-release + v1.0 - 2007/2008 by migius planned tasks: + -- (to see more, search for "--todo--" in script code) -- command-line-mode/batch-mode -- in-place-editing for dupliGroups - -- filtering of unused/not-inserted BLOCKs - -- support for MLine - -- support for Ellipse - -- support for Mtext - -- blender_object.ID.properties[dxf_layer_name] + -- 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 - -- Configuration files(.ini) should/can handle various material setups + -- 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 - -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname) -- "normalize Z" option to correct non-planar figures -- LINEs need "width" in 3d-space incl vGroups -- support width_force for LINEs/ELLIPSEs = "solidify" - -- bug: dxf-files without layer-section missing layersmap{} - -- color BYLAYER=256,BYBLOCK=0 - -- blocknames conventions length - v1.0.11: 2007.11.17 by migius + -- 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 scene, lights and cameras + -- support ortho mode for VIEWs and VPORTs as cameras + + + 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 anoname/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 @@ -101,17 +179,19 @@ History: 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 first try to fix malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. - a3 bugfix: open POLYLINEs with end_point.loc==start_point.loc + 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" option to draw top and bottom sides of CIRCLEs and ELLIPSEs + 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: Cylinders/Arcs were drawn at <0,0,0>location - beta09: 2007.09.02 by migius + 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 @@ -124,7 +204,7 @@ History: 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(cntrolled by ini-parameters) + 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 @@ -139,23 +219,24 @@ History: 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 - beta08: 2007.07.27 by migius + + 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 interface using UIBlock() with own FileSelector, cause Window.FileSelector() too buggy + 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 polylines and solids generated Meshes, for easier material assignment + 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 Object/Mesh for all simple-entities from the same Layer, - sorted in Vertex-Groups(color_name) (fewer objects = better import performance) + h- added "one Mesh" option for all entities from the same Layer, sorted in<br> + Vertex-Groups(color_name) (fewer objects = better import performance) g- rewrote: insert-point-handle-object is a small tetrahedron e- bugfix: closed-polymesh3d - - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut) + - 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 @@ -167,7 +248,7 @@ History: - 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_calcBulge for correct import the arc-segments of Polylines + - 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 @@ -180,13 +261,16 @@ History: - 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 """ @@ -213,9 +297,9 @@ History: # -------------------------------------------------------------------------- import Blender -#import bpy from Blender import * #from Blender.Mathutils import Vector, Matrix +import bpy #import BPyMessages from dxfReader import readDXF @@ -239,8 +323,10 @@ except ImportError: #print 'psyco not imported' pass -print '\n\n\n\n' -print 'Import DXF to Blender *** start ***' #--------------------- +#try: Curve.orderU + +print '\n\n\n' +print 'DXF-Importer v%s *** start ***' %(__version__) #--------------------- SCENE = None WORLDX = Mathutils.Vector((1,0,0)) @@ -248,10 +334,13 @@ WORLDY = Mathutils.Vector((1,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 #(3-50) Bezier curves resolution +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 @@ -259,119 +348,232 @@ 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 +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 = "*) 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' +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 -cur_COUNTER = 0 #counter for progress_bar -"""This module provides wrapper objects for dxf entities. +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 - The wrappers expect a "dxf object" as input. The dxf object is - an object with a type and a data attribute. Type is a lowercase - string matching the 0 code of a dxf entity. Data is a list containing - dxf objects or lists of [code, data] pairs. + self.type = obj.type + self.name = obj.get_type(2)[0] +# self.data = obj.data[:] - This module is not general, and is only for dxf import. -""" -# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) -#---color values -BYBLOCK = 0 -BYLAYER = 256 + 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) -#---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) - -#---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 - -#---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 + 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 -class Layer: #----------------------------------------------------------------- - """Class for objects representing dxf LAYERs. + 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, name=None, color=None, frozen=None): - """Expects an object of type layer as input. + 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.data = obj.data[:] + 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 - 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 + self.flags = getit(obj, 70, 0) + self.paperspace = self.flags & 1 # - if color: - self.color = color - else: - self.color = obj.get_type(62)[0] #color of object + self.mode = obj.get_type(71)[0] #view mode (VIEWMODE system variable) - if frozen: - self.frozen = frozen + 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: - self.flags = obj.get_type(70)[0] - self.frozen = self.flags & 1 + 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) @@ -415,6 +617,14 @@ def get_extrusion(data): #------------------------------------------------- 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. @@ -426,16 +636,17 @@ class Solid: #----------------------------------------------------------------- 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.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.data, 8, None) - self.extrusion = get_extrusion(obj.data) - self.points = self.get_points(obj.data) + self.layer = getit(obj, 8, None) + self.extrusion = get_extrusion(obj) + self.points = self.get_points(obj) @@ -516,16 +727,16 @@ class Solid: #----------------------------------------------------------------- if l == 4: faces = [[0,1,3,2]] elif l == 3: faces = [[0,1,2]] elif l == 2: edges = [[0,1]] - - - - me = Mesh.New(obname) # create a new 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 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 - ob = SCENE.objects.new(me) # create a new mesh_object - if settings.var['vGroup_on']: + if settings.var['vGroup_on'] and not M_OBJ: # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) @@ -539,9 +750,6 @@ class Solid: #----------------------------------------------------------------- return ob - - - class Line: #----------------------------------------------------------------- """Class for objects representing dxf LINEs. """ @@ -551,16 +759,16 @@ class Line: #----------------------------------------------------------------- if not obj.type == 'line': raise TypeError, "Wrong type \'%s\' for line object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# 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.data, 8, None) - self.extrusion = get_extrusion(obj.data) - self.points = self.get_points(obj.data) + self.layer = getit(obj, 8, None) + self.extrusion = get_extrusion(obj) + self.points = self.get_points(obj) def get_points(self, data): @@ -597,10 +805,10 @@ class Line: #----------------------------------------------------------------- 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 + elif settings.var['lines_as'] == 3: # as thin cylinder cyl_rad = 0.5 * settings.var['width_min'] - if settings.var['curves_on']: # LINE curve representation------------------------- + elif settings.var['lines_as'] == 5: # LINE curve representation------------------------- obname = 'li_%s' %self.layer # create object name from layer name obname = obname[:MAX_NAMELENGTH] @@ -610,6 +818,7 @@ class Line: #----------------------------------------------------------------- for point in curve: point.handleTypes = [VECT, VECT] 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 @@ -633,20 +842,23 @@ class Line: #----------------------------------------------------------------- global activObjectName #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- - ob = Object.Get(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - me = Mesh.Get(ob.name) # open objects mesh data - 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) #--------------------- + 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) @@ -665,7 +877,7 @@ class Line: #----------------------------------------------------------------- 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']: + 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 @@ -694,16 +906,16 @@ class Point: #----------------------------------------------------------------- if not obj.type == 'point': raise TypeError, "Wrong type %s for point object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# 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.data, 8, None) - self.extrusion = get_extrusion(obj.data) - self.points = self.get_points(obj.data) + self.layer = getit(obj, 8, None) + self.extrusion = get_extrusion(obj) + self.points = self.get_points(obj) def get_points(self, data): @@ -733,13 +945,13 @@ class Point: #----------------------------------------------------------------- thic = settings.var['thick_min'] if thic < settings.var['dist_min']: thic = settings.var['dist_min'] - if points_as in [1,3,4]: - if points_as == 1: # as 'empty' + if points_as in [1,3,4,5]: + if True: # points_as in [1,5]: # as 'empty' c = 'Empty' - if points_as == 3: # as 'thin sphere' + elif points_as == 3: # as 'thin sphere' res = settings.var['thin_res'] c = Mesh.Primitives.UVsphere(res,res,thic) - if points_as == 4: # as 'thin box' + 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) @@ -749,156 +961,23 @@ class Point: #----------------------------------------------------------------- global activObjectLayer global activObjectName #print 'deb:draw:point.ob IN activObjectName: ', activObjectName #--------------------- - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:draw:point.ob obname from activObjectName: ', obname #--------------------- - ob = Object.Get(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - 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 LWpolyline: #----------------------------------------------------------------- - """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.color_index = getit(obj, 62, BYLAYER) - - self.elevation = getit(obj, 30, 0) - self.thic = getit(obj, 39, 0) - self.flags = getit(obj, 70, 0) - - self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen - - self.layer = getit(obj.data, 8, None) - self.points = self.get_points(obj.data) - self.extrusion = get_extrusion(obj.data) - - #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] - 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) - - - def draw(self, settings): - """for LWPOLYLINE: generate Blender_geometry. - """ - #print 'deb:LWpolyline.draw.START:----------------' #------------------------ - points = [] - obname = 'lw_%s' %self.layer # create object name from layer name - obname = obname[:MAX_NAMELENGTH] - #settings.var['curves_on'] == True - #print 'deb:index_len: ', len(self.points) #------------------ - for i, point in enumerate(self.points): - #print 'deb:index: ', i #------------------ - if not point.bulge: - points.append(point.loc) - elif point.bulge and not self.closed and i == len(self.points)-1: - points.append(point.loc) - elif point.bulge: # - if i == len(self.points)-1: - point2 = self.points[0] + 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: - point2 = self.points[i+1] - arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) - verts, center = calcBulge(point, point2, arc_res) -# if i == len(self.points)-1: -# if self.closed: -# verts.pop() #remove last(=first) vertex -# else: -# verts.pop() #remove last vertex, because this point will be writen as the next vertex - points.extend(verts) - - thic = self.thic - if settings.var['thick_force'] and thic == 0: thic = settings.var['thick_min'] - if settings.var['thick_on'] and thic != 0: - len1 = len(points) - points.extend([[point[0], point[1], point[2]+thic] for point in points]) - faces = [] - #print 'deb:len1:', len1 #----------------------- - 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]) - #print 'deb:faces_list:\n', faces #----------------------- - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object + 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 - me.faces.extend(faces) # add faces to the mesh - else: - edges = [[num, num+1] for num in xrange(len(points)-1)] - if self.closed: - edges.append([len(points)-1, 0]) - #print 'deb:edges_list:\n', edges #----------------------- - 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 - ob.LocZ = self.elevation - transform(self.extrusion, 0, ob) - - #print 'deb:LWpolyline.draw.END:----------------' #------------------------ return ob @@ -913,11 +992,8 @@ class Polyline: #-------------------------------------------------------------- if not obj.type == 'polyline': raise TypeError, "Wrong type %s for polyline object!" %obj.type self.type = obj.type - self.data = obj.data[:] - #print 'deb:polyline.obj.data[:]:\n', obj.data[:] #------------------------ - self.points = [] +# self.data = obj.data[:] - # optional data (with defaults) self.space = getit(obj, 67, 0) self.elevation = getit(obj, 30, 0) #print 'deb:elevation: ', self.elevation #--------------- @@ -927,17 +1003,17 @@ class Polyline: #-------------------------------------------------------------- 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 # Bspline-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 - if self.poly3d or self.plface or self.plmesh: - self.poly2d = False # its not a 2D-polyline - else: - self.poly2d = True # it is a 2D-polyline + 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 @@ -946,18 +1022,18 @@ class Polyline: #-------------------------------------------------------------- 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.curvetyp = getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier - self.curvNormal = False - self.curvQBspline = False - self.curvCBspline = False + self.curvNoFitted = False + self.curvQuadrati = False + self.curvCubicBsp = False self.curvBezier = False - if self.curvetyp == 0: self.curvNormal = True - elif self.curvetyp == 5: self.curvQBspline = True - elif self.curvetyp == 6: self.curvCBspline = True - elif self.curvetyp == 8: self.curvBezier = True + 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.data, 8, None) - self.extrusion = get_extrusion(obj.data) + 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 @@ -970,29 +1046,100 @@ class Polyline: #-------------------------------------------------------------- + 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 = [] - if self.plface: #---- 3dPolyFace - mesh with free topology + #---- 3dPolyFace - mesh with free topology + if self.pltype=='plface' and settings.drawTypes['plmesh']: ob = self.drawPlFace(settings) - elif self.plmesh: #---- 3dPolyMesh - mesh with ortogonal topology + #---- 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.poly2d or self.poly3d: - if settings.var['curves_on']: # and self.spline: + 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) - return ob + #---- 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:polyface.draw.START:----------------' #------------------------ + #print 'deb:drawPlFace.START:----------------' #------------------------ points = [] faces = [] #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ @@ -1002,23 +1149,33 @@ class Polyline: #-------------------------------------------------------------- else: points.append(point.loc) + if settings.var['plmesh_flip']: # ---------------------- + for face in faces: + face.reverse() + face = [face[-1]] + face[:-1] - #print 'deb:len of points_list:\n', len(points) #----------------------- - #print 'deb:points_list:\n', points #----------------------- - #print 'deb:faces_list:\n', faces #----------------------- + #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(faces)): + for i in xrange(len(me.faces)): me.faces[i].smooth = True #me.Mode(AUTOSMOOTH) transform(self.extrusion, 0, ob) - #print 'deb:polyface.draw.END:----------------' #------------------------ + #print 'deb:drawPlFace.END:----------------' #------------------------ return ob @@ -1058,7 +1215,10 @@ class Polyline: #-------------------------------------------------------------- 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 @@ -1077,9 +1237,9 @@ class Polyline: #-------------------------------------------------------------- #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 + 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 = [] @@ -1095,6 +1255,10 @@ class Polyline: #-------------------------------------------------------------- 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] @@ -1108,26 +1272,14 @@ class Polyline: #-------------------------------------------------------------- pline = Curve.New(obname) # create new curve data #pline.setResolu(24) #--todo----- - if False: #self.spline: # NURBSplines-----FAKE(with Bezier)----- - #print 'deb:polyline2dCurve.draw self.spline!' #--------------- - 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] - if self.closed: - curve.flagU = 1 # Set curve cyclic=close - else: - curve.flagU = 0 # Set curve not cyclic=open - curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- - curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- - - elif self.spline: # NURBSplines-----OK----- + if False: #old self.spline: # NURBSplines-----OK----- #print 'deb:polyline2dCurve.draw self.spline!' #--------------- weight1 = 0.5 weight2 = 1.0 - # generate middlepoints except start/end-segments --- - if self.curvQBspline: + if self.curvQuadrati: + # Bezier-curve form simulated in NURBS-curve + # generate middlepoints except start/end-segments --- + #print 'deb:polyline2dCurve.draw extraQBspline!' #--------------- temp_points = [] point = d_points[0].loc point.append(weight1) @@ -1180,7 +1332,27 @@ class Polyline: #-------------------------------------------------------------- else: curve.flagU = 0 # Set curve not cyclic=open - elif self.curved: #--Bezier-curves---OK------- + 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 curvetype NURBS + for point in nurbs_points[1:]: + curve.append(point) + 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 False: #orig self.curved: #--Bezier-curves---OK------- #print 'deb:polyline2dCurve.draw self.curved!' #--------------- curve = pline.appendNurb(BezTriple.New(d_points[0])) for p in d_points[1:]: @@ -1194,7 +1366,45 @@ class Polyline: #-------------------------------------------------------------- curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- - else: #--straight line- and arc-segments----OK------ + 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] + #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----- + 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----- + + + + else: #-- only straight line- and arc-segments----OK------ #print 'deb:polyline2dCurve.draw curve:', curve #----- points = [] arc_res = settings.var['curve_arc'] @@ -1288,6 +1498,7 @@ class Polyline: #-------------------------------------------------------------- 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 @@ -1314,6 +1525,7 @@ class Polyline: #-------------------------------------------------------------- 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' @@ -1350,8 +1562,10 @@ class Polyline: #-------------------------------------------------------------- #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 #------------------------ - # routine to sort out of "double.vertices" ------------------------------------ + """# routine to sort out of "double.vertices" ------------------------------------ minimal_dist = settings.var['dist_min'] * 0.1 temp_points = [] for i in xrange(len(d_points)-1): @@ -1366,6 +1580,7 @@ class Polyline: #-------------------------------------------------------------- #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 #------------------------ + """ #print 'deb:drawPoly2d len of d_pointsList ====== ', len(d_points) #------------------------ if len(d_points) < 2: #if too few vertex, then return @@ -1385,9 +1600,11 @@ class Polyline: #-------------------------------------------------------------- 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'] @@ -1571,14 +1788,14 @@ class Polyline: #-------------------------------------------------------------- left_angle = False limit_dist = settings.var['dist_min'] if left_angle: # if left turning angle - print 'deb:drawPoly2d it is left turning angle' #------------- + #print 'deb:drawPoly2d it is left turning angle' #------------- # to avoid triangelface/doubleVertex delta1 = (cornerpointL - vecL1).normalize() * limit_dist delta4 = (cornerpointL - vecL4).normalize() * limit_dist pointsLc.extend((cornerpointL - delta1, cornerpointL - delta4)) pointsRc.extend((pointsRe[i],pointsRs[i+1])) else: # if right turning angle - print 'deb:drawPoly2d right turning angle' #------------- + #print 'deb:drawPoly2d right turning angle' #------------- delta1 = (cornerpointR - vecR1).normalize() * limit_dist delta4 = (cornerpointR - vecR4).normalize() * limit_dist pointsRc.extend((cornerpointR - delta1, cornerpointR - delta4)) @@ -1669,8 +1886,10 @@ class Polyline: #-------------------------------------------------------------- #faces = f_bottom + f_top #faces = f_left + f_right + f_start + f_end #print 'deb:faces_list:\n', faces #----------------------- - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object + 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 @@ -1678,7 +1897,7 @@ class Polyline: #-------------------------------------------------------------- # 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']: + if settings.var['vGroup_on'] and not M_OBJ: # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] @@ -1708,8 +1927,10 @@ class Polyline: #-------------------------------------------------------------- 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]) - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object + 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 @@ -1728,8 +1949,10 @@ class Polyline: #-------------------------------------------------------------- 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]) - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object + 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 @@ -1745,8 +1968,10 @@ class Polyline: #-------------------------------------------------------------- edges = [[num, num+1] for num in xrange(len(points)-1)] if self.closed: edges.append([len(points)-1, 0]) - me = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(me) # create a new mesh_object + 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 @@ -1758,7 +1983,8 @@ class Polyline: #-------------------------------------------------------------- class Vertex(object): #----------------------------------------------------------------- - """Generic vertex object used by POLYLINEs (and maybe others). + """Generic vertex object used by POLYLINEs, (and maybe others). + also used by class_LWPOLYLINEs but without obj-parameter """ def __init__(self, obj=None): @@ -1769,15 +1995,19 @@ class Vertex(object): #-------------------------------------------------------- #print 'deb:Vertex.init.START:----------------' #----------------------- self.loc = [0,0,0] self.face = [] - self.swidth = 0 - self.ewidth = 0 + 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.data) +# self.data = obj.data[:] + self.get_props(obj) + else: + pass #print 'deb:Vertex.init.END:----------------' #------------------------ @@ -1798,24 +2028,29 @@ class Vertex(object): #-------------------------------------------------------- self.flags = getit(data, 70, 0) # flags self.curved = self.flags&1 # Bezier-curve-fit:additional-vertex - self.curv_t = self.flags&2 # Bezier-curve-fit:tangent exists - self.spline = self.flags&8 # Bspline-fit:additional-vertex - self.splin2 = self.flags&16 # Bspline-fit:control-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.curv_t: - self.curv_tangent = getit(data, 50, None) # curve_tangent - - if 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 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 @@ -1870,6 +2105,263 @@ class Vertex(object): #-------------------------------------------------------- +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) + + #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 'spline_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. """ @@ -1879,7 +2371,7 @@ class Text: #----------------------------------------------------------------- if not obj.type == 'text': raise TypeError, "Wrong type %s for text object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# self.data = obj.data[:] # required data self.height = 1.7 * obj.get_type(40)[0] #text.height @@ -1911,14 +2403,13 @@ class Text: #----------------------------------------------------------------- #3=aligned, 4=middle, 5=fit self.halignment = getit(obj, 72, 0) - self.layer = getit(obj.data, 8, None) - self.loc1, self.loc2 = self.get_loc(obj.data) + 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.data) - + self.extrusion = get_extrusion(obj) def get_loc(self, data): @@ -2027,13 +2518,13 @@ class Mtext: #----------------------------------------------------------------- if not obj.type == 'mtext': raise TypeError, "Wrong type %s for mtext object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# 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.data) # The text string value + self.value = self.get_text(obj) # The text string value # optional data (with defaults) self.space = getit(obj, 67, 0) @@ -2043,9 +2534,9 @@ class Mtext: #----------------------------------------------------------------- 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.data, 8, None) - self.loc = self.get_loc(obj.data) - self.extrusion = get_extrusion(obj.data) + self.layer = getit(obj, 8, None) + self.loc = self.get_loc(obj) + self.extrusion = get_extrusion(obj) def get_text(self, data): @@ -2114,8 +2605,6 @@ class Mtext: #----------------------------------------------------------------- return ob - - class Circle: #----------------------------------------------------------------- """Class for objects representing dxf CIRCLEs. """ @@ -2126,7 +2615,7 @@ class Circle: #---------------------------------------------------------------- if not obj.type == 'circle': raise TypeError, "Wrong type %s for circle object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# self.data = obj.data[:] # required data self.radius = obj.get_type(40)[0] @@ -2136,9 +2625,9 @@ class Circle: #---------------------------------------------------------------- self.thic = getit(obj, 39, 0) self.color_index = getit(obj, 62, BYLAYER) - self.layer = getit(obj.data, 8, None) - self.loc = self.get_loc(obj.data) - self.extrusion = get_extrusion(obj.data) + self.layer = getit(obj, 8, None) + self.loc = self.get_loc(obj) + self.extrusion = get_extrusion(obj) @@ -2167,18 +2656,15 @@ class Circle: #---------------------------------------------------------------- radius = self.radius thic = set_thick(self.thic, settings) - if settings.var['curves_on']: - if False: # universal version - arc_res = 4 # ONLY 4 works well for point.handleTypes = [AUTO, AUTO] - start, end = 0.0, 360.0 - verts = calcArc(None, radius, start, end, arc_res, True) - c = Curve.New(obname) # create new curve data - curve = c.appendNurb(BezTriple.New(verts[0])) - for p in verts[1:-1]: - curve.append(BezTriple.New(p)) - for point in curve: - point.handleTypes = [AUTO, AUTO] - elif True: # universal version + 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 ------------- + if True: # universal version arc_res = settings.var['curve_arc'] #arc_res = 3 start, end = 0.0, 360.0 @@ -2214,9 +2700,10 @@ class Circle: #---------------------------------------------------------------- else: c.setFlag(c.getFlag() & ~6) # dont set top and button caps + c.setResolu(settings.var['curve_res']) c.update() - #remi --todo-----to check--------------------------- + #--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 @@ -2247,14 +2734,17 @@ class Circle: #---------------------------------------------------------------- return ob else: # draw CIRCLE as mesh ----------------------------------------------- - cir = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(cir) # create a new circle_object + 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:edges:', edges #--------------- + #print 'deb:circleDraw: verts:', verts #--------------- + if thic != 0: len1 = len(verts) thic_verts = [] @@ -2286,24 +2776,24 @@ class Circle: #---------------------------------------------------------------- #print 'deb:circleDraw:verts:', verts #--------------- faces = f_band + f_bottom + f_top #print 'deb:circleDraw:faces:', faces #--------------- - cir.verts.extend(verts) # add vertices to mesh - cir.faces.extend(faces) # add faces to the mesh + 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): - cir.faces[i].smooth = True + me.faces[i].smooth = True # each MeshSide becomes vertexGroup for easier material assignment --------------------- - if settings.var['vGroup_on']: + if settings.var['vGroup_on'] and not M_OBJ: # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD vg_band, vg_top, vg_bottom = [], [], [] for v in f_band: vg_band.extend(v) - cir.addVertGroup('side.band') ; cir.assignVertsToGroup('side.band', list(set(vg_band)), 1.0, replace) + me.addVertGroup('side.band') ; me.assignVertsToGroup('side.band', list(set(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) - cir.addVertGroup('side.top') ; cir.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) - cir.addVertGroup('side.bottom'); cir.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) + me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) else: # if thic == 0 if settings.var['fill_on']: @@ -2315,20 +2805,18 @@ class Circle: #---------------------------------------------------------------- faces.append([len1-1, 0, center1]) #print 'deb:circleDraw:verts:', verts #--------------- #print 'deb:circleDraw:faces:', faces #--------------- - cir.verts.extend(verts) # add vertices to mesh - cir.faces.extend(faces) # add faces to the mesh + me.verts.extend(verts) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh else: - cir.verts.extend(verts) # add vertices to mesh + 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 - cir.edges.extend(edges) # add edges to the mesh + 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. @@ -2340,7 +2828,7 @@ class Arc: #----------------------------------------------------------------- if not obj.type == 'arc': raise TypeError, "Wrong type %s for arc object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# self.data = obj.data[:] # required data self.radius = obj.get_type(40)[0] @@ -2352,9 +2840,9 @@ class Arc: #----------------------------------------------------------------- self.thic = getit(obj, 39, 0) self.color_index = getit(obj, 62, BYLAYER) - self.layer = getit(obj.data, 8, None) - self.loc = self.get_loc(obj.data) - self.extrusion = get_extrusion(obj.data) + 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 #--------- @@ -2395,7 +2883,7 @@ class Arc: #----------------------------------------------------------------- if settings.var['lines_as'] == 3: # as thin cylinder cyl_rad = 0.5 * settings.var['width_min'] - if settings.var['curves_on']: # draw ARC as curve ------------- + 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) @@ -2406,6 +2894,8 @@ class Arc: #----------------------------------------------------------------- for point in curve: point.handleTypes = [FREE, FREE] 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 @@ -2420,8 +2910,10 @@ class Arc: #----------------------------------------------------------------- return ob else: # draw ARC as mesh -------------------- - arc = Mesh.New(obname) # create a new mesh - ob = SCENE.objects.new(arc) # create a new arc_object + 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']) @@ -2430,34 +2922,19 @@ class Arc: #----------------------------------------------------------------- len1 = len(verts) #print 'deb:len1:', len1 #----------------------- if width != 0: - if False: - 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 - else: - 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 + 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: @@ -2476,15 +2953,15 @@ class Arc: #----------------------------------------------------------------- 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 - arc.verts.extend(verts) # add vertices to mesh - arc.faces.extend(faces) # add faces to the mesh + 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): - arc.faces[i].smooth = True + me.faces[i].smooth = True # each MeshSide becomes vertexGroup for easier material assignment --------------------- - if settings.var['vGroup_on']: + if settings.var['vGroup_on'] and not M_OBJ: # each MeshSide becomes vertexGroup for easier material assignment --------------------- replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] @@ -2492,18 +2969,18 @@ class Arc: #----------------------------------------------------------------- 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) - arc.addVertGroup('side.left') ; arc.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace) - arc.addVertGroup('side.right') ; arc.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) - arc.addVertGroup('side.top') ; arc.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) - arc.addVertGroup('side.bottom'); arc.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) - arc.addVertGroup('side.start'); arc.assignVertsToGroup('side.start', f_start[0], 1.0, replace) - arc.addVertGroup('side.end') ; arc.assignVertsToGroup('side.end', f_end[0], 1.0, replace) + me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace) + me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) + me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(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)] - arc.verts.extend(verts) # add vertices to mesh - arc.faces.extend(faces) # add faces to the mesh + me.verts.extend(verts) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh elif thic != 0: thic_verts = [] @@ -2518,20 +2995,20 @@ class Arc: #----------------------------------------------------------------- #print 'deb:verts:', verts #--------------------- faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] - arc.verts.extend(verts) # add vertices to mesh - arc.faces.extend(faces) # add faces to the mesh + 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)): - arc.faces[i].smooth = True + me.faces[i].smooth = True else: edges = [[num, num+1] for num in xrange(len(verts)-1)] - arc.verts.extend(verts) # add vertices to mesh - arc.edges.extend(edges) # add edges to the mesh + me.verts.extend(verts) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh - #arc.update() - #ob = SCENE.objects.new(arc) # create a new arc_object - #ob.link(arc) + #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) @@ -2549,7 +3026,7 @@ class BlockRecord: #----------------------------------------------------------- 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[:] +# self.data = obj.data[:] # required data self.name = getit(obj, 2, None) @@ -2557,8 +3034,8 @@ class BlockRecord: #----------------------------------------------------------- # optional data (with defaults) self.insertion_units = getit(obj, 70, None) self.insert_units = getit(obj, 1070, None) - """code 1070 Einfügeeinheiten: - 0 = Keine Einheiten; 1 = Zoll; 2 = Fuß; 3 = Meilen; 4 = Millimeter; + """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; @@ -2582,30 +3059,44 @@ class Block: #----------------------------------------------------------------- """ if not obj.type == 'block': raise TypeError, "Wrong type %s for block object!" %obj.type + self.type = obj.type - self.data = obj.data[:] self.name = obj.name + self.data = obj.data[:] # required data - self.flags = obj.get_type(70)[0] - 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.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, '') + self.path = getit(obj, 1, '') # Xref path name self.discription = getit(obj, 4, '') - self.layer = getit(obj.data, 8, None) - self.loc = self.get_loc(obj.data) + 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, None) # 10 = x - loc[1] = getit(data, 20, None) # 20 = y - loc[2] = getit(data, 30, 0.0) # 30 = z + 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 @@ -2626,21 +3117,24 @@ class 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.blockname = obj.get_type(2)[0] + 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.data, 8, None) - self.loc = self.get_loc(obj.data) - self.scale = self.get_scale(obj.data) - self.rows, self.columns = self.get_array(obj.data) - self.extrusion = get_extrusion(obj.data) + 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): @@ -2653,7 +3147,6 @@ class Insert: #---------------------------------------------------------------- return loc - def get_scale(self, data): """Gets the x/y/z scale factors of the insert. """ @@ -2664,7 +3157,6 @@ class Insert: #---------------------------------------------------------------- return scale - def get_array(self, data): """Returns the pair (row number, row spacing), (column number, column spacing). """ @@ -2675,9 +3167,38 @@ class Insert: #---------------------------------------------------------------- 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, blockname - %s" %(self.__class__.__name__, self.layer, self.blockname) + return "%s: layer - %s, name - %s" %(self.__class__.__name__, self.layer, self.name) def draw(self, settings, deltaloc): @@ -2692,11 +3213,89 @@ class Insert: #---------------------------------------------------------------- insert object gives the location/scale/rotation of the block instances. """ - obname = settings.blocknamesmap[self.blockname] - obname = 'in_%s' %obname # create object name from block name - #obname = obname[:MAX_NAMELENGTH] - - if settings.drawTypes['insert']: #if insert_drawType activated + 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 + elif False: # 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) @@ -2704,19 +3303,22 @@ class Insert: #---------------------------------------------------------------- ob.drawSize = empty_size # get our block_def-group - block = settings.blocks(self.blockname) + block = settings.blocks(self.name) ob.DupGroup = block ob.enableDupGroup = True - #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 + 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 @@ -2731,11 +3333,11 @@ class Ellipse: #--------------------------------------------------------------- if not obj.type == 'ellipse': raise TypeError, "Wrong type %s for ellipse object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# self.data = obj.data[:] # required data - self.ratio = obj.get_type(40)[0] - self.start_angle = obj.get_type(41)[0] + 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) @@ -2743,11 +3345,10 @@ class Ellipse: #--------------------------------------------------------------- self.thic = getit(obj, 39, 0.0) self.color_index = getit(obj, 62, BYLAYER) - self.layer = getit(obj.data, 8, None) - self.loc = self.get_loc(obj.data) - self.major = self.get_major(obj.data) - self.extrusion = get_extrusion(obj.data) - self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) + 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): @@ -2781,31 +3382,176 @@ class Ellipse: #--------------------------------------------------------------- def draw(self, settings): """for ELLIPSE: generate Blender_geometry. """ - # Generate the geometery + obname = 'el_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + center = self.loc + if True: + 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 + + else: # bug in AutoCAD_2002 dxf-exporter into r12 for ELLIPSE->POLYLINE_ARC + #print 'deb:calcEllipse---------:\n start=%s\n end=%s' %(self.start_angle, self.end_angle) #--------- + if self.start_angle > pi+pi: self.start_angle %= pi+pi + if self.end_angle > pi+pi: self.end_angle %= pi+pi + if abs(self.end_angle - pi - pi) < 0.00001: self.end_angle = pi + pi + ellipse_closed = False + if abs(self.end_angle - self.start_angle) == pi + pi: ellipse_closed = True + test = self.start_angle % pi + if test < 0.001 or pi - test < 0.001: start = self.start_angle + else: + start = atan(tan(self.start_angle) * self.ratio) + if start < 0.0: start += pi + if self.start_angle > pi: start += pi + test = self.end_angle % pi + if test < 0.001 or pi - test < 0.001: end = self.end_angle + else: + end = atan(tan(self.end_angle) * self.ratio) + if end < 0.0: end += pi + if self.end_angle > pi: end += pi + start = degrees(start) + end = degrees(end) + + # 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'] - if settings.var['curves_on']: - ob = drawCurveArc(self) - else: - obname = 'el_%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 + 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] + 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] + 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 - major = Mathutils.Vector(self.major) - #remi--todo----AngleBetweenVecs makes abs(value)!----- - delta = Mathutils.AngleBetweenVecs(major, WORLDX) - radius = major.length - start = degrees(self.start_angle) - end = degrees(self.end_angle) + 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] - if thic != 0: - len1 = len(verts) + if False: #--todo--: if ellipse_closed: + verts = verts[:-1] #list without last point/edge (cause closed curve) + 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 = Blender.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', list(set(vg_left)), 1.0, replace) + me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) + me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(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: @@ -2815,21 +3561,28 @@ class Ellipse: #--------------------------------------------------------------- verts.extend(thic_verts) faces = [] #print 'deb:len1:', len1 #----------------------- - #print 'deb:verts:', verts #---------------------- + #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 + 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 - - ob.loc = tuple(center) - ob.SizeY = self.ratio - transform(self.extrusion, 0, ob) + me.verts.extend(verts) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh - return ob + #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 @@ -2843,14 +3596,14 @@ class Face: #----------------------------------------------------------------- if not obj.type == '3dface': raise TypeError, "Wrong type %s for 3dface object!" %obj.type self.type = obj.type - self.data = obj.data[:] +# 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.data, 8, None) - self.points = self.get_points(obj.data) + self.layer = getit(obj, 8, None) + self.points = self.get_points(obj) def get_points(self, data): @@ -2897,21 +3650,24 @@ class Face: #----------------------------------------------------------------- global activObjectName #print 'deb:draw:face.ob IN activObjectName: ', activObjectName #--------------------- - if activObjectLayer == self.layer and settings.var['one_mesh_on']: - obname = activObjectName - #print 'deb:face.draw obname from activObjectName: ', obname #--------------------- - ob = Object.Get(obname) # open an existing mesh_object - #ob = SCENE.getChildren(obname) # open an existing mesh_object - 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 + 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: @@ -2924,7 +3680,7 @@ class Face: #----------------------------------------------------------------- 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']: + 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 @@ -2945,6 +3701,8 @@ class Face: #----------------------------------------------------------------- #--------------------------------------------------------------------------------------- # 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, @@ -2952,10 +3710,11 @@ type_map = { 'point':Point, '3dface':Face, 'line':Line, -# 'mline':MLine, +# 'mline':MLine, 'polyline':Polyline, 'lwpolyline':LWpolyline, -# 'region':Region, + 'spline':Spline, +# 'region':Region, 'trace':Solid, 'solid':Solid, 'text':Text, @@ -2992,14 +3751,14 @@ def objectify(data): #--------------------------------------------------------- if item.type == 'vertex': #print 'deb:objectify gosub Vertex--------' #------------- v = Vertex(item) - if pline.spline: # Bspline-curve + 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.splin2): #correct for real NURBS-import - #if (v.spline and not curves_on) or (curves_on and not v.splin2): #fake for Bezier-emulation of NURBS-import + 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: # Bezier-curve + elif pline.curved: # if Bezier-curve # then for Blender-mesh filter only curve_additional_vertices # OR # then for Blender-curve filter curve_control_vertices @@ -3015,12 +3774,27 @@ def objectify(data): #--------------------------------------------------------- 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 - objects.append(type_map[item.type](item)) + try: + objects.append(type_map[item.type](item)) + except TypeError: + pass else: - # we will just let the data pass un-harrased - objects.append(item) + #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 %%%%%%%%' #------------ @@ -3039,7 +3813,7 @@ class MatColors: #------------------------------------------------------------- the material. """ - def __init__(self, layersmap): + def __init__(self): """Expects a map - a dictionary mapping layer names to layers. """ #self.layersmap = layersmap # a dictionary of layername:layerobject @@ -3052,24 +3826,29 @@ class MatColors: #------------------------------------------------------------- If a layer name is provided, the color of that layer is used. """ - if color == None: - color = 256 # color 256=BYLAYER + 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 = self.layersmap[color].color + #color = layersmap[color].color #print 'deb:color=self.map[color].color:', color #------------------ #except KeyError: #layer = Layer(name=color, color=256, frozen=False) - #self.layersmap[color] = layer + #layersmap[color] = layer #color = 0 - color = layersmap[color].color + 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 - #color = layersmap[color].color - pass + #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] @@ -3099,7 +3878,7 @@ class MatLayers: #------------------------------------------------------------- the material. """ - def __init__(self, layersmap): + def __init__(self): """Expects a map - a dictionary mapping layer names to layers. """ #self.layersmap = layersmap # a dictionary of layername:layer @@ -3116,7 +3895,8 @@ class MatLayers: #------------------------------------------------------------- layername_short = layername if layername in layernamesmap.keys(): layername_short = layernamesmap[layername] - colorlayername = str(color) + layername_short + 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] @@ -3130,14 +3910,17 @@ class MatLayers: #------------------------------------------------------------- #print 'deb:MatLayers material: ', mat #---------- #global settings #print 'deb:MatLayers material_from: ', settings.var['material_from'] #---------- - if settings.var['material_from'] == 3: mat_color = color - elif layersmap: mat_color = layersmap[layername].color + 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[mat_color]) - mat.mode |= Material.Modes.SHADELESS - mat.mode |= Material.Modes.WIRE + 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 @@ -3160,7 +3943,7 @@ class Blocks: #---------------------------------------------------------------- """ self.blocksmap = blocksmap #a dictionary mapping block_name:block_data self.settings = settings - self.blocks = {} #container for blocks + self.blocks = {} #container for blender groups representing blocks def __call__(self, name=None): @@ -3179,13 +3962,36 @@ class Blocks: #---------------------------------------------------------------- def addBlock(self, name): """Create a new 'block group' for the block name. """ - - block_def = Group.New('bl_%s' %name) # Blender groupObject contains definition of BLOCK 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) - drawEntities(block.entities, self.settings, block_def) + + 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] = block_def + self.blocks[name] = blender_group @@ -3219,14 +4025,23 @@ class Settings: #-------------------------------------------------------------- '0' ] - self.var['blockFilter_on'] = False #deb:remi------------ - self.acceptedBlocks = ['BOX01', + 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(): @@ -3236,6 +4051,13 @@ class Settings: #-------------------------------------------------------------- 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 #--------------- @@ -3243,68 +4065,127 @@ class Settings: #-------------------------------------------------------------- """Given the drawing, build dictionaries of Layers, Colors and Blocks. """ - #de: paßt die distance parameter an globalScale - if self.var['g_scale'] != 1: + 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!") + 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.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!") - # First sort out all the tables - tables = dict([(item.name, item) for item in sections["tables"].data]) - if 'layer' in tables.keys(): - self.write("Found table:layers!") - self.layersTable = True + 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(drawing) - self.colMaterials = MatColors(layersmap) - self.layMaterials = MatLayers(layersmap) + 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!") + self.write("found section:blocks") # Read the block definitions and build our block object - if self.drawTypes['insert']: #if drawing of type 'Insert' activated - blocksmap, self.blocknamesmap, self.obj_number = getBlocksmap(drawing) #Build a dictionary of blockname:block_data pairs + 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 - - #print 'deb: self.obj_number', self.obj_number #---------- + 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.write("found section:entities") self.obj_number += len(drawing.entities.data) - #print 'deb: self.obj_number', self.obj_number #---------- 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. """ @@ -3334,7 +4215,7 @@ class Settings: #-------------------------------------------------------------- """Given a layer name, and return its visible status. """ # if layer is off then color_index is negative - if layersmap[layername].color < 0: return True + if layersmap and layersmap[layername].color < 0: return True #print 'deb:layer_isOff: layer is ON' #--------------- return False @@ -3342,50 +4223,58 @@ class Settings: #-------------------------------------------------------------- def layer_isFrozen(self, layername): # no more used ------- """Given a layer name, and return its frozen status. """ - if layersmap[layername].frozen: return True + if layersmap and layersmap[layername].frozen: return True #print 'deb:layer_isFrozen: layer is not FROZEN' #--------------- return False def analyzeDXF(dxfFile): #--------------------------------------- - """list LAYER and BLOCK dependences into textfile + """list statistics about LAYER and BLOCK dependences into textfile.INF """ Window.WaitCursor(True) # Let the user know we are thinking - print 'start reading DXF file: %s.' % dxfFile + print 'reading DXF file: %s.' % dxfFile time1 = Blender.sys.time() #time marker1 drawing = readDXF(dxfFile, objectify) - print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1) - Window.WaitCursor(False) + print 'finish reading in %.4f sec.' % (Blender.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!" + 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!" + print "found section:tables" + views, vports, layers = False, False, False for table in drawing.tables.data: if table.name == 'layer': - print "Found table:layers!" + print "found table:layers" layers = table - break - if layers: - layersmap = {} + 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: layername, layercolor, frozen\n' - + layersmap_str = '#list of LAYERs: name, color, frozen_status ---------------------------\n' key_list = layersmap.keys() key_list.sort() for key in key_list: @@ -3397,58 +4286,119 @@ def analyzeDXF(dxfFile): #--------------------------------------- #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 table:layers!" + print "File contains no tables:layers,views,vports!" # The section:blocks may be omited if 'blocks' in sections.keys(): - print "Found section:blocks!" + 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': - insertList = [] + 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 dir(item2) - item2str = [item2.blockname, item2.layer, item2.color_index, item2.scale, item2.space] - insertList.append(item2str) - try: - blocksmap[item.name] = insertList - except KeyError: - # annon block - print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) + #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 #------------- - blocksmap_str = '#list of BLOCKs: child, layer, color, scale, space\n' + + for item2 in drawing.entities.data: + if type(item2) != list and item2.type == 'insert': + 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 = '\''+block_name + '\':\n' #------------- - blocksmap_str += block_str + 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: + 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!" - output_str = '%s\n%s' %(layersmap_str, blocksmap_str) - infFile = dxfFile[:-4] + '_DXF.inf' # replace last char:'.dxf' with '.INF' + 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') + f.write(INFFILE_HEADER + '\n# this is a comment line\n\n') f.write(output_str) f.close() - Draw.PupMenu('DXF importer: INF-file: Done!%t|see listing of DXF-model saved in:|' + '\'%s\'' %infFile) + Draw.PupMenu('DXF importer: report saved in INF-file:%t|' + '\'%s\'' %infFile) except: - Draw.PupMenu('DXF importer: INF-file: Error!%t|failure by writing to ' + '\'%s\'|no listings saved!' %infFile) - + Draw.PupMenu('DXF importer: ERROR by writing report in INF-file:%t|' + '\'%s\'' %infFile) + finally: + f.close() @@ -3456,6 +4406,7 @@ def analyzeDXF(dxfFile): #--------------------------------------- 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 @@ -3467,17 +4418,9 @@ def main(dxfFile): #---------------#############################----------- cur_COUNTER = 0 try: - print "Getting settings..." - global GUI_A, GUI_B - if GUI_A['g_scale_on'].val: - if GUI_A['g_scale_as'].val == 6: #scale inches to meters - GUI_A['g_scale'].val = 0.02540 - elif GUI_A['g_scale_as'].val == 7: #scale feets to meters - GUI_A['g_scale'].val = 0.30480 - elif GUI_A['g_scale_as'].val == 8: #scale yards to meters - GUI_A['g_scale'].val = 0.91440 - else: GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val) - else: + #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 = {} @@ -3505,45 +4448,53 @@ def main(dxfFile): #---------------#############################----------- #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 'start reading DXF file: %s.' % dxfFile + print 'reading file: %s.' % dxfFile time1 = Blender.sys.time() #time marker1 drawing = readDXF(dxfFile, objectify) - print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1) + print 'reading finished in %.4f sec.' % (Blender.sys.time()-time1) Window.WaitCursor(False) else: - if UI_MODE: Draw.PupMenu('DXF importer: EXIT----------!%t| no valid DXF-file selected!') - print "DXF importer: error, no DXF-file selected. Abort!" + 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 - settings.validate(drawing) + # Draw all the know entity types in the current scene + oblist = [] # a list of all created AND linked objects for final f_globalScale + time2 = Blender.sys.time() #time marker2 Window.WaitCursor(True) # Let the user know we are thinking settings.write("\n\nDrawing entities...") - # Draw all the know entity types in the current scene - global oblist - oblist = [] # a list of all created AND linked objects for final f_globalScale - time2 = Blender.sys.time() #time marker2 + 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 the visable layers + # 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) - #Blender.Redraw(-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 = Blender.sys.time() - time2 Window.WaitCursor(False) - message = 'DXF Import to Blender: done in %.4f sec. --------------------' % time_text + 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) @@ -3561,16 +4512,15 @@ 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 az[2] == 1.0: + #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] == -1.0: + 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 - #elif abs(az[0]) < 0.0001 and abs(az[1]) < 0.0001: - # return False az = Mathutils.Vector(az) @@ -3625,60 +4575,94 @@ def rotXY_Vec(rotation, vec): #------------------------------------------------ -def getLayersmap(drawing): #------------------------------------------------------ - """Build two dictionaries: 1.layername:layer pairs and 2.layername:layername_short +def getLayersmap(dxflayers): #------------------------------------------------------ + """Build two dictionaries: 1.layername:layer object, and 2.layername:layername_short + gets set of layers from TABLES SECTION LAYERS """ - tables = drawing.tables - for table in tables.data: - if table.name == 'layer': - layers = table - break layersmap = {} layernamesmap = {} - for item in layers.data: + 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) + suffix = str(i) #--todo--set zero-leading number format layername_short = layername_short[:-2] + suffix layernamesmap[item.name] = layername_short - return layersmap, layernamesmap + #print 'deb:getLayersmap layersmap:\n', layersmap #------------ + #print 'deb:getLayersmap layernamesmap:\n', layernamesmap #------------ + return layersmap, layernamesmap -def getBlocksmap(drawing): #-------------------------------------------------------- - """Build a dictionary of blockname:block_data pairs and 2.blockname:blockname_short pairs + +def getBlocksmap(drawing, layersmap, layFrozen_on=False): #-------------------------------------------------------- + """Build a dictionary of blockname:block_data pairs """ - blocksmap = {} - blocksmap_short = {} - blocknamesmap = {} - obj_number = 0 + usedblocks = {} 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 #-------- + #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 map "%s" - "%s" as Block!' %(item.name, item) + #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: pass + + 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 + usedblocks[child[0]][0] = True # marked as used BLOCK + + 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: - # annon block - print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) - - blockname_short = item.name[: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[item.name] = blockname_short + try: blocksmap[item.name] = item + except KeyError: print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) + - return blocksmap, blocknamesmap, obj_number + #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. @@ -3688,7 +4672,8 @@ def drawEntities(entities, settings, block_def=None): #------------------------ 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 - drawer(_type, entities.get_type(_type), settings, block_def) + entities_type = entities.get_type(_type) + if entities_type: drawer(_type, entities_type, settings, block_def) def drawer(_type, entities, settings, block_def): #------------------------------------------ @@ -3696,6 +4681,7 @@ def drawer(_type, entities, settings, block_def): #---------------------------- 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: @@ -3729,6 +4715,21 @@ def drawer(_type, entities, settings, block_def): #---------------------------- #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] @@ -3756,14 +4757,21 @@ def drawer(_type, entities, settings, block_def): #---------------------------- if cur_temp == show_progress: settings.progress(cur_COUNTER, message) cur_temp = 0 - #print 'deb:drawer show_progress=',show_progress #----------------------- + #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 _type == 'insert': #---- INSERT and MINSERT=array -------------------- + if not settings.var['block_nn'] and entity.name.startswith('*X'): #---- support for noname BLOCKs + #print 'deb:drawer entity.name:', entity.name #------------ + continue + elif 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] @@ -3776,23 +4784,44 @@ def drawer(_type, entities, settings, block_def): #---------------------------- 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_scale'] != 1: globalScaleOne(ob, True, settings.var['g_scale']) + #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, True)) + else: oblist.append((ob, insertFlag, blockFlag)) else: #---draw entities except BLOCKs/INSERTs--------------------- + insertFlag = False alt_obname = activObjectName ob = entity.draw(settings) - if ob and ob.name != alt_obname: - setObjectProperties(ob, group, entity, settings, block_def) - if settings.var['optimization'] <= settings.MIN: - if settings.var['g_scale'] != 1: globalScaleOne(ob, False, settings.var['g_scale']) - settings.redraw() - else: oblist.append((ob, False)) - + 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) @@ -3806,20 +4835,32 @@ def globalScale(oblist, SCALE): #---------------------------------------------- """ #print 'deb:globalScale.oblist: ---------%\n', oblist #--------------------- for l in oblist: - ob, insertFlag = l[0], l[1] - globalScaleOne(ob, insertFlag, SCALE) + ob, insertFlag, blockFlag = l[0], l[1], l[2] + globalScaleOne(ob, insertFlag, blockFlag, SCALE) -def globalScaleOne(ob, insertFlag, 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 must be scaled------------ + 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 ------------ - ob.setMatrix(ob.matrixWorld*SCALE_MAT) - + 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): #----------------------- @@ -3835,7 +4876,7 @@ def setObjectProperties(ob, group, entity, settings, block_def): #------------- 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, ob) + setGroup(block_def[0], ob) #print 'deb:setObjectProperties \'%s\' set to block_def_group!' %ob.name #--------- ob.layers = [19] else: @@ -3843,7 +4884,7 @@ def setObjectProperties(ob, group, entity, settings, block_def): #------------- ob.layers = [settings.var['target_layer']] # Set material for any objects except empties - if ob.type != 'Empty': + if ob.type != 'Empty' and settings.var['material_on']: setMaterial_from(entity, ob, settings, block_def) # Set the visibility @@ -3884,12 +4925,13 @@ def setMaterial_from(entity, ob, settings, block_def): #----------------------- - controlled by settings.var['material_from'] """ if settings.var['material_from'] == 1: # 1= material from color - if entity.color_index == BYLAYER: + if entity.color_index == BYLAYER or entity.color_index == 256: mat = settings.colMaterials(entity.layer) - elif entity.color_index == BYBLOCK: + elif entity.color_index == BYBLOCK or entity.color_index == 0: #--todo-- looking for block.color_index #mat = settings.colMaterials(block.color_index) - mat = settings.colMaterials(entity.color_index) + #if block_def: mat = settings.colMaterials(block_def[2]) + mat = settings.colMaterials(3) else: mat = settings.colMaterials(entity.color_index) @@ -3910,10 +4952,11 @@ def setMaterial_from(entity, ob, settings, block_def): #----------------------- mat = Material.Get('dxf-neutral') except: mat = Material.New('dxf-neutral') - mat.mode |= Material.Modes.SHADELESS - mat.mode |= Material.Modes.WIRE -# try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug -# except: pass + 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 @@ -4205,15 +5248,19 @@ EVENT_START = 2 EVENT_REDRAW = 3 EVENT_LOAD_INI = 4 EVENT_SAVE_INI = 5 -EVENT_PRESET = 6 +EVENT_RESET = 6 EVENT_CHOOSE_INI = 7 EVENT_CHOOSE_DXF = 8 EVENT_HELP = 9 -EVENT_CONFIG = 10 +EVENT_PRESETCURV = 10 EVENT_PRESETS = 11 EVENT_DXF_DIR = 12 -EVENT_LIST = 13 +# = 13 +EVENT_LIST = 14 +EVENT_ORIGIN = 15 +EVENT_SCALE = 16 EVENT_PRESET2D = 20 +EVENT_PRESET3D = 21 EVENT_EXIT = 100 GUI_EVENT = EVENT_NONE @@ -4222,22 +5269,41 @@ 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" -lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" -mlines_as_menu = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x4" -plines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" -plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" -plmesh_as_menu = "convert to: %t|mesh %x1" -solids_as_menu = "convert to: %t|mesh %x1" -blocks_as_menu = "convert to: %t|dupl.group %x1|*real.group %x2|*exploded %x3" -texts_as_menu = "convert to: %t|text %x1|*mesh %x2" +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 = "scale factor: %t|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|cm to m %x-2|mm to m %x-3|x 0.0001 %x-4|x 0.00001 %x-5" +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, @@ -4245,12 +5311,25 @@ keywords_org = { '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': 1, +# 'g_scale_as': int(log10(G_SCALE)), # 0, + 'g_scale_on': 0, 'thick_on' : 1, 'thick_min' : float(MIN_THICK), 'thick_force': 0, @@ -4262,7 +5341,6 @@ keywords_org = { 'dist_force': 0, 'material_on': 1, 'material_from': 2, - 'pl_3d' : 1, 'fill_on' : 1, 'meshSmooth_on': 1, 'curve_res' : CURV_RESOLUTION, @@ -4272,6 +5350,8 @@ keywords_org = { '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, @@ -4280,9 +5360,10 @@ keywords_org = { 'lines_as' : 2, 'mlines_as' : 2, 'plines_as' : 2, + 'splines_as' : 5, 'plines3_as': 2, - 'plmesh_as' : 1, - 'solids_as' : 1, + 'plmesh_as' : 2, + 'solids_as' : 2, 'blocks_as' : 1, 'texts_as' : 1 } @@ -4292,9 +5373,10 @@ drawTypes_org = { 'line' : 1, 'arc' : 1, 'circle': 1, - 'ellipse': 0, + 'ellipse': 1, 'mline' : 0, 'polyline': 1, + 'spline': 1, 'plmesh': 1, 'pline3': 1, 'lwpolyline': 1, @@ -4302,9 +5384,10 @@ drawTypes_org = { 'mtext' : 0, 'block' : 1, 'insert': 1, - 'face' : 1, 'solid' : 1, - 'trace' : 1 + 'trace' : 1, + 'face' : 1, +# 'view' : 0, } # creating of GUI-buttons @@ -4316,12 +5399,40 @@ 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 saveConfig(): #remi--todo----------------------------------------------- +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. @@ -4331,18 +5442,31 @@ def saveConfig(): #remi--todo----------------------------------------------- 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:12]): + try: + f = file(iniFile, 'r') + try: header_str = f.readline() + finally: f.close() + except: pass + 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-format| ! it may belong to another aplication !') == 1: + '|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 @@ -4356,10 +5480,11 @@ def saveConfig(): #remi--todo----------------------------------------------- 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) + try: + f.write(INIFILE_HEADER + '\n# this is a comment line\n') + f.write(output_str) + finally: 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) @@ -4380,28 +5505,28 @@ def loadConfig(): #remi--todo----------------------------------------------- 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 not header_str.startswith(INIFILE_HEADER): - f.close() - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) - else: - 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) + try: + f = file(iniFile, 'r') + try: + 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: + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) + finally: f.close() + except: pass else: Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!') print "DXF importer: Alert!: no valid INI-file selected." @@ -4411,27 +5536,57 @@ def loadConfig(): #remi--todo----------------------------------------------- -def resetDefaultConfig(): #----------------------------------------------- - """Resets settings/config/materials to defaults. +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_org.iteritems(): + for k, v in keywords.iteritems(): GUI_A[k].val = v - for k, v in drawTypes_org.iteritems(): + 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. """ - resetDefaultConfig() - global GUI_A, GUI_B + presetConfig_curv(1) keywords2d = { - 'curves_on' : 0, - 'one_mesh_on': 1, + 'views_on' : 0, + 'cams_on' : 0, + 'lights_on' : 0, 'vGroup_on' : 1, 'thick_on' : 0, 'thick_force': 0, @@ -4439,16 +5594,11 @@ def resetDefaultConfig_2D(): #----------------------------------------------- 'width_force': 0, 'dist_on' : 1, 'dist_force': 0, - 'pl_3d' : 0, 'fill_on' : 0, 'pl_trim_on': 1, 'Z_force_on': 0, 'meshSmooth_on': 0, - 'points_as' : 2, - 'lines_as' : 2, - 'mlines_as' : 2, - 'plines_as' : 2, - 'solids_as' : 1, + 'solids_as' : 2, 'blocks_as' : 1, 'texts_as' : 1 } @@ -4458,33 +5608,117 @@ def resetDefaultConfig_2D(): #----------------------------------------------- 'line' : 1, 'arc' : 1, 'circle': 1, - 'ellipse': 0, + 'ellipse': 1, 'mline' : 0, 'polyline': 1, + 'spline': 1, 'plmesh': 0, - 'pline3': 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 + 'trace' : 1, + 'face' : 1, +# 'view' : 0, } - for k, v in keywords2d.iteritems(): - GUI_A[k].val = v - for k, v in drawTypes2d.iteritems(): - GUI_B[k].val = v + 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 + 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 @@ -4495,8 +5729,8 @@ def draw_UI(): #--------------------------------------------------------------- butt_margin = 10 menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width - simple_menu_h = 110 - extend_menu_h = 400 + 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 @@ -4504,199 +5738,328 @@ def draw_UI(): #--------------------------------------------------------------- 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 Importer ver." + __version__, but0c, y, menu_w, 20) + Draw.Label("DXF-Importer v" + __version__, but0c, y, menu_w, 20) if config_UI.val: - y -= 30 - Draw.BeginAlign() - GUI_B['point'] = Draw.Toggle('POINT', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['point'].val, "support dxf-POINT on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['points_as'].val, "select target Blender-object") - Draw.EndAlign() + b0, b0_ = but0c, but_0c + butt_margin + b1, b1_ = but1c, but_1c + y_top = y + y -= 10 y -= 20 Draw.BeginAlign() - GUI_B['line'] = Draw.Toggle('LINE.ARC.CIRCLE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['lines_as'].val, "select target Blender-object") + 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['mline'] = Draw.Toggle('*MLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['mline'].val, "(*wip)support dxf-MLINE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['mlines_as'].val, "select target Blender-object") + 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['polyline'] = Draw.Toggle('2D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['plines_as'] = Draw.Menu(plines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines_as'].val, "select target Blender-object") + GUI_B['mline'] = Draw.Toggle('*MLINE', EVENT_REDRAW, b0, y, b0_, 20, GUI_B['mline'].val, "(*wip)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['pline3'] = Draw.Toggle('3D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines3_as'].val, "select target Blender-object") + 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['plmesh'] = Draw.Toggle('POLYMESH/-FACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plmesh_as'].val, "select target Blender-object") + 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['solid'] = Draw.Toggle('3DFACE.SOLID.TRACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['solid'].val, "support dxf-3DFACE, SOLID and TRACE on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - 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") + 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['text'] = Draw.Toggle('TEXT', EVENT_NONE, but0c, y, but_0c, 20, GUI_B['text'].val, "support dxf-TEXT on/off") - GUI_B['mtext'] = Draw.Toggle('*MTEXT', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_B['mtext'].val, "(*wip)support dxf-MTEXT on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - 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") + 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, "(*wip)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_NONE, but0c, y, but_0c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") - GUI_A['dummy_on'] = Draw.Toggle('*XREF', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_A['dummy_on'].val, "(*wip)support XREF-BLOCK on/off") - Draw.Label('-->', but2c, y, but_2c, 20) - GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['blocks_as'].val, "select target Blender-object") + 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['dummy_on'] = Draw.Toggle('*views', EVENT_NONE, but0c, y, but_0c-25, 20, GUI_A['dummy_on'].val, "(*wip)support VIEWPORTs on/off") - GUI_A['dummy_on'] = Draw.Toggle('*cams', EVENT_NONE, but1c-25, y, but_1c-25, 20, GUI_A['dummy_on'].val, "(*wip)support CAMERAs on/off") - GUI_A['dummy_on'] = Draw.Toggle('*lights', EVENT_NONE, but1c+25, y, but_1c-25, 20, GUI_A['dummy_on'].val, "(*wip)support LIGHTs on/off") + 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, "(*wip) 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, "(*wip) 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['material_on'] = Draw.Toggle('material', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['material_on'].val, "support for material assignment on/off") - GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, but3c-20, y, but_3c+20, 20, GUI_A['material_from'].val, "material assignment from?") + 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, "(*wip) LAYER filtering on/off") + GUI_A['colorFilter_on'] = Draw.Toggle('color', EVENT_NONE, b0+but_*3, y, but_, 20, GUI_A['colorFilter_on'].val, "(*wip) COLOR filtering on/off") + GUI_A['groupFilter_on'] = Draw.Toggle('group', EVENT_NONE, b0+but_*4, y, but_, 20, GUI_A['groupFilter_on'].val, "(*wip) GROUP filtering on/off") + GUI_A['blockFilter_on'] = Draw.Toggle('block', EVENT_NONE, b0+but_*5, y, but_, 20, GUI_A['blockFilter_on'].val, "(*wip) 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['paper_space_on'] = Draw.Toggle('paperSpace', EVENT_NONE, but0c, y, but_0c+20, 20, GUI_A['paper_space_on'].val, "import from paper space only on/off") - GUI_A['layFrozen_on'] = Draw.Toggle('frozen', EVENT_NONE, but1c+20, y, but_1c-20, 20, GUI_A['layFrozen_on'].val, "import also from frozen layers on/off") - #GUI_A['dummy_on'] = Draw.Toggle('-', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dummy_on'].val, "dummy on/off") + 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_NONE, but2c, y, but_2c, 20, GUI_A['g_scale_on'].val, "scaling all DXF objects on/off") - GUI_A['g_scale_as'] = Draw.Menu(g_scale_list, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['g_scale_as'].val, "10^ factor for scaling the DXFdata") + 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------------------------------------------ - y -= 30 - GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") - GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off") + 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['Z_force_on'] = Draw.Toggle('*elevation', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['Z_force_on'].val, "*set objects Z-coordinates to elevation on/off") - GUI_A['Z_elev'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['Z_elev'].val, -1000, 1000, "set default elevation(Z)") + 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['meshSmooth_on'] = Draw.Toggle('smooth', EVENT_NONE, but0c, y, but_0c-20, 20, GUI_A['meshSmooth_on'].val, "mesh smooth for circles/arcsegments on/off") - GUI_A['pl_trim_on'] = Draw.Toggle('trim', EVENT_NONE, but1c-20, y, 32, 20, GUI_A['pl_trim_on'].val, "intersection of POLYLINE-wide-segments on/off") - GUI_A['pl_trim_max'] = Draw.Number('', EVENT_NONE, but1c+12, y, but_1c-12, 20, GUI_A['pl_trim_max'].val, 0, 5, "limit for intersection of POLYLINE-wide-segments: 0.0-5.0") +# 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['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['dist_on'].val, "support distance on/off") - GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off") - GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal length/distance (double.vertex removing)") + 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['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, but0c, y, but_0c, 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, but1c, y, but_1c/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, but1c+but_1c/2, y, but_1c/2, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs/closed curves on/off") + 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['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['thick_on'].val, "support thickness on/off") - GUI_A['thick_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['thick_force'].val, "force minimal thickness on/off") - GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['thick_min'].val, 0, 10, "minimal thickness") + 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['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") - GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off") - GUI_A['curve_arc'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c/2, 20, GUI_A['curve_arc'].val, 3, 32, "Bezier circle resolution - number of segments: 3-32") - GUI_A['curve_res'] = Draw.Number('', EVENT_NONE, but1c+but_1c/2, y, but_1c/2, 20, GUI_A['curve_res'].val, 3, 50, "Bezier curve resolution: 3-50") + 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, but2c, y, but_2c-20, 20, GUI_A['width_on'].val, "support width on/off") - GUI_A['width_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['width_force'].val, "force minimal width on/off") - GUI_A['width_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['width_min'].val, 0, 10, "minimal width") + 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 - #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved") - GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "draw DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") - GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off") - GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)") - GUI_A['optimization'] = Draw.Number('optim:', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest") + 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_0c-butt_margin, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file") + 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() - y -= 20 - Draw.BeginAlign() - Draw.PushButton('Presets', EVENT_PRESETS, but0c, y, but_0c, 20, "tipist for Preset-INI-files") - Draw.PushButton('Load', EVENT_LOAD_INI, but1c, y, but_1c, 20, ' Loads configuration from ini-file: %s' % iniFileName.val) - Draw.PushButton('Save', EVENT_SAVE_INI, but2c, y, but_2c, 20, 'Saves configuration to ini-file: %s' % iniFileName.val) -# user_preset = Draw.Number('preset:', EVENT_PRESETS, but2c, y, but_2c, 20, user_preset.val, 0, 5, "call user Preset-INI-files") - Draw.PushButton('2D', EVENT_PRESET2D, but3c, y, but_3c/2, 20, 'resets configuration to 2D-defaults') - Draw.PushButton('3D', EVENT_PRESET, but3c+but_3c/2, y, but_3c/2, 20, 'resets configuration to 3D-defaults') - Draw.EndAlign() + b0, b0_ = but2c, but_2c + butt_margin + b1, b1_ = but3c, but_3c - y -= 30 + 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-file from project directory') - dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or * for multi-import") - Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'Set asterisk * as filter') + dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or type *.dxf for multi-import") + Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'import all dxf 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 -= 50 + 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('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' ) - Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c-20, 20, 'calls BlenderWiki for Manual, Updates and Support.') - Draw.PushButton('?', EVENT_LIST, but1c+but_1c-20, y, 20, 20, 'analyze DXF-file: print listing of LAYERs and BLOCKs into the text-file.INF') - Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure') + 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() - config_UI = Draw.Toggle('CONFIG', EVENT_CONFIG, but1c-butt_margin/2, y+20, but_1c+butt_margin, 20, config_UI.val, 'Advanced configuration on/off' ) + + y -= 20 Draw.BeginAlign() Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20) - Draw.Label("*) parts under construction", but0c, y, menu_w, 20) + Draw.Label(LAB, but0c, y, menu_w, 20) Draw.Label(' ', but0c+menu_w, y, menu_margin, 20) Draw.EndAlign() @@ -4709,10 +6072,13 @@ def colorbox(x,y,xright,bottom): 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_texture): +def ini_callback(input_filename): global iniFileName - iniFileName.val=input_texture + iniFileName.val=input_filename def event(evt, val): if evt in (Draw.QKEY, Draw.ESCKEY) and not val: @@ -4721,27 +6087,46 @@ def event(evt, val): 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 ######### Manages GUI events if (evt==EVENT_EXIT): Blender.Draw.Exit() + print 'DXF-Importer *** exit ***' #--------------------- elif (evt==EVENT_CHOOSE_INI): Window.FileSelector(ini_callback, "INI-file Selection", '*.ini') - elif (evt==EVENT_CONFIG): + elif (evt==EVENT_REDRAW): Draw.Redraw() - elif (evt==EVENT_PRESET): + 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 - if user_preset > 5: user_preset = 1 - iniFileName.val = INIFILE_DEFAULT_NAME + str(user_preset) + INIFILE_EXTENSION + 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: @@ -4770,20 +6155,27 @@ http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') elif '\\' in dxfFile: dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\' dxfFileName.val = dxfPathName + '*.dxf' - global GUI_A +# dirname == Blender.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): - Window.FileSelector(dxf_callback, "DXF-file Selection", '*.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) if dxfFile.lower().endswith('*.dxf'): if Draw.PupMenu('DXF importer: OK?|will import all DXF-files from:|%s' % dxfFile) == 1: global UI_MODE UI_MODE = False - multi_import(dxfFile[:-5]) # cut last char:'*.dxf' - Draw.Exit() + multi_import(dxfFile[:-5]) # cut last 5 characters '*.dxf' + Draw.Redraw() + #Draw.Exit() else: Draw.Redraw() elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): @@ -4795,6 +6187,7 @@ http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') 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 @@ -4822,7 +6215,7 @@ def multi_import(DIR): batchTIME = Blender.sys.time() #if #DIR == "": DIR = os.path.curdir if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename')) - print 'Multifile Mode: searching for DXF-files in %s' %DIR + print 'Multifiles Import from %s' %DIR files = \ [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] if not files: @@ -4832,7 +6225,7 @@ def multi_import(DIR): i = 0 for dxfFile in files: i += 1 - print '\nImporting', dxfFile, ' NUMBER', i, 'of', len(files) + print '\nDXF-file', 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' @@ -4849,12 +6242,25 @@ def multi_import(DIR): #Blender.Redraw() print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME) + print '\a\r', # beep when done +UI_MODE = True if __name__ == "__main__": 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 = Blender.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) @@ -4892,4 +6298,4 @@ if 1: main(_dxf) print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -""" +"""
\ No newline at end of file diff --git a/release/scripts/import_lightwave_motion.py b/release/scripts/import_lightwave_motion.py new file mode 100644 index 00000000000..20c87dfd5c6 --- /dev/null +++ b/release/scripts/import_lightwave_motion.py @@ -0,0 +1,244 @@ +#!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 index 8e7b9985d3d..1ee196ab67f 100644 --- a/release/scripts/import_mdd.py +++ b/release/scripts/import_mdd.py @@ -1,11 +1,11 @@ #!BPY - #""" - #Name: 'Load MDD to Mesh RVKs' - #Blender: 242 - #Group: 'Import' - #Tooltip: 'baked vertex animation to active mesh object.' - #""" +""" + 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. diff --git a/release/scripts/import_obj.py b/release/scripts/import_obj.py index e5bdc796e16..3aad0800cf7 100644 --- a/release/scripts/import_obj.py +++ b/release/scripts/import_obj.py @@ -2,14 +2,14 @@ """ Name: 'Wavefront (.obj)...' -Blender: 242 +Blender: 248 Group: 'Import' Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' """ __author__= "Campbell Barton", "Jiri Hnidek" -__url__= ["blender.org", "blenderartists.org"] -__version__= "2.0" +__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org'] +__version__= "2.1" __bpydoc__= """\ This script imports a Wavefront OBJ files to Blender. @@ -182,7 +182,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ else: #print '\t\tloading mtl: "%s"' % mtlpath context_material= None - mtl= open(mtlpath) + mtl= open(mtlpath, 'rU') for line in mtl: #.xreadlines(): if line.startswith('newmtl'): context_material_name= line_value(line.split()) @@ -194,7 +194,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_ elif context_material: # we need to make a material to assign properties to it. line_split= line.split() - line_lower= line.lower() + 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'): @@ -588,7 +588,7 @@ def load_obj(filepath, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS print '\tpassing obj file "%s"...' % filepath, time_sub= sys.time() - file= open(filepath, 'r') + file= open(filepath, 'rU') for line in file: #.xreadlines(): if line.startswith('v '): @@ -756,19 +756,22 @@ 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, KEEP_VERT_ORDER CREATE_SMOOTH_GROUPS= Draw.Create(0) CREATE_FGONS= Draw.Create(1) CREATE_EDGES= Draw.Create(1) - SPLIT_OBJECTS= Draw.Create(1) - SPLIT_GROUPS= Draw.Create(1) - SPLIT_MATERIALS= Draw.Create(1) - MORPH_TARGET= Draw.Create(0) + 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) + KEEP_VERT_ORDER= 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'),\ @@ -779,7 +782,7 @@ def load_obj_ui(filepath, BATCH_LOAD= False): ('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...',\ - ('Morph Target', MORPH_TARGET, 'Keep vert and face order, disables some other 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)'),\ ] @@ -787,10 +790,106 @@ def load_obj_ui(filepath, BATCH_LOAD= False): if not Draw.PupBlock('Import OBJ...', pup_block): return - if MORPH_TARGET.val: + 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 + if SPLIT_OBJECTS.val or SPLIT_GROUPS.val or SPLIT_MATERIALS.val: + KEEP_VERT_ORDER.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_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, KEEP_VERT_ORDER + + 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, 70, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split) + SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+79, ui_y+89, 70, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split) + SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+149, ui_y+89, 70, 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+229, ui_y+89, 110, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder) + + 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, 211, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)') + IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+229, ui_y+39, 110, 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) @@ -859,7 +958,7 @@ else: os.system('find /fe/obj -iname "*.obj" > /tmp/temp3ds_list') print '...Done' - file= open('/tmp/temp3ds_list', 'r') + file= open('/tmp/temp3ds_list', 'rU') lines= file.readlines() file.close() diff --git a/release/scripts/import_web3d.py b/release/scripts/import_web3d.py new file mode 100755 index 00000000000..9447f15fb79 --- /dev/null +++ b/release/scripts/import_web3d.py @@ -0,0 +1,1944 @@ +#!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. +""" + +# 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))] + +# 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 pradict. + ''' + # 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('"') + + 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 + + + # 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 + + # 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 + +lines = [] + +def getNodePreText(i, words): + # print lines[i] + use_node = False + while len(words) < 5: + + if i>=len(lines): + break + 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 + + # 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: + 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? + ''' + l = lines[i] + line_end = len(l)-1 + line_end_new = l.find(' ') # comma's always have a space before them + + if line_end_new != -1: + line_end = line_end_new + + try: + float(l[:line_end]) # works for a float or int + return True + except: + return False + +class vrmlNode(object): + __slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'FIELD_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 + + # Store in the root node because each inline file needs its own root node and its own namespace + self.DEF_NAMESPACE = None + self.FIELD_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.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 getDefDict(self): + if self.DEF_NAMESPACE != None: + return self.DEF_NAMESPACE + else: + return self.parent.getDefDict() + + def setRoot(self, filename): + self.filename = filename + self.FIELD_NAMESPACE = {} + self.DEF_NAMESPACE= {} + + 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 getDefName(self): + self_real = self.getRealNode() + + if 'DEF' in self_real.id: + # print self_real.id + return self_real.id[ list(self_real.id).index('DEF')+1 ] + else: + return None + + + 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: + 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): + 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 + + return f[1:] + # print '\tfield not found', field + return None + + def getFieldAsInt(self, field, default): + self_real = self.getRealNode() # incase we're an instance + + f = self_real.getFieldName(field) + 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): + self_real = self.getRealNode() # incase we're an instance + + f = self_real.getFieldName(field) + 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): + self_real = self.getRealNode() # incase we're an instance + + f = self_real.getFieldName(field) + 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): + self_real = self.getRealNode() # incase we're an instance + + f = self_real.getFieldName(field) + 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=None): + self_real = self.getRealNode() # incase we're an instance + + f = self_real.getFieldName(field) + 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): + ''' + For this parser arrays are children + ''' + 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 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) + 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: + + # Normal vrml + array_data = child_array.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 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: + return text + + for item in self.fields: + 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 child in self.children: + text += str(child) + + text += '\n' + ind + brackets[1] + + return text + + def parse(self, i): + new_i = self.__parse(i) + + # print self.id, self.getFilename() + + # If we were an inline then try load the file + if self.node_type == NODE_NORMAL and self.getSpec() == 'Inline': + url = self.getFieldAsString('url', None) + + if url != None: + if not exists(url): + url = dirName(self.getFilename()) + baseName(url) + if not exists(url): + print '\tWarning: Inline URL could not be found:', url + else: + if url==self.getFilename(): + print '\tWarning: cant Inline yourself recursively:', url + else: + + try: + f = open(url, 'rU') + except: + print '\tWarning: cant open the file:', url + f = None + + if f: + # Tricky - inline another VRML + print '\tLoading Inline:"%s"...' % url + + # Watch it! - backup lines + lines_old = lines[:] + + + lines[:] = vrmlFormat( f.read() ) + f.close() + + lines.insert(0, '{') + lines.insert(0, 'root_node____') + lines.append('}') + + child = vrmlNode(self, NODE_NORMAL, -1) + child.setRoot(url) # initialized dicts + child.parse(0) + + # Watch it! - restore lines + lines[:] = lines_old + + + return new_i + + def __parse(self, i): + # 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. + raise "error" + + 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 + + i = new_i + + # print self.id + ok = True + while ok: + l = lines[i] + # print '\t', i, l + if l=='': + i+=1 + continue + + if l=='}': + if self.node_type != NODE_NORMAL: + print 'wrong node ending, expected an } ' + str(i) + raise "" + ### print "returning", i + return i+1 + if l==']': + if self.node_type != NODE_ARRAY: + print 'wrong node ending, expected a ] ' + str(i) + raise "" + ### print "returning", i + return i+1 + + node_type, new_i = is_nodeline(i, []) + if node_type: # check text\n{ + ### print '\t\tgroup', i + child = vrmlNode(self, node_type, i) + i = child.parse(i) + # print child.id, 'YYY' + + 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 + 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.getFieldDict()[value[2]] = value[3:] # skip the first 3 values + else: + # Get referenced field + if len(value) >= 3 and value[1]=='IS': + try: + value = [ value[0] ] + self.getFieldDict()[ value[2] ] + except: + print '\tWarning, field could not be found:', value, 'TODO add support for exposedField' + print '\t', self.getFieldDict() + self.fields.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('m:\\test.txt', 'w') + ## ff.writelines([l+'\n' for l in lines]) + + + # 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) + + # 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): + # 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): + 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 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): + cent = node.getFieldAsFloatTuple('center', None) # (0.0, 0.0, 0.0) + rot = node.getFieldAsFloatTuple('rotation', None) # (0.0, 0.0, 1.0, 0.0) + sca = node.getFieldAsFloatTuple('scale', None) # (1.0, 1.0, 1.0) + scaori = node.getFieldAsFloatTuple('scaleOrientation', None) # (0.0, 0.0, 1.0, 0.0) + tx = node.getFieldAsFloatTuple('translation', None) # (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): + cent = node.getFieldAsFloatTuple('center', None) # (0.0, 0.0) + rot = node.getFieldAsFloat('rotation', None) # 0.0 + sca = node.getFieldAsFloatTuple('scale', None) # (1.0, 1.0) + tx = node.getFieldAsFloatTuple('translation', None) # (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) + mtx = mtx * mat + + return mtx + +def importMesh_IndexedFaceSet(geom, bpyima): + # print geom.lineno, geom.id, vrmlNode.DEF_NAMESPACE.keys() + + ccw = geom.getFieldAsBool('ccw', True) + ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True) # per vertex or per face + ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True) + + # 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) + else: coord = [] + + if not coord: + print '\tWarnint: IndexedFaceSet has no points' + return None, ccw + + ifs_faces = geom.getFieldAsArray('coordIndex', 0) + + 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) + ifs_texfaces = geom.getFieldAsArray('texCoordIndex', 0) + + 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 = [[int(c*256) for c in col] for col in vcolor.getFieldAsArray('color', 3)] + ifs_color_index = geom.getFieldAsArray('colorIndex', 0) + + if not ifs_vcol: + vcolor_spot = [int(c*256) for c in vcolor.getFieldAsFloatTuple('color', [])] + + # 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: color_index = ifs_color_index[color_index] + + if len(ifs_vcol) < color_index: + c.r, c.g, c.b = ifs_vcol[color_index] + else: + print '\tWarning: per face color index out of range' + 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): + c.r, c.g, c.b = col + + bpymesh.verts.delete([0,]) # EEKADOODLE + + return bpymesh, ccw + +def importMesh_IndexedLineSet(geom): + # VRML not x3d + #coord = geom.getChildByName('coord') # 'Coordinate' + coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml + if coord: points = coord.getFieldAsArray('point', 3) + else: points = [] + + if not points: + print '\tWarning: IndexedLineSet had no points' + return None + + ils_lines = geom.getFieldAsArray('coordIndex', 0) + + 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): + # VRML not x3d + #coord = geom.getChildByName('coord') # 'Coordinate' + coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml + if coord: points = coord.getFieldAsArray('point', 3) + 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): + # bpymesh = bpy.data.meshes.new() + diameter = geom.getFieldAsFloat('radius', 0.5) * 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): + # bpymesh = bpy.data.meshes.new() + diameter = geom.getFieldAsFloat('radius', 1.0) * 2 # * 2 for the diameter + height = geom.getFieldAsFloat('height', 2) + 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) + side = geom.getFieldAsBool('side', True) + top = geom.getFieldAsBool('top', True) + + 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): + # bpymesh = bpy.data.meshes.new() + diameter = geom.getFieldAsFloat('bottomRadius', 1.0) * 2 # * 2 for the diameter + height = geom.getFieldAsFloat('height', 2) + 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) + side = geom.getFieldAsBool('side', True) + + 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): + # bpymesh = bpy.data.meshes.new() + + size = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0)) + 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 + 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) + + + + # 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) + bpymat.rgbCol = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8]) + + # NOTE - blender dosnt support emmisive color + # Store in mirror color and approximate with emit. + emit = mat.getFieldAsFloatTuple('emissiveColor', [0.0, 0.0, 0.0]) + bpymat.mirCol = emit + bpymat.emit = (emit[0]+emit[1]+emit[2])/3.0 + + bpymat.hard = int(1+(510*mat.getFieldAsFloat('shininess', 0.2))) # 0-1 -> 1-511 + bpymat.specCol = mat.getFieldAsFloatTuple('specularColor', [0.0, 0.0, 0.0]) + bpymat.alpha = 1.0 - mat.getFieldAsFloat('transparency', 0.0) + if bpymat.alpha < 0.999: + bpymat.mode |= Material.Modes.ZTRANSP + + + if ima: + # print ima + ima_url = ima.getFieldAsString('url') + 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) + 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) + ima_repT = ima.getFieldAsBool('repeatT', True) + + 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) + elif geom_spec == 'IndexedLineSet': + bpydata = importMesh_IndexedLineSet(geom) + elif geom_spec == 'PointSet': + bpydata = importMesh_PointSet(geom) + elif geom_spec == 'Sphere': + bpydata = importMesh_Sphere(geom) + elif geom_spec == 'Box': + bpydata = importMesh_Box(geom) + elif geom_spec == 'Cylinder': + bpydata = importMesh_Cylinder(geom) + elif geom_spec == 'Cone': + bpydata = importMesh_Cone(geom) + 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) + creaseAngle = geom.getFieldAsFloat('creaseAngle', None) + + 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 and 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): + vrmlname = node.getDefName() + if not vrmlname: vrmlname = 'PointLight' + + # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0) # TODO + # attenuation = node.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0)) # TODO + color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0)) + intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. + location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0)) + # is_on = node.getFieldAsBool('on', True) # TODO + radius = node.getFieldAsFloat('radius', 100.0) + + 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): + 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)) + direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0)) + intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. + # is_on = node.getFieldAsBool('on', True) # 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): + vrmlname = node.getDefName() + if not vrmlname: vrmlname = 'SpotLight' + + # ambientIntensity = geom.getFieldAsFloat('ambientIntensity', 0.0) # TODO + # attenuation = geom.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0)) # TODO + beamWidth = node.getFieldAsFloat('beamWidth', 1.570796) * 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)) + cutOffAngle = node.getFieldAsFloat('cutOffAngle', 0.785398) * 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)) + intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. + location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0)) + # is_on = node.getFieldAsBool('on', True) # TODO + radius = node.getFieldAsFloat('radius', 100.0) + + 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 = TranslationMatrix(Vector(location)) * Vector(direction).toTrackQuat('-z', 'y').toMatrix().resize4x4() + + return bpylamp, mtx + + +def importLamp(node, spec, ancestry): + if spec=='PointLight': + bpylamp,mtx = importLamp_PointLight(node) + elif spec=='DirectionalLight': + bpylamp,mtx = importLamp_DirectionalLight(node) + elif spec=='SpotLight': + bpylamp,mtx = importLamp_SpotLight(node) + else: + print "Error, not a lamp" + raise "" + + 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) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. + # jump = node.getFieldAsBool('jump', True) + orientation = node.getFieldAsFloatTuple('orientation', (0.0, 0.0, 1.0, 0.0)) + position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 10.0)) + description = node.getFieldAsString('description', '') + + bpycam = bpy.data.cameras.new(name) + + bpycam.angle = fieldOfView + + mtx = TranslationMatrix(Vector(position)) * translateRotation(orientation) * MATRIX_Z_TO_Y + + + 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) ) + + +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() + 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) + else: + + # Note, include this function so the VRML/X3D importer can be extended + # by an external script. + if HELPER_FUNC: + HELPER_FUNC(node, ancestry) + + # 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 + +''' +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 < 12803 or i > 1000000: + continue + #if i != 12686: + # continue + + f = f.strip() + print f, i, tot + sce = bpy.data.scenes.new(f.split('/')[-1]) + bpy.data.scenes.active = sce + # Window. + load_web3d(f, PREF_FLAT=True) +'''
\ No newline at end of file diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py index b0fc1cc7faf..458e61f3a28 100644 --- a/release/scripts/lightwave_export.py +++ b/release/scripts/lightwave_export.py @@ -8,7 +8,7 @@ Tooltip: 'Export selected meshes to LightWave File Format (.lwo)' """ __author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py index 24e072f018a..6d02467cef8 100644 --- a/release/scripts/lightwave_import.py +++ b/release/scripts/lightwave_import.py @@ -106,6 +106,12 @@ try: 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 @@ -656,7 +662,12 @@ def read_clip(lwochunk, dir_part): # ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf clip_dict = {} data = cStringIO.StringIO(lwochunk.read()) - image_index, = struct.unpack(">L", data.read(4)) + 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): @@ -1634,11 +1645,11 @@ def main(): return Blender.Window.FileSelector(read, "Import LWO", '*.lwo') - if __name__=='__main__': main() + # Cams debugging lwo loader """ TIME= Blender.sys.time() diff --git a/release/scripts/md2_export.py b/release/scripts/md2_export.py index 71e056a5f53..588336ed447 100644 --- a/release/scripts/md2_export.py +++ b/release/scripts/md2_export.py @@ -8,9 +8,9 @@ Tooltip: 'Export to Quake file format (.md2).' """ __author__ = 'Bob Holcomb' -__version__ = '0.18.1' +__version__ = '0.18.1 patch 1' __url__ = ["Bob's site, http://bane.servebeer.com", - "Support forum, http://bane.servebeer.com", "blender", "elysiun"] + "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). @@ -19,6 +19,12 @@ This script Exports a Quake 2 file (MD2). 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 @@ -105,13 +111,13 @@ def draw_gui(): 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("Search",EVENT_CHOOSE_FILENAME,220,75,80,18) + 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("Search",EVENT_CHOOSE_FRAME,220,55,80,18) + 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, @@ -143,14 +149,9 @@ def bevent(evt): elif (evt==EVENT_CHOOSE_FRAME): FileSelector(frame_callback, "Frame Selection") elif (evt==EVENT_SAVE_MD2): - if (g_filename.val == "model"): - save_md2("blender.md2") - Blender.Draw.Exit() - return - else: - save_md2(g_filename.val) - Blender.Draw.Exit() - return + save_md2(g_filename.val) + Blender.Draw.Exit() + return Register(draw_gui, event, bevent) @@ -616,21 +617,24 @@ def validation(object): #move the object to the origin if it's not already there if object.getLocation('worldspace')!=(0.0, 0.0, 0.0): - object.setLocation(0.0,0.0,0.0) - print "Model not centered at origin-Centering" - result=Blender.Draw.PupMenu("Model not centered at origin-Centering for you") + print "Model not centered at origin" + result=Blender.Draw.PupMenu("Model not centered at origin%t|Center (will not work with animations!)|Do not center") + if result==1: + object.setLocation(0.0,0.0,0.0) #resize the object in case it is not the right size if object.getSize('worldspace')!=(1.0,1.0,1.0): - object.setSize(1.0,1.0,1.0) print "Object is scaled-You should scale the mesh verts, not the object" - result=Blender.Draw.PupMenu("Object is scaled-You should scale the mesh verts, not the object-fixing for you") + result=Blender.Draw.PupMenu("Object is scaled-You should scale the mesh verts, not the object%t|Fix scale (will not work with animations!)|Do not scale") + if result==1: + object.setSize(1.0,1.0,1.0) if object.getEuler('worldspace')!=Blender.Mathutils.Euler(0.0,0.0,0.0): print "object.rot: ", object.getEuler('worldspace') - object.setEuler([0.0,0.0,0.0]) print "Object is rotated-You should rotate the mesh verts, not the object" - result=Blender.Draw.PupMenu("Object is rotated-You should rotate the mesh verts, not the object-fixing for you") + result=Blender.Draw.PupMenu("Object is rotated-You should rotate the mesh verts, not the object%t|Fix rotation (will not work with animations!)|Do not rotate") + if result==1: + object.setEuler([0.0,0.0,0.0]) #get access to the mesh data mesh=object.getData(False, True) #get the object (not just name) and the Mesh, not NMesh @@ -643,7 +647,7 @@ def validation(object): face.sel=1 if result==0: #first time we have this problem, don't pop-up a window every time it finds a quad print "Model not made entirely of triangles" - result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|NO") + result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|Quit") #triangulate or quit if result==1: @@ -672,36 +676,34 @@ def validation(object): else: print "Model does not have UV (face or vertex)" - result=Blender.Draw.PupMenu("Model does not have UV (face or vertex)%t|Quit") - return False + result=Blender.Draw.PupMenu("Model does not have UV (face or vertex)%t|Output (0,0) as UV coordinates and do not generate GL commands|Quit") + if result==2: + return False #check it has an associated texture map last_face="" - last_face=mesh.faces[0].image - if last_face=="": - print "Model does not have a texture Map" - result=Blender.Draw.PupMenu("Model does not have a texture Map%t|Quit") - return False + if mesh.faceUV: + last_face=mesh.faces[0].image + #check if each face uses the same texture map (only one allowed) + for face in mesh.faces: + mesh_image=face.image + if not mesh_image: + print "Model has a face without a texture Map" + result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|This should never happen!") + #return False + if mesh_image!=last_face: + print "Model has more than 1 texture map assigned" + result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit") + #return False + if mesh_image: + size=mesh_image.getSize() + #is this really what the user wants + if (size[0]!=256 or size[1]!=256): + print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1] + result=Blender.Draw.PupMenu("Texture map size is non-standard (not 256x256), it is: "+str(size[0])+"x"+str(size[1])+": Continue?%t|YES|NO") + if(result==2): + return False - #check if each face uses the same texture map (only one allowed) - for face in mesh.faces: - mesh_image=face.image - if not mesh_image: - print "Model has a face without a texture Map" - result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|Quit") - return False - if mesh_image!=last_face: - print "Model has more than 1 texture map assigned" - result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit") - return False - - size=mesh_image.getSize() - #is this really what the user wants - if (size[0]!=256 or size[1]!=256): - print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1] - result=Blender.Draw.PupMenu("Texture map size is non-standard (not 256x256), it is: "+str(size[0])+"x"+str(size[1])+": Continue?%t|YES|NO") - if(result==2): - return False #verify frame list data user_frame_list=get_frame_list() @@ -743,7 +745,8 @@ def fill_md2(md2, object): #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 @@ -758,31 +761,35 @@ def fill_md2(md2, object): #get the skin information #use the first faces' image for the texture information - mesh_image=mesh.faces[0].image - size=mesh_image.getSize() - 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 + if mesh.faceUV: + mesh_image=mesh.faces[0].image + size=mesh_image.getSize() + 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) for face in mesh.faces: - for i in range(0,3): - t=(face.uv[i]) + for i in xrange(0,3): + if mesh.faceUV: + t=(face.uv[i]) + else: + t=(0,0) 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 range (0, md2.num_tex_coords): + 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()) @@ -791,13 +798,16 @@ def fill_md2(md2, object): #put faces in the md2 structure #for each face in the model - for this_face in range(0, md2.num_faces): + for this_face in xrange(0, md2.num_faces): md2.faces.append(md2_face()) - for i in range(0,3): + for i in xrange(0,3): #blender uses indexed vertexes so this works very well md2.faces[this_face].vertex_index[i]=mesh.faces[this_face].verts[i].index #lookup texture index in dictionary - uv_coord=(mesh.faces[this_face].uv[i]) + if mesh.faceUV: + uv_coord=(mesh.faces[this_face].uv[i]) + else: + uv_coord=(0,0) tex_key=(uv_coord[0],uv_coord[1]) tex_index=tex_list[tex_key] md2.faces[this_face].texture_index[i]=tex_index @@ -824,7 +834,7 @@ def fill_md2(md2, object): 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 range(0,md2.num_frames): + for frame_counter in xrange(0,md2.num_frames): progress+=progressIncrement Blender.Window.DrawProgressBar(progress, "Calculating Frame: "+str(frame_counter)) @@ -865,6 +875,10 @@ def fill_md2(md2, object): frame_scale_y=(frame_max_y-frame_min_y)/255 frame_scale_z=(frame_max_z-frame_min_z)/255 + if frame_scale_x == 0: frame_scale_x = 1.0 + if frame_scale_y == 0: frame_scale_y = 1.0 + if frame_scale_z == 0: frame_scale_z = 1.0 + #translate value of the mesh to center it on the origin frame_trans_x=frame_min_x frame_trans_y=frame_min_y @@ -875,7 +889,7 @@ def fill_md2(md2, object): md2.frames[frame_counter].translate=(-frame_trans_x, frame_trans_y, frame_trans_z) #now for the vertices - for vert_counter in range(0, md2.num_vertices): + for vert_counter in xrange(0, md2.num_vertices): #add a vertex to the md2 structure md2.frames[frame_counter].vertices.append(md2_point()) #figure out the new coords based on scale and transform @@ -893,12 +907,12 @@ def fill_md2(md2, object): maxdotindex = -1; - for j in range(0,162): + #swap y and x for difference in axis orientation + x1=-mesh.verts[vert_counter].no[1] + y1=mesh.verts[vert_counter].no[0] + z1=mesh.verts[vert_counter].no[2] + for j in xrange(0,162): #dot = (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) - #swap y and x for difference in axis orientation - x1=-mesh.verts[vert_counter].no[1] - y1=mesh.verts[vert_counter].no[0] - z1=mesh.verts[vert_counter].no[2] dot = (x1*MD2_NORMALS[j][0]+ y1*MD2_NORMALS[j][1]+ z1*MD2_NORMALS[j][2]); @@ -916,7 +930,7 @@ def fill_md2(md2, object): #output all the frame names-user_frame_list is loaded during the validation for frame_set in user_frame_list: - for counter in range(frame_set[1]-1, frame_set[2]): + 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 @@ -954,14 +968,14 @@ def get_frame_list(): file.close() #check header (first line) - if lines[0].stip()<>"# MD2 Frame Name List": + 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 range(1, len(lines)): + for counter in xrange(1, len(lines)): current_line=lines[counter].strip() if current_line[0]=="#": #found a comment @@ -1025,7 +1039,7 @@ def find_strip_length(mesh, start_tri, edge_key): pass else: #find non-shared vert - for vert_counter in range(0,3): + 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 @@ -1089,11 +1103,11 @@ def stripify_tri_list(mesh, edge_key): #print "strip tris: ", strip_tris #print "strip_tri length: ", len(strip_tris) - for tri_counter in range(0, 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 range(0,3): + 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) @@ -1105,7 +1119,7 @@ def stripify_tri_list(mesh, edge_key): strip_verts.append(face.verts[(start_vert+1)%3].index) strip_st.append(face.uv[(start_vert+1)%3]) else: - for vert_counter in range(0,3): + 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]) @@ -1117,8 +1131,13 @@ def stripify_tri_list(mesh, edge_key): # 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 @@ -1138,7 +1157,7 @@ def build_GL_commands(md2, mesh): #print "edge Dict: ", edge_dict - for tri_counter in range(0,len(mesh.faces)): + for tri_counter in xrange(0,len(mesh.faces)): if used_tris[tri_counter]!=0: #print "Found a used triangle: ", tri_counter pass @@ -1156,7 +1175,7 @@ def build_GL_commands(md2, mesh): strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0]) #mark tris as used - for used_counter in range(0,strip_length): + 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]) @@ -1169,7 +1188,7 @@ def build_GL_commands(md2, mesh): num_commands+=1 #add s,t,vert for this command list - for command_counter in range(0, len(strip_tris)+2): + 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 @@ -1245,3 +1264,4 @@ def save_md2(filename): md2=0 print "Closed the file" + diff --git a/release/scripts/md2_import.py b/release/scripts/md2_import.py index e39b2ca85ec..f52746259a6 100644 --- a/release/scripts/md2_import.py +++ b/release/scripts/md2_import.py @@ -10,7 +10,7 @@ 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", "elysiun"] + "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, @@ -448,6 +448,8 @@ def load_md2(md2_filename, texture_filename): 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 diff --git a/release/scripts/mesh_boneweight_copy.py b/release/scripts/mesh_boneweight_copy.py index 8aa9a1e3213..d2a477fbc0b 100644 --- a/release/scripts/mesh_boneweight_copy.py +++ b/release/scripts/mesh_boneweight_copy.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Bone Weight Copy' -Blender: 243 +Blender: 245 Group: 'Object' Tooltip: 'Copy Bone Weights from 1 mesh, to all other selected meshes.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py index 1eb3e3968b2..27adca335cb 100644 --- a/release/scripts/mesh_cleanup.py +++ b/release/scripts/mesh_cleanup.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Clean Meshes' -Blender: 242 +Blender: 245 Group: 'Mesh' Tooltip: 'Clean unused data from all selected mesh objects.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ Clean Meshes @@ -121,25 +121,29 @@ def rem_unused_materials(me): 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=0 - material_users[f.mat] += 1 + 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)] ) - i= len_materials - while i: - i-=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: - mat_idx_subtract+=1 - reindex_mapping[i]= mat_idx_subtract - materials.pop(i) + 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= f.mat - reindex_mapping[f.mat] + f.mat= reindex_mapping[f.mat] me.materials= materials return rem_materials @@ -449,4 +453,4 @@ def main(): if __name__ == '__main__': - main() + main()
\ No newline at end of file diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py index f65eccae9a4..006bdf10b49 100644 --- a/release/scripts/mesh_edges2curves.py +++ b/release/scripts/mesh_edges2curves.py @@ -6,7 +6,7 @@ Group: 'Mesh' Tip: 'Edges not used by a face are converted into polyline(s)' """ __author__ = ("Campbell Barton") -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0 2006/02/08" __bpydoc__ = """\ diff --git a/release/scripts/mesh_mirror_tool.py b/release/scripts/mesh_mirror_tool.py index 045f37b8333..33ce6936c7f 100644 --- a/release/scripts/mesh_mirror_tool.py +++ b/release/scripts/mesh_mirror_tool.py @@ -6,8 +6,8 @@ Group: 'Mesh' Tooltip: 'Snap Verticies to X mirrord locations and weights.' """ -__author__= ['Campbell Barton'] -__url__= ["blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/"] +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__= '1.0' __bpydoc__= '''\ This script is used to mirror vertex locations and weights diff --git a/release/scripts/mesh_poly_reduce.py b/release/scripts/mesh_poly_reduce.py index 9d8bb61f652..6dfd7a90efc 100644 --- a/release/scripts/mesh_poly_reduce.py +++ b/release/scripts/mesh_poly_reduce.py @@ -7,7 +7,7 @@ Tooltip: 'Removed polygons from a mesh while maintaining the shape, textures and """ __author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0 2006/02/07" __bpydoc__ = """\ diff --git a/release/scripts/ms3d_import.py b/release/scripts/ms3d_import.py new file mode 100644 index 00000000000..c1438cbfc97 --- /dev/null +++ b/release/scripts/ms3d_import.py @@ -0,0 +1,487 @@ +#!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()<fileSize: + + # read sub version + subVersion = struct.unpack("i", file.read(4))[0] + + # Is the sub version a supported one + if subVersion==1: + + # Group 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 "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()<fileSize: + + # read the subversion + subVersion = struct.unpack("i", file.read(4))[0] + + # is the version supported + if subVersion==2: + # read the 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)) + # extra + extra = struct.unpack("I", file.read(4)) + # 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) + + 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 new file mode 100644 index 00000000000..d8c22a1ec99 --- /dev/null +++ b/release/scripts/ms3d_import_ascii.py @@ -0,0 +1,479 @@ +#!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 index 561e40e15da..2f5617951de 100644 --- a/release/scripts/obdatacopier.py +++ b/release/scripts/obdatacopier.py @@ -8,7 +8,7 @@ Tip: 'Copy data from active object to other selected ones.' """ __author__ = "Jean-Michel Soler (jms), Campbell Barton (Ideasman42)" -__url__ = ("blender", "elysiun", +__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" diff --git a/release/scripts/object_apply_def.py b/release/scripts/object_apply_def.py index 67e4179a674..006e97463d8 100644 --- a/release/scripts/object_apply_def.py +++ b/release/scripts/object_apply_def.py @@ -12,7 +12,7 @@ __author__ = "Martin Poirier (theeth), Jean-Michel Soler (jms), Campbell Barton # Martin Poirier's Apply_Def.py and # Jean-Michel Soler's Fix From Everything -__url__ = ("http://www.blender.org", "http://blenderartists.org", "http://members.iinet.net.au/~cpbarton/ideasman/", "http://jmsoler.free.fr") +__url__ = ("http://www.blender.org", "http://blenderartists.org", "http://jmsoler.free.fr") __version__ = "1.6 07/07/2006" __bpydoc__ = """\ @@ -77,7 +77,11 @@ def copy_vgroups(source_ob, target_ob): for vgroupname in vgroups: target_me.addVertGroup(vgroupname) if len(target_me.verts) == len(source_me.verts): - vlist = source_me.getVertsFromGroup(vgroupname, True) + 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) @@ -171,4 +175,4 @@ def apply_deform(): Blender.Window.RedrawAll() if __name__=='__main__': - apply_deform()
\ No newline at end of file + apply_deform() diff --git a/release/scripts/object_batch_name_edit.py b/release/scripts/object_batch_name_edit.py index 05ca5868d19..4db3a6210db 100644 --- a/release/scripts/object_batch_name_edit.py +++ b/release/scripts/object_batch_name_edit.py @@ -6,7 +6,7 @@ Group: 'Object' Tooltip: 'Apply the chosen rule to rename all selected objects at once.' """ __author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0" __bpydoc__ = """\ diff --git a/release/scripts/object_drop.py b/release/scripts/object_drop.py index 4ea8bde2ca8..f4803e62d98 100644 --- a/release/scripts/object_drop.py +++ b/release/scripts/object_drop.py @@ -1,7 +1,7 @@ #!BPY """ Name: 'Drop Onto Ground' -Blender: 243 +Blender: 245 Group: 'Object' Tooltip: 'Drop the selected objects onto "ground" objects' """ @@ -216,9 +216,10 @@ def main(): # hack so the toggle buttons redraw. this is not nice at all while GLOBALS['EVENT'] == EVENT_REDRAW: - Draw.UIBlock(terain_clamp_ui) + Draw.UIBlock(terain_clamp_ui, 0) if __name__ == '__main__': main() -GLOBALS.clear()
\ No newline at end of file +GLOBALS.clear() + diff --git a/release/scripts/object_find.py b/release/scripts/object_find.py index 0cfd6ad1d92..f12af07e3e4 100644 --- a/release/scripts/object_find.py +++ b/release/scripts/object_find.py @@ -61,8 +61,20 @@ def get_object_images(ob): me.activeUVLayer = orig_uvlayer + + # Now get material images + for mat in me.materials: + if mat: + for mtex in mat.getTextures(): + if mtex: + tex = mtex.tex + i = tex.getImage() + if i: unique_images[i.name] = i + return unique_images.values() + + # Todo, support other object types, materials return [] @@ -118,7 +130,7 @@ def main(): def activate(ob, scn): bpy.data.scenes.active = scn scn.objects.selected = [] - scn.Layers = ob.Layers + scn.Layers = ob.Layers & (1<<20)-1 ob.sel = 1 def name_cmp(name_search, name_found): @@ -195,11 +207,13 @@ def main(): activate(ob, scn) return if NAME_TEXTURE: - for tex in mat.getTextures(): - if tex: - if name_cmp(NAME_MATERIAL, tex.name): - activate(ob, scn) - return + for mtex in mat.getTextures(): + if mtex: + tex = mtex.tex + if tex: + if name_cmp(NAME_TEXTURE, tex.name): + activate(ob, scn) + return Draw.PupMenu('No Objects Found') diff --git a/release/scripts/object_timeofs_follow_act.py b/release/scripts/object_timeofs_follow_act.py new file mode 100644 index 00000000000..83863da7d8f --- /dev/null +++ b/release/scripts/object_timeofs_follow_act.py @@ -0,0 +1,107 @@ +#!BPY +""" +Name: 'TimeOffset follow Active' +Blender: 245 +Group: 'Object' +Tooltip: 'ActObs animated loc sets TimeOffset on other objects at closest frame' +""" +__author__= "Campbell Barton" +__url__= ["blender.org", "blenderartists.org"] +__version__= "1.0" + +__bpydoc__= """ +""" + +# -------------------------------------------------------------------------- +# TimeOffset follow Active v1.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 Image, sys, Draw, Window, Scene, Group +import bpy +import BPyMessages + + +def main(): + + sce = Scene.GetCurrent() + + ob_act = sce.objects.active + + if not ob_act: + Draw.PupMenu("Error%t|no active object") + return + + objects = list(sce.objects.context) + + try: objects.remove(ob_act) + except: pass + + if not objects: + Draw.PupMenu("Error%t|no objects selected") + return + + curframe = Blender.Get('curframe') + + FRAME_START= Draw.Create( Blender.Get('staframe') ) + FRAME_END= Draw.Create( Blender.Get('endframe') ) + + # Get USER Options + pup_block= [\ + ('Start:', FRAME_START, 1, 300000, 'Use the active objects position starting at this frame'),\ + ('End:', FRAME_END, 1, 300000, 'Use the active objects position starting at this frame'),\ + ] + + if not Draw.PupBlock('Set timeoffset...', pup_block): + return + + FRAME_START = FRAME_START.val + FRAME_END = FRAME_END.val + + if FRAME_START >= FRAME_END: + Draw.PupMenu("Error%t|frames are not valid") + + + # Ok - all error checking + locls_act = [] + for f in xrange((FRAME_END-FRAME_START)): + i = FRAME_START+f + Blender.Set('curframe', i) + locls_act.append(ob_act.matrixWorld.translationPart()) + + for ob in objects: + loc = ob.matrixWorld.translationPart() + best_frame = -1 + best_dist = 100000000 + for i, loc_act in enumerate(locls_act): + dist = (loc_act-loc).length + if dist < best_dist: + best_dist = dist + best_frame = i + FRAME_START + + ob.timeOffset = float(best_frame) + + # Set the original frame + Blender.Set('curframe', curframe) + +if __name__ == '__main__': + main() + diff --git a/release/scripts/off_export.py b/release/scripts/off_export.py index 236e6195690..6aac3ff885b 100644 --- a/release/scripts/off_export.py +++ b/release/scripts/off_export.py @@ -8,7 +8,7 @@ Tooltip: 'Export selected mesh to DEC Object File Format (*.off)' """ __author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" diff --git a/release/scripts/off_import.py b/release/scripts/off_import.py index 50c0d3d6f7e..e8ab96c51c5 100644 --- a/release/scripts/off_import.py +++ b/release/scripts/off_import.py @@ -8,7 +8,7 @@ Tooltip: 'Import DEC Object File Format (*.off)' """ __author__ = "Anthony D'Agostino (Scorpius), Campbell Barton (Ideasman)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" diff --git a/release/scripts/paths_import.py b/release/scripts/paths_import.py index f36454978ba..b35d7fe5c65 100644 --- a/release/scripts/paths_import.py +++ b/release/scripts/paths_import.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Name: 'Paths (.svg, .ps, .eps, .ai, Gimp)' Blender: 233 @@ -13,7 +13,7 @@ Tip: 'Import a path from any of a set of formats (still experimental)' """ __author__ = "Jean-Michel Soler (jms)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "AI importer's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai.htm", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") __version__ = "0.1.1" @@ -92,4 +92,5 @@ elif argv=='Gimp_2_0': fonctionSELECT = functionSELECT # can they all be called function? text = 'Import %s' % argv -Blender.Window.FileSelector (fonctionSELECT, text)
\ No newline at end of file +Blender.Window.FileSelector (fonctionSELECT, text) + diff --git a/release/scripts/ply_export.py b/release/scripts/ply_export.py index cecde5a0b59..46d08050302 100644 --- a/release/scripts/ply_export.py +++ b/release/scripts/ply_export.py @@ -13,7 +13,7 @@ from Blender import Mesh, Scene, Window, sys, Image, Draw import BPyMesh __author__ = "Bruce Merry" -__version__ = "0.92" +__version__ = "0.93" __bpydoc__ = """\ This script exports Stanford PLY files from Blender. It supports normals, colours, and texture coordinates per face or per vertex. @@ -37,6 +37,8 @@ Only one mesh can be exported at a time. # 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 @@ -141,10 +143,10 @@ def file_callback(filename): normal_key = rvec3d(normal) if faceUV: - uvcoord= tuple(uv[j]) + uvcoord= uv[j][0], 1.0-uv[j][1] uvcoord_key = rvec2d(uvcoord) elif vertexUV: - uvcoord= tuple(v.uvco) + uvcoord= v.uvco[0], 1.0-v.uvco[1] uvcoord_key = rvec2d(uvcoord) if vertexColors: color= col[j].r, col[j].g, col[j].b @@ -162,7 +164,7 @@ def file_callback(filename): file.write('ply\n') file.write('format ascii 1.0\n') - file.write('Created by Blender3D %s - www.blender.org, source file: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) + file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('element vertex %d\n' % len(verts)) @@ -207,10 +209,9 @@ def file_callback(filename): for j, v in enumerate(f): if f.smooth: normal= rvec3d(v.no) else: normal= no - if faceUV: uvcoord= rvec2d(uv[j]) - elif vertexUV: uvcoord= rvec2d(v.uvco) + if faceUV: uvcoord= rvec2d((uv[j][0], 1.0-uv[j][1])) + elif vertexUV: uvcoord= rvec2d((v.uvco[0], 1.0-v.uvco[1])) if vertexColors: color= col[j].r, col[j].g, col[j].b - co = v.co file.write('%d ' % vdict[v.index][normal, uvcoord, color]) diff --git a/release/scripts/ply_import.py b/release/scripts/ply_import.py index 6b96777102a..302e21a0a43 100644 --- a/release/scripts/ply_import.py +++ b/release/scripts/ply_import.py @@ -2,13 +2,13 @@ """ Name: 'Stanford PLY (*.ply)...' -Blender: 241 +Blender: 248 Group: 'Import' Tip: 'Import a Stanford PLY file' """ __author__ = 'Bruce Merry' -__version__ = '0.92' +__version__ = '0.93' __bpydoc__ = """\ This script imports Stanford PLY files into Blender. It supports per-vertex normals, and per-face colours and texture coordinates. @@ -35,20 +35,20 @@ Run this script from "File->Import" and select the desired PLY file. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# Updated by Campbell Barton AKA Ideasman, 10% faster code. +# 20th Oct 2008, 0.93 - Updated by Campbell Barton AKA ideasman42, use Mesh rather then NMesh, dont import normals, vcolors work again. +# Updated by Campbell Barton AKA Ideasman42, 10% faster code. # Portions of this code are taken from mod_meshtools.py in Blender # 2.32. import Blender try: - import re, struct, StringIO + import re, struct except: struct= None -class element_spec: - name = '' - count = 0 +class element_spec(object): + __slots__ = 'name', 'count', 'properties' def __init__(self, name, count): self.name = name self.count = count @@ -64,10 +64,8 @@ class element_spec: if p.name == name: return i return -1 -class property_spec: - name = '' - list_type = '' - numeric_type = '' +class property_spec(object): + __slots__ = 'name', 'list_type', 'numeric_type' def __init__(self, name, list_type, numeric_type): self.name = name self.list_type = list_type @@ -117,14 +115,17 @@ class property_spec: else: return self.read_format(format, 1, self.numeric_type, stream)[0] -class object_spec: +class object_spec(object): + __slots__ = 'specs' 'A list of element_specs' - specs = [] - + def __init__(self): + self.specs = [] + def load(self, format, stream): return dict([(i.name,[i.load(format, stream) for j in xrange(i.count) ]) for i in self.specs]) ''' + # Longhand for above LC answer = {} for i in self.specs: answer[i.name] = [] @@ -176,7 +177,7 @@ def read(filename): if (len(tokens) < 3): print 'Invalid format line' return None - if (tokens[1] not in format_specs.keys()): + if (tokens[1] not in format_specs): # .keys()): # keys is implicit print 'Unknown format', tokens[1] return None if (tokens[2] != version): @@ -209,115 +210,132 @@ def read(filename): return (obj_spec, obj); - -def add_face(vertices, varr, indices, uvindices, colindices): - face = Blender.NMesh.Face([varr[i] for i in indices]) - for index in indices: - vertex = vertices[index]; - - if uvindices: - face.uv.append((vertex[uvindices[0]], 1.0 - vertex[uvindices[1]])) - face.mode &= ~Blender.NMesh.FaceModes.TEX - if colindices: - if not uvindices: face.uv.append((0, 0)) # Force faceUV - face.col.append(Blender.NMesh.Col(vertex[colindices[0]], vertex[colindices[1]], vertex[colindices[2]], 255)) - face.mode &= ~Blender.NMesh.FaceModes.TEX - return face - -def filesel_callback(filename): +def load_ply(filename): t = Blender.sys.time() - (obj_spec, obj) = read(filename) + obj_spec, obj = read(filename) if obj == None: print 'Invalid file' return - vmap = {} - varr = [] - uvindices = None - noindices = None - colindices = None + + uvindices = colindices = None + # noindices = None # Ignore normals + for el in obj_spec.specs: if el.name == 'vertex': vindices = vindices_x, vindices_y, vindices_z = (el.index('x'), el.index('y'), el.index('z')) - if el.index('nx') >= 0 and el.index('ny') >= 0 and el.index('nz') >= 0: - noindices = (el.index('nx'), el.index('ny'), el.index('nz')) - if el.index('s') >= 0 and el.index('t') >= 0: - uvindices = (el.index('s'), el.index('t')) - if el.index('red') >= 0 and el.index('green') and el.index('blue') >= 0: - colindices = (el.index('red'), el.index('green'), el.index('blue')) + # noindices = (el.index('nx'), el.index('ny'), el.index('nz')) + # if -1 in noindices: noindices = None + uvindices = (el.index('s'), el.index('t')) + if -1 in uvindices: uvindices = None + colindices = (el.index('red'), el.index('green'), el.index('blue')) + if -1 in colindices: colindices = None elif el.name == 'face': findex = el.index('vertex_indices') + + mesh_faces = [] + mesh_uvs = [] + mesh_colors = [] + + def add_face(vertices, indices, uvindices, colindices): + mesh_faces.append(indices) + if uvindices: mesh_uvs.append([ (vertices[index][uvindices[0]], 1.0 - vertices[index][uvindices[1]]) for index in indices]) + if colindices: mesh_colors.append([ (vertices[index][colindices[0]], vertices[index][colindices[1]], vertices[index][colindices[2]]) for index in indices]) + + + if uvindices or colindices: + # If we have Cols or UVs then we need to check the face order. + add_face_simple = add_face - - mesh = Blender.NMesh.GetRaw() - NMVert = Blender.NMesh.Vert - for v in obj['vertex']: - - if noindices > 0: - x,y,z,nx,ny,nz = vkey =\ - (v[vindices_x], v[vindices_y], v[vindices_z],\ - v[noindices[0]], v[noindices[1]], v[noindices[2]]) - else: - x,y,z = vkey = (v[vindices_x], v[vindices_y], v[vindices_z]) - #if not vmap.has_key(vkey): - try: # try uses 1 less dict lookup - varr.append(vmap[vkey]) - except: - nmv = NMVert(vkey[0], vkey[1], vkey[2]) - mesh.verts.append(nmv) - if noindices > 0: - nmv.no[0] = vkey[3] - nmv.no[1] = vkey[4] - nmv.no[2] = vkey[5] - vmap[vkey] = nmv - varr.append(vmap[vkey]) + # EVIL EEKADOODLE - face order annoyance. + def add_face(vertices, indices, uvindices, colindices): + if len(indices)==4: + if indices[2]==0 or indices[3]==0: + indices= indices[2], indices[3], indices[0], indices[1] + elif len(indices)==3: + if indices[2]==0: + indices= indices[1], indices[2], indices[0] + + add_face_simple(vertices, indices, uvindices, colindices) verts = obj['vertex'] if 'face' in obj: for f in obj['face']: ind = f[findex] - nind = len(ind) - if nind <= 4: - mesh.faces.append(add_face(verts, varr, ind, uvindices, colindices)) + len_ind = len(ind) + if len_ind <= 4: + add_face(verts, ind, uvindices, colindices) else: - for j in xrange(nind - 2): - mesh.faces.append(add_face(verts, varr, (ind[0], ind[j + 1], ind[j + 2]), uvindices, colindices)) - + # Fan fill the face + for j in xrange(len_ind - 2): + add_face(verts, (ind[0], ind[j + 1], ind[j + 2]), uvindices, colindices) + + mesh = Blender.Mesh.New() + + mesh.verts.extend([(v[vindices_x], v[vindices_y], v[vindices_z]) for v in obj['vertex']]) + + if mesh_faces: + mesh.faces.extend(mesh_faces, smooth=True, ignoreDups=True) + + if uvindices or colindices: + if uvindices: mesh.faceUV = True + if colindices: mesh.vertexColors = True + + for i, f in enumerate(mesh.faces): + if uvindices: + ply_uv = mesh_uvs[i] + for j, uv in enumerate(f.uv): + uv[:] = ply_uv[j] + + if colindices: + ply_col = mesh_colors[i] + for j, col in enumerate(f.col): + col.r, col.g, col.b = ply_col[j] - del obj # Reclaim memory + mesh.calcNormals() - ''' - if noindices: - normals = 1 - else: - normals = 0 - ''' objname = Blender.sys.splitext(Blender.sys.basename(filename))[0] scn= Blender.Scene.GetCurrent() scn.objects.selected = [] mesh.name= objname - scn.objects.new(mesh) + scn.objects.active = scn.objects.new(mesh) Blender.Redraw() Blender.Window.DrawProgressBar(1.0, '') - print '\nSuccessfully imported ' + Blender.sys.basename(filename) + ' ' + str(Blender.sys.time()-t) - - - + print '\nSuccessfully imported "%s" in %.3f sec' % (filename, Blender.sys.time()-t) def main(): if not struct: - Blender.Draw.PupMenu('This importer requires a full python install') + msg = 'This importer requires a full python install' + if Blender.mode == 'background': print msg + else: Blender.Draw.PupMenu(msg) return - Blender.Window.FileSelector(filesel_callback, 'Import PLY', '*.ply') + Blender.Window.FileSelector(load_ply, 'Import PLY', '*.ply') if __name__=='__main__': main() +''' +import bpy +import os +files = os.popen('find /fe/ply -iname "*.ply"').readlines() - - +files.sort() +tot = len(files) +for i, f in enumerate(files): + if i < 26 or i > 1000000: + continue + #if i != 12686: + # continue + + f = f.strip() + print f, i, tot + sce = bpy.data.scenes.new(f.split('/')[-1]) + bpy.data.scenes.active = sce + # Window. + load_ply(f) +'''
\ No newline at end of file diff --git a/release/scripts/raw_export.py b/release/scripts/raw_export.py index 02eb5ad3f36..e3c588cac10 100644 --- a/release/scripts/raw_export.py +++ b/release/scripts/raw_export.py @@ -2,21 +2,21 @@ """ Name: 'Raw Faces (.raw)...' -Blender: 242 +Blender: 245 Group: 'Export' -Tooltip: 'Export selected mesh to Raw Triangle Format (.raw)' +Tooltip: 'Export selected mesh to Raw Format (.raw)' """ __author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" __bpydoc__ = """\ -This script exports meshes to Raw Triangle file format. +This script exports meshes to Raw file format. The raw triangle format is very simple; it has no verts or faces lists. -It's just a simple ascii text file with the vertices of each triangle +It's just a simple ascii text file with the vertices of each triangle or quad listed on each line. There were some very old utilities (when the PovRay forum was in existence on CompuServe) that preformed operations on these files. @@ -65,24 +65,24 @@ def write(filename): filename += '.raw' scn= Blender.Scene.GetCurrent() - object= scn.getActiveObject() - if not object: + ob= scn.objects.active + if not ob: Blender.Draw.PupMenu('Error%t|Select 1 active object') return file = open(filename, 'wb') - mesh = BPyMesh.getMeshFromObject(object, None, True, False, scn) + mesh = BPyMesh.getMeshFromObject(ob, None, True, False, scn) if not mesh: Blender.Draw.PupMenu('Error%t|Could not get mesh data from active object') return - mesh.transform(object.matrixWorld) + mesh.transform(ob.matrixWorld) file = open(filename, "wb") for f in mesh.faces: - for v in f.v: + for v in f: file.write('%.6f %.6f %.6f ' % tuple(v.co)) file.write('\n') file.close() diff --git a/release/scripts/raw_import.py b/release/scripts/raw_import.py index a77ed9cc03a..76c03c77337 100644 --- a/release/scripts/raw_import.py +++ b/release/scripts/raw_import.py @@ -8,7 +8,7 @@ Tooltip: 'Import Raw Triangle File Format (.raw)' """ __author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" diff --git a/release/scripts/renameobjectbyblock.py b/release/scripts/renameobjectbyblock.py index 403aa32717e..eeea815c650 100644 --- a/release/scripts/renameobjectbyblock.py +++ b/release/scripts/renameobjectbyblock.py @@ -8,7 +8,7 @@ Tip: 'GUI to select and rename objects.' """ __author__ = "Jean-Michel Soler (jms)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_renameobjectgui.htm", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") __version__ = "233" diff --git a/release/scripts/render_save_layers.py b/release/scripts/render_save_layers.py new file mode 100644 index 00000000000..c91fcce7948 --- /dev/null +++ b/release/scripts/render_save_layers.py @@ -0,0 +1,120 @@ +#!BPY + +""" +Name: 'Save Render Layers...' +Blender: 245 +Group: 'Render' +Tooltip: 'Save current renderlayers as a BPython script' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender", "blenderartists.org") +__version__ = "1.0" + +__bpydoc__ = """\ +""" + +# -------------------------------------------------------------------------- +# The scripts generated by this script are put under Public Domain by +# default, but you are free to edit the ones you generate with this script +# and change their license to another one of your choice. +# -------------------------------------------------------------------------- +# ***** 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.Window import Theme, FileSelector +from Blender import Scene + +sce = Scene.GetCurrent() +rend = sce.render + +# default filename: filename + scenename + '_renderlayer.py' in user's scripts dir: +default_fname = Blender.Get("scriptsdir") +if not default_fname: + default_fname = Blender.Get("uscriptsdir") + +if default_fname: + default_fname = Blender.sys.join(default_fname, sce.name + '_renderlayer.py') + default_fname = default_fname.replace(' ','_') + +def write_renderlayers(filename): + "Write the current renderlayer as a bpython script" + + if not filename.endswith('.py'): filename += '.py' + + fout = file(filename, "w") + + fout.write("""#!BPY + +# \"\"\" +# Name: '%s' +# Blender: 245 +# Group: 'Render' +# Tooltip: '' +# \"\"\" + +__%s__ = "????" +__%s__ = "2.43" +__%s__ = ["blender"] +__%s__ = \"\"\"\\ +You can edit this section to write something about your script that can +be read then with the Scripts Help Browser script in Blender. + +Remember to also set author, version and possibly url(s) above. You can also +define an __email__ tag, check some bundled script's source for examples. +\"\"\" + +# This script was automatically generated by the render_save_layers.py bpython script. +# By default, these generated scripts are released as Public Domain, but you +# are free to change the license of the scripts you generate with +# render_save_layers.py before releasing them. + +import Blender +from Blender import Scene + +sce = Scene.GetCurrent() +rend = sce.render +""" % (sce.name, "author", "version", "url", "bpydoc")) + + for lay in rend.renderLayers: # + fout.write("\nlay = rend.addRenderLayer()\n") + fout.write("lay.name = \"%s\"\n" % lay.name) + + exec("vars = dir(lay)") + + for var in vars: + if var.startswith('_'): + continue + + v = "lay.%s" % var + exec("value = %s" % v) + if type(value) == str: + fout.write("%s = '%s'\n" % (v, value)) + else: + fout.write("%s = %s\n" % (v, value)) + + fout.write('\nBlender.Redraw(-1)') + fout.close() + try: + Blender.UpdateMenus() + except: + Blender.Draw.PupMenu("Warning - check console!%t|Menus could not be automatically updated") + +FileSelector(write_renderlayers, "Save RenderLayers", default_fname) diff --git a/release/scripts/rvk1_torvk2.py b/release/scripts/rvk1_torvk2.py index 754d2d0af2d..a48d065813a 100644 --- a/release/scripts/rvk1_torvk2.py +++ b/release/scripts/rvk1_torvk2.py @@ -1,5 +1,5 @@ #!BPY - +# coding: utf-8 """ Registration info for Blender menus: <- these words are ignored Name: 'Deformed mesh to Rvk' Blender: 243 @@ -8,13 +8,13 @@ Tip: 'Copy deform data (not surf. subdiv) of active obj to rvk of the 2nd select """ __author__ = "Jean-Michel Soler (jms)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_rvk1versrvk2.htm", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") __version__ = "2007/04/27" __bpydoc__ = """\ -"DEFORM to RVK2" copies deform data (except EDGESPLIT,DECIMATE,SUBSURF,BOOLEAN, +"DEFORM to RVK2" copies deform data (except EDGESPLIT,DECIMATE,SUBSURF,BOOLEAN, BUILD,MIRROR,ARRAY) of the active object to the RVK (relative vertex key) of the other selected object. @@ -25,7 +25,7 @@ key. The new version of this scrit (Blender 2.43) manages the modifier changes. There are a lot of modifiers but only the ones which just deforms the shape can be used : LATTICE, CURVE, WAVE, ARMATURE. You can unset these modifiers -from the script. +from the script. Usage: @@ -35,7 +35,7 @@ the 3d View. If the active object has subsurf turned on and nonzero subdiv level, the script will ask if it should change that. Before copying data to the rvk it will also ask whether it should replace or add a new vertex group. - + """ #---------------------------------------------- @@ -70,7 +70,7 @@ 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 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ # Copy the rvk (1, or armature, lattice, or # any mesh deformation except surface @@ -83,7 +83,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # download the script : # http://jmsoler.free.fr/util/blenderfile/py/rvk1_torvk2.py # Communicate upon problems or errors: -# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender #---------------------------------------------- # Page officielle : # http://jmsoler.free.fr/util/blenderfile/py/rvk1_torvk2.py @@ -101,22 +101,22 @@ def Value(t): exec "t=Modifier.Types.%s"%t return t -def deform2rvk(): +def deform2rvk(): POSSMOD_list=['EDGESPLIT', 'DECIMATE', - 'SUBSURF', - 'BOOLEAN', + 'SUBSURF', + 'BOOLEAN', 'BUILD', - 'MIRROR', + 'MIRROR', 'ARRAY'] AUTHMOD_list=['LATTICE', - 'CURVE', + 'CURVE', 'WAVE', 'ARMATURE'] MODIFIERS=0 - + BMOD=[['Possible Modifiers'], ['Allowed Modifiers']] @@ -129,8 +129,8 @@ def deform2rvk(): # ============================================================= # must be 2 meshes ============================================ # ============================================================= - if RVK1.getType()=='Mesh' and RVK2.getType()=='Mesh': - FRAME=Blender.Get('curframe') + if RVK1.getType()=='Mesh' and RVK2.getType()=='Mesh': + FRAME=Blender.Get('curframe') DATA2=RVK2.getData() if DEBUG: print DATA2.getKey() # ============================================================ @@ -151,7 +151,7 @@ def deform2rvk(): # === Bloc Menu Modifiers ===1 doc ================= # =================================================== m=0 - for mod in MODRVK1: + for mod in MODRVK1: if DEBUG: print mod.type if mod.type in POSSMOD: BMOD[0].append([Draw.Create(0),mod.type, @@ -183,7 +183,7 @@ def deform2rvk(): retval = Blender.Draw.PupBlock("MESH 2 RVK", block) # =================================================== # === unset Modifiers ============================= - # =================================================== + # =================================================== for B in BMOD[0][1:]: if DEBUG: print B[2] MODRVK1[B[2]][Modifier.Settings.RENDER]=0 @@ -193,12 +193,12 @@ def deform2rvk(): # =================================================== # === update Modifiers ============================= # =================================================== - RVK1.makeDisplayList() + #RVK1.makeDisplayList() # ======================================================= # === get deformed mesh ================================ # ======================================================= RVK1NAME=Object.GetSelected()[0].getName() - meshrvk1=NMesh.GetRawFromObject(RVK1NAME) + meshrvk1=NMesh.GetRawFromObject(RVK1NAME) if DEBUG: print len(meshrvk1.verts) # ======================================================= # === get normal mesh for vertex group ================= @@ -209,18 +209,18 @@ def deform2rvk(): # ======================================================= DATA2=RVK2.getData() if DEBUG: print len(meshrvk1.verts) - if DEBUG: print len(DATA2.verts) + if DEBUG: print len(DATA2.verts) # ======================================================== # ===== is there the same number of vertices ============= # ======================================================== - if len(meshrvk1.verts)==len(DATA2.verts): - name = "Do you want to replace or add vertex groups ? %t| YES %x1| NO ? %x2 " + if len(meshrvk1.verts)==len(DATA2.verts): + name = "Do you want to replace or add vertex groups ? %t| YES %x1| NO ? %x2 " result = Draw.PupMenu(name) - if result==1: + if result==1: # ===================================================== # ===== Do we save vertex groups ? =================== # ===================================================== - GROUPNAME2=DATA2.getVertGroupNames() + GROUPNAME2=DATA2.getVertGroupNames() if len(GROUPNAME2)!=0: for GROUP2 in GROUPNAME2: DATA2.removeVertGroup(GROUP2) @@ -233,11 +233,11 @@ def deform2rvk(): # ===== now copy the vertices coords ===================== # ======================================================== for v in meshrvk1.verts: - i= meshrvk1.verts.index(v) + i= meshrvk1.verts.index(v) v1=DATA2.verts[i] for n in [0,1,2]: v1.co[n]=v.co[n] - DATA2.update() + DATA2.update() DATA2.insertKey(FRAME,'relative') DATA2.update() RVK2.makeDisplayList() @@ -251,22 +251,22 @@ def deform2rvk(): if not B[1]: MODRVK1[B[2]][Modifier.Settings.RENDER]|=B[-2] else: - name = "Meshes Objects must the same number of vertices %t| Ok. %x1" + name = "Meshes Objects must the same number of vertices %t| Ok. %x1" result = Draw.PupMenu(name) return else: - name = "Second Object must have at least a shape key %t| Ok. %x1" + name = "Second Object must have at least a shape key %t| Ok. %x1" result = Draw.PupMenu(name) return - else: - name = "Object must be Meshes %t| Ok. %x1" + else: + name = "Object must be Meshes %t| Ok. %x1" result = Draw.PupMenu(name) - return + return else : - name = "At least 2 Meshes as to be selected %t| Ok. %x1" + name = "At least 2 Meshes as to be selected %t| Ok. %x1" result = Draw.PupMenu(name) return - Blender.Redraw() + Blender.Redraw() EDITMODE=Blender.Window.EditMode() Blender.Window.EditMode(0) deform2rvk() diff --git a/release/scripts/save_theme.py b/release/scripts/save_theme.py index 7b21b5c74f7..1d23b12403a 100644 --- a/release/scripts/save_theme.py +++ b/release/scripts/save_theme.py @@ -8,7 +8,7 @@ Tooltip: 'Save current theme as a BPython script' """ __author__ = "Willian P. Germano" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "2.43 2006/12/30" __bpydoc__ = """\ @@ -73,7 +73,11 @@ theme = Theme.Get()[0] # get current theme # default filename: theme's name + '_theme.py' in user's scripts dir: default_fname = Blender.Get("scriptsdir") -default_fname = Blender.sys.join(default_fname, theme.name + '_theme.py') +if (default_fname): + default_fname = Blender.sys.join(default_fname, theme.name + '_theme.py') +else: + default_fname = theme.name + '_theme.py' + default_fname = default_fname.replace(' ','_') def write_theme(filename): diff --git a/release/scripts/scripttemplate_camer_object.py b/release/scripts/scripttemplate_camer_object.py new file mode 100644 index 00000000000..cacc35ed1a5 --- /dev/null +++ b/release/scripts/scripttemplate_camer_object.py @@ -0,0 +1,104 @@ +#!BPY +""" +Name: 'Camera/Object Example' +Blender: 245 +Group: 'ScriptTemplate' +Tooltip: 'Script template for setting the camera direction' +""" + +from Blender import Window +import bpy + +script_data = \ +'''#!BPY +""" +Name: 'My Camera script' +Blender: 245 +Group: 'Object' +Tooltip: 'Rotate the camera to center on the active object' +""" + +import Blender +from Blender import Window, Scene, Draw, Mathutils + +# Rotate the camera in such a way that it centers on the currently active object +def RotCamToOb(cam, ob): + + # Get the camera matrix + camMat = cam.getMatrix('worldspace'); + + # Get the location of the camera and object and make sure they're vectors + camLoc = Mathutils.Vector(cam.loc) + obLoc = Mathutils.Vector(ob.loc) + + # Get the vector (direction) from the camera to the object + newVec = obLoc - camLoc + + # Make a quaternion that points the camera along the vector + newQuat = newVec.toTrackQuat('-z', 'y') + + # Convert the new quaternion to a rotation matrix (and resize it to 4x4 so it matches the other matrices) + rotMat = newQuat.toMatrix().resize4x4() + + # Make a matrix with only the current location of the camera + transMat = Mathutils.TranslationMatrix(camMat.translationPart()); + + # Multiply the rotation and translation matrixes to make 1 matrix with all data + newMat = rotMat * transMat + + # Now we make this matrix the camera matrix and voila done! + cam.setMatrix(newMat) + +#Make sure blender and the objects are in the right state and start doing stuff +def SceneCheck(): + + # Show a neat waitcursor whilst the script runs + Window.WaitCursor(1) + + # If we are in edit mode, go out of edit mode and store the status in a var + emode = int(Window.EditMode()) + if emode: Window.EditMode(0) + + # Get the scene, the camera and the currently active object + scn = Scene.GetCurrent() + cam = scn.getCurrentCamera() + ob = scn.getActiveObject() + + # Lets do some checks to make sure we have everything + # And if we don't then call a return which stops the entire script + if not cam: + Draw.PupMenu('Error, no active camera, aborting.') + return + + if not ob: + Draw.PupMenu('Error, no active object, aborting.') + return + + if cam == ob: + Draw.PupMenu('Error, select an object other than the camera, aborting.') + return + + # Start the main function of the script if we didn't encounter any errors + RotCamToOb(cam, ob) + + # Update the scene + scn.update() + + # Redraw the 3d view so we can instantly see what was changed + Window.Redraw(Window.Types.VIEW3D) + + # If we were in edit mode when the script started, go back into edit mode + if emode: Window.EditMode(1) + + # Remove the waitcursor + Window.WaitCursor(0) + +# Start the script +SceneCheck() + +''' + +new_text = bpy.data.texts.new('camobject_template.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_gamelogic.py b/release/scripts/scripttemplate_gamelogic.py new file mode 100644 index 00000000000..7184d7e424f --- /dev/null +++ b/release/scripts/scripttemplate_gamelogic.py @@ -0,0 +1,94 @@ +#!BPY +""" +Name: 'GameLogic Example' +Blender: 245 +Group: 'ScriptTemplate' +Tooltip: 'Script template with examples of how to use game logic' +""" + +from Blender import Window +import bpy + +script_data = \ +''' +# GameLogic has been added to the global namespace no need to import + +# for keyboard event comparison +# import GameKeys + +# support for Vector(), Matrix() types and advanced functions like AngleBetweenVecs(v1,v2) and RotationMatrix(...) +# import Mathutils + +# for functions like getWindowWidth(), getWindowHeight() +# import Rasterizer + +def main(): + cont = GameLogic.getCurrentController() + + # The KX_GameObject that owns this controller. + own = cont.getOwner() + + # for scripts that deal with spacial logic + own_pos = own.getPosition() + + + # Some example functions, remove to write your own script. + # check for a positive sensor, will run on any object without errors. + print 'Logic info for KX_GameObject', own.getName() + input = False + + for sens in cont.getSensors(): + # The sensor can be on another object, we may want to use it + own_sens = sens.getOwner() + print ' sensor:', sens.getName(), + if sens.isPositive(): + print '(true)' + input = True + else: + print '(false)' + + for actu in cont.getActuators(): + # The actuator can be on another object, we may want to use it + own_actu = actu.getOwner() + print ' actuator:', sens.getName() + + # This runs the actuator or turns it off + # note that actuators will continue to run unless explicitly turned off. + if input: + GameLogic.addActiveActuator(actu, True) + else: + GameLogic.addActiveActuator(actu, False) + + # Its also good practice to get sensors and actuators by names + # so any changes to their order wont break the script. + + # sens_key = cont.getSensor('key_sensor') + # actu_motion = cont.getActuator('motion') + + + # Loop through all other objects in the scene + sce = GameLogic.getCurrentScene() + print 'Scene Objects:', sce.getName() + for ob in sce.getObjectList(): + print ' ', ob.getName(), ob.getPosition() + + + # Example where collision objects are checked for their properties + # adding to our objects "life" property + """ + actu_collide = cont.getSensor('collision_sens') + for ob in actu_collide.getHitObjectList(): + # Check to see the object has this property + if hasattr(ob, 'life'): + own.life += ob.life + ob.life = 0 + print own.life + """ + +main() +''' + +new_text = bpy.data.texts.new('gamelogic_example.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_gamelogic_basic.py b/release/scripts/scripttemplate_gamelogic_basic.py new file mode 100644 index 00000000000..1584659d317 --- /dev/null +++ b/release/scripts/scripttemplate_gamelogic_basic.py @@ -0,0 +1,33 @@ +#!BPY +""" +Name: 'GameLogic Template' +Blender: 245 +Group: 'ScriptTemplate' +Tooltip: 'Basic template for new game logic scripts' +""" + +from Blender import Window +import bpy + +script_data = \ +''' +def main(): + + cont = GameLogic.getCurrentController() + own = cont.getOwner() + + sens = cont.getSensor('mySensor') + actu = cont.getActuator('myActuator') + + if sens.isPositive(): + GameLogic.addActiveActuator(actu, True) + else: + GameLogic.addActiveActuator(actu, False) + +main() +''' + +new_text = bpy.data.texts.new('gamelogic_simple.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_ipo_gen.py b/release/scripts/scripttemplate_ipo_gen.py new file mode 100644 index 00000000000..a333b4f20bf --- /dev/null +++ b/release/scripts/scripttemplate_ipo_gen.py @@ -0,0 +1,92 @@ +#!BPY +""" +Name: 'IPO Example' +Blender: 245 +Group: 'ScriptTemplate' +Tooltip: 'Script template for setting the IPO' +""" + +from Blender import Window +import bpy + +script_data = \ +'''#!BPY +""" +Name: 'My Ipo Script' +Blender: 245 +Group: 'Animation' +Tooltip: 'Put some useful info here' +""" + +# Add a licence here if you wish to re-distribute, we recommend the GPL + +from Blender import Ipo, Mathutils, Window +import bpy, BPyMessages + +def makeRandomIpo(object, firstFrame, numberOfFrames, frameStep): + # Create an new Ipo Curve of name myIpo and type Object + myIpo = bpy.data.ipos.new('myIpo', 'Object') + + # Create LocX, LocY, and LocZ Ipo curves in our new Curve Object + # and store them so we can access them later + myIpo_x = myIpo.addCurve('LocX') + myIpo_y = myIpo.addCurve('LocY') + myIpo_z = myIpo.addCurve('LocZ') + + # What value we want to scale our random value by + ipoScale = 4 + + # This Calculates the End Frame for use in an xrange() expression + endFrame = firstFrame + (numberOfFrames * frameStep) + frameStep + + for frame in xrange(firstFrame, endFrame, frameStep): + + # Use the Mathutils Rand() function to get random numbers + ipoValue_x = Mathutils.Rand(-1, 1) * ipoScale + ipoValue_y = Mathutils.Rand(-1, 1) * ipoScale + ipoValue_z = Mathutils.Rand(-1, 1) * ipoScale + + # Append to the Ipo curve at location frame, with the value ipoValue_x + # Note that we should pass the append function a tuple or a BezTriple + myIpo_x.append((frame, ipoValue_x)) + + # Similar to above + myIpo_y.append((frame, ipoValue_y)) + myIpo_z.append((frame, ipoValue_z)) + + # Link our new Ipo Curve to the passed object + object.setIpo(myIpo) + print object + + +def main(): + + # Get the active scene, since there can be multiple ones + sce = bpy.data.scenes.active + + # Get the active object + object = sce.objects.active + + # If there is no active object, pop up an error message + if not object: + BPyMessages.Error_NoActive() + + Window.WaitCursor(1) + + # Call our makeRandomIpo function + # Pass it our object, Tell it to keys from the start frame until the end frame, at a step of 10 frames + # between them + + makeRandomIpo(object, sce.render.sFrame, sce.render.eFrame, 10) + + Window.WaitCursor(0) + +if __name__ == '__main__': + main() + +''' + +new_text = bpy.data.texts.new('ipo_template.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_metaball_create.py b/release/scripts/scripttemplate_metaball_create.py new file mode 100644 index 00000000000..28db9de3af6 --- /dev/null +++ b/release/scripts/scripttemplate_metaball_create.py @@ -0,0 +1,76 @@ +#!BPY +""" +Name: 'Metaball Generation' +Blender: 245 +Group: 'ScriptTemplate' +Tooltip: 'Script template to make metaballs from a mesh' +""" + +from Blender import Window +import bpy + +script_data = \ +'''#!BPY +""" +Name: 'My Metaball Script' +Blender: 245 +Group: 'Misc' +Tooltip: 'Put some useful info here' +""" + +# Add a license here if you wish to re-disribute, we recommend the GPL + +from Blender import Metaball, Mesh, Window +import bpy + +def makeMetaSculpture(sce): + #Create a base mesh for our sculpture to use + monkey = Mesh.Primitives.Monkey() + + #Create a new meta datablock to use and give it a name + metaObj = Metaball.New() + metaObj.name = "MetaSuzanne" + + #Increase the resolution so it looks better + metaObj.wiresize = 0.2 + metaObj.rendersize = 0.1 + + #The radius for our new meta objects to take + metaRadius = 2.0 + + for f in monkey.faces: + + #Create a new metaball as part of the Meta Object Data + newBall = metaObj.elements.add() + + #Make the new ball have the same coordinates as a vertex on our Mesh + newBall.co = f.cent + + #Assign the same radius to all balls + newBall.radius = f.area * metaRadius + + #Create the new object and put our meta data there + sce.objects.new(metaObj, "MetaSuzanne") + + +def main(): + scene = bpy.data.scenes.active #Get the active scene + + Window.WaitCursor(1) + + #Call the sculpture making function + makeMetaSculpture(scene) + + Window.WaitCursor(0) + + #Redraw the Screen When Finished + Window.RedrawAll(1) + +if __name__ == '__main__': + main() +''' + +new_text = bpy.data.texts.new('metaball_template.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_object_edit.py b/release/scripts/scripttemplate_object_edit.py index 4f8e0bccfa2..3ba20f20dd1 100644 --- a/release/scripts/scripttemplate_object_edit.py +++ b/release/scripts/scripttemplate_object_edit.py @@ -13,7 +13,7 @@ script_data = \ '''#!BPY """ Name: 'My Object Script' -Blender: 244 +Blender: 245 Group: 'Object' Tooltip: 'Put some useful info here' """ @@ -78,4 +78,4 @@ if __name__ == '__main__': new_text = bpy.data.texts.new('object_template.py') new_text.write(script_data) bpy.data.texts.active = new_text -Window.RedrawAll()
\ No newline at end of file +Window.RedrawAll() diff --git a/release/scripts/scripttemplate_pyconstraint.py b/release/scripts/scripttemplate_pyconstraint.py index 68aa9194435..0215e47a1bd 100644 --- a/release/scripts/scripttemplate_pyconstraint.py +++ b/release/scripts/scripttemplate_pyconstraint.py @@ -36,13 +36,13 @@ NUM_TARGETS = 1 constraint instance's idproperties ''' def doConstraint(obmatrix, targetmatrices, idprop): - # Separate out the tranformation components for easy access. + # Separate out the transformation components for easy access. obloc = obmatrix.translationPart() # Translation obrot = obmatrix.toEuler() # Rotation obsca = obmatrix.scalePart() # Scale - # Define user-settable parameters.\ - # Must also be defined in getSettings(). + # Define user-settable parameters + # Must also be defined in getSettings(). if not idprop.has_key('user_toggle'): idprop['user_toggle'] = 1 if not idprop.has_key('user_slider'): idprop['user_slider'] = 1.0 @@ -51,7 +51,7 @@ def doConstraint(obmatrix, targetmatrices, idprop): # Convert back into a matrix for loc, scale, rotation, - mtxloc = Mathutils.TranslationMatrix( obloc ) + mtxloc = Mathutils.TranslationMatrix(obloc) mtxrot = obrot.toMatrix().resize4x4() mtxsca = Mathutils.Matrix([obsca[0],0,0,0], [0,obsca[1],0,0], [0,0,obsca[2],0], [0,0,0,1]) diff --git a/release/scripts/scripttemplate_text_plugin.py b/release/scripts/scripttemplate_text_plugin.py new file mode 100644 index 00000000000..4ae562736d3 --- /dev/null +++ b/release/scripts/scripttemplate_text_plugin.py @@ -0,0 +1,69 @@ +#!BPY +""" +Name: 'Text Plugin' +Blender: 246 +Group: 'ScriptTemplate' +Tooltip: 'Add a new text for writing a text plugin' +""" + +from Blender import Window +import bpy + +script_data = \ +'''#!BPY +""" +Name: 'My Plugin Script' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Ctrl+Alt+U' +Tooltip: 'Put some useful info here' +""" + +# Add a licence here if you wish to re-distribute, we recommend the GPL + +from Blender import Window, sys +import BPyTextPlugin, bpy + +def my_script_util(txt): + # This function prints out statistical information about a script + + desc = BPyTextPlugin.get_cached_descriptor(txt) + print '---------------------------------------' + print 'Script Name:', desc.name + print 'Classes:', len(desc.classes) + print ' ', desc.classes.keys() + print 'Functions:', len(desc.defs) + print ' ', desc.defs.keys() + print 'Variables:', len(desc.vars) + print ' ', desc.vars.keys() + +def main(): + + # Gets the active text object, there can be many in one blend file. + txt = bpy.data.texts.active + + # Silently return if the script has been run with no active text + if not txt: + return + + # Text plug-ins should run quickly so we time it here + Window.WaitCursor(1) + t = sys.time() + + # Run our utility function + my_script_util(txt) + + # Timing the script is a good way to be aware on any speed hits when scripting + print 'Plugin script finished in %.2f seconds' % (sys.time()-t) + Window.WaitCursor(0) + + +# This lets you import the script without running it +if __name__ == '__main__': + main() +''' + +new_text = bpy.data.texts.new('textplugin_template.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() diff --git a/release/scripts/slp_import.py b/release/scripts/slp_import.py index 95f6900cf10..30387ad7440 100644 --- a/release/scripts/slp_import.py +++ b/release/scripts/slp_import.py @@ -8,7 +8,7 @@ Tooltip: 'Import Pro Engineer (.slp) File Format' """ __author__ = "Anthony D'Agostino (Scorpius)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius") __version__ = "Part of IOSuite 0.5" diff --git a/release/scripts/sysinfo.py b/release/scripts/sysinfo.py index 01cff8ae57f..3a671e7221e 100644 --- a/release/scripts/sysinfo.py +++ b/release/scripts/sysinfo.py @@ -8,7 +8,7 @@ Tooltip: 'Information about your Blender environment, useful to diagnose problem """ __author__ = "Willian P. Germano" -__url__ = ("blender", "elysiun") +__url__ = ("blenderartists.org", "blenderartists.org") __version__ = "1.1" __bpydoc__ = """\ This script creates a text in Blender's Text Editor with information @@ -94,6 +94,8 @@ output = Blender.Text.New(output_filename) output.write(header + "\n\n") +output.write("%s\n\n" % Blender.Get('buildinfo')) + output.write("Platform: %s\n========\n\n" % sys.platform) output.write("Python:\n======\n\n") diff --git a/release/scripts/textplugin_functiondocs.py b/release/scripts/textplugin_functiondocs.py new file mode 100644 index 00000000000..41c8d4842a0 --- /dev/null +++ b/release/scripts/textplugin_functiondocs.py @@ -0,0 +1,64 @@ +#!BPY +""" +Name: 'Function Documentation | Ctrl I' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Ctrl+I' +Tooltip: 'Attempts to display documentation about the function preceding the cursor.' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * +except ImportError: + OK = False +else: + OK = True + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + (line, c) = current_line(txt) + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + # Identify the name under the cursor + llen = len(line) + while c<llen and (line[c].isalnum() or line[c]=='_'): + c += 1 + + targets = get_targets(line, c) + + # If no name under cursor, look backward to see if we're in function parens + if len(targets) == 0 or targets[0] == '': + # Look backwards for first '(' without ')' + b = 0 + found = False + for i in range(c-1, -1, -1): + if line[i] == ')': b += 1 + elif line[i] == '(': + b -= 1 + if b < 0: + found = True + c = i + break + if found: targets = get_targets(line, c) + if len(targets) == 0 or targets[0] == '': + return + + obj = resolve_targets(txt, targets) + if not obj: return + + if isinstance(obj, Definition): # Local definition + txt.showDocs(obj.doc) + elif hasattr(obj, '__doc__') and obj.__doc__: + txt.showDocs(obj.__doc__) + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/textplugin_imports.py b/release/scripts/textplugin_imports.py new file mode 100644 index 00000000000..ec608243c2b --- /dev/null +++ b/release/scripts/textplugin_imports.py @@ -0,0 +1,91 @@ +#!BPY +""" +Name: 'Import Complete|Space' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Space' +Tooltip: 'Lists modules when import or from is typed' +""" + +# Only run if we have the required modules +try: + import bpy, sys + from BPyTextPlugin import * +except ImportError: + OK = False +else: + OK = True + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + line, c = current_line(txt) + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + pos = line.rfind('from ', 0, c) + + # No 'from' found + if pos == -1: + # Check instead for straight 'import xxxx' + pos2 = line.rfind('import ', 0, c) + if pos2 != -1: + pos2 += 7 + for i in range(pos2, c): + if line[i]==',' or (line[i]==' ' and line[i-1]==','): + pos2 = i+1 + elif not line[i].isalnum() and line[i] != '_': + return + items = [(m, 'm') for m in get_modules()] + items.sort(cmp = suggest_cmp) + txt.suggest(items, line[pos2:c].strip()) + return + + # Found 'from xxxxx' before cursor + immediate = True + pos += 5 + for i in range(pos, c): + if not line[i].isalnum() and line[i] != '_' and line[i] != '.': + immediate = False + break + + # Immediate 'from' followed by at most a module name + if immediate: + items = [(m, 'm') for m in get_modules()] + items.sort(cmp = suggest_cmp) + txt.suggest(items, line[pos:c]) + return + + # Found 'from' earlier, suggest import if not already there + pos2 = line.rfind('import ', pos, c) + + # No 'import' found after 'from' so suggest it + if pos2 == -1: + txt.suggest([('import', 'k')], '') + return + + # Immediate 'import' before cursor and after 'from...' + for i in range(pos2+7, c): + if line[i]==',' or (line[i]==' ' and line[i-1]==','): + pass + elif not line[i].isalnum() and line[i] != '_': + return + between = line[pos:pos2-1].strip() + try: + mod = get_module(between) + except ImportError: + return + + items = [('*', 'k')] + for (k,v) in mod.__dict__.items(): + items.append((k, type_char(v))) + items.sort(cmp = suggest_cmp) + txt.suggest(items, '') + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/textplugin_membersuggest.py b/release/scripts/textplugin_membersuggest.py new file mode 100644 index 00000000000..7c0de78b704 --- /dev/null +++ b/release/scripts/textplugin_membersuggest.py @@ -0,0 +1,90 @@ +#!BPY +""" +Name: 'Member Suggest | .' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Period' +Tooltip: 'Lists members of the object preceding the cursor in the current text space' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * +except ImportError: + OK = False +else: + OK = True + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + (line, c) = current_line(txt) + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + targets = get_targets(line, c) + + if targets[0] == '': # Check if we are looking at a constant [] {} '' etc. + i = c - len('.'.join(targets)) - 1 + if i >= 0: + if line[i] == '"' or line[i] == "'": + targets[0] = 'str' + elif line[i] == '}': + targets[0] = 'dict' + elif line[i] == ']': # Could be array elem x[y] or list [y] + i = line.rfind('[', 0, i) - 1 + while i >= 0: + if line[i].isalnum() or line[i] == '_': + break + elif line[i] != ' ' and line[i] != '\t': + i = -1 + break + i -= 1 + if i < 0: + targets[0] = 'list' + + obj = resolve_targets(txt, targets[:-1]) + if not obj: + return + + items = [] + + if isinstance(obj, VarDesc): + obj = obj.type + + if isinstance(obj, Definition): # Locally defined + if hasattr(obj, 'classes'): + items.extend([(s, 'f') for s in obj.classes.keys()]) + if hasattr(obj, 'defs'): + items.extend([(s, 'f') for s in obj.defs.keys()]) + if hasattr(obj, 'vars'): + items.extend([(s, 'v') for s in obj.vars.keys()]) + + else: # Otherwise we have an imported or builtin object + try: + attr = obj.__dict__.keys() + except AttributeError: + attr = dir(obj) + else: + if not attr: attr = dir(obj) + + for k in attr: + try: + v = getattr(obj, k) + except (AttributeError, TypeError): # Some attributes are not readable + pass + else: + items.append((k, type_char(v))) + + if items != []: + items.sort(cmp = suggest_cmp) + txt.suggest(items, targets[-1]) + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/textplugin_outliner.py b/release/scripts/textplugin_outliner.py new file mode 100644 index 00000000000..3879a2819a5 --- /dev/null +++ b/release/scripts/textplugin_outliner.py @@ -0,0 +1,142 @@ +#!BPY +""" +Name: 'Code Outline | Ctrl T' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Ctrl+T' +Tooltip: 'Provides a menu for jumping to class and functions definitions.' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * + from Blender import Draw +except ImportError: + OK = False +else: + OK = True + +def make_menu(items, eventoffs): + n = len(items) + if n < 20: + return [(items[i], i+1+eventoffs) for i in range(len(items))] + + letters = [] + check = 'abcdefghijklmnopqrstuvwxyz_' # Names cannot start 0-9 + for c in check: + for item in items: + if item[0].lower() == c: + letters.append(c) + break + + entries = {} + i = 0 + for item in items: + i += 1 + c = item[0].lower() + entries.setdefault(c, []).append((item, i+eventoffs)) + + subs = [] + for c in letters: + subs.append((c, entries[c])) + + return subs + +def find_word(txt, word): + i = 0 + txt.reset() + while True: + try: + line = txt.readline() + except StopIteration: + break + c = line.find(word) + if c != -1: + txt.setCursorPos(i, c) + break + i += 1 + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + # Identify word under cursor + if get_context(txt) == CTX_NORMAL: + line, c = current_line(txt) + start = c-1 + end = c + while start >= 0: + if not line[start].lower() in 'abcdefghijklmnopqrstuvwxyz0123456789_': + break + start -= 1 + while end < len(line): + if not line[end].lower() in 'abcdefghijklmnopqrstuvwxyz0123456789_': + break + end += 1 + word = line[start+1:end] + if word in KEYWORDS: + word = None + else: + word = None + + script = get_cached_descriptor(txt) + items = [] + desc = None + + tmp = script.classes.keys() + tmp.sort(cmp = suggest_cmp) + class_menu = make_menu(tmp, len(items)) + class_menu_length = len(tmp) + items.extend(tmp) + + tmp = script.defs.keys() + tmp.sort(cmp = suggest_cmp) + defs_menu = make_menu(tmp, len(items)) + defs_menu_length = len(tmp) + items.extend(tmp) + + tmp = script.vars.keys() + tmp.sort(cmp = suggest_cmp) + vars_menu = make_menu(tmp, len(items)) + vars_menu_length = len(tmp) + items.extend(tmp) + + menu = [('Script %t', 0), + ('Classes', class_menu), + ('Functions', defs_menu), + ('Variables', vars_menu)] + if word: + menu.extend([None, ('Locate', [(word, -10)])]) + + i = Draw.PupTreeMenu(menu) + if i == -1: + return + + # Chosen to search for word under cursor + if i == -10: + if script.classes.has_key(word): + desc = script.classes[word] + elif script.defs.has_key(word): + desc = script.defs[word] + elif script.vars.has_key(word): + desc = script.vars[word] + else: + find_word(txt, word) + return + else: + i -= 1 + if i < class_menu_length: + desc = script.classes[items[i]] + elif i < class_menu_length + defs_menu_length: + desc = script.defs[items[i]] + elif i < class_menu_length + defs_menu_length + vars_menu_length: + desc = script.vars[items[i]] + + if desc: + txt.setCursorPos(desc.lineno-1, 0) + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/textplugin_suggest.py b/release/scripts/textplugin_suggest.py new file mode 100644 index 00000000000..d8122212d3b --- /dev/null +++ b/release/scripts/textplugin_suggest.py @@ -0,0 +1,94 @@ +#!BPY +""" +Name: 'Suggest All | Ctrl Space' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Ctrl+Space' +Tooltip: 'Performs suggestions based on the context of the cursor' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * +except ImportError: + OK = False +else: + OK = True + +def check_membersuggest(line, c): + pos = line.rfind('.', 0, c) + if pos == -1: + return False + for s in line[pos+1:c]: + if not s.isalnum() and s != '_': + return False + return True + +def check_imports(line, c): + pos = line.rfind('import ', 0, c) + if pos > -1: + for s in line[pos+7:c]: + if not s.isalnum() and s != '_': + return False + return True + pos = line.rfind('from ', 0, c) + if pos > -1: + for s in line[pos+5:c]: + if not s.isalnum() and s != '_': + return False + return True + return False + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + line, c = current_line(txt) + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + # Check the character preceding the cursor and execute the corresponding script + + if check_membersuggest(line, c): + import textplugin_membersuggest + textplugin_membersuggest.main() + return + + elif check_imports(line, c): + import textplugin_imports + textplugin_imports.main() + return + + # Otherwise we suggest globals, keywords, etc. + list = [] + targets = get_targets(line, c) + desc = get_cached_descriptor(txt) + + for k in KEYWORDS: + list.append((k, 'k')) + + for k, v in get_builtins().items(): + list.append((k, type_char(v))) + + for k, v in desc.imports.items(): + list.append((k, type_char(v))) + + for k, v in desc.classes.items(): + list.append((k, 'f')) + + for k, v in desc.defs.items(): + list.append((k, 'f')) + + for k, v in desc.vars.items(): + list.append((k, 'v')) + + list.sort(cmp = suggest_cmp) + txt.suggest(list, targets[-1]) + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/textplugin_templates.py b/release/scripts/textplugin_templates.py new file mode 100644 index 00000000000..8f949563ac0 --- /dev/null +++ b/release/scripts/textplugin_templates.py @@ -0,0 +1,123 @@ +#!BPY +""" +Name: 'Template Completion | Tab' +Blender: 246 +Group: 'TextPlugin' +Shortcut: 'Tab' +Tooltip: 'Completes templates based on the text preceding the cursor' +""" + +# Only run if we have the required modules +try: + import bpy + from BPyTextPlugin import * + from Blender import Text +except ImportError: + OK = False +else: + OK = True + +templates = { + 'ie': + 'if ${1:cond}:\n' + '\t${2}\n' + 'else:\n' + '\t${3}\n', + 'iei': + 'if ${1:cond}:\n' + '\t${2}\n' + 'elif:\n' + '\t${3}\n' + 'else:\n' + '\t${4}\n', + 'def': + 'def ${1:name}(${2:params}):\n' + '\t"""(${2}) - ${3:comment}"""\n' + '\t${4}', + 'cls': + 'class ${1:name}(${2:parent}):\n' + '\t"""${3:docs}"""\n' + '\t\n' + '\tdef __init__(self, ${4:params}):\n' + '\t\t"""Creates a new ${1}"""\n' + '\t\t${5}', + 'class': + 'class ${1:name}(${2:parent}):\n' + '\t"""${3:docs}"""\n' + '\t\n' + '\tdef __init__(self, ${4:params}):\n' + '\t\t"""Creates a new ${1}"""\n' + '\t\t${5}' +} + +def main(): + txt = bpy.data.texts.active + if not txt: + return + + row, c = txt.getCursorPos() + line = txt.asLines(row, row+1)[0] + indent=0 + while indent<c and (line[indent]==' ' or line[indent]=='\t'): + indent += 1 + + # Check we are in a normal context + if get_context(txt) != CTX_NORMAL: + return + + targets = get_targets(line, c-1); + if len(targets) != 1: return + + color = (0, 192, 32) + + for trigger, template in templates.items(): + if trigger != targets[0]: continue + inserts = {} + txt.delete(-len(trigger)-1) + y, x = txt.getCursorPos() + first = None + + # Insert template text and parse for insertion points + count = len(template); i = 0 + while i < count: + if i<count-1 and template[i]=='$' and template[i+1]=='{': + i += 2 + e = template.find('}', i) + item = template[i:e].split(':') + if len(item)<2: item.append('') + if not inserts.has_key(item[0]): + inserts[item[0]] = (item[1], [(x, y)]) + else: + inserts[item[0]][1].append((x, y)) + item[1] = inserts[item[0]][0] + if not first: first = (item[1], x, y) + txt.insert(item[1]) + x += len(item[1]) + i = e + else: + txt.insert(template[i]) + if template[i] == '\n': + txt.insert(line[:indent]) + y += 1 + x = indent + else: + x += 1 + i += 1 + + # Insert markers at insertion points + for id, (text, points) in inserts.items(): + for x, y in points: + txt.setCursorPos(y, x) + txt.setSelectPos(y, x+len(text)) + txt.markSelection((hash(text)+int(id)) & 0xFFFF, color, + Text.TMARK_TEMP | Text.TMARK_EDITALL) + if first: + text, x, y = first + txt.setCursorPos(y, x) + txt.setSelectPos(y, x+len(text)) + break + + +# Check we are running as a script and not imported as a module +if __name__ == "__main__" and OK: + main() diff --git a/release/scripts/unweld.py b/release/scripts/unweld.py index 34877837bb7..3385e66e2d8 100644 --- a/release/scripts/unweld.py +++ b/release/scripts/unweld.py @@ -7,7 +7,7 @@ Tip: 'Unweld all faces from a (or several) selected and common vertex. Made vert """ __author__ = "Jean-Michel Soler (jms)" -__url__ = ("blender", "elysiun", +__url__ = ("blender", "blenderartists.org", "Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_faces2vertex.htm#exemple", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") __version__ = "0.4.6 " diff --git a/release/scripts/uv_from_adjacent.py b/release/scripts/uv_from_adjacent.py deleted file mode 100644 index dfdad3118d9..00000000000 --- a/release/scripts/uv_from_adjacent.py +++ /dev/null @@ -1,129 +0,0 @@ -#!BPY -""" -Name: 'UVs from unselected adjacent' -Blender: 242 -Group: 'UVCalculation' -Tooltip: 'Assign UVs to selected faces from surrounding unselected faces.' -""" -__author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") -__version__ = "1.0 2006/02/07" - -__bpydoc__ = """\ -This script sets the UV mapping and image of selected faces from adjacent unselected faces. - -Use this script in face select mode for texturing between textured faces. -""" - -# ***** 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 - -def mostUsedImage(imageList): # Returns the image most used in the list. - if not imageList: - return None - elif len(imageList) < 3: - return imageList[0] - - # 3+ Images, Get the most used image for surrounding faces. - imageCount = {} - for image in imageList: - if image: - image_key= image.name - else: - image_key = None - - try: - imageCount[image_key]['imageCount'] +=1 # an extra user of this image - except: - imageCount[image_key] = {'imageCount':1, 'blenderImage':image} # start with 1 user. - - # Now a list of tuples, (imageName, {imageCount, image}) - imageCount = imageCount.items() - - try: imageCount.sort(key=lambda a: a[1]) - except: imageCount.sort(lambda a,b: cmp(a[1], b[1])) - - - return imageCount[-1][1]['blenderImage'] - - -def main(): - sce = bpy.data.scenes.active - ob = sce.objects.active - - if ob == None or ob.type != 'Mesh': - Draw.PupMenu('ERROR: No mesh object in face select mode.') - return - me = ob.getData(mesh=1) - - if not me.faceUV: - Draw.PupMenu('ERROR: No mesh object in face select mode.') - return - - selfaces = [f for f in me.faces if f.sel] - unselfaces = [f for f in me.faces if not f.sel] - - - # Gather per Vert UV and Image, store in vertUvAverage - vertUvAverage = [[[],[]] for i in xrange(len(me.verts))] - - for f in unselfaces: # Unselected faces only. - fuv = f.uv - for i,v in enumerate(f): - vertUvAverage[v.index][0].append(fuv[i]) - vertUvAverage[v.index][1].append(f.image) - - # Average per vectex UV coords - for vertUvData in vertUvAverage: - uvList = vertUvData[0] - if uvList: - # Convert from a list of vectors into 1 vector. - vertUvData[0] = reduce(lambda a,b: a+b, uvList, Mathutils.Vector(0,0)) * (1.0/len(uvList)) - else: - vertUvData[0] = None - - # Assign to selected faces - TEX_FLAG = Mesh.FaceModes['TEX'] - for f in selfaces: - uvlist = [] - imageList = [] - for i,v in enumerate(f): - uv, vImages = vertUvAverage[v.index] - uvlist.append( uv ) - imageList.extend(vImages) - - if None not in uvlist: - # all the faces images used by this faces vert. some faces will be added twice but thats ok. - # Get the most used image and assign to the face. - image = mostUsedImage(imageList) - f.uv = uvlist - - if image: - f.image = image - f.mode |= TEX_FLAG - Window.RedrawAll() - -if __name__ == '__main__': - main()
\ No newline at end of file diff --git a/release/scripts/uv_seams_from_islands.py b/release/scripts/uv_seams_from_islands.py index 241f38fc4aa..7f156efde7d 100644 --- a/release/scripts/uv_seams_from_islands.py +++ b/release/scripts/uv_seams_from_islands.py @@ -1,12 +1,31 @@ #!BPY """ Name: 'Seams from Islands' -Blender: 243 +Blender: 246 Group: 'UV' Tooltip: 'Add seams onto the mesh at the bounds of UV islands' """ -# Add a licence here if you wish to re-distribute, we recommend the GPL +# ***** 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 Scene, Mesh, Window, sys import BPyMessages @@ -37,8 +56,11 @@ def seams_from_islands(me): # add seams SEAM = Mesh.EdgeFlags.SEAM for ed in me.edges: - if len(set(edge_uvs[ed.key])) > 1: - ed.flag |= SEAM + try: # the edge might not be in a face + if len(set(edge_uvs[ed.key])) > 1: + ed.flag |= SEAM + except: + pass def main(): diff --git a/release/scripts/uvcalc_follow_active_coords.py b/release/scripts/uvcalc_follow_active_coords.py index 2a79d0d05df..79a445329cc 100644 --- a/release/scripts/uvcalc_follow_active_coords.py +++ b/release/scripts/uvcalc_follow_active_coords.py @@ -6,7 +6,7 @@ Group: 'UVCalculation' Tooltip: 'Follow from active quads.' """ __author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.0 2006/02/07" __bpydoc__ = """\ diff --git a/release/scripts/uvcalc_lightmap.py b/release/scripts/uvcalc_lightmap.py index af9acb09e17..1433ccbd13a 100644 --- a/release/scripts/uvcalc_lightmap.py +++ b/release/scripts/uvcalc_lightmap.py @@ -5,8 +5,8 @@ Blender: 242 Group: 'UVCalculation' Tooltip: 'Give each face non overlapping space on a texture.' """ -__author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ("blender", "blenderartists.org") __version__ = "1.0 2006/02/07" __bpydoc__ = """\ @@ -41,6 +41,18 @@ import BPyMesh from math import sqrt +def AngleBetweenVecs(a1,a2): + try: + return Mathutils.AngleBetweenVecs(a1,a2) + except: + return 180.0 + +# python 2.3 has no reversed() iterator. this will only work on lists and tuples +try: + reversed +except: + def reversed(l): return l[::-1] + class prettyface(object): __slots__ = 'uv', 'width', 'height', 'children', 'xoff', 'yoff', 'has_parent', 'rot' def __init__(self, data): @@ -148,9 +160,9 @@ class prettyface(object): if len(uv) == 2: # match the order of angle sizes of the 3d verts with the UV angles and rotate. def get_tri_angles(v1,v2,v3): - a1= Mathutils.AngleBetweenVecs(v2-v1,v3-v1) - a2= Mathutils.AngleBetweenVecs(v1-v2,v3-v2) - a3 = 180 - (a1+a2) #a3= Mathutils.AngleBetweenVecs(v2-v3,v1-v3) + a1= AngleBetweenVecs(v2-v1,v3-v1) + a2= AngleBetweenVecs(v1-v2,v3-v2) + a3 = 180 - (a1+a2) #a3= AngleBetweenVecs(v2-v3,v1-v3) return [(a1,0),(a2,1),(a3,2)] @@ -237,8 +249,17 @@ PREF_MARGIN_DIV= 512): face_groups.append(faces) if PREF_NEW_UVLAYER: - me.addUVLayer('lightmap') - me.activeUVLayer = 'lightmap' + uvname_org = uvname = 'lightmap' + uvnames = me.getUVLayerNames() + i = 1 + while uvname in uvnames: + uvname = '%s.%03d' % (uvname_org, i) + i+=1 + + me.addUVLayer(uvname) + me.activeUVLayer = uvname + + del uvnames, uvname_org, uvname for face_sel in face_groups: print "\nStarting unwrap" @@ -328,6 +349,9 @@ PREF_MARGIN_DIV= 512): if curr_len/4 < side_len/PREF_MARGIN_DIV: break + if not lengths: + lengths.append(curr_len) + # convert into ints lengths_to_ints = {} @@ -399,11 +423,14 @@ PREF_MARGIN_DIV= 512): # ...limiting this is needed or you end up with bug unused texture spaces # ...however if its too high, boxpacking is way too slow for high poly meshes. float_to_int_factor = lengths_to_ints[0][0] - max_int_dimension = int(((side_len / float_to_int_factor)) / PREF_BOX_DIV) - + if float_to_int_factor > 0: + max_int_dimension = int(((side_len / float_to_int_factor)) / PREF_BOX_DIV) + ok = True + else: + max_int_dimension = 0.0 # wont be used + ok = False # RECURSIVE prettyface grouping - ok = True while ok: ok = False @@ -430,7 +457,10 @@ PREF_MARGIN_DIV= 512): # Even boxes in groups of 4 for d, boxes in even_dict.items(): if d < max_int_dimension: - boxes.sort(key = lambda a: len(a.children)) + # py 2.3 compat + try: boxes.sort(key = lambda a: len(a.children)) + except: boxes.sort(lambda a, b: cmp(len(a.children), len(b.children))) + while len(boxes) >= 4: # print "bar", len(boxes) ok = True @@ -517,7 +547,7 @@ def main(): if not Draw.PupBlock('Lightmap Pack', [\ 'Context...', - ('Active Object', PREF_ACT_ONLY, 'If disabled, use all objects for packing the lightmap.'),\ + ('Active Object', PREF_ACT_ONLY, 'If disabled, include other selected objects for packing the lightmap.'),\ ('Selected Faces', PREF_SEL_ONLY, 'Use only selected faces from all selected meshes.'),\ 'Image & UVs...', ('Share Tex Space', PREF_PACK_IN_ONE, 'Objects Share texture space, map all objects into 1 uvmap'),\ @@ -538,7 +568,7 @@ def main(): return meshes = [ ob.getData(mesh=1) ] else: - meshes = dict([ (me.name, me) for ob in scn.objects.context for me in (ob.getData(mesh=1),) if not me.lib]) + meshes = dict([ (me.name, me) for ob in scn.objects.context if ob.type == 'Mesh' for me in (ob.getData(mesh=1),) if not me.lib if len(me.faces)]) meshes = meshes.values() if not meshes: Draw.PupMenu('Error%t|No mesh objects selected.') diff --git a/release/scripts/uvcalc_quad_clickproj.py b/release/scripts/uvcalc_quad_clickproj.py index 791fd661cc9..0bba747e010 100644 --- a/release/scripts/uvcalc_quad_clickproj.py +++ b/release/scripts/uvcalc_quad_clickproj.py @@ -2,13 +2,13 @@ """ Registration info for Blender menus: <- these words are ignored Name: 'Click project from face' -Blender: 242 +Blender: 245 Group: 'UVCalculation' Tooltip: '3 Clicks to project uvs onto selected faces.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__=\ ''' diff --git a/release/scripts/uvcalc_smart_project.py b/release/scripts/uvcalc_smart_project.py index 49d52d12d47..d622e1a2af8 100644 --- a/release/scripts/uvcalc_smart_project.py +++ b/release/scripts/uvcalc_smart_project.py @@ -9,7 +9,7 @@ Tooltip: 'UV Unwrap mesh faces for all select mesh objects' __author__ = "Campbell Barton" -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.1 12/18/05" __bpydoc__ = """\ diff --git a/release/scripts/uvcopy.py b/release/scripts/uvcopy.py index 1ac63dd52b5..73206e47109 100644 --- a/release/scripts/uvcopy.py +++ b/release/scripts/uvcopy.py @@ -7,9 +7,7 @@ Tip: 'Copy UV coords from a mesh to another that has same vertex indices' """ __author__ = "Toni Alatalo, Martin Poirier et. al." -__url__ = ("blender", "elysiun", -"Script's homepage, http://www.elysiun.com/forum/viewtopic.php?t=14897", -"Communicate problems and errors, http://www.elysiun.com/forum/viewtopic.php?t=14897") +__url__ = ("blender", "blenderartists.org") __version__ = "0.2 01/2006" __bpydoc__ = """\ diff --git a/release/scripts/vertexpaint_gradient.py b/release/scripts/vertexpaint_gradient.py index d0b7de329df..17eccb4f67f 100644 --- a/release/scripts/vertexpaint_gradient.py +++ b/release/scripts/vertexpaint_gradient.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'VCol Gradient...' -Blender: 241 +Blender: 245 Group: 'VertexPaint' Tooltip: 'Click on the start and end grad points for the mesh for selected faces.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" # ***** BEGIN GPL LICENSE BLOCK ***** diff --git a/release/scripts/vertexpaint_selfshadow_ao.py b/release/scripts/vertexpaint_selfshadow_ao.py index 7a6f4f9176d..95ba7d2fb23 100644 --- a/release/scripts/vertexpaint_selfshadow_ao.py +++ b/release/scripts/vertexpaint_selfshadow_ao.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Self Shadow VCols (AO)...' -Blender: 241 +Blender: 245 Group: 'VertexPaint' Tooltip: 'Generate Fake Ambient Occlusion with vertex colors.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ diff --git a/release/scripts/vrml97_export.py b/release/scripts/vrml97_export.py index 57ffd243bfc..bd1a35f7c3b 100644 --- a/release/scripts/vrml97_export.py +++ b/release/scripts/vrml97_export.py @@ -3,14 +3,11 @@ Name: 'VRML97 (.wrl)...' Blender: 241 Group: 'Export' -Submenu: 'All Objects...' all -Submenu: 'All Objects compressed...' comp -Submenu: 'Selected Objects...' selected Tooltip: 'Export to VRML97 file (.wrl)' """ __author__ = ("Rick Kimball", "Ken Miller", "Steve Matthews", "Bart") -__url__ = ["blender", "elysiun", +__url__ = ["blender", "blenderartists.org", "Author's (Rick) homepage, http://kimballsoftware.com/blender", "Author's (Bart) homepage, http://www.neeneenee.de/vrml"] __email__ = ["Bart, bart:neeneenee*de"] @@ -55,7 +52,7 @@ want to export only selected or all relevant objects. import Blender from Blender import Object, Mesh, Lamp, Draw, BGL, \ - Image, Text, sys, Mathutils + Image, Text, sys, Mathutils, Registry from Blender.Scene import Render import math @@ -70,8 +67,9 @@ worldmat = Blender.Texture.Get() filename = Blender.Get('filename') _safeOverwrite = True extension = '' -ARG='' +# Matrices below are used only when export_rotate_z_to_y.val: +# # Blender is Z up, VRML is Y up, both are right hand coordinate # systems, so to go from Blender coords to VRML coords we rotate # by 90 degrees around the X axis. In matrix notation, we have a @@ -208,7 +206,7 @@ class VRML2Export: if scene != inlines[0]: return else: - for i in range(allinlines): + for i in xrange(allinlines): nameinline=inlines[i].getName() if (nameinline not in self.namesStandard) and (i > 0): self.writeIndented("DEF %s Inline {\n" % \ @@ -221,7 +219,7 @@ class VRML2Export: def writeScript(self): textEditor = Blender.Text.Get() alltext = len(textEditor) - for i in range(alltext): + for i in xrange(alltext): nametext = textEditor[i].getName() nlines = textEditor[i].getNLines() if (self.proto == 1): @@ -229,14 +227,14 @@ class VRML2Export: nametext == "proto.txt") and (nlines != None): nalllines = len(textEditor[i].asLines()) alllines = textEditor[i].asLines() - for j in range(nalllines): + 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 range(nalllines): + for j in xrange(nalllines): self.writeIndented(alllines[j] + "\n") self.writeIndented("\n") @@ -456,6 +454,8 @@ class VRML2Export: if mat: if (mat.mode & Blender.Material.Modes['VCOL_PAINT']): self.vcolors = 1 + else: + self.vcolors = 0 # check if object is wireframe only if ob.drawType == Blender.Object.DrawTypes.WIRE: @@ -556,31 +556,28 @@ class VRML2Export: issmooth = 0 maters = me.materials - nummats = self.getNumMaterials(me) + nummats = len(me.materials) # Vertex and Face colors trump materials and image textures if (self.facecolors or self.vcolors): if nummats > 0: - if maters[0]: - self.writeShape(ob, me, 0, None) - else: - self.writeShape(ob, me, -1, None) + self.writeShape(ob, me, 0, None) else: self.writeShape(ob, me, -1, None) - # Do meshes with materials, possible with image textures + + # Do meshes with materials, possibly with image textures elif nummats > 0: - for matnum in range(len(maters)): - if maters[matnum]: - images = [] - if me.faceUV: - images = self.getImages(me, matnum) - if len(images) > 0: - for image in images: - self.writeShape(ob, me, matnum, image) - else: - self.writeShape(ob, me, matnum, None) + for matnum in xrange(len(maters)): + images = [] + if me.faceUV: + images = self.getImages(me, matnum) + if len(images) > 0: + for image in images: + self.writeShape(ob, me, matnum, image) else: self.writeShape(ob, me, matnum, None) + else: + self.writeShape(ob, me, matnum, None) else: if me.faceUV: images = self.getImages(me, -1) @@ -608,15 +605,6 @@ class VRML2Export: imageNames[imName]=1 return images - def getNumMaterials(self, me): - # Oh silly Blender, why do you sometimes have 'None' as - # a member of the me.materials array? - num = 0 - for mat in me.materials: - if mat: - num = num + 1 - return num - def writeCoordinates(self, me, meshName): coordName = "coord_%s" % (meshName) # look up coord name, use it if available @@ -633,8 +621,9 @@ class VRML2Export: meshVertexList = me.verts for vertex in meshVertexList: - blenvert = Mathutils.Vector(vertex.co) - vrmlvert = M_blen2vrml * blenvert + vrmlvert = blenvert = Mathutils.Vector(vertex.co) + if export_rotate_z_to_y.val: + vrmlvert = M_blen2vrml * vrmlvert self.writeUnindented("%s %s %s\n " % \ (vrmlvert[0], \ vrmlvert[1], \ @@ -643,20 +632,43 @@ class VRML2Export: self.writeIndented("}\n", -1) self.writeIndented("\n") + def testShape(self, ob, me, matnum, image): + if ( (matnum == -1) and (image == None) ): + if ( len(me.faces) > 0 ): + return True + # Check if any faces the material or image + for face in me.faces: + if (matnum == -1): + if (face.image == image): + return True + elif (image == None): + if (face.mat == matnum): + return True + else: + if ((face.image == image) and (face.mat == matnum)): + return True + + return False + def writeShape(self, ob, me, matnum, image): - # Note: at this point it is assumed for matnum!=-1 that the - # material in me.materials[matnum] is not equal to 'None'. - # Such validation should be performed by the function that - # calls this one. + # matnum == -1 means don't check the face.mat + # image == None means don't check face.image + + if ( not self.testShape(ob, me, matnum, image) ): + return False + self.writeIndented("Shape {\n",1) self.writeIndented("appearance Appearance {\n", 1) if (matnum != -1): mater = me.materials[matnum] - self.writeMaterial(mater, self.cleanStr(mater.name,'')) - if (mater.mode & Blender.Material.Modes['TEXFACE']): - if image != None: - self.writeImageTexture(image.name, image.filename) + if (mater): + self.writeMaterial(mater, self.cleanStr(mater.name,'')) + if (mater.mode & Blender.Material.Modes['TEXFACE']): + if image != None: + self.writeImageTexture(image.name, image.filename) + else: + self.writeDefaultMaterial() else: if image != None: self.writeImageTexture(image.name, image.filename) @@ -667,6 +679,8 @@ class VRML2Export: self.writeIndented("}\n", -1) + return True + def writeGeometry(self, ob, me, matnum, image): #-- IndexedFaceSet or IndexedLineSet @@ -722,7 +736,7 @@ class VRML2Export: indexStr = "" if (matnum == -1) or (face.mat == matnum): if (face.image == image): - for i in range(len(face.verts)): + for i in xrange(len(face.verts)): uv = face.uv[i] indexStr += "%s " % (j) coordStr += "%s %s, " % \ @@ -730,8 +744,8 @@ class VRML2Export: round(uv[1], self.tp)) j=j+1 indexStr += "-1" - texIndexList.append(indexStr) - texCoordList.append(coordStr) + texIndexList.append(indexStr) + texCoordList.append(coordStr) self.writeIndented("texCoord TextureCoordinate {\n", 1) self.writeIndented("point [\n", 1) @@ -769,13 +783,13 @@ class VRML2Export: cols = [None] * len(me.verts) for face in me.faces: - for vind in range(len(face.v)): + for vind in xrange(len(face.v)): vertex = face.v[vind] i = vertex.index if cols[i] == None: cols[i] = face.col[vind] - for i in range(len(me.verts)): + for i in xrange(len(me.verts)): aColor = self.rgbToFS(cols[i]) self.writeUnindented("%s\n" % aColor) @@ -783,6 +797,23 @@ class VRML2Export: self.writeIndented("]\n",-1) self.writeIndented("}\n",-1) + def writeDefaultMaterial(self): + matName = "default" + + # look up material name, use it if available + if self.matNames.has_key(matName): + self.writeIndented("material USE MA_%s\n" % matName) + self.matNames[matName]+=1 + return; + + self.matNames[matName]=1 + self.writeIndented("material DEF MA_%s Material {\n" % matName, 1) + self.writeIndented("diffuseColor 0.8 0.8 0.8\n") + self.writeIndented("specularColor 1.0 1.0 1.0\n") + self.writeIndented("shininess 0.5\n") + self.writeIndented("transparency 0.0\n") + self.writeIndented("}\n",-1) + def writeMaterial(self, mat, matName): # look up material name, use it if available if self.matNames.has_key(matName): @@ -1016,7 +1047,10 @@ class VRML2Export: return ob_matrix = Mathutils.Matrix(ob.getMatrix('worldspace')) - matrix = M_blen2vrml * ob_matrix * M_vrml2blen + if export_rotate_z_to_y.val: + matrix = M_blen2vrml * ob_matrix * M_vrml2blen + else: + matrix = ob_matrix e = matrix.rotationPart().toEuler() v = matrix.translationPart() @@ -1089,7 +1123,7 @@ class VRML2Export: self.writeFog() self.proto = 0 allObj = [] - if ARG == 'selected': + if export_selection_only.val: allObj = list(scene.objects.context) else: allObj = list(scene.objects) @@ -1098,7 +1132,7 @@ class VRML2Export: for thisObj in allObj: self.writeObject(thisObj) - if ARG != 'selected': + if not export_selection_only.val: self.writeScript() self.cleanup() @@ -1213,26 +1247,54 @@ def select_file(filename): wrlexport=VRML2Export(filename) wrlexport.export(scene, world, worldmat) +######################################################### +# UI and Registry utilities +######################################################### + +export_selection_only = Draw.Create(0) +export_rotate_z_to_y = Draw.Create(1) +export_compressed = Draw.Create(0) + +def save_to_registry(): + d = {} + d['selection_only'] = export_selection_only.val + d['rotate_z_to_y'] = export_rotate_z_to_y.val + d['compressed'] = export_compressed.val + Registry.SetKey('vrml97_export', d, True) + +def load_from_registry(): + d = Registry.GetKey('vrml97_export', True) + if d: + try: + export_selection_only.val = d['selection_only'] + export_rotate_z_to_y.val = d['rotate_z_to_y'] + export_compressed.val = d['compressed'] + except: save_to_registry() # If data is not valid, rewrite it. + +def show_popup(): + pup_block = [ + ('Selection Only', export_selection_only, 'Only export objects in visible selection. Else export whole scene.'), + ('Rotate +Z to +Y', export_rotate_z_to_y, 'Rotate such that +Z axis (Blender up) becomes +Y (VRML up).'), + ('Compress', export_compressed, 'Generate a .wrz file (normal VRML compressed by gzip).') + ] + return Draw.PupBlock('Export VRML 97...', pup_block) ######################################################### # main routine ######################################################### -try: - ARG = __script__['arg'] # user selected argument -except: - print "older version" - -if Blender.Get('version') < 235: - print "Warning: VRML97 export failed, wrong blender version!" - print " You aren't running blender version 2.35 or greater" - print " download a newer version from http://blender3d.org/" -else: - if ARG == 'comp': +load_from_registry() + +# Note that show_popup must be done before Blender.Window.FileSelector, +# because export_compressed affects the suggested extension of resulting +# file. + +if show_popup(): + save_to_registry() + if export_compressed.val: extension=".wrz" from gzip import * else: extension=".wrl" Blender.Window.FileSelector(select_file, "Export VRML97", \ sys.makename(ext=extension)) - diff --git a/release/scripts/weightpaint_clean.py b/release/scripts/weightpaint_clean.py index d6cddba5fa2..ca2184bade4 100644 --- a/release/scripts/weightpaint_clean.py +++ b/release/scripts/weightpaint_clean.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Clean Weight...' -Blender: 241 +Blender: 245 Group: 'WeightPaint' Tooltip: 'Removed verts from groups below a weight limit.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ @@ -25,7 +25,7 @@ It removes very low weighted verts from the current group with a weight option. # 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 @@ -51,13 +51,14 @@ def weightClean(me, PREF_THRESH, PREF_KEEP_SINGLE, PREF_OTHER_GROUPS): for wd in vWeightDict: l = len(wd) if not PREF_KEEP_SINGLE or l > 1: + # cant use iteritems because the dict is having items removed for group in wd.keys(): w= wd[group] if w <= PREF_THRESH: # small weight, remove. del wd[group] rem_count +=1 - l-=1 + l-=1 if PREF_KEEP_SINGLE and l == 1: break @@ -117,4 +118,4 @@ def main(): Draw.PupMenu('Removed %i verts from groups' % rem_count) if __name__=='__main__': - main()
\ No newline at end of file + main() diff --git a/release/scripts/weightpaint_gradient.py b/release/scripts/weightpaint_gradient.py index a2bff999610..eb7aff7eb89 100644 --- a/release/scripts/weightpaint_gradient.py +++ b/release/scripts/weightpaint_gradient.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Weight Gradient...' -Blender: 241 +Blender: 245 Group: 'WeightPaint' Tooltip: 'Click on the start and end grad points for the mesh for selected faces.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__=\ ''' diff --git a/release/scripts/weightpaint_grow_shrink.py b/release/scripts/weightpaint_grow_shrink.py index 5527f59e5ae..5c0f28685f9 100644 --- a/release/scripts/weightpaint_grow_shrink.py +++ b/release/scripts/weightpaint_grow_shrink.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Grow/Shrink Weight...' -Blender: 241 +Blender: 245 Group: 'WeightPaint' Tooltip: 'Grow/Shrink active vertex group.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ diff --git a/release/scripts/weightpaint_normalize.py b/release/scripts/weightpaint_normalize.py index 1f6c3d201aa..6059922eecb 100644 --- a/release/scripts/weightpaint_normalize.py +++ b/release/scripts/weightpaint_normalize.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'Normalize/Scale Weight...' -Blender: 241 +Blender: 245 Group: 'WeightPaint' Tooltip: 'Normalize the weight of the active weightgroup.' """ -__author__ = ["Campbell Barton"] -__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__author__ = "Campbell Barton aka ideasman42" +__url__ = ["www.blender.org", "blenderartists.org", "www.python.org"] __version__ = "0.1" __bpydoc__ = """\ diff --git a/release/scripts/widgetwizard.py b/release/scripts/widgetwizard.py index 8facf115d9e..a7ddd68268a 100644 --- a/release/scripts/widgetwizard.py +++ b/release/scripts/widgetwizard.py @@ -8,7 +8,7 @@ Tip: 'Adds Widgets for Driven Shapes' """ __author__ = ["Johnny Matthews (guitargeek)"] -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "0.0.9 12/15/05" __bpydoc__ = """\ diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py index 5b454578db1..1965f9a5070 100644 --- a/release/scripts/wizard_curve2tree.py +++ b/release/scripts/wizard_curve2tree.py @@ -46,12 +46,27 @@ from Blender.Noise import randuvec GLOBALS = {} GLOBALS['non_bez_error'] = 0 +''' +def debugVec(v1,v2): + sce = bpy.data.scenes.active + me = bpy.data.meshes.new() + me.verts.extend( [v1,v2] ) + me.edges.extend( [(0,1)] ) + sce.objects.new(me) +''' + def AngleBetweenVecsSafe(a1, a2): try: return AngleBetweenVecs(a1,a2) except: return 180.0 +# Python 2.3 has no reversed. +try: + reversed +except: + def reversed(l): return l[::-1] + # Copied from blender, we could wrap this! - BKE_curve.c # But probably not toooo bad in python def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis): @@ -257,7 +272,9 @@ class tree: brch.calcData() # Sort from big to small, so big branches get priority - self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius ) + # Py 2.3 dosnt have keywords in sort + try: self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius ) + except: self.branches_all.sort( lambda brch_a, brch_b: cmp(brch_b.bpoints[0].radius, brch_a.bpoints[0].radius) ) # py2.3 def closestBranchPt(self, co): @@ -360,7 +377,12 @@ class tree: pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co) # Check its in range, allow for a bit out - hense the sloppy - if dist < pt_best_j.radius * sloppy: + # The second check in the following IF was added incase the point is close enough to the line but the midpoint is further away + # ...in this case the the resulting mesh will be adjusted to fit the join so its best to make it. + if (dist < pt_best_j.radius * sloppy) or \ + ((brch_i.bpoints[0].co - pt_best_j.co).length < pt_best_j.radius * sloppy): + + brch_i.parent_pt = pt_best_j pt_best_j.childCount += 1 # dont remove me @@ -1130,7 +1152,8 @@ class tree: # Try sorting by other properties! this is ok for now for segments_level_current in segments_level: - segments_level_current.sort( key = lambda seg: -(seg.headCo-seg.tailCo).length ) + try: segments_level_current.sort( key = lambda seg: -(seg.headCo-seg.tailCo).length ) + except: segments_level_current.sort( lambda a,b: cmp((b.headCo-b.tailCo).length, (a.headCo-a.tailCo).length) ) # py2.3 for level in xrange(twig_fill_levels): if len(segments_level) > level: @@ -1356,18 +1379,23 @@ class tree: # Get the branches based on our selection method! if twig_select_mode==0: - branches_sorted.sort( key = lambda brch: brch.getLength()) + try: branches_sorted.sort( key = lambda brch: brch.getLength()) + except: branches_sorted.sort( lambda a,b: cmp(a.getLength(),a.getLength()) ) # py2.3 elif twig_select_mode==1: - branches_sorted.sort( key = lambda brch:-brch.getLength()) + try: branches_sorted.sort( key = lambda brch:-brch.getLength()) + except: branches_sorted.sort( lambda a,b: cmp(b.getLength(), a.getLength()) ) # py2.3 elif twig_select_mode==2: - branches_sorted.sort( key = lambda brch:brch.getStraightness()) + try: branches_sorted.sort( key = lambda brch:brch.getStraightness()) + except: branches_sorted.sort( lambda a,b: cmp(a.getStraightness(), b.getStraightness())) # py2.3 elif twig_select_mode==3: - branches_sorted.sort( key = lambda brch:-brch.getStraightness()) + try: branches_sorted.sort( key = lambda brch:-brch.getStraightness()) + except: branches_sorted.sort( lambda a,b: cmp(b.getStraightness(), a.getStraightness())) # py2.3 factor_int = int(len(self.branches_all) * twig_select_factor) branches_sorted[factor_int:] = [] # remove the last part of the list - branches_sorted.sort( key = lambda brch: len(brch.bpoints)) + try: branches_sorted.sort( key = lambda brch: len(brch.bpoints)) + except: branches_sorted.sort( lambda a,b: cmp(len(a.bpoints), len(b.bpoints)) ) # py2.3 branches_new = [] #for i in xrange(ratio_int): @@ -1487,7 +1515,7 @@ class tree: else: # our roll was set from the branches parent and needs no changing # set it to zero so the following functions know to interpolate. - brch.bpoints[0].roll_angle = 45.0 + brch.bpoints[0].roll_angle = 0.0 #brch.bpoints[1].roll_angle = 0.0 ''' @@ -1921,7 +1949,7 @@ class tree: mat_pitch = RotationMatrix( angle, 3, 'r', cross1) mat = mat * mat_pitch if leaf_branch_roll_rand: - mat_roll = RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no * mat_pitch) + mat_roll = RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no) mat = mat * mat_roll mat = mat.resize4x4() * TranslationMatrix(leaf_co) @@ -2407,6 +2435,7 @@ class bpoint(object): Roll the quad about its normal use for aurienting the sides of a quad to meet a branch that stems from here... ''' + # debugVec(self.co, self.co + self.no) mat = RotationMatrix(angle, 3, 'r', self.no) for i in xrange(4): @@ -2451,7 +2480,7 @@ class bpoint(object): def calcVerts(self): if self.prev == None: if self.branch.parent_pt: - cross = CrossVecs(self.no, self.branch.getParentFaceCent() - self.branch.parent_pt.getAbsVec( self.branch.getParentQuadIndex() )) + cross = CrossVecs(self.no, self.branch.parent_pt.no) * RotationMatrix(-45, 3, 'r', self.no) else: # parentless branch - for best results get a cross thats not the same as the normal, in rare cases this happens. @@ -2666,6 +2695,7 @@ class branch: co_on_line, fac = ClosestPointOnLine(co, pt.co, pt.next.co) print fac if fac >= 0.0 and fac <= 1.0: + return pt, (co-co_on_line).length return best, best_dist @@ -3041,7 +3071,7 @@ EVENT_REDRAW = 3 # Prefs for each tree PREFS = {} -PREFS['connect_sloppy'] = Draw.Create(1.0) +PREFS['connect_sloppy'] = Draw.Create(1.5) PREFS['connect_base_trim'] = Draw.Create(1.0) PREFS['seg_density'] = Draw.Create(0.5) PREFS['seg_density_angle'] = Draw.Create(20.0) @@ -3389,7 +3419,7 @@ def buildTree(ob_curve, single=False): if leaf_object: ob_leaf_dupliface.enableDupFaces = True ob_leaf_dupliface.enableDupFacesScale = True - ob_leaf_dupliface.makeParent([leaf_object]) + ob_leaf_dupliface.makeParent([leaf_object], 1) else: ob_leaf_dupliface.enableDupFaces = False @@ -3537,7 +3567,7 @@ def do_pref_clear(e,v): return for ob in objects: - try: del idprop[ID_SLOT_NAME] + try: del ob.properties[ID_SLOT_NAME] except: pass def do_tex_check(e,v): @@ -3620,8 +3650,18 @@ def do_tree_generate(e,v): Blender.Draw.PupMenu('Error%t|Nurbs and Poly curve types cant be used!') GLOBALS['non_bez_error'] = 0 +def do_tree_help(e,v): + url = 'http://wiki.blender.org/index.php/Scripts/Manual/Wizards/TreeFromCurves' + 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 evt(e,val): pass @@ -3957,7 +3997,7 @@ def gui(): xtmp = x # ---------- ---------- ---------- ---------- - PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 2.0, 'Strictness when connecting branches'); xtmp += but_width*2; + PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 3.0, 'Strictness when connecting branches'); xtmp += but_width*2; PREFS['connect_base_trim'] = Draw.Number('Joint Bevel', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'low value for a tight join, hi for a smoother bevel'); xtmp += but_width*2; Blender.Draw.EndAlign() y-=but_height+MARGIN @@ -3989,8 +4029,9 @@ def gui(): # ---------- ---------- ---------- ---------- Blender.Draw.BeginAlign() - Draw.PushButton('Exit', EVENT_EXIT, xtmp, y, but_width, but_height, '', do_active_image); xtmp += but_width; - Draw.PushButton('Generate from selection', EVENT_REDRAW, xtmp, y, but_width*3, but_height, 'Generate mesh', do_tree_generate); xtmp += but_width*3; + Draw.PushButton('Exit', EVENT_EXIT, xtmp, y, but_width, but_height, ''); xtmp += but_width; + Draw.PushButton('Help', EVENT_NONE, xtmp, y, but_width, but_height, '', do_tree_help); xtmp += but_width; + Draw.PushButton('Generate from selection', EVENT_REDRAW, xtmp, y, but_width*2, but_height, 'Generate mesh', do_tree_generate); xtmp += but_width*3; Blender.Draw.EndAlign() y-=but_height+MARGIN xtmp = x diff --git a/release/scripts/x3d_export.py b/release/scripts/x3d_export.py index 36359f1d122..b12ff67d8a6 100644 --- a/release/scripts/x3d_export.py +++ b/release/scripts/x3d_export.py @@ -1,15 +1,12 @@ #!BPY """ Registration info for Blender menus: Name: 'X3D Extensible 3D (.x3d)...' -Blender: 235 +Blender: 245 Group: 'Export' -Submenu: 'All Objects...' all -Submenu: 'All Objects compressed...' comp -Submenu: 'Selected Objects...' selected -Tooltip: 'Export to Extensible 3D file (.x3d)' +Tooltip: 'Export selection to Extensible 3D file (.x3d)' """ -__author__ = ("Bart") +__author__ = ("Bart", "Campbell Barton") __email__ = ["Bart, bart:neeneenee*de"] __url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml"] __version__ = "2006/01/17" @@ -22,10 +19,9 @@ 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:<br> - Doesn't handle multiple materials (don't use material indices);<br> - Doesn't handle multiple UV textures on a single mesh (create a mesh -for each texture);<br> - Can't get the texture array associated with material * not the UV ones; + Doesn't handle multiple materials (don't use material indices);<br> + Doesn't handle multiple UV textures on a single mesh (create a mesh for each texture);<br> + Can't get the texture array associated with material * not the UV ones; """ @@ -58,951 +54,998 @@ for each texture);<br> #################################### import Blender -from Blender import Object, NMesh, Lamp, Draw, Image, Text, sys +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 #################################### -scene = Blender.Scene.GetCurrent() -world = Blender.World.GetCurrent() -worldmat = Blender.Texture.Get() filename = Blender.Get('filename') _safeOverwrite = True -ARG='' -extension = '' - -class DrawTypes: - """Object DrawTypes enum values - BOUNDS - draw only the bounding box of the object - WIRE - draw object as a wire frame - SOLID - draw object with flat shading - SHADED - draw object with OpenGL shading -""" - BOUNDBOX = 1 - WIRE = 2 - SOLID = 3 - SHADED = 4 - TEXTURE = 5 -if not hasattr(Blender.Object,'DrawTypes'): - Blender.Object.DrawTypes = DrawTypes() +extension = '' ########################################################## # Functions for writing output file ########################################################## -class VRML2Export: - - def __init__(self, filename): - #--- public you can change these --- - self.writingcolor = 0 - self.writingtexture = 0 - self.writingcoords = 0 - self.wire = 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 = open(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","" ] +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')) - self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n") - self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n") - self.file.write("<head>\n") - self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile)) - self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version')) - self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.55 (2006/01/17)\" />\n") - self.file.write("</head>\n") - self.file.write("<Scene>\n") - - 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("<Inline DEF=\"%s\" " % (self.cleanStr(nameinline))) - nameinline = nameinline+".x3d" - self.file.write("url=\"%s\" />" % nameinline) - self.file.write("\n\n") - - def writeScript(self): - textEditor = Blender.Text.Get() - alltext = len(textEditor) - for i in xrange(alltext): - nametext = textEditor[i].getName() - 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, thisObj): - context = scene.getRenderingContext() - ratio = float(context.imageSizeY())/float(context.imageSizeX()) - lens = (360* (math.atan(ratio *16 / thisObj.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 - loc = self.rotatePointForVRML(thisObj.loc) - rot = [thisObj.RotX - 1.57, thisObj.RotY, thisObj.RotZ] - 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("<Viewpoint DEF=\"%s\" " % (self.cleanStr(thisObj.name))) - self.file.write("description=\"%s\" " % (thisObj.name)) - self.file.write("centerOfRotation=\"0 0 0\" ") - self.file.write("position=\"%3.2f %3.2f %3.2f\" " % (loc[0], loc[1], loc[2])) - self.file.write("orientation=\"%3.2f %3.2f %3.2f %3.2f\" " % (angleAxis[0], angleAxis[1], -angleAxis[2], angleAxis[3])) - self.file.write("fieldOfView=\"%.3f\" />\n\n" % (lens)) - - def writeFog(self): - 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("<Fog fogType=\"%s\" " % self.namesFog[mtype]) - self.file.write("color=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) - self.file.write("visibilityRange=\"%s\" />\n\n" % round(mparam[2],self.cp)) - else: - return - - def writeNavigationInfo(self, scene): - allObj = [] - allObj = list(scene.objects) - headlight = "TRUE" - vislimit = 0.0 - for thisObj in allObj: - objType=thisObj.type - if objType == "Camera": - vislimit = thisObj.data.clipEnd - elif objType == "Lamp": - headlight = "FALSE" - self.file.write("<NavigationInfo headlight=\"%s\" " % headlight) - self.file.write("visibilityLimit=\"%s\" " % (round(vislimit,self.cp))) - self.file.write("type=\"EXAMINE, ANY\" avatarSize=\"0.25, 1.75, 0.75\" />\n\n") - - def writeSpotLight(self, ob, lamp): - 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(ob) - # 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.getLocation('worldspace') - radius = lamp.dist*math.cos(beamWidth) - self.file.write("<SpotLight DEF=\"%s\" " % safeName) - self.file.write("radius=\"%s\" " % (round(radius,self.cp))) - self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) - self.file.write("intensity=\"%s\" " % (round(intensity,self.cp))) - self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) - self.file.write("beamWidth=\"%s\" " % (round(beamWidth,self.cp))) - self.file.write("cutOffAngle=\"%s\" " % (round(cutOffAngle,self.cp))) - self.file.write("direction=\"%s %s %s\" " % (round(dx,3),round(dy,3),round(dz,3))) - self.file.write("location=\"%s %s %s\" />\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) - - def writeDirectionalLight(self, ob, lamp): - 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(ob) - self.file.write("<DirectionalLight DEF=\"%s\" " % safeName) - self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) - self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) - self.file.write("intensity=\"%s\" " % (round(intensity,self.cp))) - self.file.write("direction=\"%s %s %s\" />\n\n" % (round(dx,4),round(dy,4),round(dz,4))) - - def writePointLight(self, ob, lamp): - 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.getLocation('worldspace') - intensity=min(lamp.energy/1.75,1.0) - radius = lamp.dist - self.file.write("<PointLight DEF=\"%s\" " % safeName) - self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) - self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) - self.file.write("intensity=\"%s\" " % (round(intensity,self.cp))) - self.file.write("radius=\"%s\" " % radius ) - self.file.write("location=\"%s %s %s\" />\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3))) - - def writeNode(self, thisObj): - obname=str(thisObj.getName()) - if obname in self.namesStandard: - return - else: - dx,dy,dz = self.computeDirection(thisObj) - location = thisObj.getLocation('worldspace') - 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, normals = 0): - imageMap={} # set of used images - sided={} # 'one':cnt , 'two':cnt - vColors={} # 'multi':1 - meshName = self.cleanStr(ob.name) - mesh=ob.data - meshME = self.cleanStr(mesh.name) - if len(mesh.faces) == 0: return - for face in mesh.faces: - if face.mode & Blender.NMesh.FaceModes['HALO'] and self.halonode == 0: - self.writeIndented("<Billboard axisOfRotation=\"0 0 0\">\n",1) - self.halonode = 1 - elif face.mode & Blender.NMesh.FaceModes['BILLBOARD'] and self.billnode == 0: - self.writeIndented("<Billboard axisOfRotation=\"0 1 0\">\n",1) - self.billnode = 1 - elif face.mode & Blender.NMesh.FaceModes['OBCOL'] and self.matonly == 0: - self.matonly = 1 - elif face.mode & Blender.NMesh.FaceModes['SHAREDCOL'] and self.share == 0: - self.share = 1 - elif face.mode & Blender.NMesh.FaceModes['TILES'] and self.tilenode == 0: - self.tilenode = 1 - elif not face.mode & Blender.NMesh.FaceModes['DYNAMIC'] and self.collnode == 0: - self.writeIndented("<Collision enabled=\"false\">\n",1) - self.collnode = 1 - - nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) - - if nIFSCnt > 1: - self.writeIndented("<Group DEF=\"%s%s\">\n" % ("G_", meshName),1) - - if sided.has_key('two') and sided['two'] > 0: - bTwoSided=1 - else: - bTwoSided=0 - - location= ob.getLocation('worldspace') - self.writeIndented("<Transform DEF=\"%s\" translation=\"%s %s %s\">\n" % (meshName, round(location[0],3), round(location[1],3), round(location[2],3)),1) - self.writeIndented("<Shape>\n",1) - - maters=mesh.materials - hasImageTexture=0 - issmooth=0 - - if len(maters) > 0 or mesh.hasFaceUV(): - self.writeIndented("<Appearance>\n", 1) - # right now this script can only handle a single material per mesh. - if len(maters) >= 1: - mat=Blender.Material.Get(maters[0].name) - matFlags = mat.getMode() - if not matFlags & Blender.Material.Modes['TEXFACE']: - self.writeMaterial(mat, self.cleanStr(maters[0].name,'')) - if len(maters) > 1: - print "Warning: mesh named %s has multiple materials" % meshName - print "Warning: only one material per object handled" - - #-- textures - if mesh.hasFaceUV(): - 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("<TextureTransform scale=\"%s %s\" />\n" % (face.image.xrep, face.image.yrep)) - self.tilenode = 0 - self.writeIndented("</Appearance>\n", -1) - - #-- IndexedFaceSet or IndexedLineSet - - # check if object is wireframe only - if ob.drawType == Blender.Object.DrawTypes.WIRE: - # user selected WIRE=2 on the Drawtype=Wire on (F9) Edit page - ifStyle="IndexedLineSet" - self.wire = 1 - else: - # 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 ob.drawType != Blender.Object.DrawTypes.WIRE: - if bTwoSided == 1: - self.file.write("solid=\"false\" ") - else: - self.file.write("solid=\"true\" ") - - for face in mesh.faces: - if face.smooth: - issmooth=1 - if issmooth==1 and self.wire == 0: - creaseAngle=(mesh.getMaxSmoothAngle())*(math.pi/180.0) - self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp))) - - #--- output vertexColors - if self.share == 1 and self.matonly == 0: - self.writeVertexColors(mesh) - if ob.drawType != Blender.Object.DrawTypes.WIRE: - #--- output textureCoordinates if UV texture used - if mesh.hasFaceUV(): - if self.matonly == 1 and self.share == 1: - self.writeFaceColors(mesh) - elif hasImageTexture == 1: - self.writeTextureCoordinates(mesh) - #--- output coordinates - self.writeCoordinates(ob, mesh, meshName) - - self.writingcoords = 1 - self.writingtexture = 1 - self.writingcolor = 1 - self.writeCoordinates(ob, mesh, meshName) - - if ob.drawType != Blender.Object.DrawTypes.WIRE: - #--- output textureCoordinates if UV texture used - if mesh.hasFaceUV(): - if hasImageTexture == 1: - self.writeTextureCoordinates(mesh) - elif self.matonly == 1 and self.share == 1: - self.writeFaceColors(mesh) - #--- output vertexColors - if self.share == 1 and self.matonly == 0: - self.writeVertexColors(mesh) - self.matonly = 0 - self.share = 0 - self.wire = 0 - self.writingcoords = 0 - self.writingtexture = 0 - self.writingcolor = 0 - #--- output closing braces - self.writeIndented("</%s>\n" % ifStyle, -1) - self.writeIndented("</Shape>\n", -1) - self.writeIndented("</Transform>\n", -1) - - if self.halonode == 1: - self.writeIndented("</Billboard>\n", -1) - self.halonode = 0 - - if self.billnode == 1: - self.writeIndented("</Billboard>\n", -1) - self.billnode = 0 - - if self.collnode == 1: - self.writeIndented("</Collision>\n", -1) - self.collnode = 0 - - if nIFSCnt > 1: - self.writeIndented("</Group>\n", -1) - - self.file.write("\n") - - def writeCoordinates(self, ob, mesh, meshName): - meshVertexList = mesh.verts - - # create vertex list and pre rotate -90 degrees X for VRML - location= ob.getLocation('worldspace') - if self.writingcoords == 0: - self.file.write('coordIndex="') - for face in mesh.faces: - for i in xrange(len(face)): - indx=face[i].index - self.file.write("%s " % indx) - self.file.write("-1, ") - self.file.write("\">\n") - else: - #-- vertices - mesh.transform(ob.matrixWorld) - self.writeIndented("<Coordinate DEF=\"%s%s\" \n" % ("coord_",meshName), 1) - self.file.write("\t\t\t\tpoint=\"") - for v in meshVertexList: - self.file.write("%.6f %.6f %.6f, " % tuple(v.co)) - self.file.write("\" />") - self.writeIndented("\n", -1) - - def writeTextureCoordinates(self, mesh): - texCoordList=[] - texIndexList=[] - j=0 - - for face in mesh.faces: - for i in xrange(len(face)): - texIndexList.append(j) - texCoordList.append(face.uv[i]) - 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("<TextureCoordinate point=\"", 1) - for i in xrange(len(texCoordList)): - self.file.write("%s %s, " % (round(texCoordList[i][0],self.tp), round(texCoordList[i][1],self.tp))) - self.file.write("\" />") - self.writeIndented("\n", -1) - - def writeFaceColors(self, mesh): - if self.writingcolor == 0: - self.file.write("colorPerVertex=\"false\" ") - else: - self.writeIndented("<Color color=\"", 1) - 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 writeVertexColors(self, mesh): - if self.writingcolor == 0: - self.file.write("colorPerVertex=\"false\" ") - else: - self.writeIndented("<Color color=\"", 1) - for i in xrange(len(mesh.verts)): - c=self.getVertexColorByIndx(mesh,i) - if self.verbose > 2: - print "Debug: vertex[%d].col r=%d g=%d b=%d" % (i, 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): - # look up material name, use it if available - if self.matNames.has_key(matName): - self.writeIndented("<Material USE=\"MA_%s\" />\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.getSpec()+0.001)) - specG = (mat.specCol[1]+0.001)/(1.25/(mat.getSpec()+0.001)) - specB = (mat.specCol[2]+0.001)/(1.25/(mat.getSpec()+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("<Material DEF=\"MA_%s\" " % matName, 1) - self.file.write("diffuseColor=\"%s %s %s\" " % (round(diffuseR,self.cp), round(diffuseG,self.cp), round(diffuseB,self.cp))) - self.file.write("specularColor=\"%s %s %s\" " % (round(specR,self.cp), round(specG,self.cp), round(specB,self.cp))) - self.file.write("emissiveColor=\"%s %s %s\" \n" % (round(emisR,self.cp), round(emisG,self.cp), round(emisB,self.cp))) - self.writeIndented("ambientIntensity=\"%s\" " % (round(ambient,self.cp))) - self.file.write("shininess=\"%s\" " % (round(shininess,self.cp))) - self.file.write("transparency=\"%s\" />" % (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("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name)) - self.texNames[name] += 1 - return - else: - self.writeIndented("<ImageTexture DEF=\"%s\" " % self.cleanStr(name), 1) - self.file.write("url=\"%s\" />" % name) - self.writeIndented("\n",-1) - self.texNames[name] = 1 - - def writeBackground(self): - 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("<Background ") - if worldname not in self.namesStandard: - self.file.write("DEF=\"%s\" " % self.secureName(worldname)) - # No Skytype - just Hor color - 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: - 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: - 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: - 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: - 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))) - self.writeIndented("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) - # Any Other two colors - 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(worldmat) - for i in xrange(alltexture): - namemat = worldmat[i].getName() - pic = worldmat[i].getImage() - if (namemat == "back") and (pic != None): - self.file.write("\n\tbackUrl=\"%s\" " % str(pic.getName())) - elif (namemat == "bottom") and (pic != None): - self.writeIndented("bottomUrl=\"%s\" " % str(pic.getName())) - elif (namemat == "front") and (pic != None): - self.writeIndented("frontUrl=\"%s\" " % str(pic.getName())) - elif (namemat == "left") and (pic != None): - self.writeIndented("leftUrl=\"%s\" " % str(pic.getName())) - elif (namemat == "right") and (pic != None): - self.writeIndented("rightUrl=\"%s\" " % str(pic.getName())) - elif (namemat == "top") and (pic != None): - self.writeIndented("topUrl=\"%s\" " % str(pic.getName())) - self.writeIndented("/>\n\n") + def writeHeader(self): + #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '<').replace('>', '>') + bfile = self.filename.replace('<', '<').replace('>', '>') # use outfile name + self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n") + self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n") + self.file.write("<head>\n") + self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile)) + self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version')) + self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.55 (2006/01/17)\" />\n") + self.file.write("</head>\n") + self.file.write("<Scene>\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("<Inline DEF=\"%s\" " % (self.cleanStr(nameinline))) + nameinline = nameinline+".x3d" + self.file.write("url=\"%s\" />" % 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("<Viewpoint DEF=\"%s\" " % (self.cleanStr(ob.name))) + self.file.write("description=\"%s\" " % (ob.name)) + self.file.write("centerOfRotation=\"0 0 0\" ") + self.file.write("position=\"%3.2f %3.2f %3.2f\" " % (loc[0], loc[1], loc[2])) + self.file.write("orientation=\"%3.2f %3.2f %3.2f %3.2f\" " % (angleAxis[0], angleAxis[1], -angleAxis[2], angleAxis[3])) + self.file.write("fieldOfView=\"%.3f\" />\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("<Fog fogType=\"%s\" " % self.namesFog[mtype]) + self.file.write("color=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) + self.file.write("visibilityRange=\"%s\" />\n\n" % round(mparam[2],self.cp)) + else: + return + + def writeNavigationInfo(self, scene): + self.file.write('<NavigationInfo headlight="FALSE" visibilityLimit="0.0" type=\'"EXAMINE","ANY"\' avatarSize="0.25, 1.75, 0.75" />\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("<SpotLight DEF=\"%s\" " % safeName) + self.file.write("radius=\"%s\" " % (round(radius,self.cp))) + self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) + self.file.write("intensity=\"%s\" " % (round(intensity,self.cp))) + self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) + self.file.write("beamWidth=\"%s\" " % (round(beamWidth,self.cp))) + self.file.write("cutOffAngle=\"%s\" " % (round(cutOffAngle,self.cp))) + self.file.write("direction=\"%s %s %s\" " % (round(dx,3),round(dy,3),round(dz,3))) + self.file.write("location=\"%s %s %s\" />\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("<DirectionalLight DEF=\"%s\" " % safeName) + self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) + self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) + self.file.write("intensity=\"%s\" " % (round(intensity,self.cp))) + self.file.write("direction=\"%s %s %s\" />\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("<PointLight DEF=\"%s\" " % safeName) + self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp))) + self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp))) + self.file.write("intensity=\"%s\" " % (round( min(lamp.energy/1.75,1.0) ,self.cp))) + self.file.write("radius=\"%s\" " % lamp.dist ) + self.file.write("location=\"%s %s %s\" />\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("<Billboard axisOfRotation=\"0 0 0\">\n",1) + self.halonode = 1 + elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0: + self.writeIndented("<Billboard axisOfRotation=\"0 1 0\">\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("<Collision enabled=\"false\">\n",1) + self.collnode = 1 + + nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors) + + if nIFSCnt > 1: + self.writeIndented("<Group DEF=\"%s%s\">\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('<Transform rotation="%.6f %.6f %.6f %.6f">\n' % (rot[0], rot[1], rot[2], rot[3])) + self.writeIndented('<Transform DEF="%s" translation="%.6f %.6f %.6f" scale="%.6f %.6f %.6f" rotation="%.6f %.6f %.6f %.6f">\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("<Shape>\n",1) + maters=mesh.materials + hasImageTexture=0 + issmooth=0 + + if len(maters) > 0 or mesh.faceUV: + self.writeIndented("<Appearance>\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("<TextureTransform scale=\"%s %s\" />\n" % (face.image.xrep, face.image.yrep)) + self.tilenode = 0 + self.writeIndented("</Appearance>\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("</%s>\n" % ifStyle, -1) + self.writeIndented("</Shape>\n", -1) + self.writeIndented("</Transform>\n", -1) + + if self.halonode == 1: + self.writeIndented("</Billboard>\n", -1) + self.halonode = 0 + + if self.billnode == 1: + self.writeIndented("</Billboard>\n", -1) + self.billnode = 0 + + if self.collnode == 1: + self.writeIndented("</Collision>\n", -1) + self.collnode = 0 + + if nIFSCnt > 1: + self.writeIndented("</Group>\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("<Coordinate DEF=\"%s%s\" \n" % ("coord_",meshName), 1) + self.file.write("\t\t\t\tpoint=\"") + for v in mesh.verts: + self.file.write("%.6f %.6f %.6f, " % tuple(v.co)) + self.file.write("\" />") + 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("<TextureCoordinate point=\"", 1) + for i in xrange(len(texCoordList)): + self.file.write("%s %s, " % (round(texCoordList[i][0],self.tp), round(texCoordList[i][1],self.tp))) + self.file.write("\" />") + self.writeIndented("\n", -1) + + def writeFaceColors(self, mesh): + if self.writingcolor == 0: + self.file.write("colorPerVertex=\"false\" ") + else: + self.writeIndented("<Color color=\"", 1) + 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 self.matNames.has_key(matName): + self.writeIndented("<Material USE=\"MA_%s\" />\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("<Material DEF=\"MA_%s\" " % matName, 1) + self.file.write("diffuseColor=\"%s %s %s\" " % (round(diffuseR,self.cp), round(diffuseG,self.cp), round(diffuseB,self.cp))) + self.file.write("specularColor=\"%s %s %s\" " % (round(specR,self.cp), round(specG,self.cp), round(specB,self.cp))) + self.file.write("emissiveColor=\"%s %s %s\" \n" % (round(emisR,self.cp), round(emisG,self.cp), round(emisB,self.cp))) + self.writeIndented("ambientIntensity=\"%s\" " % (round(ambient,self.cp))) + self.file.write("shininess=\"%s\" " % (round(shininess,self.cp))) + self.file.write("transparency=\"%s\" />" % (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("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name)) + self.texNames[name] += 1 + return + else: + self.writeIndented("<ImageTexture DEF=\"%s\" " % self.cleanStr(name), 1) + self.file.write("url=\"%s\" />" % 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("<Background ") + if worldname not in self.namesStandard: + self.file.write("DEF=\"%s\" " % self.secureName(worldname)) + # No Skytype - just Hor color + 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: + 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: + 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: + 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: + 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))) + self.writeIndented("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp))) + # Any Other two colors + 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 xrange(alltexture): + namemat = alltextures[i].name + pic = alltextures[i].getImage() + if (namemat == "back") and (pic != None): + 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]) + elif (namemat == "front") and (pic != None): + 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]) + elif (namemat == "right") and (pic != None): + 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("/>\n\n") ########################################################## # export routine ########################################################## - def export(self, scene, world, worldmat): - print "Info: starting X3D export to " + self.filename + "..." - self.writeHeader() - self.writeScript() - self.writeNavigationInfo(scene) - self.writeBackground() - self.writeFog() - self.proto = 0 - allObj = [] - if ARG == 'selected': - allObj = list(scene.objects.context) - else: - allObj = list(scene.objects) - self.writeInline() - for thisObj in allObj: - try: - objType=thisObj.type - objName=thisObj.name - self.matonly = 0 - if objType == "Camera": - self.writeViewpoint(thisObj) - elif objType == "Mesh": - self.writeIndexedFaceSet(thisObj, normals = 0) - elif objType == "Lamp": - lmpName= thisObj.data - lmpType=lmpName.getType() - if lmpType == Lamp.Types.Lamp: - self.writePointLight(thisObj, lmpName) - elif lmpType == Lamp.Types.Spot: - self.writeSpotLight(thisObj, lmpName) - elif lmpType == Lamp.Types.Sun: - self.writeDirectionalLight(thisObj, lmpName) - else: - self.writeDirectionalLight(thisObj, lmpName) - elif objType == "Empty" and objName != "Empty": - self.writeNode(thisObj) - else: - #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType()) - print "" - except AttributeError: - print "Error: Unable to get type info for %s" % thisObj.getName() - if ARG != 'selected': - self.writeScript() - self.file.write("\n</Scene>\n</X3D>") - self.cleanup() - + 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</Scene>\n</X3D>") + + 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 - - for face in mesh.faces: - sidename=''; - if (face.mode & NMesh.FaceModes.TWOSIDE) == NMesh.FaceModes.TWOSIDE: - sidename='two' - else: - sidename='one' - - if sided.has_key(sidename): - sided[sidename]+=1 - else: - sided[sidename]=1 - - if face.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 & NMesh.FaceModes.TWOSIDE) == NMesh.FaceModes.TWOSIDE: - print "Debug: face.mode twosided" - - print "Debug: face.transp=0x%x (enum)" % face.transp - if face.transp == NMesh.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.hasVertexUV() - print "Debug: mesh.hasFaceUV=%d" % mesh.hasFaceUV() - 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, ob): - x,y,z=(0,-1.0,0) # point down - ax,ay,az = (ob.RotX,ob.RotZ,ob.RotY) - - # 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 + 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 select_file(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 - - wrlexport=VRML2Export(filename) - wrlexport.export(scene, world, worldmat) +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) -def createWRLPath(): - filename = Blender.Get('filename') - print filename - - if filename.find('.') != -1: - filename = filename.split('.')[0] - filename += extension - print filename - return filename ######################################################### # main routine ######################################################### -try: - ARG = __script__['arg'] # user selected argument -except: - print "older version" - -if Blender.Get('version') < 235: - print "Warning: X3D export failed, wrong blender version!" - print " You aren't running blender version 2.35 or greater" - print " download a newer version from http://blender3d.org/" -else: - if ARG == 'comp': - from gzip import * - extension=".x3dz" - else: - extension=".x3d" - Blender.Window.FileSelector(select_file,"Export X3D",createWRLPath()) + +if __name__ == '__main__': + Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d')) + diff --git a/release/scripts/xfig_export.py b/release/scripts/xfig_export.py index e8e0c0ded0e..ddc0dd4dcea 100644 --- a/release/scripts/xfig_export.py +++ b/release/scripts/xfig_export.py @@ -7,7 +7,7 @@ Tooltip: 'Export selected mesh to xfig Format (.fig)' """ __author__ = 'Dino Ghilardi', 'Campbell Barton AKA Ideasman42' -__url__ = ("blender", "elysiun") +__url__ = ("blender", "blenderartists.org") __version__ = "1.1" __bpydoc__ = """\ diff --git a/release/scripts/xsi_export.py b/release/scripts/xsi_export.py index 62dc32cbc78..d86d8cb82cf 100644 --- a/release/scripts/xsi_export.py +++ b/release/scripts/xsi_export.py @@ -10,7 +10,7 @@ Tooltip: 'Export to a SoftImage XSI file' __author__ = ("Elira") __url__ = ["Author's site, http://www.creative-realms.net/~elira/blender.html", -"SoftImage's site, www.softimage.com", "elysiun"] +"SoftImage's site, www.softimage.com", "blenderartists.org"] __email__ = ["scripts"] __version__ = "2005/11/01" |