diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-14 20:32:24 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-12-14 20:32:24 +0300 |
commit | ec00764dd2349f723ba22b45515ec34ee81edcc3 (patch) | |
tree | cf506e71af7172ec63b89aa3d284fab27a2085e6 /release | |
parent | 131fa2e00c35ff78042a4f793891eaeb880d715c (diff) | |
parent | 8449f0d77640c466acbda7d6ceeb71bc48317b44 (diff) |
2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17434:HEAD
Diffstat (limited to 'release')
-rw-r--r-- | release/Makefile | 6 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyImage.py | 19 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyMathutils.py | 14 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPySys.py | 60 | ||||
-rw-r--r-- | release/scripts/export_fbx.py | 38 | ||||
-rw-r--r-- | release/scripts/import_dxf.py | 107 | ||||
-rwxr-xr-x | release/scripts/import_web3d.py | 458 |
7 files changed, 588 insertions, 114 deletions
diff --git a/release/Makefile b/release/Makefile index f440e2dface..43a369d8f77 100644 --- a/release/Makefile +++ b/release/Makefile @@ -57,6 +57,12 @@ ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris")) NOPLUGINS?=true endif endif + # don"t build plugins on irix if using gcc + ifeq ($(OS), irix) + ifeq ($(IRIX_USE_GCC), true) + NOPLUGINS?=true + endif + endif endif ifeq ($(OS),windows) diff --git a/release/scripts/bpymodules/BPyImage.py b/release/scripts/bpymodules/BPyImage.py index 2c342ddec39..504e4ee29ba 100644 --- a/release/scripts/bpymodules/BPyImage.py +++ b/release/scripts/bpymodules/BPyImage.py @@ -79,7 +79,7 @@ def addSlash(path): return path + sys.sep -def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False): +def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False, CONVERT_CALLBACK=None): ''' imagePath: The image filename If a path precedes it, this will be searched as well. @@ -93,13 +93,30 @@ def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=Tr RECURSIVE: If True, directories will be recursivly searched. Be carefull with this if you have files in your root directory because it may take a long time. + + CASE_INSENSITIVE: for non win32 systems, find the correct case for the file. + + CONVERT_CALLBACK: a function that takes an existing path and returns a new one. + Use this when loading image formats blender may not support, the CONVERT_CALLBACK + can take the path for a GIF (for example), convert it to a PNG and return the PNG's path. + For formats blender can read, simply return the path that is given. ''' + # VERBOSE = True + if VERBOSE: print 'img:', imagePath, 'file:', filePath + + if os == None and CASE_INSENSITIVE: + CASE_INSENSITIVE = True + # When we have the file load it with this. try/except niceness. def imageLoad(path): #if path.endswith('\\') or path.endswith('/'): # raise 'INVALID PATH' + + if CONVERT_CALLBACK: + path = CONVERT_CALLBACK(path) + try: img = bpy.data.images.new(filename=path) if VERBOSE: print '\t\tImage loaded "%s"' % path diff --git a/release/scripts/bpymodules/BPyMathutils.py b/release/scripts/bpymodules/BPyMathutils.py index 27736b4169e..bfa1dcc3c61 100644 --- a/release/scripts/bpymodules/BPyMathutils.py +++ b/release/scripts/bpymodules/BPyMathutils.py @@ -225,15 +225,5 @@ from math import pi, sin, cos, sqrt def angleToLength(angle): # Alredy accounted for - if angle < 0.000001: - return 1.0 - - angle = 2*pi*angle/360 - x,y = cos(angle), sin(angle) - # print "YX", x,y - # 0 d is hoz to the right. - # 90d is vert upward. - fac=1/x - x=x*fac - y=y*fac - return sqrt((x*x)+(y*y)) + if angle < 0.000001: return 1.0 + else: return abs(1.0 / cos(pi*angle/180)); diff --git a/release/scripts/bpymodules/BPySys.py b/release/scripts/bpymodules/BPySys.py index 594264fad84..a2d2120ebff 100644 --- a/release/scripts/bpymodules/BPySys.py +++ b/release/scripts/bpymodules/BPySys.py @@ -12,3 +12,63 @@ def cleanName(name): for ch in invalid: name = name.replace(ch, '_') return name +def caseInsensitivePath(path, RET_FOUND=False): + ''' + Get a case insensitive path on a case sensitive system + + RET_FOUND is for internal use only, to avoid too many calls to os.path.exists + # Example usage + getCaseInsensitivePath('/hOmE/mE/sOmEpAtH.tXt') + ''' + import os # todo, what happens with no os? + + if os==None: + if RET_FOUND: ret = path, True + else: ret = path + return ret + + if path=='' or os.path.exists(path): + if RET_FOUND: ret = path, True + else: ret = path + return ret + + f = os.path.basename(path) # f may be a directory or a file + d = os.path.dirname(path) + + suffix = '' + if not f: # dir ends with a slash? + if len(d) < len(path): + suffix = path[:len(path)-len(d)] + + f = os.path.basename(d) + d = os.path.dirname(d) + + if not os.path.exists(d): + d, found = caseInsensitivePath(d, True) + + if not found: + if RET_FOUND: ret = path, False + else: ret = path + return ret + + # at this point, the directory exists but not the file + + try: # we are expecting 'd' to be a directory, but it could be a file + files = os.listdir(d) + except: + if RET_FOUND: ret = path, False + else: ret = path + + f_low = f.lower() + + try: f_nocase = [fl for fl in files if fl.lower() == f_low][0] + except: f_nocase = None + + if f_nocase: + if RET_FOUND: ret = os.path.join(d, f_nocase) + suffix, True + else: ret = os.path.join(d, f_nocase) + suffix + return ret + else: + if RET_FOUND: ret = path, False + else: ret = path + return ret # cant find the right one, just return the path as is.
\ No newline at end of file diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py index 3f02a71f951..ce17f78c5e2 100644 --- a/release/scripts/export_fbx.py +++ b/release/scripts/export_fbx.py @@ -66,8 +66,6 @@ import BPyMesh import BPySys import BPyMessages -import sys - ## This was used to make V, but faster not to do all that ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' ##v = range(255) @@ -184,7 +182,19 @@ def sane_texname(data): return sane_name(data, sane_name_mapping_tex) def sane_takename(data): return sane_name(data, sane_name_mapping_take) def sane_groupname(data): return sane_name(data, sane_name_mapping_group) - +def derived_paths(fname_orig, basepath, FORCE_CWD=False): + ''' + fname_orig - blender path, can be relative + basepath - fname_rel will be relative to this + FORCE_CWD - dont use the basepath, just add a ./ to the filename. + use when we know the file will be in the basepath. + ''' + fname = Blender.sys.expandpath(fname_orig) + fname_strip = strip_path(fname) + if FORCE_CWD: fname_rel = '.' + Blender.sys.sep + fname_strip + else: fname_rel = Blender.sys.relpath(fname, basepath) + if fname_rel.startswith('//'): fname_rel = '.' + Blender.sys.sep + fname_rel[2:] + return fname, fname_strip, fname_rel def mat4x4str(mat): @@ -342,6 +352,8 @@ def write(filename, batch_objects = None, \ # end batch support + # Use this for working out paths relative to the export location + basepath = Blender.sys.dirname(filename) # ---------------------------------------------- # storage classes @@ -1141,10 +1153,9 @@ def write(filename, batch_objects = None, \ Property: "Width", "int", "",0 Property: "Height", "int", "",0''') if tex: - fname = tex.filename - fname_strip = strip_path(fname) + fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: - fname = fname_strip = '' + fname = fname_strip = fname_rel = '' file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) @@ -1163,7 +1174,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tFilename: "%s"' % fname_strip) if fname_strip: fname_strip = '/' + fname_strip - file.write('\n\t\tRelativeFilename: "fbx%s"' % fname_strip) # make relative + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative file.write('\n\t}') @@ -1202,13 +1213,14 @@ def write(filename, batch_objects = None, \ }''') file.write('\n\t\tMedia: "Video::%s"' % texname) + if tex: - fname = tex.filename - file.write('\n\t\tFileName: "%s"' % strip_path(fname)) - file.write('\n\t\tRelativeFilename: "fbx/%s"' % strip_path(fname)) # need some make relative command + fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY) else: - file.write('\n\t\tFileName: ""') - file.write('\n\t\tRelativeFilename: "fbx"') + fname = fname_strip = fname_rel = '' + + file.write('\n\t\tFileName: "%s"' % fname_strip) + file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command file.write(''' ModelUVTranslation: 0,0 @@ -2658,7 +2670,7 @@ Takes: {''') # copy images if enabled if EXP_IMAGE_COPY: - copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ]) + copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ]) print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) return True diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py index bb0119a9a81..6a1981bb262 100644 --- a/release/scripts/import_dxf.py +++ b/release/scripts/import_dxf.py @@ -7,7 +7,7 @@ Group: 'Import' Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).' """ __author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' -__version__ = '1.12 - 2008.08.03 by migius' +__version__ = '1.12 - 2008.11.16 by migius' __url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] __email__ = ["migius(at)4d-vectors.de","Kitsune_e(at)yahoo.com"] @@ -111,6 +111,9 @@ History: -- support ortho mode for VIEWs and VPORTs as cameras + v1.12 - 2008.11.16 by migius + d1 remove try_finally: cause not supported in python <2.5 + d1 add Bezier curves bevel radius support (default 1.0) v1.12 - 2008.08.03 by migius c2 warningfix: relocating of globals: layersmap, oblist c2 modif UI: buttons newScene+targetLayer moved to start panel @@ -299,7 +302,7 @@ History: import Blender from Blender import * #from Blender.Mathutils import Vector, Matrix -import bpy +#import bpy #not used yet #import BPyMessages from dxfReader import readDXF @@ -311,7 +314,7 @@ from math import * try: import os - if os.name:# != 'mac': + if os.name != 'mac': import psyco psyco.log(Blender.Get('tempdir')+"/blender.log-psyco") #psyco.log() @@ -320,7 +323,7 @@ try: psyco.profile(0.2) #print 'psyco imported' except ImportError: - #print 'psyco not imported' + print 'psyco not imported' pass #try: Curve.orderU @@ -346,7 +349,7 @@ THIN_RESOLUTION = 8 #(4-64) thin_cylinder arc_resolution - number of segments MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width TRIM_LIMIT = 3.0 #limit for triming of polylines-wide-segments (values:0.0 - 5.0) -ELEVATION = 0.0 #standard elevation = coordinate Z +ELEVATION = 0.0 #standard elevation = coordinate Z value BYBLOCK = 0 BYLAYER = 256 @@ -817,6 +820,7 @@ class Line: #----------------------------------------------------------------- curve.append(BezTriple.New(points[1])) for point in curve: point.handleTypes = [VECT, VECT] + point.radius = 1.0 curve.flagU = 0 # 0 sets the curve not cyclic=open c.setResolu(settings.var['curve_res']) c.update() #important for handles calculation @@ -1341,9 +1345,11 @@ class Polyline: #-------------------------------------------------------------- nurbs_points.append(pkt) firstpoint = nurbs_points[0] curve = pline.appendNurb(firstpoint) - curve.setType(4) # set curvetype NURBS + curve.setType(4) # set curve_type NURBS + print 'deb: dir(curve):', dir(curve[-1]) #---------------- for point in nurbs_points[1:]: curve.append(point) + #TODO: what is the trick for bevel radius? curve[-1].radius = 1.0 if self.closed: curve.flagU = 1+0 # Set curve cyclic=close and uni else: @@ -1359,6 +1365,7 @@ class Polyline: #-------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [AUTO, AUTO] + point.radius = 1.0 if self.closed: curve.flagU = 1 # Set curve cyclic=close else: @@ -1380,6 +1387,7 @@ class Polyline: #-------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [AUTO, AUTO] + point.radius = 1.0 #curve.setType(1) #Bezier curve if self.closed: curve.flagU = 5 #1 # Set curve cyclic=close @@ -1392,6 +1400,7 @@ class Polyline: #-------------------------------------------------------------- p0h1 = [p0h1[i]+begtangent[i] for i in range(3)] curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2)) curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- + curve[0].radius = 1.0 if endtangent: #print 'deb:polyline2dCurve.draw curve[-1].vec:', curve[-1].vec #----- #print 'deb:polyline2dCurve.draw endtangent:', endtangent #----- @@ -1401,6 +1410,7 @@ class Polyline: #-------------------------------------------------------------- curve.__setitem__(-1,BezTriple.New(p0h1+p0+p0h2)) #print 'deb:polyline2dCurve.draw curve[-1].vec:', curve[-1].vec #----- curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- + curve[-1].radius = 1.0 @@ -1420,13 +1430,16 @@ class Polyline: #-------------------------------------------------------------- if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0])) else: curve.append(BezTriple.New(verts[0])) curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents + curve[-1].radius = 1.0 for p in verts[1:]: curve.append(BezTriple.New(p)) curve[-1].handleTypes = [AUTO, AUTO] + curve[-1].radius = 1.0 else: if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) else: curve.append(BezTriple.New(point1.loc)) curve[-1].handleTypes = [VECT, VECT] #--todo--calculation of bezier-tangents + curve[-1].radius = 1.0 elif True: #----- optimised Bezier-Handles calculation -------------------------------- #print 'deb:drawPlineCurve: i:', i #--------- @@ -1446,10 +1459,12 @@ class Polyline: #-------------------------------------------------------------- if i == 0: curve = pline.appendNurb(BezTriple.New(VectorTriples[0])) else: curve.append(BezTriple.New(VectorTriples[0])) curve[-1].handleTypes = [prevHandleType, FREE] + curve[-1].radius = 1.0 for p in VectorTriples[1:-1]: curve.append(BezTriple.New(p)) curve[-1].handleTypes = [FREE, FREE] + curve[-1].radius = 1.0 prevHandleVect = VectorTriples[-1][:3] prevHandleType = FREE @@ -1462,11 +1477,13 @@ class Polyline: #-------------------------------------------------------------- curve.append(BezTriple.New(VectorTriples)) curve[-1].handleTypes = [FREE, VECT] prevHandleType = VECT + curve[-1].radius = 1.0 else: if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) else: curve.append(BezTriple.New(point1.loc)) curve[-1].handleTypes = [VECT, VECT] - + curve[-1].radius = 1.0 + #print 'deb:drawPlineCurve: curve[-1].vec[0]', curve[-1].vec[0] #---------- @@ -1486,10 +1503,12 @@ class Polyline: #-------------------------------------------------------------- curve.__setitem__(0,BezTriple.New(p0h1+p0+p0h2)) curve[0].handleTypes = [FREE,prevHandleType2] + curve[0].radius = 1.0 #print 'deb:drawPlineCurve:closed curve[0].vec:', curve[0].vec #---------- #print 'deb:drawPlineCurve:closed curve[0].handleTypes:', curve[0].handleTypes #---------- else: curve[0].handleTypes[0] = VECT + curve[0].radius = 1.0 else: curve.flagU = 0 # Set curve not cyclic=open @@ -2177,9 +2196,10 @@ DXF: X value; APP: 3D point, Y and Z values of control points (in WCS) (one entr self.ctrlpk_len = getit(obj, 73, 0) # Number of control points self.fit_pk_len = getit(obj, 74, 0) # Number of fit points (if any) + #TODO: import SPLINE as Bezier curve directly, possible? #print 'deb:Spline self.fit_pk_len=', self.fit_pk_len #------------------------ #self.fit_pk_len = 0 # temp for debug - if self.fit_pk_len and 'spline_as'==5: + if self.fit_pk_len and settings.var['splines_as']==5: self.spline = False self.curved = True else: @@ -2675,6 +2695,7 @@ class Circle: #---------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [FREE, FREE] + point.radius = 1.0 else: # standard version c = Curve.New(obname) # create new curve data p1 = (0, -radius, 0) @@ -2693,6 +2714,7 @@ class Circle: #---------------------------------------------------------------- curve.append(p4) for point in curve: point.handleTypes = [AUTO, AUTO] + point.radius = 1.0 curve.flagU = 1 # 1 sets the curve cyclic=closed if settings.var['fill_on']: @@ -2893,6 +2915,7 @@ class Arc: #----------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [FREE, FREE] + point.radius = 1.0 curve.flagU = 0 # 0 sets the curve not cyclic=open arc.setResolu(settings.var['curve_res']) @@ -3449,6 +3472,7 @@ class Ellipse: #--------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [FREE, FREE] + point.radius = 1.0 curve.flagU = 1 # 0 sets the curve not cyclic=open if settings.var['fill_on']: arc.setFlag(6) # 2+4 set top and button caps @@ -3459,6 +3483,7 @@ class Ellipse: #--------------------------------------------------------------- curve.append(BezTriple.New(p)) for point in curve: point.handleTypes = [FREE, FREE] + point.radius = 1.0 curve.flagU = 0 # 0 sets the curve not cyclic=open arc.setResolu(settings.var['curve_res']) @@ -4397,8 +4422,7 @@ def analyzeDXF(dxfFile): #--------------------------------------- Draw.PupMenu('DXF importer: report saved in INF-file:%t|' + '\'%s\'' %infFile) except: Draw.PupMenu('DXF importer: ERROR by writing report in INF-file:%t|' + '\'%s\'' %infFile) - finally: - f.close() + #finally: f.close() @@ -4417,7 +4441,8 @@ def main(dxfFile): #---------------#############################----------- global cur_COUNTER #counter for progress_bar cur_COUNTER = 0 - try: + #try: + if 1: #print "Getting settings..." global GUI_A, GUI_B, g_scale_as if not GUI_A['g_scale_on'].val: @@ -4500,7 +4525,7 @@ def main(dxfFile): #---------------#############################----------- #settings.write(message) if UI_MODE: Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % time_text) - finally: + #finally: # restore state even if things didn't work #print 'deb:drawEntities finally!' #----------------------- Window.WaitCursor(False) @@ -5190,6 +5215,7 @@ def drawCurveCircle(circle): #--- no more used -------------------------------- curve.append(p4) for point in curve: point.handleTypes = [AUTO, AUTO] + point.radius = 1.0 curve.flagU = 1 # Set curve cyclic c.update() @@ -5231,6 +5257,7 @@ def drawCurveArc(self): #---- only for ELLIPSE -------------------------------- curve.append(p4) for point in curve: point.handleTypes = [AUTO, AUTO] + point.radius = 1.0 curve.flagU = 1 # Set curve cyclic a.update() @@ -5270,12 +5297,12 @@ GUI_B = {} # GUI-buttons dictionary for drawingTypes # settings default, initialize ------------------------ points_as_menu = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4|*curve.vertex %x5" -lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|thin box %x4|Bezier-curve %x5|NURBS-curve %x6" +lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|thin box %x4|Bezier-curve %x5|*NURBS-curve %x6" mlines_as_menu = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x|*curve %x5" plines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4|Bezier-curve %x5|NURBS-curve %x6" -splines_as_menu = "convert to: %t|mesh %x2|*thin cylinder %x3|*thin box %x4|Bezier-curve %x5|NURBS-curve %x6" +splines_as_menu = "convert to: %t|mesh %x2|*thin cylinder %x3|*thin box %x4|*Bezier-curve %x5|NURBS-curve %x6" plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4|Bezier-curve %x5|NURBS-curve %x6" -plmesh_as_menu = "convert to: %t|*edge %x1|mesh %x2|NURBS-surface %x6" +plmesh_as_menu = "convert to: %t|*edge %x1|mesh %x2|*NURBS-surface %x6" solids_as_menu = "convert to: %t|*edge %x1|mesh %x2" blocks_as_menu = "convert to: %t|dupliGroup %x1|*real.Group %x2|*exploded %x3" texts_as_menu = "convert to: %t|text %x1|*mesh %x2|*curve %x5" @@ -5456,11 +5483,9 @@ def saveConfig(): #--todo----------------------------------------------- else: #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct if sys.exists(iniFile): - try: - f = file(iniFile, 'r') - try: header_str = f.readline() - finally: f.close() - except: pass + f = file(iniFile, 'r') + header_str = f.readline() + f.close() if header_str.startswith(INIFILE_HEADER[0:13]): if Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1: save_ok = True @@ -5480,10 +5505,9 @@ def saveConfig(): #--todo----------------------------------------------- output_str = '{\n'.join(output_str.split('{')) try: f = file(iniFile, 'w') - try: - f.write(INIFILE_HEADER + '\n# this is a comment line\n') - f.write(output_str) - finally: f.close() + f.write(INIFILE_HEADER + '\n# this is a comment line\n') + f.write(output_str) + f.close() #Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) except: Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile) @@ -5508,25 +5532,22 @@ def loadConfig(): #remi--todo----------------------------------------------- update_RegistryKey('iniFileName', iniFile) #print 'deb:loadConfig iniFile: ', iniFile #---------------------- if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile): - try: - f = file(iniFile, 'r') - try: - header_str = f.readline() - if header_str.startswith(INIFILE_HEADER): - data_str = f.read() - f.close() - #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #----------------- - data = eval(data_str) - for k, v in data[0].iteritems(): - try: GUI_A[k].val = v - except: GUI_A[k] = Draw.Create(v) - for k, v in data[1].iteritems(): - try: GUI_B[k].val = v - except: GUI_B[k] = Draw.Create(v) - else: - Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) - finally: f.close() - except: pass + f = file(iniFile, 'r') + header_str = f.readline() + if header_str.startswith(INIFILE_HEADER): + data_str = f.read() + f.close() + #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #----------------- + data = eval(data_str) + for k, v in data[0].iteritems(): + try: GUI_A[k].val = v + except: GUI_A[k] = Draw.Create(v) + for k, v in data[1].iteritems(): + try: GUI_B[k].val = v + except: GUI_B[k] = Draw.Create(v) + else: + f.close() + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) else: Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!') print "DXF importer: Alert!: no valid INI-file selected." diff --git a/release/scripts/import_web3d.py b/release/scripts/import_web3d.py index 9447f15fb79..06cde898ef2 100755 --- a/release/scripts/import_web3d.py +++ b/release/scripts/import_web3d.py @@ -48,6 +48,27 @@ def baseName(path): def dirName(path): return path[:-len(baseName(path))] +def imageConvertCompat(path): + + try: import os + except: + return path + + if path.endswith('.gif'): + path_to = path[:-3] + 'png' + + ''' + if exists(path_to): + return path_to + ''' + # print '\n'+path+'\n'+path_to+'\n' + os.system('convert "%s" "%s"' % (path, path_to)) # for now just hope we have image magick + + if exists(path_to): + return path_to + + return path + # notes # transform are relative # order dosnt matter for loc/size/rot @@ -78,6 +99,7 @@ def vrmlFormat(data): return l # Most cases accounted for! if we have a comment at the end of the line do this... + #j = l.find('url "') j = l.find('"') if j == -1: # simple no strings @@ -96,7 +118,40 @@ def vrmlFormat(data): data = '\n'.join([strip_comment(l) for l in data.split('\n') ]) # remove all whitespace + EXTRACT_STRINGS = True # only needed when strings or filesnames containe ,[]{} chars :/ + + if EXTRACT_STRINGS: + + # We need this so we can detect URL's + data = '\n'.join([' '.join(l.split()) for l in data.split('\n')]) # remove all whitespace + string_ls = [] + + #search = 'url "' + search = '"' + + ok = True + last_i = 0 + while ok: + ok = False + i = data.find(search, last_i) + if i != -1: + + start = i + len(search) # first char after end of search + end = data.find('"', start) + if end != -1: + item = data[start:end] + string_ls.append( item ) + data = data[:start] + data[end:] + ok = True # keep looking + + last_i = end - len(item) + 1 + # print last_i, item, '|' + data[last_i] + '|' + + # done with messy extracting strings part + + + # Bad, dont take strings into account ''' data = data.replace('#', '\n#') @@ -108,6 +163,27 @@ def vrmlFormat(data): data = data.replace(']', '\n]\n') data = data.replace(',', ' , ') # make sure comma's seperate + if EXTRACT_STRINGS: + # add strings back in + + search = '"' # fill in these empty strings + + ok = True + last_i = 0 + while ok: + ok = False + i = data.find(search + '"', last_i) + + if i != -1: + start = i + len(search) # first char after end of search + item = string_ls.pop(0) + data = data[:start] + item + data[start:] + + last_i = start + len(item) + + ok = True + + # More annoying obscure cases where USE or DEF are placed on a newline # data = data.replace('\nDEF ', ' DEF ') # data = data.replace('\nUSE ', ' USE ') @@ -199,21 +275,46 @@ def is_numline(i): ''' Does this line start with a number? ''' + + # Works but too slow. + ''' l = lines[i] + for w in l.split(): + if w==',': + pass + else: + try: + float(w) + return True + + except: + return False + + return False + ''' + + l = lines[i] + + line_start = 0 + + if l.startswith(', '): + line_start += 2 + line_end = len(l)-1 - line_end_new = l.find(' ') # comma's always have a space before them + line_end_new = l.find(' ', line_start) # comma's always have a space before them if line_end_new != -1: line_end = line_end_new try: - float(l[:line_end]) # works for a float or int + float(l[line_start:line_end]) # works for a float or int return True except: return False + class vrmlNode(object): - __slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode' + __slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode' def __init__(self, parent, node_type, lineno): self.id = None self.node_type = node_type @@ -231,6 +332,7 @@ class vrmlNode(object): # Store in the root node because each inline file needs its own root node and its own namespace self.DEF_NAMESPACE = None + self.ROUTE_IPO_NAMESPACE = None self.FIELD_NAMESPACE = None self.reference = None @@ -257,12 +359,25 @@ class vrmlNode(object): return self.DEF_NAMESPACE else: return self.parent.getDefDict() + + def getRouteIpoDict(self): + if self.ROUTE_IPO_NAMESPACE != None: + return self.ROUTE_IPO_NAMESPACE + else: + return self.parent.getRouteIpoDict() def setRoot(self, filename): self.filename = filename - self.FIELD_NAMESPACE = {} - self.DEF_NAMESPACE= {} - + self.FIELD_NAMESPACE = {} + self.DEF_NAMESPACE = {} + self.ROUTE_IPO_NAMESPACE = {} + + def isRoot(self): + if self.filename == None: + return False + else: + return True + def getFilename(self): if self.filename: return self.filename @@ -284,6 +399,11 @@ class vrmlNode(object): except: return None + def getPrefix(self): + if self.id: + return self.id[0] + return None + def getDefName(self): self_real = self.getRealNode() @@ -464,11 +584,13 @@ class vrmlNode(object): child_array = None for child in self_real.children: + # print "ID IS", child.id if child.id and len(child.id) == 1 and child.id[0] == field: child_array = child break if child_array==None: + # For x3d, should work ok with vrml too # for x3d arrays are fields, vrml they are nodes, annoying but not tooo bad. data_split = self.getFieldName(field) @@ -489,9 +611,12 @@ class vrmlNode(object): print '\tWarning, could not parse array data from field' array_data = [] else: - + # print child_array # Normal vrml array_data = child_array.array_data + + + # print 'array_data', array_data if group==-1 or len(array_data)==0: return array_data @@ -520,8 +645,6 @@ class vrmlNode(object): # We requested a flat array if group == 0: return flat_array - - new_array = [] sub_array = [] @@ -537,6 +660,30 @@ class vrmlNode(object): return new_array + def getFieldAsStringArray(self, field): + ''' + Get a list of strings + ''' + self_real = self.getRealNode() # incase we're an instance + + child_array = None + for child in self_real.children: + if child.id and len(child.id) == 1 and child.id[0] == field: + child_array = child + break + if not child_array: + return [] + + # each string gets its own list, remove ""'s + try: + new_array = [f[0][1:-1] for f in child_array.fields] + except: + print '\twarning, string array could not be made' + new_array = [] + + return new_array + + def getLevel(self): # Ignore self_real level = 0 @@ -564,19 +711,24 @@ class vrmlNode(object): else: text = '' - text += ind + 'ID: ' + str(self.id) + ' ' + str(level) + ('lineno %d\n' % self.lineno) + text += ind + 'ID: ' + str(self.id) + ' ' + str(level) + (' lineno %d\n' % self.lineno) if self.node_type==NODE_REFERENCE: + text += ind + "(reference node)\n" return text - for item in self.fields: + text += ind + 'FIELDS:\n' + + for i,item in enumerate(self.fields): + text += ind + 'FIELD:\n' text += ind + str(item) +'\n' #text += ind + 'ARRAY: ' + str(len(self.array_data)) + ' ' + str(self.array_data) + '\n' text += ind + 'ARRAY: ' + str(len(self.array_data)) + '[...] \n' text += ind + 'CHILDREN: ' + str(len(self.children)) + '\n' - for child in self.children: + for i, child in enumerate(self.children): + text += ind + ('CHILD%d:\n' % i) text += str(child) text += '\n' + ind + brackets[1] @@ -590,12 +742,24 @@ class vrmlNode(object): # If we were an inline then try load the file if self.node_type == NODE_NORMAL and self.getSpec() == 'Inline': + url = self.getFieldAsString('url', None) if url != None: - if not exists(url): - url = dirName(self.getFilename()) + baseName(url) - if not exists(url): + urls = [] + urls.append( url ) + urls.append( BPySys.caseInsensitivePath(urls[-1]) ) + + urls.append( dirName(self.getFilename()) + baseName(url) ) + urls.append( BPySys.caseInsensitivePath(urls[-1]) ) + + try: + url = [url for url in urls if exists(url)][0] + url_found = True + except: + url_found = False + + if not url_found: print '\tWarning: Inline URL could not be found:', url else: if url==self.getFilename(): @@ -603,12 +767,12 @@ class vrmlNode(object): else: try: - f = open(url, 'rU') + data = gzipOpen(url) except: print '\tWarning: cant open the file:', url - f = None + data = None - if f: + if data: # Tricky - inline another VRML print '\tLoading Inline:"%s"...' % url @@ -616,12 +780,15 @@ class vrmlNode(object): lines_old = lines[:] - lines[:] = vrmlFormat( f.read() ) - f.close() + lines[:] = vrmlFormat( data ) lines.insert(0, '{') lines.insert(0, 'root_node____') lines.append('}') + ''' + ff = open('/test.txt', 'w') + ff.writelines([l+'\n' for l in lines]) + ''' child = vrmlNode(self, NODE_NORMAL, -1) child.setRoot(url) # initialized dicts @@ -723,7 +890,9 @@ class vrmlNode(object): values = l_split # This should not extend over multiple lines however it is possible - self.array_data.extend( values ) + # print self.array_data + if values: + self.array_data.extend( values ) i+=1 else: words = l.split() @@ -843,12 +1012,12 @@ def vrml_parse(path): lines.insert(0, '{') lines.insert(0, 'dymmy_node') lines.append('}') - # Use for testing our parsed output, so we can check on line numbers. - ## ff = open('m:\\test.txt', 'w') - ## ff.writelines([l+'\n' for l in lines]) - + ''' + ff = open('/test.txt', 'w') + ff.writelines([l+'\n' for l in lines]) + ''' # Now evaluate it node_type, new_i = is_nodeline(0, []) @@ -866,9 +1035,14 @@ def vrml_parse(path): # Parse recursively root.parse(0) - # print root + # This prints a load of text + ''' + print root + ''' + return root, '' + # ====================== END VRML @@ -996,6 +1170,9 @@ for i, f in enumerate(files): # ----------------------------------------------------------------------------------- import bpy import BPyImage +import BPySys +reload(BPySys) +reload(BPyImage) import Blender from Blender import Texture, Material, Mathutils, Mesh, Types, Window from Blender.Mathutils import TranslationMatrix @@ -1090,6 +1267,7 @@ def translateTexTransform(node): return new_mat + def getFinalMatrix(node, mtx, ancestry): transform_nodes = [node_tx for node_tx in ancestry if node_tx.getSpec() == 'Transform'] @@ -1343,7 +1521,8 @@ def importMesh_IndexedFaceSet(geom, bpyima): if len(ifs_vcol) < color_index: c.r, c.g, c.b = ifs_vcol[color_index] else: - print '\tWarning: per face color index out of range' + #print '\tWarning: per face color index out of range' + pass else: if vcolor_spot: # use 1 color, when ifs_vcol is [] for c in fcol: @@ -1517,6 +1696,9 @@ def importShape(node, ancestry): bpymat = None bpyima = None texmtx = None + + depth = 0 # so we can set alpha face flag later + if appr: #mat = appr.getChildByName('material') # 'Material' @@ -1561,12 +1743,17 @@ def importShape(node, ancestry): if ima: - # print ima + ima_url = ima.getFieldAsString('url') + + if ima_url==None: + try: ima_url = ima.getFieldAsStringArray('url')[0] # in some cases we get a list of images. + except: ima_url = None + if ima_url==None: print "\twarning, image with no URL, this is odd" else: - bpyima= BPyImage.comprehensiveImageLoad(ima_url, dirName(node.getFilename()), PLACE_HOLDER= False, RECURSIVE= False) + bpyima= BPyImage.comprehensiveImageLoad(ima_url, dirName(node.getFilename()), PLACE_HOLDER= False, RECURSIVE= False, CONVERT_CALLBACK= imageConvertCompat) if bpyima: texture= bpy.data.textures.new() texture.setType('Image') @@ -1588,7 +1775,8 @@ def importShape(node, ancestry): ima_repS = ima.getFieldAsBool('repeatS', True) ima_repT = ima.getFieldAsBool('repeatT', True) - texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512) + # To make this work properly we'd need to scale the UV's too, better to ignore th + # texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512) if not ima_repS: bpyima.clampX = True if not ima_repT: bpyima.clampY = True @@ -1632,15 +1820,22 @@ def importShape(node, ancestry): # Only ever 1 material per shape if bpymat: bpydata.materials = [bpymat] - if bpydata.faceUV and texmtx: - # Apply texture transform? - uv_copy = Vector() - for f in bpydata.faces: - for uv in f.uv: - uv_copy.x = uv.x - uv_copy.y = uv.y - - uv.x, uv.y = (uv_copy * texmtx)[0:2] + if bpydata.faceUV: + + if depth==32: # set the faces alpha flag? + transp = Mesh.FaceTranspModes.ALPHA + for f in bpydata.faces: + f.transp = transp + + if texmtx: + # Apply texture transform? + uv_copy = Vector() + for f in bpydata.faces: + for uv in f.uv: + uv_copy.x = uv.x + uv_copy.y = uv.y + + uv.x, uv.y = (uv_copy * texmtx)[0:2] # Done transforming the texture @@ -1733,7 +1928,7 @@ def importLamp_SpotLight(node): # Convert # lamps have their direction as -z, y==up - mtx = TranslationMatrix(Vector(location)) * Vector(direction).toTrackQuat('-z', 'y').toMatrix().resize4x4() + mtx = Vector(direction).toTrackQuat('-z', 'y').toMatrix().resize4x4() * TranslationMatrix(Vector(location)) return bpylamp, mtx @@ -1760,14 +1955,14 @@ def importViewpoint(node, ancestry): fieldOfView = node.getFieldAsFloat('fieldOfView', 0.785398) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. # jump = node.getFieldAsBool('jump', True) orientation = node.getFieldAsFloatTuple('orientation', (0.0, 0.0, 1.0, 0.0)) - position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 10.0)) + position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 0.0)) description = node.getFieldAsString('description', '') bpycam = bpy.data.cameras.new(name) bpycam.angle = fieldOfView - mtx = TranslationMatrix(Vector(position)) * translateRotation(orientation) * MATRIX_Z_TO_Y + mtx = translateRotation(orientation) * TranslationMatrix(Vector(position)) bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpycam) @@ -1781,6 +1976,149 @@ def importTransform(node, ancestry): bpyob = node.blendObject = bpy.data.scenes.active.objects.new('Empty', name) # , name) bpyob.setMatrix( getFinalMatrix(node, None, ancestry) ) + +#def importTimeSensor(node): + + +def translatePositionInterpolator(node, ipo): + key = node.getFieldAsArray('key', 0) + keyValue = node.getFieldAsArray('keyValue', 3) + + loc_x = ipo.addCurve('LocX') + loc_y = ipo.addCurve('LocY') + loc_z = ipo.addCurve('LocZ') + + loc_x.interpolation = loc_y.interpolation = loc_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + for i, time in enumerate(key): + x,y,z = keyValue[i] + + loc_x.append((time,x)) + loc_y.append((time,y)) + loc_z.append((time,z)) + +def translateOrientationInterpolator(node, ipo): + key = node.getFieldAsArray('key', 0) + keyValue = node.getFieldAsArray('keyValue', 4) + + rot_x = ipo.addCurve('RotX') + rot_y = ipo.addCurve('RotY') + rot_z = ipo.addCurve('RotZ') + + rot_x.interpolation = rot_y.interpolation = rot_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + for i, time in enumerate(key): + + mtx = translateRotation(keyValue[i]) + eul = mtx.toEuler() + rot_x.append((time,eul.x/10.0)) + rot_y.append((time,eul.y/10.0)) + rot_z.append((time,eul.z/10.0)) + +# Untested! +def translateScalarInterpolator(node, ipo): + key = node.getFieldAsArray('key', 0) + keyValue = node.getFieldAsArray('keyValue', 4) + + sca_x = ipo.addCurve('SizeX') + sca_y = ipo.addCurve('SizeY') + sca_z = ipo.addCurve('SizeZ') + + sca_x.interpolation = sca_y.interpolation = sca_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + for i, time in enumerate(key): + x,y,z = keyValue[i] + sca_x.append((time,x/10.0)) + sca_y.append((time,y/10.0)) + sca_z.append((time,z/10.0)) + +def translateTimeSensor(node, ipo): + ''' + Apply a time sensor to an IPO, VRML has many combinations of loop/start/stop/cycle times + to give different results, for now just do the basics + ''' + + time_cu = ipo.addCurve('Time') + time_cu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + cycleInterval = node.getFieldAsFloat('cycleInterval', None) + + startTime = node.getFieldAsFloat('startTime', 0.0) + stopTime = node.getFieldAsFloat('stopTime', 250.0) + + if cycleInterval != None: + stopTime = startTime+cycleInterval + + loop = node.getFieldAsBool('loop', False) + + time_cu.append((1+startTime, 0.0)) + time_cu.append((1+stopTime, 1.0/10.0))# anoying, the UI uses /10 + + + if loop: + time_cu.extend = Blender.IpoCurve.ExtendTypes.CYCLIC # or - EXTRAP, CYCLIC_EXTRAP, CONST, + + +def importRoute(node): + ''' + Animation route only at the moment + ''' + + routeIpoDict = node.getRouteIpoDict() + + def getIpo(id): + try: ipo = routeIpoDict[id] + except: ipo = routeIpoDict[id] = bpy.data.ipos.new('web3d_ipo', 'Object') + return ipo + + # for getting definitions + defDict = node.getDefDict() + ''' + Handles routing nodes to eachother + +ROUTE vpPI.value_changed TO champFly001.set_position +ROUTE vpOI.value_changed TO champFly001.set_orientation +ROUTE vpTs.fraction_changed TO vpPI.set_fraction +ROUTE vpTs.fraction_changed TO vpOI.set_fraction +ROUTE champFly001.bindTime TO vpTs.set_startTime + ''' + + #from_id, from_type = node.id[1].split('.') + #to_id, to_type = node.id[3].split('.') + + #value_changed + set_position_node = None + set_orientation_node = None + time_node = None + + for field in node.fields: + if field and field[0]=='ROUTE': + from_id, from_type = field[1].split('.') + to_id, to_type = field[3].split('.') + + if from_type == 'value_changed': + if to_type == 'set_position': + ipo = getIpo(to_id) + set_data_from_node = defDict[from_id] + translatePositionInterpolator(set_data_from_node, ipo) + + if to_type == 'set_orientation': + ipo = getIpo(to_id) + set_data_from_node = defDict[from_id] + translateOrientationInterpolator(set_data_from_node, ipo) + + if to_type == 'set_scale': + ipo = getIpo(to_id) + set_data_from_node = defDict[from_id] + translateScalarInterpolator(set_data_from_node, ipo) + + elif from_type == 'bindTime': + ipo = getIpo(from_id) + time_node = defDict[to_id] + translateTimeSensor(time_node, ipo) + + + def load_web3d(path, PREF_FLAT=False, PREF_CIRCLE_DIV=16, HELPER_FUNC = None): @@ -1818,14 +2156,44 @@ def load_web3d(path, PREF_FLAT=False, PREF_CIRCLE_DIV=16, HELPER_FUNC = None): elif spec=='Transform': # Only use transform nodes when we are not importing a flat object hierarchy if PREF_FLAT==False: - importTransform(node, ancestry) - else: + importTransform(node, ancestry) + ''' + # These are delt with later within importRoute + elif spec=='PositionInterpolator': + ipo = bpy.data.ipos.new('web3d_ipo', 'Object') + translatePositionInterpolator(node, ipo) + ''' + else: # Note, include this function so the VRML/X3D importer can be extended # by an external script. if HELPER_FUNC: HELPER_FUNC(node, ancestry) + + + + # After we import all nodes, route events - anim paths + for node, ancestry in all_nodes: + importRoute(node) + + for node, ancestry in all_nodes: + if node.isRoot(): + # we know that all nodes referenced from will be in + # routeIpoDict so no need to run node.getDefDict() for every node. + routeIpoDict = node.getRouteIpoDict() + defDict = node.getDefDict() + for key, ipo in routeIpoDict.iteritems(): + + # Assign anim curves + node = defDict[key] + if node.blendObject==None: # Add an object if we need one for animation + node.blendObject = bpy.data.scenes.active.objects.new('Empty', 'AnimOb') # , name) + + node.blendObject.setIpo(ipo) + + + # Add in hierarchy if PREF_FLAT==False: child_dict = {} @@ -1886,7 +2254,7 @@ def load_ui(path): if __name__ == '__main__': Window.FileSelector(load_ui, 'Import X3D/VRML97') - + # Testing stuff # load_web3d('/test.x3d') |