~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to release/scripts/vrml97_export.py

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!BPY
 
2
""" Registration info for Blender menus:
 
3
Name: 'VRML97 (.wrl)...'
 
4
Blender: 241
 
5
Group: 'Export'
 
6
Tooltip: 'Export to VRML97 file (.wrl)'
 
7
"""
 
8
 
 
9
__author__ = ("Rick Kimball", "Ken Miller", "Steve Matthews", "Bart")
 
10
__url__ = ["blender", "blenderartists.org",
 
11
"Author's (Rick) homepage, http://kimballsoftware.com/blender",
 
12
"Author's (Bart) homepage, http://www.neeneenee.de/vrml"]
 
13
__email__ = ["Bart, bart:neeneenee*de"]
 
14
__version__ = "2006/01/17"
 
15
__bpydoc__ = """\
 
16
This script exports to VRML97 format.
 
17
 
 
18
Usage:
 
19
 
 
20
Run this script from "File->Export" menu.  A pop-up will ask whether you
 
21
want to export only selected or all relevant objects.
 
22
"""
 
23
 
 
24
 
 
25
# $Id: vrml97_export.py 16949 2008-10-06 17:11:10Z hos $
 
26
#
 
27
#------------------------------------------------------------------------
 
28
# VRML97 exporter for blender 2.36 or above
 
29
#
 
30
# ***** BEGIN GPL LICENSE BLOCK *****
 
31
#
 
32
# This program is free software; you can redistribute it and/or
 
33
# modify it under the terms of the GNU General Public License
 
34
# as published by the Free Software Foundation; either version 2
 
35
# of the License, or (at your option) any later version.
 
36
#
 
37
# This program is distributed in the hope that it will be useful,
 
38
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
39
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
40
# GNU General Public License for more details.
 
41
#
 
42
# You should have received a copy of the GNU General Public License
 
43
# along with this program; if not, write to the Free Software Foundation,
 
44
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
45
#
 
46
# ***** END GPL LICENCE BLOCK *****
 
47
#
 
48
 
 
49
####################################
 
50
# Library dependancies
 
51
####################################
 
52
 
 
53
import Blender
 
54
from Blender import Object, Mesh, Lamp, Draw, BGL, \
 
55
         Image, Text, sys, Mathutils, Registry
 
56
from Blender.Scene import Render
 
57
 
 
58
import math
 
59
 
 
60
####################################
 
61
# Global Variables
 
62
####################################
 
63
 
 
64
scene = Blender.Scene.getCurrent()
 
65
world = Blender.World.GetCurrent() 
 
66
worldmat = Blender.Texture.Get()
 
67
filename = Blender.Get('filename')
 
68
_safeOverwrite = True
 
69
extension = ''
 
70
 
 
71
# Matrices below are used only when export_rotate_z_to_y.val:
 
72
#
 
73
# Blender is Z up, VRML is Y up, both are right hand coordinate
 
74
# systems, so to go from Blender coords to VRML coords we rotate
 
75
# by 90 degrees around the X axis. In matrix notation, we have a
 
76
# matrix, and it's inverse, as:
 
77
M_blen2vrml = Mathutils.Matrix([1,0,0,0], \
 
78
                                                           [0,0,1,0], \
 
79
                                                           [0,-1,0,0], \
 
80
                                                           [0,0,0,1])
 
81
M_vrml2blen = Mathutils.Matrix([1,0,0,0], \
 
82
                                                           [0,0,-1,0], \
 
83
                                                           [0,1,0,0], \
 
84
                                                           [0,0,0,1])
 
85
 
 
86
 
 
87
class DrawTypes:
 
88
        """Object DrawTypes enum values
 
89
    BOUNDS - draw only the bounding box of the object
 
90
    WIRE - draw object as a wire frame
 
91
    SOLID - draw object with flat shading
 
92
    SHADED - draw object with OpenGL shading
 
93
"""
 
94
        BOUNDBOX  = 1
 
95
        WIRE      = 2
 
96
        SOLID     = 3
 
97
        SHADED    = 4
 
98
        TEXTURE   = 5
 
99
 
 
100
if not hasattr(Blender.Object,'DrawTypes'):
 
101
        Blender.Object.DrawTypes = DrawTypes()
 
102
 
 
103
##########################################################
 
104
# Functions for writing output file
 
105
##########################################################
 
106
 
 
107
class VRML2Export:
 
108
 
 
109
        def __init__(self, filename):
 
110
                #--- public you can change these ---
 
111
                self.wire = 0
 
112
                self.proto = 1
 
113
                self.facecolors = 0
 
114
                self.vcolors = 0
 
115
                self.billnode = 0
 
116
                self.halonode = 0
 
117
                self.collnode = 0
 
118
                self.tilenode = 0
 
119
                self.wire     = 0
 
120
                self.twosided = 0
 
121
 
 
122
                # level of verbosity in console 0-none, 1-some, 2-most
 
123
                try:
 
124
                        rt = Blender.Get('rt')
 
125
                        if (rt == 42):
 
126
                                self.verbose = 1
 
127
                        elif (rt == 43):
 
128
                                self.verbose = 2
 
129
                        else:
 
130
                                self.verbose = 0
 
131
                except:
 
132
                        self.verbose = 0
 
133
                        
 
134
                # decimals for material color values     0.000 - 1.000
 
135
                self.cp=7
 
136
                # decimals for vertex coordinate values  0.000 - n.000
 
137
                self.vp=7
 
138
                # decimals for texture coordinate values 0.000 - 1.000
 
139
                self.tp=7
 
140
                
 
141
                #--- class private don't touch ---
 
142
                self.texNames={}   # dictionary of textureNames
 
143
                self.matNames={}   # dictionary of materialNames
 
144
                self.meshNames={}   # dictionary of meshNames
 
145
                self.coordNames={}   # dictionary of coordNames
 
146
                self.indentLevel=0 # keeps track of current indenting
 
147
                self.filename=filename
 
148
                self.file = open(filename, "w")
 
149
                self.bNav=0
 
150
                self.nodeID=0
 
151
                self.namesReserved=[ "Anchor", "Appearance", "AudioClip",
 
152
                                                         "Background","Billboard", "Box",
 
153
                                                         "Collision", "Color", "ColorInterpolator",
 
154
                                                         "Cone", "Coordinate",
 
155
                                                         "CoordinateInterpolator", "Cylinder",
 
156
                                                         "CylinderSensor",
 
157
                                                         "DirectionalLight",
 
158
                                                         "ElevationGrid", "Extrustion",
 
159
                                                         "Fog", "FontStyle", "Group",
 
160
                                                         "ImageTexture", "IndexedFaceSet",
 
161
                                                         "IndexedLineSet", "Inline",
 
162
                                                         "LOD", "Material", "MovieTexture",
 
163
                                                         "NavigationInfo", "Normal",
 
164
                                                         "NormalInterpolator",
 
165
                                                         "OrientationInterpolator", "PixelTexture",
 
166
                                                         "PlaneSensor", "PointLight", "PointSet",
 
167
                                                         "PositionInterpolator", "ProxmimitySensor",
 
168
                                                         "ScalarInterpolator", "Script", "Shape",
 
169
                                                         "Sound", "Sphere", "SphereSensor",
 
170
                                                         "SpotLight", "Switch", "Text",
 
171
                                                         "TextureCoordinate", "TextureTransform",
 
172
                                                         "TimeSensor", "TouchSensor", "Transform",
 
173
                                                         "Viewpoint", "VisibilitySensor", "WorldInfo" ]
 
174
                self.namesStandard=[ "Empty", "Empty.000", "Empty.001",
 
175
                                                         "Empty.002", "Empty.003", "Empty.004",
 
176
                                                         "Empty.005", "Empty.006", "Empty.007",
 
177
                                                         "Empty.008", "Empty.009", "Empty.010",
 
178
                                                         "Empty.011", "Empty.012",
 
179
                                                         "Scene.001", "Scene.002", "Scene.003",
 
180
                                                         "Scene.004", "Scene.005", "Scene.06",
 
181
                                                         "Scene.013", "Scene.006", "Scene.007",
 
182
                                                         "Scene.008", "Scene.009", "Scene.010",
 
183
                                                         "Scene.011","Scene.012",
 
184
                                                         "World", "World.000", "World.001",
 
185
                                                         "World.002", "World.003", "World.004",
 
186
                                                         "World.005" ]
 
187
                self.namesFog=[ "", "LINEAR"," EXPONENTIAL", "" ]
 
188
 
 
189
##########################################################
 
190
# Writing nodes routines
 
191
##########################################################
 
192
 
 
193
        def writeHeader(self):
 
194
                bfile = sys.expandpath(Blender.Get('filename'))
 
195
                self.file.write("#VRML V2.0 utf8\n\n")
 
196
                self.file.write("# This file was authored with Blender " \
 
197
                                                "(http://www.blender.org/)\n")
 
198
                self.file.write("# Blender version %s\n" % Blender.Get('version'))
 
199
                self.file.write("# Blender file %s\n" % sys.basename(bfile))
 
200
                self.file.write("# Exported using VRML97 exporter " \
 
201
                                                "v1.55 (2006/01/17)\n\n")
 
202
 
 
203
        def writeInline(self):
 
204
                inlines = Blender.Scene.Get()
 
205
                allinlines = len(inlines)
 
206
                if scene != inlines[0]:
 
207
                        return
 
208
                else:
 
209
                        for i in xrange(allinlines):
 
210
                                nameinline=inlines[i].getName()
 
211
                                if (nameinline not in self.namesStandard) and (i > 0):
 
212
                                        self.writeIndented("DEF %s Inline {\n" % \
 
213
                                                                           (self.cleanStr(nameinline)), 1)
 
214
                                        nameinline = nameinline+".wrl"
 
215
                                        self.writeIndented("url \"%s\" \n" % nameinline)
 
216
                                        self.writeIndented("}\n", -1)
 
217
                                        self.writeIndented("\n")
 
218
 
 
219
        def writeScript(self):
 
220
                textEditor = Blender.Text.Get() 
 
221
                alltext = len(textEditor)
 
222
                for i in xrange(alltext):
 
223
                        nametext = textEditor[i].getName()
 
224
                        nlines = textEditor[i].getNLines()
 
225
                        if (self.proto == 1):
 
226
                                if (nametext == "proto" or nametext == "proto.js" or \
 
227
                                        nametext == "proto.txt") and (nlines != None):
 
228
                                        nalllines = len(textEditor[i].asLines())
 
229
                                        alllines = textEditor[i].asLines()
 
230
                                        for j in xrange(nalllines):
 
231
                                                self.writeIndented(alllines[j] + "\n")
 
232
                        elif (self.proto == 0):
 
233
                                if (nametext == "route" or nametext == "route.js" or \
 
234
                                        nametext == "route.txt") and (nlines != None):
 
235
                                        nalllines = len(textEditor[i].asLines())
 
236
                                        alllines = textEditor[i].asLines()
 
237
                                        for j in xrange(nalllines):
 
238
                                                self.writeIndented(alllines[j] + "\n")
 
239
                self.writeIndented("\n")
 
240
 
 
241
        def writeViewpoint(self, thisObj):
 
242
                # NOTE: The transform node above this will take care of
 
243
                # the position and orientation of the camera
 
244
                context = scene.getRenderingContext()
 
245
                ratio = float(context.imageSizeY()) / float(context.imageSizeX())
 
246
                temp  = ratio * 16 / thisObj.data.getLens()
 
247
                lens = 2 * math.atan(temp)
 
248
                lens = min(lens, math.pi) 
 
249
 
 
250
                self.writeIndented("DEF %s Viewpoint {\n" % \
 
251
                                                   (self.cleanStr(thisObj.name)), 1)
 
252
                self.writeIndented('description "%s" \n' % thisObj.name)
 
253
                self.writeIndented("position 0.0 0.0 0.0\n")
 
254
                # Need camera to point to -y in local space to accomodate
 
255
                # the transforma node above
 
256
                self.writeIndented("orientation 1.0 0.0 0.0 %f\n" % (-math.pi/2.0))
 
257
                self.writeIndented("fieldOfView %.3f\n" % (lens))
 
258
                self.writeIndented("}\n", -1)
 
259
                self.writeIndented("\n")
 
260
 
 
261
        def writeFog(self):
 
262
                if world:
 
263
                        mtype = world.getMistype()
 
264
                        mparam = world.getMist()
 
265
                        grd = world.getHor()
 
266
                        grd0, grd1, grd2 = grd[0], grd[1], grd[2]
 
267
                else:
 
268
                        return
 
269
                if (mtype == 1 or mtype == 2):
 
270
                        self.writeIndented("Fog {\n",1)
 
271
                        self.writeIndented('fogType "%s"\n' % self.namesFog[mtype])
 
272
                        self.writeIndented("color %s %s %s\n" % \
 
273
                                                           (round(grd0,self.cp), \
 
274
                                                                round(grd1,self.cp), \
 
275
                                                                round(grd2,self.cp)))
 
276
                        self.writeIndented("visibilityRange %s\n" % \
 
277
                                                           round(mparam[2],self.cp))  
 
278
                        self.writeIndented("}\n",-1)
 
279
                        self.writeIndented("\n")   
 
280
                else:
 
281
                        return
 
282
 
 
283
        def writeNavigationInfo(self, scene):
 
284
                allObj = []
 
285
                allObj = list(scene.objects)
 
286
                headlight = "TRUE"
 
287
                vislimit = 0.0
 
288
                for thisObj in allObj:
 
289
                        objType=thisObj.type
 
290
                        if objType == "Camera":
 
291
                                vislimit = thisObj.data.getClipEnd()
 
292
                        elif objType == "Lamp":
 
293
                                headlight = "FALSE"
 
294
                self.writeIndented("NavigationInfo {\n",1)
 
295
                self.writeIndented("headlight %s\n" % headlight)
 
296
                self.writeIndented("visibilityLimit %s\n" % \
 
297
                                                   (round(vislimit,self.cp)))
 
298
                self.writeIndented("type [\"EXAMINE\", \"ANY\"]\n")            
 
299
                self.writeIndented("avatarSize [0.25, 1.75, 0.75]\n")
 
300
                self.writeIndented("} \n",-1)
 
301
                self.writeIndented(" \n")
 
302
 
 
303
        def writeSpotLight(self, object, lamp):
 
304
                # Note: location and orientation are handled by the
 
305
                # transform node above this object
 
306
                if world:
 
307
                        ambi = world.getAmb()
 
308
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
 
309
                else:
 
310
                        ambi = 0
 
311
                        ambientIntensity = 0
 
312
 
 
313
                # compute cutoff and beamwidth
 
314
                intensity=min(lamp.energy/1.75,1.0)
 
315
                beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
 
316
                cutOffAngle=beamWidth*1.3
 
317
 
 
318
                radius = lamp.dist*math.cos(beamWidth)
 
319
                self.writeIndented("DEF %s SpotLight {\n" % \
 
320
                                                   self.cleanStr(object.name),1)
 
321
                self.writeIndented("radius %s\n" % (round(radius,self.cp)))
 
322
                self.writeIndented("ambientIntensity %s\n" % \
 
323
                                                   (round(ambientIntensity,self.cp)))
 
324
                self.writeIndented("intensity %s\n" % (round(intensity,self.cp)))
 
325
                self.writeIndented("color %s %s %s\n" % \
 
326
                                                   (round(lamp.col[0],self.cp), \
 
327
                                                        round(lamp.col[1],self.cp), \
 
328
                                                        round(lamp.col[2],self.cp)))
 
329
                self.writeIndented("beamWidth %s\n" % (round(beamWidth,self.cp)))
 
330
                self.writeIndented("cutOffAngle %s\n" % \
 
331
                                                   (round(cutOffAngle,self.cp)))
 
332
                # Note: point down -Y axis, transform node above will rotate
 
333
                self.writeIndented("direction 0.0 -1.0 0.0\n")
 
334
                self.writeIndented("location 0.0 0.0 0.0\n")
 
335
                self.writeIndented("}\n",-1)
 
336
                self.writeIndented("\n")
 
337
                
 
338
        def writeDirectionalLight(self, object, lamp):
 
339
                # Note: location and orientation are handled by the
 
340
                # transform node above this object
 
341
                if world:
 
342
                        ambi = world.getAmb()
 
343
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
 
344
                else:
 
345
                        ambi = 0
 
346
                        ambientIntensity = 0
 
347
 
 
348
                intensity=min(lamp.energy/1.75,1.0) 
 
349
                self.writeIndented("DEF %s DirectionalLight {\n" % \
 
350
                                                   self.cleanStr(object.name),1)
 
351
                self.writeIndented("ambientIntensity %s\n" % \
 
352
                                                   (round(ambientIntensity,self.cp)))
 
353
                self.writeIndented("color %s %s %s\n" % \
 
354
                                                   (round(lamp.col[0],self.cp), \
 
355
                                                        round(lamp.col[1],self.cp), \
 
356
                                                        round(lamp.col[2],self.cp)))
 
357
                self.writeIndented("intensity %s\n" % \
 
358
                                                   (round(intensity,self.cp)))
 
359
                # Note: point down -Y axis, transform node above will rotate
 
360
                self.writeIndented("direction 0.0 -1.0 0.0\n")
 
361
                self.writeIndented("}\n",-1)
 
362
                self.writeIndented("\n")
 
363
 
 
364
        def writePointLight(self, object, lamp):
 
365
                # Note: location is at origin because parent transform node
 
366
                # takes care of this
 
367
                if world:
 
368
                        ambi = world.getAmb()
 
369
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
 
370
                else:
 
371
                        ambi = 0
 
372
                        ambientIntensity = 0
 
373
                om = object.getMatrix()
 
374
                intensity=min(lamp.energy/1.75,1.0) 
 
375
                radius = lamp.dist
 
376
                self.writeIndented("DEF %s PointLight {\n" % \
 
377
                                                   self.cleanStr(object.name),1)
 
378
                self.writeIndented("ambientIntensity %s\n" % \
 
379
                                                   (round(ambientIntensity,self.cp)))
 
380
                self.writeIndented("color %s %s %s\n" % \
 
381
                                                   (round(lamp.col[0],self.cp), \
 
382
                                                        round(lamp.col[1],self.cp), \
 
383
                                                        round(lamp.col[2],self.cp)))
 
384
                self.writeIndented("intensity %s\n" % (round(intensity,self.cp)))
 
385
                self.writeIndented("location 0.0 0.0 0.0\n")
 
386
                self.writeIndented("radius %s\n" % radius )
 
387
                self.writeIndented("}\n",-1)
 
388
                self.writeIndented("\n")
 
389
 
 
390
        def writeNode(self, thisObj):
 
391
                # Note: location and orientation are handled by the
 
392
                # transform node above this object
 
393
                objectname=str(thisObj.getName())
 
394
                if objectname in self.namesStandard:
 
395
                        return
 
396
                else:
 
397
                        self.writeIndented("%s {\n" % objectname,1)
 
398
                        # May need to check that the direction is done right
 
399
                        self.writeIndented("direction 0.0 -1.0 0.0\n")
 
400
                        self.writeIndented("location 0.0 0.0 0.0\n")
 
401
                        self.writeIndented("}\n",-1)
 
402
                        self.writeIndented("\n")
 
403
 
 
404
        def secureName(self, name):
 
405
                name = name + str(self.nodeID)
 
406
                self.nodeID += 1
 
407
                if len(name) <= 3:
 
408
                        newname = "_" + str(self.nodeID)
 
409
                        return "%s" % (newname)
 
410
                else:
 
411
                        for bad in ['"','#',"'",',','.','[','\\',']','{','}']:
 
412
                                name=name.replace(bad,'_')
 
413
                        if name in self.namesReserved:
 
414
                                newname = name[0:3] + "_" + str(self.nodeID)
 
415
                                return "%s" % (newname)
 
416
                        elif name[0].isdigit():
 
417
                                newname = "_" + name + str(self.nodeID)
 
418
                                return "%s" % (newname)
 
419
                        else:
 
420
                                newname = name
 
421
                                return "%s" % (newname)
 
422
 
 
423
        def classifyMesh(self, me, ob):
 
424
                self.halonode = 0
 
425
                self.billnode = 0
 
426
                self.facecolors = 0
 
427
                self.vcolors = 0
 
428
                self.tilenode = 0
 
429
                self.colnode = 0
 
430
                self.wire = 0
 
431
                if me.faceUV:
 
432
                        for face in me.faces:
 
433
                                if (face.mode & Mesh.FaceModes['HALO']):
 
434
                                        self.halonode = 1
 
435
                                if (face.mode & Mesh.FaceModes['BILLBOARD']):
 
436
                                        self.billnode = 1
 
437
                                if (face.mode & Mesh.FaceModes['OBCOL']):
 
438
                                        self.facecolors = 1
 
439
                                if (face.mode & Mesh.FaceModes['SHAREDCOL']):
 
440
                                        self.vcolors = 1
 
441
                                if (face.mode & Mesh.FaceModes['TILES']):
 
442
                                        self.tilenode = 1
 
443
                                if not (face.mode & Mesh.FaceModes['DYNAMIC']):
 
444
                                        self.collnode = 1
 
445
                                if (face.mode & Mesh.FaceModes['TWOSIDE']):
 
446
                                        self.twosided = 1
 
447
 
 
448
                # Bit of a crufty trick, but if mesh has vertex colors
 
449
                # (as a non-face property) and if first material has
 
450
                # vcol paint set, we export the vertex colors
 
451
                if (me.vertexColors):
 
452
                        if len(me.materials) > 0:
 
453
                                mat = me.materials[0]
 
454
                                if mat:
 
455
                                        if (mat.mode & Blender.Material.Modes['VCOL_PAINT']):
 
456
                                                self.vcolors = 1
 
457
                else:
 
458
                        self.vcolors = 0
 
459
                        
 
460
                # check if object is wireframe only
 
461
                if ob.drawType == Blender.Object.DrawTypes.WIRE:
 
462
                        # user selected WIRE=2 on the Drawtype=Wire on (F9) Edit page
 
463
                        self.wire = 1
 
464
 
 
465
        ###
 
466
        ### The next few functions nest Collision/Billboard/Halo nodes.
 
467
        ### For real mesh data export, jump down to writeMeshData()
 
468
        ###
 
469
        def writeMesh(self, ob, normals = 0):
 
470
 
 
471
                imageMap={}   # set of used images
 
472
                sided={}      # 'one':cnt , 'two':cnt
 
473
                vColors={}    # 'multi':1
 
474
 
 
475
                if (len(ob.modifiers) > 0):
 
476
                        me = Mesh.New()
 
477
                        me.getFromObject(ob.name)
 
478
                        # Careful with the name, the temporary mesh may
 
479
                        # reuse the default name for other meshes. So we
 
480
                        # pick our own name.
 
481
                        me.name = "MOD_%s" % (ob.name)
 
482
                else:
 
483
                        me = ob.getData(mesh = 1)
 
484
 
 
485
                self.classifyMesh(me, ob)
 
486
 
 
487
                if (self.collnode):
 
488
                        self.writeCollisionMesh(me, ob, normals)
 
489
                        return
 
490
                else:
 
491
                        self.writeRegularMesh(me, ob, normals)
 
492
                        return
 
493
 
 
494
        def writeCollisionMesh(self, me, ob, normals = 0):
 
495
                self.writeIndented("Collision {\n",1)
 
496
                self.writeIndented("collide FALSE\n")
 
497
                self.writeIndented("children [\n")
 
498
 
 
499
                self.writeRegularMesh(me, ob, normals)
 
500
 
 
501
                self.writeIndented("]\n", -1)
 
502
                self.writeIndented("}\n", -1)
 
503
                
 
504
        def writeRegularMesh(self, me, ob, normals = 0):
 
505
                if (self.billnode):
 
506
                        self.writeBillboardMesh(me, ob, normals)
 
507
                elif (self.halonode):
 
508
                        self.writeHaloMesh(me, ob, normals)
 
509
                else:
 
510
                        self.writeMeshData(me, ob, normals)
 
511
 
 
512
        def writeBillboardMesh(self, me, ob, normals = 0):
 
513
                self.writeIndented("Billboard {\n",1)
 
514
                self.writeIndented("axisOfRotation 0 1 0\n")
 
515
                self.writeIndented("children [\n")
 
516
 
 
517
                self.writeMeshData(me, ob, normals)
 
518
 
 
519
                self.writeIndented("]\n", -1)
 
520
                self.writeIndented("}\n", -1)
 
521
                
 
522
        def writeHaloMesh(self, me, ob, normals = 0):
 
523
                self.writeIndented("Billboard {\n",1)
 
524
                self.writeIndented("axisOfRotation 0 0 0\n")
 
525
                self.writeIndented("children [\n")
 
526
 
 
527
                self.writeMeshData(me, ob, normals)
 
528
 
 
529
                self.writeIndented("]\n", -1)
 
530
                self.writeIndented("}\n", -1)
 
531
 
 
532
        ###
 
533
        ### Here is where real mesh data is written
 
534
        ### 
 
535
        def writeMeshData(self, me, ob, normals = 0):
 
536
                meshName = self.cleanStr(me.name)
 
537
 
 
538
                if self.meshNames.has_key(meshName):
 
539
                        self.writeIndented("USE ME_%s\n" % meshName, 0)
 
540
                        self.meshNames[meshName]+=1
 
541
                        if (self.verbose == 1):
 
542
                                print "  Using Mesh %s (Blender mesh: %s)\n" % \
 
543
                                          (meshName, me.name)
 
544
                        return
 
545
                self.meshNames[meshName]=1
 
546
 
 
547
                if (self.verbose == 1):
 
548
                        print "  Writing Mesh %s (Blender mesh: %s)\n" % \
 
549
                                  (meshName, me.name)
 
550
                        return
 
551
 
 
552
                self.writeIndented("DEF ME_%s Group {\n" % meshName,1)
 
553
                self.writeIndented("children [\n", 1)
 
554
                        
 
555
                hasImageTexture = 0
 
556
                issmooth = 0
 
557
 
 
558
                maters = me.materials
 
559
                nummats = len(me.materials)
 
560
 
 
561
                # Vertex and Face colors trump materials and image textures
 
562
                if (self.facecolors or self.vcolors):
 
563
                        if nummats > 0:
 
564
                                self.writeShape(ob, me, 0, None)
 
565
                        else:
 
566
                                self.writeShape(ob, me, -1, None)
 
567
 
 
568
                # Do meshes with materials, possibly with image textures
 
569
                elif nummats > 0:
 
570
                        for matnum in xrange(len(maters)):
 
571
                                images = []
 
572
                                if me.faceUV:
 
573
                                        images = self.getImages(me, matnum)
 
574
                                        if len(images) > 0:
 
575
                                                for image in images:
 
576
                                                        self.writeShape(ob, me, matnum, image)
 
577
                                        else:
 
578
                                                self.writeShape(ob, me, matnum, None)
 
579
                                else:
 
580
                                        self.writeShape(ob, me, matnum, None)
 
581
                else:
 
582
                        if me.faceUV:
 
583
                                images = self.getImages(me, -1)
 
584
                                if len(images) > 0:
 
585
                                        for image in images:
 
586
                                                self.writeShape(ob, me, -1, image)
 
587
                                else:
 
588
                                        self.writeShape(ob, me, -1, None)
 
589
                        else:
 
590
                                self.writeShape(ob, me, -1, None)
 
591
 
 
592
                        
 
593
                self.writeIndented("]\n", -1)
 
594
                self.writeIndented("}\n", -1)
 
595
 
 
596
        def getImages(self, me, matnum):
 
597
                imageNames = {}
 
598
                images = []
 
599
                for face in me.faces:
 
600
                        if (matnum == -1) or (face.mat == matnum):
 
601
                                if (face.image):
 
602
                                        imName = self.cleanStr(face.image.name)
 
603
                                        if not imageNames.has_key(imName):
 
604
                                                images.append(face.image)
 
605
                                                imageNames[imName]=1
 
606
                return images
 
607
 
 
608
        def writeCoordinates(self, me, meshName):
 
609
                coordName = "coord_%s" % (meshName)
 
610
                # look up coord name, use it if available
 
611
                if self.coordNames.has_key(coordName):
 
612
                        self.writeIndented("coord USE %s\n" % coordName, 0)
 
613
                        self.coordNames[coordName]+=1
 
614
                        return;
 
615
        
 
616
                self.coordNames[coordName]=1
 
617
 
 
618
                #-- vertices
 
619
                self.writeIndented("coord DEF %s Coordinate {\n" % (coordName), 1)
 
620
                self.writeIndented("point [\n", 1)
 
621
                meshVertexList = me.verts
 
622
 
 
623
                for vertex in meshVertexList:
 
624
                        vrmlvert = blenvert = Mathutils.Vector(vertex.co)
 
625
                        if export_rotate_z_to_y.val:
 
626
                                vrmlvert = M_blen2vrml * vrmlvert
 
627
                        self.writeUnindented("%s %s %s\n " % \
 
628
                                                                 (vrmlvert[0], \
 
629
                                                                  vrmlvert[1], \
 
630
                                                                  vrmlvert[2]))
 
631
                self.writeIndented("]\n", -1)
 
632
                self.writeIndented("}\n", -1)
 
633
                self.writeIndented("\n")
 
634
 
 
635
        def testShape(self, ob, me, matnum, image):
 
636
                if ( (matnum == -1) and (image == None) ):
 
637
                        if ( len(me.faces) > 0 ):
 
638
                                return True
 
639
                # Check if any faces the material or image
 
640
                for face in me.faces:
 
641
                        if (matnum == -1):
 
642
                                if (f.image == image):
 
643
                                        return True
 
644
                        elif (image == None):
 
645
                                if (face.mat == matnum):
 
646
                                        return True
 
647
                        else:
 
648
                                if ((face.image == image) and (face.mat == matnum)):
 
649
                                        return True
 
650
 
 
651
                return False
 
652
 
 
653
        def writeShape(self, ob, me, matnum, image):
 
654
                # matnum == -1  means don't check the face.mat
 
655
                # image == None means don't check face.image
 
656
 
 
657
                if ( not self.testShape(ob, me, matnum, image) ):
 
658
                        return False
 
659
 
 
660
                self.writeIndented("Shape {\n",1)
 
661
 
 
662
                self.writeIndented("appearance Appearance {\n", 1)
 
663
                if (matnum != -1):
 
664
                        mater = me.materials[matnum]
 
665
                        if (mater):
 
666
                                self.writeMaterial(mater, self.cleanStr(mater.name,''))
 
667
                                if (mater.mode & Blender.Material.Modes['TEXFACE']):
 
668
                                        if image != None:
 
669
                                                self.writeImageTexture(image.name, image.filename)
 
670
                        else:
 
671
                                self.writeDefaultMaterial()     
 
672
                else:
 
673
                        if image != None:
 
674
                                self.writeImageTexture(image.name, image.filename)
 
675
 
 
676
                self.writeIndented("}\n", -1)
 
677
 
 
678
                self.writeGeometry(ob, me, matnum, image)
 
679
 
 
680
                self.writeIndented("}\n", -1)
 
681
 
 
682
                return True
 
683
 
 
684
        def writeGeometry(self, ob, me, matnum, image):
 
685
 
 
686
                #-- IndexedFaceSet or IndexedLineSet
 
687
                meshName = self.cleanStr(me.name)
 
688
 
 
689
                # check if object is wireframe only
 
690
                if (self.wire):
 
691
                        ifStyle="IndexedLineSet"
 
692
                else:
 
693
                        # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5
 
694
                        ifStyle="IndexedFaceSet"
 
695
 
 
696
                self.writeIndented("geometry %s {\n" % ifStyle, 1)
 
697
                if not self.wire:
 
698
                        if self.twosided == 1:
 
699
                                self.writeIndented("solid FALSE\n")
 
700
                        else:
 
701
                                self.writeIndented("solid TRUE\n")
 
702
 
 
703
                self.writeCoordinates(me, meshName)
 
704
                self.writeCoordIndex(me, meshName, matnum, image)
 
705
                self.writeTextureCoordinates(me, meshName, matnum, image)
 
706
                if self.facecolors:
 
707
                        self.writeFaceColors(me)
 
708
                elif self.vcolors:
 
709
                        self.writeVertexColors(me)
 
710
                self.writeIndented("}\n", -1)
 
711
 
 
712
        def writeCoordIndex(self, me, meshName, matnum, image):
 
713
                meshVertexList = me.verts
 
714
                self.writeIndented("coordIndex [\n", 1)
 
715
                coordIndexList=[]  
 
716
                for face in me.faces:
 
717
                        if (matnum == -1) or (face.mat == matnum):
 
718
                                if (image == None) or (face.image == image):
 
719
                                        cordStr=""
 
720
                                        for v in face.verts:
 
721
                                                indx=v.index
 
722
                                                cordStr = cordStr + "%s " % indx
 
723
                                        self.writeUnindented(cordStr + "-1, \n")
 
724
                self.writeIndented("]\n", -1)
 
725
 
 
726
        def writeTextureCoordinates(self, me, meshName, matnum, image):
 
727
                if (image == None):
 
728
                        return
 
729
                
 
730
                texCoordList=[] 
 
731
                texIndexList=[]
 
732
                j=0
 
733
 
 
734
                for face in me.faces:
 
735
                        coordStr = ""
 
736
                        indexStr = ""
 
737
                        if (matnum == -1) or (face.mat == matnum):
 
738
                                if (face.image == image):
 
739
                                        for i in xrange(len(face.verts)):
 
740
                                                uv = face.uv[i]
 
741
                                                indexStr += "%s " % (j)
 
742
                                                coordStr += "%s %s, " % \
 
743
                                                                        (round(uv[0], self.tp), \
 
744
                                                                         round(uv[1], self.tp))
 
745
                                                j=j+1
 
746
                                        indexStr += "-1"
 
747
                                        texIndexList.append(indexStr)
 
748
                                        texCoordList.append(coordStr)
 
749
 
 
750
                self.writeIndented("texCoord TextureCoordinate {\n", 1)
 
751
                self.writeIndented("point [\n", 1)
 
752
                for coord in texCoordList:
 
753
                        self.writeUnindented("%s\n" % (coord))
 
754
                self.writeIndented("]\n", -1)
 
755
                self.writeIndented("}\n", -1)
 
756
 
 
757
                self.writeIndented("texCoordIndex [\n", 1)
 
758
                for ind in texIndexList:
 
759
                        self.writeUnindented("%s\n" % (ind))
 
760
                self.writeIndented("]\n", -1)
 
761
 
 
762
        def writeFaceColors(self, me):
 
763
                self.writeIndented("colorPerVertex FALSE\n")
 
764
                self.writeIndented("color Color {\n",1)
 
765
                self.writeIndented("color [\n", 1)
 
766
 
 
767
                for face in me.faces:
 
768
                        if face.col:
 
769
                                c=face.col[0]
 
770
                                if self.verbose >= 2:
 
771
                                        print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)
 
772
 
 
773
                                aColor = self.rgbToFS(c)
 
774
                                self.writeUnindented("%s,\n" % aColor)
 
775
                self.writeIndented("]\n",-1)
 
776
                self.writeIndented("}\n",-1)
 
777
 
 
778
        def writeVertexColors(self, me):
 
779
                self.writeIndented("colorPerVertex TRUE\n")
 
780
                self.writeIndented("color Color {\n",1)
 
781
                self.writeIndented("color [\n\t\t\t\t\t\t", 1)
 
782
 
 
783
                cols = [None] * len(me.verts)
 
784
 
 
785
                for face in me.faces:
 
786
                        for vind in xrange(len(face.v)):
 
787
                                vertex = face.v[vind]
 
788
                                i = vertex.index
 
789
                                if cols[i] == None:
 
790
                                        cols[i] = face.col[vind]
 
791
                                        
 
792
                for i in xrange(len(me.verts)):
 
793
                        aColor = self.rgbToFS(cols[i])
 
794
                        self.writeUnindented("%s\n" % aColor)
 
795
 
 
796
                self.writeIndented("\n", 0)
 
797
                self.writeIndented("]\n",-1)
 
798
                self.writeIndented("}\n",-1)
 
799
 
 
800
        def writeDefaultMaterial(self):
 
801
                matName = "default"
 
802
 
 
803
                # look up material name, use it if available
 
804
                if self.matNames.has_key(matName):
 
805
                        self.writeIndented("material USE MA_%s\n" % matName)
 
806
                        self.matNames[matName]+=1
 
807
                        return;
 
808
 
 
809
                self.matNames[matName]=1
 
810
                self.writeIndented("material DEF MA_%s Material {\n" % matName, 1)
 
811
                self.writeIndented("diffuseColor 0.8 0.8 0.8\n")
 
812
                self.writeIndented("specularColor 1.0 1.0 1.0\n")
 
813
                self.writeIndented("shininess 0.5\n")
 
814
                self.writeIndented("transparency 0.0\n")
 
815
                self.writeIndented("}\n",-1)
 
816
 
 
817
        def writeMaterial(self, mat, matName):
 
818
                # look up material name, use it if available
 
819
                if self.matNames.has_key(matName):
 
820
                        self.writeIndented("material USE MA_%s\n" % matName)
 
821
                        self.matNames[matName]+=1
 
822
                        return;
 
823
        
 
824
                self.matNames[matName]=1
 
825
 
 
826
                ambient = mat.amb/3
 
827
                diffuseR, diffuseG, diffuseB = \
 
828
                                  mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
 
829
                if world:
 
830
                        ambi = world.getAmb()
 
831
                        ambi0, ambi1, ambi2 = (ambi[0]*mat.amb) * 2, \
 
832
                                                                  (ambi[1]*mat.amb) * 2, \
 
833
                                                                  (ambi[2]*mat.amb) * 2
 
834
                else:
 
835
                        ambi0, ambi1, ambi2 = 0, 0, 0
 
836
                emisR, emisG, emisB = (diffuseR*mat.emit+ambi0) / 2, \
 
837
                                                          (diffuseG*mat.emit+ambi1) / 2, \
 
838
                                                          (diffuseB*mat.emit+ambi2) / 2
 
839
 
 
840
                shininess = mat.hard/512.0
 
841
                specR = (mat.specCol[0]+0.001) / (1.25/(mat.getSpec()+0.001))
 
842
                specG = (mat.specCol[1]+0.001) / (1.25/(mat.getSpec()+0.001))
 
843
                specB = (mat.specCol[2]+0.001) / (1.25/(mat.getSpec()+0.001))
 
844
                transp = 1 - mat.alpha
 
845
                matFlags = mat.getMode()
 
846
                if matFlags & Blender.Material.Modes['SHADELESS']:
 
847
                        ambient = 1
 
848
                        shine = 1
 
849
                        specR = emitR = diffuseR
 
850
                        specG = emitG = diffuseG
 
851
                        specB = emitB = diffuseB
 
852
                self.writeIndented("material DEF MA_%s Material {\n" % matName, 1)
 
853
                self.writeIndented("diffuseColor %s %s %s\n" % \
 
854
                                                   (round(diffuseR,self.cp), \
 
855
                                                        round(diffuseG,self.cp), \
 
856
                                                        round(diffuseB,self.cp)))
 
857
                self.writeIndented("ambientIntensity %s\n" % \
 
858
                                                   (round(ambient,self.cp)))
 
859
                self.writeIndented("specularColor %s %s %s\n" % \
 
860
                                                   (round(specR,self.cp), \
 
861
                                                        round(specG,self.cp), \
 
862
                                                        round(specB,self.cp)))
 
863
                self.writeIndented("emissiveColor  %s %s %s\n" % \
 
864
                                                   (round(emisR,self.cp), \
 
865
                                                        round(emisG,self.cp), \
 
866
                                                        round(emisB,self.cp)))
 
867
                self.writeIndented("shininess %s\n" % (round(shininess,self.cp)))
 
868
                self.writeIndented("transparency %s\n" % (round(transp,self.cp)))
 
869
                self.writeIndented("}\n",-1)
 
870
 
 
871
        def writeImageTexture(self, name, filename):
 
872
                if self.texNames.has_key(name):
 
873
                        self.writeIndented("texture USE %s\n" % self.cleanStr(name))
 
874
                        self.texNames[name] += 1
 
875
                        return
 
876
                else:
 
877
                        self.writeIndented("texture DEF %s ImageTexture {\n" % \
 
878
                                                           self.cleanStr(name), 1)
 
879
                        self.writeIndented('url "%s"\n' % \
 
880
                                                           filename.split("\\")[-1].split("/")[-1])
 
881
                        self.writeIndented("}\n",-1)
 
882
                        self.texNames[name] = 1
 
883
 
 
884
        def writeBackground(self):
 
885
                if world:
 
886
                        worldname = world.getName()
 
887
                else:
 
888
                        return
 
889
                blending = world.getSkytype()   
 
890
                grd = world.getHor()
 
891
                grd0, grd1, grd2 = grd[0], grd[1], grd[2]
 
892
                sky = world.getZen()
 
893
                sky0, sky1, sky2 = sky[0], sky[1], sky[2]
 
894
                mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2]
 
895
                mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2
 
896
                if worldname in self.namesStandard:
 
897
                        self.writeIndented("Background {\n",1)
 
898
                else:
 
899
                        self.writeIndented("DEF %s Background {\n" % \
 
900
                                                           self.secureName(worldname),1)
 
901
                # No Skytype - just Hor color
 
902
                if blending == 0:
 
903
                        self.writeIndented("groundColor %s %s %s\n" % \
 
904
                                                           (round(grd0,self.cp), \
 
905
                                                                round(grd1,self.cp), \
 
906
                                                                round(grd2,self.cp)))
 
907
                        self.writeIndented("skyColor %s %s %s\n" % \
 
908
                                                           (round(grd0,self.cp), \
 
909
                                                                round(grd1,self.cp), \
 
910
                                                                round(grd2,self.cp)))
 
911
                # Blend Gradient
 
912
                elif blending == 1:
 
913
                        self.writeIndented("groundColor [ %s %s %s, " % \
 
914
                                                           (round(grd0,self.cp), \
 
915
                                                                round(grd1,self.cp), \
 
916
                                                                round(grd2,self.cp)))
 
917
                        self.writeIndented("%s %s %s ]\n" % \
 
918
                                                           (round(mix0,self.cp), \
 
919
                                                                round(mix1,self.cp), \
 
920
                                                                round(mix2,self.cp)))
 
921
                        self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
 
922
                        self.writeIndented("skyColor [ %s %s %s, " % \
 
923
                                                           (round(sky0,self.cp), \
 
924
                                                                round(sky1,self.cp), \
 
925
                                                                round(sky2,self.cp)))
 
926
                        self.writeIndented("%s %s %s ]\n" % \
 
927
                                                           (round(mix0,self.cp), \
 
928
                                                                round(mix1,self.cp), \
 
929
                                                                round(mix2,self.cp)))
 
930
                        self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
 
931
                # Blend+Real Gradient Inverse
 
932
                elif blending == 3:
 
933
                        self.writeIndented("groundColor [ %s %s %s, " % \
 
934
                                                           (round(sky0,self.cp), \
 
935
                                                                round(sky1,self.cp), \
 
936
                                                                round(sky2,self.cp)))
 
937
                        self.writeIndented("%s %s %s ]\n" % \
 
938
                                                           (round(mix0,self.cp), \
 
939
                                                                round(mix1,self.cp), \
 
940
                                                                round(mix2,self.cp)))
 
941
                        self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
 
942
                        self.writeIndented("skyColor [ %s %s %s, " % \
 
943
                                                           (round(grd0,self.cp), \
 
944
                                                                round(grd1,self.cp), \
 
945
                                                                round(grd2,self.cp)))
 
946
                        self.writeIndented("%s %s %s ]\n" % \
 
947
                                                           (round(mix0,self.cp), \
 
948
                                                                round(mix1,self.cp), \
 
949
                                                                round(mix2,self.cp)))
 
950
                        self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
 
951
                # Paper - just Zen Color
 
952
                elif blending == 4:
 
953
                        self.writeIndented("groundColor %s %s %s\n" % \
 
954
                                                           (round(sky0,self.cp), \
 
955
                                                                round(sky1,self.cp), \
 
956
                                                                round(sky2,self.cp)))
 
957
                        self.writeIndented("skyColor %s %s %s\n" % \
 
958
                                                           (round(sky0,self.cp), \
 
959
                                                                round(sky1,self.cp), \
 
960
                                                                round(sky2,self.cp)))
 
961
                # Blend+Real+Paper - komplex gradient
 
962
                elif blending == 7:
 
963
                        self.writeIndented("groundColor [ %s %s %s, " % \
 
964
                                                           (round(sky0,self.cp), \
 
965
                                                                round(sky1,self.cp), \
 
966
                                                                round(sky2,self.cp)))
 
967
                        self.writeIndented("%s %s %s ]\n" % \
 
968
                                                           (round(grd0,self.cp), \
 
969
                                                                round(grd1,self.cp), \
 
970
                                                                round(grd2,self.cp)))
 
971
                        self.writeIndented("groundAngle [ 1.57, 1.57 ]\n")
 
972
                        self.writeIndented("skyColor [ %s %s %s, " % \
 
973
                                                           (round(sky0,self.cp), \
 
974
                                                                round(sky1,self.cp), \
 
975
                                                                round(sky2,self.cp)))
 
976
                        self.writeIndented("%s %s %s ]\n" % \
 
977
                                                           (round(grd0,self.cp),
 
978
                                                                round(grd1,self.cp),
 
979
                                                                round(grd2,self.cp)))
 
980
                        self.writeIndented("skyAngle [ 1.57, 1.57 ]\n")
 
981
                # Any Other two colors
 
982
                else:
 
983
                        self.writeIndented("groundColor %s %s %s\n" % \
 
984
                                                           (round(grd0,self.cp), \
 
985
                                                                round(grd1,self.cp), \
 
986
                                                                round(grd2,self.cp)))
 
987
                        self.writeIndented("skyColor %s %s %s\n" % \
 
988
                                                           (round(sky0,self.cp), \
 
989
                                                                round(sky1,self.cp), \
 
990
                                                                round(sky2,self.cp)))
 
991
                alltexture = len(worldmat)
 
992
                for i in xrange(alltexture):
 
993
                        namemat = worldmat[i].getName()
 
994
                        pic = worldmat[i].getImage()
 
995
                        if pic:
 
996
                                # Stripped path.
 
997
                                pic_path= pic.filename.split('\\')[-1].split('/')[-1]
 
998
                                if namemat == "back":
 
999
                                        self.writeIndented('backUrl "%s"\n' % pic_path)
 
1000
                                elif namemat == "bottom":
 
1001
                                        self.writeIndented('bottomUrl "%s"\n' % pic_path)
 
1002
                                elif namemat == "front":
 
1003
                                        self.writeIndented('frontUrl "%s"\n' % pic_path)
 
1004
                                elif namemat == "left":
 
1005
                                        self.writeIndented('leftUrl "%s"\n' % pic_path)
 
1006
                                elif namemat == "right":
 
1007
                                        self.writeIndented('rightUrl "%s"\n' % pic_path)
 
1008
                                elif namemat == "top":
 
1009
                                        self.writeIndented('topUrl "%s"\n' % pic_path)
 
1010
                self.writeIndented("}",-1)
 
1011
                self.writeIndented("\n\n")
 
1012
 
 
1013
        def writeLamp(self, ob):
 
1014
                la = ob.data
 
1015
                laType = la.getType()
 
1016
 
 
1017
                if laType == Lamp.Types.Lamp:
 
1018
                        self.writePointLight(ob, la)
 
1019
                elif laType == Lamp.Types.Spot:
 
1020
                        self.writeSpotLight(ob, la)
 
1021
                elif laType == Lamp.Types.Sun:
 
1022
                        self.writeDirectionalLight(ob, la)
 
1023
                else:
 
1024
                        self.writeDirectionalLight(ob, la)
 
1025
 
 
1026
        def writeObject(self, ob):
 
1027
 
 
1028
                obname = self.cleanStr(ob.name)
 
1029
 
 
1030
                try:
 
1031
                        obtype=ob.getType()
 
1032
                except AttributeError:
 
1033
                        print "Error: Unable to get type info for %s" % obname
 
1034
                        return
 
1035
 
 
1036
                if self.verbose >= 1:
 
1037
                        print "++ Writing %s object %s (Blender name: %s)\n" % \
 
1038
                                  (obtype, obname, ob.name)
 
1039
 
 
1040
                # Note: I am leaving empties out for now -- the original
 
1041
                # script does some really weird stuff with empties
 
1042
                if ( (obtype != "Camera") and \
 
1043
                         (obtype != "Mesh") and \
 
1044
                         (obtype != "Lamp") ):
 
1045
                        print "Info: Ignoring [%s], object type [%s] " \
 
1046
                                  "not handle yet" % (obname, obtype)
 
1047
                        return
 
1048
 
 
1049
                ob_matrix = Mathutils.Matrix(ob.getMatrix('worldspace'))
 
1050
                if export_rotate_z_to_y.val:
 
1051
                        matrix = M_blen2vrml * ob_matrix * M_vrml2blen
 
1052
                else:
 
1053
                        matrix = ob_matrix
 
1054
                e      = matrix.rotationPart().toEuler()
 
1055
 
 
1056
                v = matrix.translationPart()
 
1057
                (axis, angle) = self.eulToVecRot(self.deg2rad(e.x), \
 
1058
                                                                                 self.deg2rad(e.y), \
 
1059
                                                                                 self.deg2rad(e.z))
 
1060
 
 
1061
                mrot = e.toMatrix().resize4x4()
 
1062
                try:
 
1063
                        mrot.invert()
 
1064
                except:
 
1065
                        print "Warning: %s has degenerate transformation!" % (obname)
 
1066
                        return
 
1067
                
 
1068
                diag = matrix * mrot
 
1069
                sizeX = diag[0][0]
 
1070
                sizeY = diag[1][1]
 
1071
                sizeZ = diag[2][2]
 
1072
 
 
1073
                if self.verbose >= 1:
 
1074
                        print "  Transformation:\n" \
 
1075
                                  "    loc:  %f %f %f\n" \
 
1076
                                  "    size: %f %f %f\n" \
 
1077
                                  "    Rot:  (%f %f %f), %f\n" % \
 
1078
                                  (v.x, v.y, v.z, \
 
1079
                                   sizeX, sizeY, sizeZ, \
 
1080
                                   axis[0], axis[1], axis[2], angle)
 
1081
 
 
1082
                self.writeIndented("DEF OB_%s Transform {\n" % (obname), 1)
 
1083
                self.writeIndented("translation %f %f %f\n" % \
 
1084
                                                   (v.x, v.y, v.z) )
 
1085
 
 
1086
                self.writeIndented("rotation %f %f %f %f\n" % \
 
1087
                                                   (axis[0],axis[1],axis[2],angle) )
 
1088
                
 
1089
                self.writeIndented("scale %f %f %f\n" % \
 
1090
                                                   (sizeX, sizeY, sizeZ) )
 
1091
 
 
1092
                self.writeIndented("children [\n", 1)
 
1093
 
 
1094
                self.writeObData(ob)
 
1095
 
 
1096
                self.writeIndented("]\n", -1) # end object
 
1097
                self.writeIndented("}\n", -1) # end object
 
1098
 
 
1099
        def writeObData(self, ob):
 
1100
 
 
1101
                obtype = ob.getType()
 
1102
 
 
1103
                if obtype == "Camera":
 
1104
                        self.writeViewpoint(ob)
 
1105
                elif obtype == "Mesh":
 
1106
                        self.writeMesh(ob)
 
1107
                elif obtype == "Lamp":
 
1108
                        self.writeLamp(ob)
 
1109
                elif obtype == "Empty":
 
1110
                        self.writeNode(ob)
 
1111
 
 
1112
 
 
1113
##########################################################
 
1114
# export routine
 
1115
##########################################################
 
1116
 
 
1117
        def export(self, scene, world, worldmat):
 
1118
                print "Info: starting VRML97 export to " + self.filename + "..."
 
1119
                self.writeHeader()
 
1120
                self.writeScript()
 
1121
                self.writeNavigationInfo(scene)
 
1122
                self.writeBackground()
 
1123
                self.writeFog()
 
1124
                self.proto = 0
 
1125
                allObj = []
 
1126
                if export_selection_only.val:
 
1127
                        allObj = list(scene.objects.context)
 
1128
                else:
 
1129
                        allObj = list(scene.objects)
 
1130
                        self.writeInline()
 
1131
 
 
1132
                for thisObj in allObj:
 
1133
                        self.writeObject(thisObj)
 
1134
 
 
1135
                if not export_selection_only.val:
 
1136
                        self.writeScript()
 
1137
                self.cleanup()
 
1138
 
 
1139
##########################################################
 
1140
# Utility methods
 
1141
##########################################################
 
1142
 
 
1143
        def cleanup(self):
 
1144
                self.file.close()
 
1145
                self.texNames={}
 
1146
                self.matNames={}
 
1147
                self.indentLevel=0
 
1148
                print "Info: finished VRML97 export to %s\n" % self.filename
 
1149
 
 
1150
        def cleanStr(self, name, prefix='rsvd_'):
 
1151
                """cleanStr(name,prefix) - try to create a valid VRML DEF \
 
1152
                name from object name"""
 
1153
 
 
1154
                newName=name[:]
 
1155
                if len(newName) == 0:
 
1156
                        self.nNodeID+=1
 
1157
                        return "%s%d" % (prefix, self.nNodeID)
 
1158
                
 
1159
                if newName in self.namesReserved:
 
1160
                        newName='%s%s' % (prefix,newName)
 
1161
                
 
1162
                if newName[0].isdigit():
 
1163
                        newName='%s%s' % ('_',newName)
 
1164
 
 
1165
                for bad in (' ','"','#',"'",',','.','[','\\',']','{','}'):
 
1166
                        newName=newName.replace(bad,'_')
 
1167
                return newName
 
1168
 
 
1169
        def rgbToFS(self, c):
 
1170
                s = "%s %s %s" % \
 
1171
                        (round(c.r/255.0,self.cp), \
 
1172
                         round(c.g/255.0,self.cp), \
 
1173
                         round(c.b/255.0,self.cp))
 
1174
                return s
 
1175
 
 
1176
        def rad2deg(self, v):
 
1177
                return round(v*180.0/math.pi,4)
 
1178
 
 
1179
        def deg2rad(self, v):
 
1180
                return (v*math.pi)/180.0;
 
1181
 
 
1182
        def eulToVecRot(self, RotX, RotY, RotZ):
 
1183
                
 
1184
                ti = RotX*0.5
 
1185
                tj = RotY*0.5
 
1186
                th = RotZ*0.5
 
1187
 
 
1188
                ci = math.cos(ti)
 
1189
                cj = math.cos(tj)
 
1190
                ch = math.cos(th)
 
1191
                si = math.sin(ti)
 
1192
                sj = math.sin(tj)
 
1193
                sh = math.sin(th)
 
1194
                cc = ci*ch
 
1195
                cs = ci*sh
 
1196
                sc = si*ch
 
1197
                ss = si*sh
 
1198
        
 
1199
                q0 = cj*cc + sj*ss
 
1200
                q1 = cj*sc - sj*cs
 
1201
                q2 = cj*ss + sj*cc
 
1202
                q3 = cj*cs - sj*sc
 
1203
 
 
1204
                angle = 2 * math.acos(q0)
 
1205
                if (math.fabs(angle) < 0.000001):
 
1206
                        axis = [1.0, 0.0, 0.0]
 
1207
                else:
 
1208
                        sphi = 1.0/math.sqrt(1.0 - (q0*q0))
 
1209
                        axis = [q1 * sphi, q2 * sphi, q3 * sphi]
 
1210
 
 
1211
                a = Mathutils.Vector(axis)
 
1212
                a.normalize()
 
1213
                return ([a.x, a.y, a.z], angle)
 
1214
 
 
1215
 
 
1216
        # For writing well formed VRML code
 
1217
        #----------------------------------
 
1218
        def writeIndented(self, s, inc=0):
 
1219
                if inc < 1:
 
1220
                        self.indentLevel = self.indentLevel + inc
 
1221
                
 
1222
                self.file.write( self.indentLevel*"\t" + s)
 
1223
 
 
1224
                if inc > 0:
 
1225
                        self.indentLevel = self.indentLevel + inc
 
1226
 
 
1227
        # Sometimes better to not have too many
 
1228
        # tab characters in a long list, for file size
 
1229
        #----------------------------------
 
1230
        def writeUnindented(self, s):
 
1231
                self.file.write(s)
 
1232
 
 
1233
##########################################################
 
1234
# Callbacks, needed before Main
 
1235
##########################################################
 
1236
 
 
1237
def select_file(filename):
 
1238
        if sys.exists(filename) and _safeOverwrite:
 
1239
                result = \
 
1240
                        Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0")
 
1241
                if(result != 1):
 
1242
                        return
 
1243
 
 
1244
        if not filename.endswith(extension):
 
1245
                filename += extension
 
1246
 
 
1247
        wrlexport=VRML2Export(filename)
 
1248
        wrlexport.export(scene, world, worldmat)
 
1249
 
 
1250
#########################################################
 
1251
# UI and Registry utilities
 
1252
#########################################################
 
1253
 
 
1254
export_selection_only = Draw.Create(0)
 
1255
export_rotate_z_to_y = Draw.Create(1)
 
1256
export_compressed = Draw.Create(0)
 
1257
 
 
1258
def save_to_registry():
 
1259
        d = {}
 
1260
        d['selection_only'] = export_selection_only.val
 
1261
        d['rotate_z_to_y'] = export_rotate_z_to_y.val
 
1262
        d['compressed'] = export_compressed.val
 
1263
        Registry.SetKey('vrml97_export', d, True)
 
1264
 
 
1265
def load_from_registry():
 
1266
        d = Registry.GetKey('vrml97_export', True)
 
1267
        if d:
 
1268
                try:
 
1269
                        export_selection_only.val = d['selection_only']
 
1270
                        export_rotate_z_to_y.val = d['rotate_z_to_y']
 
1271
                        export_compressed.val = d['compressed']
 
1272
                except: save_to_registry() # If data is not valid, rewrite it.
 
1273
 
 
1274
def show_popup():
 
1275
        pup_block = [
 
1276
                ('Selection Only', export_selection_only, 'Only export objects in visible selection. Else export whole scene.'),
 
1277
                ('Rotate +Z to +Y', export_rotate_z_to_y, 'Rotate such that +Z axis (Blender up) becomes +Y (VRML up).'),
 
1278
                ('Compress', export_compressed, 'Generate a .wrz file (normal VRML compressed by gzip).')
 
1279
                ]
 
1280
        return Draw.PupBlock('Export VRML 97...', pup_block) 
 
1281
 
 
1282
#########################################################
 
1283
# main routine
 
1284
#########################################################
 
1285
 
 
1286
load_from_registry()
 
1287
 
 
1288
# Note that show_popup must be done before Blender.Window.FileSelector,
 
1289
# because export_compressed affects the suggested extension of resulting
 
1290
# file.
 
1291
 
 
1292
if show_popup():
 
1293
        save_to_registry()
 
1294
        if export_compressed.val:
 
1295
                extension=".wrz"
 
1296
                from gzip import *
 
1297
        else:
 
1298
                extension=".wrl"
 
1299
        Blender.Window.FileSelector(select_file, "Export VRML97", \
 
1300
                                                                sys.makename(ext=extension))