* added support for exporting dupli objects
authorCampbell Barton <ideasman42@gmail.com>
Wed, 7 May 2008 15:38:40 +0000 (15:38 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 7 May 2008 15:38:40 +0000 (15:38 +0000)
* option to export modifier applied objects
* option to export quads as tri's
* added back compress option (will default to enabled if you use .x3dz as the extension)

release/scripts/x3d_export.py
source/blender/blenkernel/intern/blender.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/src/space.c

index ac4a8e9ca5be2a0d0e3b6acabc70cf4d35f6070b..b12ff67d8a606842d8851cfbce7c506900c910aa 100644 (file)
@@ -57,6 +57,8 @@ import Blender
 from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh
 from Blender.Scene import Render
 import math
+import BPyObject
+import BPyMesh
 
 # 
 DEG2RAD=0.017453292519943295
@@ -68,14 +70,14 @@ MATWORLD= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
 
 filename = Blender.Get('filename')
 _safeOverwrite = True
-ARG=''
+
 extension = ''
 
 ##########################################################
 # Functions for writing output file
 ##########################################################
 
-class VRML2Export:
+class x3d_class:
 
        def __init__(self, filename):
                #--- public you can change these ---
@@ -101,7 +103,18 @@ class VRML2Export:
                self.meshNames={}   # dictionary of meshNames
                self.indentLevel=0 # keeps track of current indenting
                self.filename=filename
-               self.file = open(filename, "w")
+               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",
@@ -169,7 +182,7 @@ class VRML2Export:
                                        nameinline = nameinline+".x3d"
                                        self.file.write("url=\"%s\" />" % nameinline)
                                        self.file.write("\n\n")
-       '''
+
        
        def writeScript(self):
                textEditor = Blender.Text.Get() 
@@ -190,15 +203,17 @@ class VRML2Export:
                                        for j in xrange(nalllines):
                                                self.writeIndented(alllines[j] + "\n")
                self.writeIndented("\n")
-
-       def writeViewpoint(self, ob, scene):
+       '''
+       
+       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 = 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)
@@ -229,23 +244,11 @@ class VRML2Export:
                        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 ob in allObj:
-                       objType=ob.type
-                       if objType == "Camera":
-                               vislimit = ob.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, world):
+               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
@@ -259,12 +262,14 @@ class VRML2Export:
                beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
                cutOffAngle=beamWidth*1.3
 
-               dx,dy,dz=self.computeDirection(ob)
+               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()
+               #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)))
@@ -277,7 +282,7 @@ class VRML2Export:
                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, world):
+       def writeDirectionalLight(self, ob, mtx, lamp, world):
                safeName = self.cleanStr(ob.name)
                if world:
                        ambi = world.amb
@@ -287,14 +292,14 @@ class VRML2Export:
                        ambientIntensity = 0
 
                intensity=min(lamp.energy/1.75,1.0) 
-               (dx,dy,dz)=self.computeDirection(ob)
+               (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, lamp, world):
+       def writePointLight(self, ob, mtx, lamp, world):
                safeName = self.cleanStr(ob.name)
                if world:
                        ambi = world.amb
@@ -303,29 +308,30 @@ class VRML2Export:
                        ambi = 0
                        ambientIntensity = 0
                
-               location=(ob.matrixWorld*MATWORLD).translationPart()
-               intensity=min(lamp.energy/1.75,1.0) 
-               radius = lamp.dist
+               # 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(intensity,self.cp)))
-               self.file.write("radius=\"%s\" " % radius )
+               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):
+       '''
+       def writeNode(self, ob, mtx):
                obname=str(ob.name)
                if obname in self.namesStandard:
                        return
                else:
-                       dx,dy,dz = self.computeDirection(ob)
-                       location=(ob.matrixWorld*MATWORLD).translationPart()
+                       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("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
@@ -345,13 +351,13 @@ class VRML2Export:
                                newname = name
                                return "%s" % (newname)
 
-       def writeIndexedFaceSet(self, ob, world, normals = 0):
+       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)
-               mesh=ob.getData(mesh=1)
-               meshME = self.cleanStr(mesh.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:
@@ -371,7 +377,7 @@ class VRML2Export:
                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:
@@ -382,7 +388,8 @@ class VRML2Export:
                else:
                        bTwoSided=0
 
-               mtx = ob.matrixWorld * MATWORLD
+               # mtx = ob.matrixWorld * MATWORLD # mtx is now passed
+               mtx = mtx * MATWORLD
                
                loc= mtx.translationPart()
                sca= mtx.scalePart()
@@ -456,12 +463,12 @@ class VRML2Export:
                                elif hasImageTexture == 1:
                                        self.writeTextureCoordinates(mesh)
                        #--- output coordinates
-                       self.writeCoordinates(ob, mesh, meshName)
+                       self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
 
                        self.writingcoords = 1
                        self.writingtexture = 1
                        self.writingcolor = 1
-                       self.writeCoordinates(ob, mesh, meshName)
+                       self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
                        
                        #--- output textureCoordinates if UV texture used
                        if mesh.faceUV:
@@ -498,17 +505,23 @@ class VRML2Export:
 
                self.file.write("\n")
 
-       def writeCoordinates(self, ob, mesh, meshName):
+       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)==4:
-                                       self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index))
+                               
+                               if len(face)==3:
+                                               self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
                                else:
-                                       self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
+                                       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
@@ -679,43 +692,74 @@ class VRML2Export:
 # export routine
 ##########################################################
 
-       def export(self, scene, world, alltextures):
+       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) # This seems to position me in some strange area I cant see the model (with BS Contact) - Campbell
+               self.writeScript()
+               self.writeNavigationInfo(scene)
                self.writeBackground(world, alltextures)
                self.writeFog(world)
                self.proto = 0
                
-               for ob in scene.objects.context:
-                       objType=ob.type
-                       objName=ob.name
-                       self.matonly = 0
-                       if objType == "Camera":
-                               self.writeViewpoint(ob, scene)
-                       elif objType == "Mesh":
-                               self.writeIndexedFaceSet(ob, world, normals = 0)
-                       elif objType == "Lamp":
-                               data= ob.data
-                               datatype=data.type
-                               if datatype == Lamp.Types.Lamp:
-                                       self.writePointLight(ob, data, world)
-                               elif datatype == Lamp.Types.Spot:
-                                       self.writeSpotLight(ob, data, world)
-                               elif datatype == Lamp.Types.Sun:
-                                       self.writeDirectionalLight(ob, data, world)
+               
+               # 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:
-                                       self.writeDirectionalLight(ob, data, world)
-                       elif objType == "Empty" and objName != "Empty":
-                               self.writeNode(ob)
-                       else:
-                               #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
-                               print ""
+                                       #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
+                                       pass
                
-               if ARG != 'selected':
-                       self.writeScript()
                self.file.write("\n</Scene>\n</X3D>")
+               
+               if EXPORT_APPLY_MODIFIERS:
+                       if containerMesh:
+                               containerMesh.verts = None
+               
                self.cleanup()
                
 ##########################################################
@@ -837,10 +881,10 @@ class VRML2Export:
                        round(c.b/255.0,self.cp))
                return s
 
-       def computeDirection(self, ob):
+       def computeDirection(self, mtx):
                x,y,z=(0,-1.0,0) # point down
                
-               ax,ay,az = (ob.matrixWorld*MATWORLD).toEuler()
+               ax,ay,az = (mtx*MATWORLD).toEuler()
                
                ax *= DEG2RAD
                ay *= DEG2RAD
@@ -931,7 +975,36 @@ class VRML2Export:
 # Callbacks, needed before Main
 ##########################################################
 
-def select_file(filename):
+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):
@@ -939,18 +1012,40 @@ def select_file(filename):
        #if(result != 1):
        #       return
        
-       scene = Blender.Scene.GetCurrent()
-       world = scene.world
-       alltextures = Blender.Texture.Get()
+       # 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)
 
-       wrlexport=VRML2Export(filename)
-       wrlexport.export(scene, world, alltextures)
 
 
 #########################################################
 # main routine
 #########################################################
 
+
 if __name__ == '__main__':
-       Blender.Window.FileSelector(select_file,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
-       # select_file('/shared/bed1.x3d')
+       Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
+
+
index 230b7080b38668fb23129ef14c6068a6c91712b3..81f496e97d6dfbdeb518b2a3e0305e1e4980dc23 100644 (file)
@@ -383,7 +383,8 @@ static void setup_app_data(BlendFileData *bfd, char *filename)
        /* special cases, override loaded flags: */
        if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG;
        else bfd->globalf &= ~G_DEBUG;
-       if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS;
+
+       if ((U.flag & USER_DONT_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS;
 
        G.f= bfd->globalf;
 
index c45571cb5834673c78d2c16f47a24b1eef0f019e..acc1651e9fa8af2862a048ecf559d1834f251bd1 100644 (file)
@@ -224,7 +224,7 @@ extern UserDef U; /* from usiblender.c !!!! */
 #define USER_DUPLILINK                 (1 << 6)
 #define USER_FSCOLLUM                  (1 << 7)
 #define USER_MAT_ON_OB                 (1 << 8)
-#define USER_NO_CAPSLOCK               (1 << 9)
+/*#define USER_NO_CAPSLOCK             (1 << 9)*/ /* not used anywhere */
 #define USER_VIEWMOVE                  (1 << 10)
 #define USER_TOOLTIPS                  (1 << 11)
 #define USER_TWOBUTTONMOUSE            (1 << 12)
@@ -236,7 +236,8 @@ extern UserDef U; /* from usiblender.c !!!! */
 #define USER_ADD_EDITMODE              (1 << 18)
 #define USER_ADD_VIEWALIGNED   (1 << 19)
 #define USER_RELPATHS                  (1 << 20)
-#define USER_DRAGIMMEDIATE                     (1 << 21)
+#define USER_DRAGIMMEDIATE             (1 << 21)
+#define USER_DONT_DOSCRIPTLINKS        (1 << 22)
 
 /* viewzom */
 #define USER_ZOOM_CONT                 0
index 292b1f1bc1e343eb7dd06823ea1208d932d84f79..e396e0787391e2c2e395741c9f3147ea2f9d961b 100644 (file)
@@ -4158,9 +4158,9 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                        (xpos+edgsp+(1*midsp)+(1*mpref)),y6label,mpref,buth,
                        0, 0, 0, 0, 0, "");
 
-               uiDefButBitI(block, TOG, G_DOSCRIPTLINKS, REDRAWBUTSSCRIPT, "Enabled by Default",
+               uiDefButBitI(block, TOGN, USER_DONT_DOSCRIPTLINKS, REDRAWBUTSSCRIPT, "Enabled by Default",
                        (xpos+edgsp+(1*mpref)+(1*midsp)),y5,mpref,buth,
-                       &(G.f), 0, 0, 0, 0, "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)");
+                       &(U.flag), 0, 0, 0, 0, "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)");
                
                uiDefBut(block, LABEL,0,"Keyboard:",
                        (xpos+edgsp+(3*midsp)+(3*mpref)),y2label,mpref,buth,