diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-01-26 11:34:40 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-01-26 11:34:40 +0300 |
commit | 87627374000b7de7445736a7239a3f2b168ce7eb (patch) | |
tree | 2f0fe5d42d0938fc1b684af702d8613099bea1bd /release | |
parent | 784d8ee37a52f3ef689aa6d02e75e50566efe93f (diff) | |
parent | ba8ea9ec63c25b1ce134a846176f7bf252f4d487 (diff) |
2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17853:HEAD
Diffstat (limited to 'release')
21 files changed, 830 insertions, 387 deletions
diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py index 6a2b290e010..2f5512e7150 100644 --- a/release/scripts/ac3d_import.py +++ b/release/scripts/ac3d_import.py @@ -10,7 +10,7 @@ Tip: 'Import an AC3D (.ac) file.' __author__ = "Willian P. Germano" __url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org", "PLib 3d gaming lib, http://plib.sf.net") -__version__ = "2.43.1 2007-02-21" +__version__ = "2.48.1 2009-01-11" __bpydoc__ = """\ This script imports AC3D models into Blender. @@ -31,6 +31,7 @@ Known issues:<br> Config Options:<br> - display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.<br> - subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.<br> + - emis as mircol: store the emissive rgb color from AC3D as mirror color in Blender -- this is a hack to preserve the values and be able to export them using the equivalent option in the exporter.<br> - textures dir (string): if non blank, when imported texture paths are wrong in the .ac file, Blender will also look for them at this dir. @@ -50,11 +51,12 @@ users can configure (see config options above). # -------------------------------------------------------------------------- # Thanks: Melchior Franz for extensive bug testing and reporting, making this # version cope much better with old or bad .ac files, among other improvements; -# Stewart Andreason for reporting a serious crash. +# Stewart Andreason for reporting a serious crash; Francesco Brisa for the +# emis as mircol functionality (w/ patch). # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # -# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br +# Copyright (C) 2004-2009: Willian P. Germano, wgermano _at_ ig.com.br # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -89,15 +91,19 @@ DISPLAY_TRANSP = True SUBDIV = True +EMIS_AS_MIRCOL = False + + tooltips = { 'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.', 'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.', - 'TEXTURES_DIR': 'Additional folder to look for missing textures.' + 'TEXTURES_DIR': 'Additional folder to look for missing textures.', + 'EMIS_AS_MIRCOL': 'Store emis color as mirror color in Blender.' } def update_registry(): - global TEXTURES_DIR, DISPLAY_TRANSP - rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV)]) + global TEXTURES_DIR, DISPLAY_TRANSP, EMIS_AS_MIRCOL + rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV), ('EMIS_AS_MIRCOL', EMIS_AS_MIRCOL)]) Registry.SetKey('ac3d_import', rd, True) rd = Registry.GetKey('ac3d_import', True) @@ -109,6 +115,7 @@ if rd: TEXTURES_DIR = rd['TEXTURES_DIR'] DISPLAY_TRANSP = rd['DISPLAY_TRANSP'] SUBDIV = rd['SUBDIV'] + EMIS_AS_MIRCOL = rd['EMIS_AS_MIRCOL'] except: update_registry() else: update_registry() @@ -299,7 +306,7 @@ class AC3DImport: lines = self.lines line = lines[i].split() mat_name = '' - mat_col = mat_amb = mat_emit = mat_spec_col = [0,0,0] + mat_col = mat_amb = mat_emit = mat_spec_col = mat_mir_col = [0,0,0] mat_alpha = 1 mat_spec = 1.0 @@ -310,11 +317,15 @@ class AC3DImport: mat_amb = (v[0]+v[1]+v[2]) / 3.0 v = map(float,[line[11],line[12],line[13]]) mat_emit = (v[0]+v[1]+v[2]) / 3.0 + if EMIS_AS_MIRCOL: + mat_emit = 0 + mat_mir_col = map(float,[line[11],line[12],line[13]]) + mat_spec_col = map(float,[line[15],line[16],line[17]]) mat_spec = float(line[19]) / 64.0 mat_alpha = float(line[-1]) mat_alpha = 1 - mat_alpha - self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_alpha]) + self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_mir_col, mat_alpha]) i += 1 line = lines[i].split() @@ -590,7 +601,8 @@ class AC3DImport: m.emit = mat[3] m.specCol = (mat[4][0], mat[4][1], mat[4][2]) m.spec = mat[5] - m.alpha = mat[6] + m.mirCol = (mat[6][0], mat[6][1], mat[6][2]) + m.alpha = mat[7] if m.alpha < 1.0: m.mode |= MAT_MODE_ZTRANSP has_transp_mats = True diff --git a/release/scripts/animation_bake_constraints.py b/release/scripts/animation_bake_constraints.py index 58e9e2b1d02..16855828460 100644 --- a/release/scripts/animation_bake_constraints.py +++ b/release/scripts/animation_bake_constraints.py @@ -155,7 +155,7 @@ usrObjectNamePrefix= "" # if that armature had bones (spine, neck, arm) and the bone prefix was "a." # the bones and IPO curves will be (a.spine, a.neck, a.arm) -R2D = 18/3.1415 # radian to grad +R2D = 18/3.141592653589793 # radian to grad BLENDER_VERSION = Blender.Get('version') # Gets the current scene, there can be many scenes in 1 blend file. diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py index 415c2a12c69..6bbfaa463d0 100644 --- a/release/scripts/bpymodules/BPyMesh.py +++ b/release/scripts/bpymodules/BPyMesh.py @@ -479,7 +479,7 @@ def pickMeshRayFaceWeight(me, orig, rdir): w0 = (l1+l2) w1 = (l0+l2) - w2 = (l1+l2) + w2 = (l1+l0) totw= w0 + w1 + w2 w0=w0/totw diff --git a/release/scripts/bpymodules/dxfLibrary.py b/release/scripts/bpymodules/dxfLibrary.py index 5c63e7f5bf5..96caa50cc41 100644 --- a/release/scripts/bpymodules/dxfLibrary.py +++ b/release/scripts/bpymodules/dxfLibrary.py @@ -1,10 +1,10 @@ #dxfLibrary.py : provides functions for generating DXF files # -------------------------------------------------------------------------- -__version__ = "v1.27beta - 2008.10.05" -__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" +__version__ = "v1.28beta - 2008.12.13" +__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" __license__ = "GPL" -__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" -__bpydoc__ ="""The script exports geometry data to DXF format r12 version. +__url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf" +__bpydoc__ ="""The library to export geometry data to DXF format r12 version. Copyright %s Version %s @@ -12,15 +12,17 @@ License %s Homepage %s See the homepage for documentation. -url: +Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439 IDEAs: - - + TODO: -- +- add support for SPLINEs History +v1.28 - 2008.12.13 by Steeve/BlenderArtists +- bugfix for EXTMIN/EXTMAX to suit Cycas-CAD v1.27 - 2008.10.07 by migius - beautifying output code: keys whitespace prefix - refactoring DXF-strings format: NewLine moved to the end of @@ -154,56 +156,56 @@ BYBLOCK=0 BYLAYER=256 #---block-type flags (bit coded values, may be combined): -ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application +ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) -XREF =4 # This block is an external reference (xref) -XREF_OVERLAY =8 # This block is an xref overlay -EXTERNAL =16 # This block is externally dependent -RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) -REFERENCED =64 # This definition is a referenced external reference (ignored on input) +XREF =4 # This block is an external reference (xref) +XREF_OVERLAY =8 # This block is an xref overlay +EXTERNAL =16 # This block is externally dependent +RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) +REFERENCED =64 # This definition is a referenced external reference (ignored on input) #---mtext flags #attachment point -TOP_LEFT = 1 -TOP_CENTER = 2 -TOP_RIGHT = 3 -MIDDLE_LEFT = 4 -MIDDLE_CENTER = 5 +TOP_LEFT = 1 +TOP_CENTER = 2 +TOP_RIGHT = 3 +MIDDLE_LEFT = 4 +MIDDLE_CENTER = 5 MIDDLE_RIGHT = 6 -BOTTOM_LEFT = 7 -BOTTOM_CENTER = 8 -BOTTOM_RIGHT = 9 +BOTTOM_LEFT = 7 +BOTTOM_CENTER = 8 +BOTTOM_RIGHT = 9 #drawing direction -LEFT_RIGHT = 1 -TOP_BOTTOM = 3 -BY_STYLE = 5 #the flow direction is inherited from the associated text style +LEFT_RIGHT = 1 +TOP_BOTTOM = 3 +BY_STYLE = 5 #the flow direction is inherited from the associated text style #line spacing style (optional): -AT_LEAST = 1 #taller characters will override -EXACT = 2 #taller characters will not override +AT_LEAST = 1 #taller characters will override +EXACT = 2 #taller characters will not override #---polyline flags -CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) -CURVE_FIT =2 # Curve-fit vertices have been added -SPLINE_FIT =4 # Spline-fit vertices have been added -POLYLINE_3D =8 # This is a 3D polyline -POLYGON_MESH =16 # This is a 3D polygon mesh -CLOSED_N =32 # The polygon mesh is closed in the N direction -POLYFACE_MESH =64 # The polyline is a polyface mesh -CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline #---text flags #horizontal -LEFT = 0 -CENTER = 1 -RIGHT = 2 -ALIGNED = 3 #if vertical alignment = 0 -MIDDLE = 4 #if vertical alignment = 0 -FIT = 5 #if vertical alignment = 0 +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 #if vertical alignment = 0 +MIDDLE = 4 #if vertical alignment = 0 +FIT = 5 #if vertical alignment = 0 #vertical -BASELINE = 0 -BOTTOM = 1 -MIDDLE = 2 -TOP = 3 +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 ####3) Classes #---entitities ----------------------------------------------- @@ -239,7 +241,7 @@ class Face(_Entity): """3dface""" def __init__(self,points,**common): _Entity.__init__(self,**common) - if len(points)<4: #fix for r12 format + while len(points)<4: #fix for r12 format points.append(points[-1]) self.points=points @@ -336,10 +338,14 @@ class PolyLine(_Entity): #----------------------------------------------- class Point(_Entity): - """Colored solid fill.""" + """Point.""" def __init__(self,points=None,**common): _Entity.__init__(self,**common) self.points=points + def __str__(self): #TODO: + return ' 0\nPOINT\n%s%s\n' %(self._common(), + _points(self.points) + ) #----------------------------------------------- class Solid(_Entity): @@ -468,7 +474,7 @@ class Block(_Collection): self.name=name self.flag=0 self.base=base - def __str__(self): + def __str__(self): #TODO: e=''.join([str(x)for x in self.entities]) return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e) @@ -552,11 +558,12 @@ def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options): #----------------------------------------------- class Drawing(_Collection): """Dxf drawing. Use append or any other list methods to add objects.""" - def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0),extmax=(0.0,0.0), + def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0), layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], views=[],entities=None,fileName='test.dxf'): # TODO: replace list with None,arial - if not entities:entities=[] + if not entities: + entities=[] _Collection.__init__(self,entities) self.insbase=insbase self.extmin=extmin @@ -680,9 +687,9 @@ def test(): #Drawing d=Drawing() #tables - d.blocks.append(b) #table blocks - d.styles.append(Style()) #table styles - d.views.append(View('Normal')) #table view + d.blocks.append(b) #table blocks + d.styles.append(Style()) #table styles + d.views.append(View('Normal')) #table view d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem #entities diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py index ce17f78c5e2..6f964118964 100644 --- a/release/scripts/export_fbx.py +++ b/release/scripts/export_fbx.py @@ -1446,13 +1446,13 @@ def write(filename, batch_objects = None, \ for f in me.faces: for col in f.col: if i==-1: - file.write('%i,%i,%i' % (col[0], col[1], col[2])) + file.write('%i,%i,%i,255' % (col[0], col[1], col[2])) i=0 else: if i==7: file.write('\n\t\t\t\t') i=0 - file.write(',%i,%i,%i' % (col[0], col[1], col[2])) + file.write(',%i,%i,%i,255' % (col[0], col[1], col[2])) i+=1 ii+=1 # One more Color diff --git a/release/scripts/help_bpy_api.py b/release/scripts/help_bpy_api.py index 484663b32b3..9c3a24af288 100644 --- a/release/scripts/help_bpy_api.py +++ b/release/scripts/help_bpy_api.py @@ -1,17 +1,17 @@ #!BPY """ Name: 'Blender/Python Scripting API' -Blender: 244 +Blender: 248 Group: 'Help' Tooltip: 'The Blender Python API reference manual' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartist") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ This script opens the user's default web browser at http://www.blender.org's -"Blenders Python API" page. +"Blender Python API Reference" page. """ # -------------------------------------------------------------------------- @@ -38,4 +38,4 @@ This script opens the user's default web browser at http://www.blender.org's import Blender, webbrowser version = str(int(Blender.Get('version'))) -webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/index.html') +webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/') diff --git a/release/scripts/help_browser.py b/release/scripts/help_browser.py index b27e266f368..c207a12068f 100644 --- a/release/scripts/help_browser.py +++ b/release/scripts/help_browser.py @@ -8,7 +8,7 @@ Tooltip: 'Show help information about a chosen installed script.' """ __author__ = "Willian P. Germano" -__version__ = "0.1 11/02/04" +__version__ = "0.3 01/21/09" __email__ = ('scripts', 'Author, wgermano:ig*com*br') __url__ = ('blender', 'blenderartists.org') @@ -47,8 +47,6 @@ Hotkeys:<br> # $Id$ # # -------------------------------------------------------------------------- -# sysinfo.py version 0.1 Jun 09, 2004 -# -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # # Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br @@ -69,6 +67,9 @@ Hotkeys:<br> # # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- +# Thanks: Brendon Murphy (suggestion) and Kevin Morgan (implementation) +# for the "run" button; Jean-Michel Soler for pointing a parsing error +# with multilines using triple single quotes. import Blender from Blender import sys as bsys, Draw, Window, Registry @@ -355,7 +356,12 @@ def parse_pyobj(var, lines, i): l = "ERROR" elif l[0] == "'": - if l[-1] == '\\': + if l[1:3] == "''": # ''' + if l.find("'''", 3) < 0: # multiline + l2, i = parse_pyobj_close("'''", lines, i) + if l[-1] == '\\': l = l[:-1] + l = "%s%s" % (l, l2) + elif l[-1] == '\\': l2, i = parse_pyobj_close("'", lines, i) l = "%s%s" % (l, l2) elif l[-1] == "'" and l[-2] != '\\': # single line: '...' @@ -543,6 +549,7 @@ BEVT_GMENU = range(100, len_gmenus + 100) BEVT_VIEWSOURCE = 1 BEVT_EXIT = 2 BEVT_BACK = 3 +BEVT_EXEC = 4 # Executes Script # gui callbacks: @@ -551,7 +558,7 @@ def gui(): # drawing the screen global SCREEN, START_SCREEN, SCRIPT_SCREEN global SCRIPT_INFO, AllGroups, GROUP_MENUS global BEVT_EMAIL, BEVT_LINK - global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU + global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU, BEVT_EXEC global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE theme = Theme.Get()[0] @@ -674,8 +681,11 @@ def gui(): # drawing the screen 'View this script\'s source code in the Text Editor (hotkey: S)') Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh, 'Exit from Scripts Help Browser (hotkey: Q)') - if not FMODE: Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh, + if not FMODE: + Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh, 'Back to scripts selection screen (hotkey: ESC)') + Draw.PushButton('run script', BEVT_EXEC, x + 3*45, 17, 60, bh, 'Run this script') + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) BGL.glRasterPos2i(x, 5) Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small') @@ -766,6 +776,14 @@ def button_event(evt): # gui button events SCRIPT_INFO = None SCROLL_DOWN = 0 Draw.Redraw() + elif evt == BEVT_EXEC: # Execute script + exec_line = '' + if SCRIPT_INFO.script.userdir: + exec_line = bsys.join(Blender.Get('uscriptsdir'), SCRIPT_INFO.script.fname) + else: + exec_line = bsys.join(Blender.Get('scriptsdir'), SCRIPT_INFO.script.fname) + + Blender.Run(exec_line) keepon = True FMODE = False # called by Blender.ShowHelp(name) API function ? diff --git a/release/scripts/help_getting_started.py b/release/scripts/help_getting_started.py index 81b002da4e4..a4f6da5cc55 100644 --- a/release/scripts/help_getting_started.py +++ b/release/scripts/help_getting_started.py @@ -1,16 +1,16 @@ #!BPY """ Name: 'Getting Started' -Blender: 234 +Blender: 248 Group: 'Help' Tooltip: 'Help for new users' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's +This script opens the user's default web browser at www.blender.org's "Getting Started" page. """ @@ -39,5 +39,4 @@ This script opens the user's default web browser at www.blender3d.org's # -------------------------------------------------------------------------- import Blender, webbrowser -version = str(Blender.Get('version')) -webbrowser.open('http://www.blender3d.org/Help/?pg=GettingStarted&ver=' + version) +webbrowser.open('http://www.blender.org/education-help/tutorials/getting-started/') diff --git a/release/scripts/help_manual.py b/release/scripts/help_manual.py index cf293bf7c2c..b830975e593 100644 --- a/release/scripts/help_manual.py +++ b/release/scripts/help_manual.py @@ -1,17 +1,17 @@ #!BPY """ Name: 'Manual' -Blender: 234 +Blender: 248 Group: 'Help' -Tooltip: 'The Blender reference manual' +Tooltip: 'The Blender Wiki manual' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's -"Blender Manual" page. +This script opens the user's default web browser at www.blender.org's +"Manual" page. """ # -------------------------------------------------------------------------- @@ -37,5 +37,4 @@ This script opens the user's default web browser at www.blender3d.org's # -------------------------------------------------------------------------- import Blender, webbrowser -version = str(Blender.Get('version')) -webbrowser.open('http://www.blender3d.org/Help/?pg=Manual&ver=' + version) +webbrowser.open('http://wiki.blender.org/index.php/Manual') diff --git a/release/scripts/help_release_notes.py b/release/scripts/help_release_notes.py index af7a7042489..919ec72da3c 100644 --- a/release/scripts/help_release_notes.py +++ b/release/scripts/help_release_notes.py @@ -1,17 +1,17 @@ #!BPY """ -Name: 'Release Notes' -Blender: 234 +Name: 'Release Logs' +Blender: 248 Group: 'Help' Tooltip: 'Information about the changes in this version of Blender' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's -"Release Notes" page. +This script opens the user's default web browser at www.blender.org's +"Release Logs" page. """ # -------------------------------------------------------------------------- @@ -37,5 +37,5 @@ This script opens the user's default web browser at www.blender3d.org's # -------------------------------------------------------------------------- import Blender, webbrowser -version = str(Blender.Get('version')) -webbrowser.open('http://www.blender3d.org/Help/?pg=ReleaseNotes&ver=' + version) + +webbrowser.open('http://www.blender.org/development/release-logs/') diff --git a/release/scripts/help_tutorials.py b/release/scripts/help_tutorials.py index 04d6c799455..1fe466560f0 100644 --- a/release/scripts/help_tutorials.py +++ b/release/scripts/help_tutorials.py @@ -2,17 +2,17 @@ """ Name: 'Tutorials' -Blender: 234 +Blender: 248 Group: 'Help' Tooltip: 'Tutorials for learning to use Blender' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's -"Blender Tutorials" page. +This script opens the user's default web browser at www.blender.org's +"Tutorials" page. """ # -------------------------------------------------------------------------- @@ -38,5 +38,4 @@ This script opens the user's default web browser at www.blender3d.org's # -------------------------------------------------------------------------- import Blender, webbrowser -version = str(Blender.Get('version')) -webbrowser.open('http://www.blender3d.org/Help/?pg=Tutorials&ver=' + version) +webbrowser.open('http://www.blender.org/education-help/tutorials/') diff --git a/release/scripts/help_web_blender.py b/release/scripts/help_web_blender.py index 0f9e32dea0e..db0a78d90f7 100644 --- a/release/scripts/help_web_blender.py +++ b/release/scripts/help_web_blender.py @@ -2,17 +2,17 @@ """ Name: 'Blender Website' -Blender: 234 +Blender: 248 Group: 'HelpWebsites' Tooltip: 'The official Blender website' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ This script opens the user's default web browser at Blender's main site, -www.blender3d.org. +www.blender.org. """ @@ -39,4 +39,4 @@ www.blender3d.org. # -------------------------------------------------------------------------- import Blender, webbrowser -webbrowser.open('http://www.blender3d.org/') +webbrowser.open('http://www.blender.org/') diff --git a/release/scripts/help_web_devcomm.py b/release/scripts/help_web_devcomm.py index 344622cc113..e04a54501f7 100644 --- a/release/scripts/help_web_devcomm.py +++ b/release/scripts/help_web_devcomm.py @@ -2,17 +2,17 @@ """ Name: 'Developer Community' -Blender: 234 +Blender: 248 Group: 'HelpWebsites' Tooltip: 'Get involved with Blender development' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender.org, the -Blender development portal. +This script opens the user's default web browser at www.blender.org's +"Get Involved" page. """ # -------------------------------------------------------------------------- @@ -38,4 +38,4 @@ Blender development portal. # -------------------------------------------------------------------------- import webbrowser -webbrowser.open('http://www.blender.org') +webbrowser.open('http://www.blender.org/community/get-involved/') diff --git a/release/scripts/help_web_eshop.py b/release/scripts/help_web_eshop.py index 451fd735150..c33849ac419 100644 --- a/release/scripts/help_web_eshop.py +++ b/release/scripts/help_web_eshop.py @@ -2,16 +2,16 @@ """ Name: 'Blender E-Shop' -Blender: 234 +Blender: 248 Group: 'HelpWebsites' Tooltip: 'Buy official Blender resources and merchandise online' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's +This script opens the user's default web browser at www.blender.org's "E-Shop" section. """ diff --git a/release/scripts/help_web_usercomm.py b/release/scripts/help_web_usercomm.py index fbe19956eb7..a77a2bb9fef 100644 --- a/release/scripts/help_web_usercomm.py +++ b/release/scripts/help_web_usercomm.py @@ -2,16 +2,16 @@ """ Name: 'User Community' -Blender: 234 +Blender: 248 Group: 'HelpWebsites' Tooltip: 'Get involved with other Blender users' """ __author__ = "Matt Ebb" __url__ = ("blender", "blenderartists.org") -__version__ = "1.0" +__version__ = "1.0.1" __bpydoc__ = """\ -This script opens the user's default web browser at www.blender3d.org's +This script opens the user's default web browser at www.blender.org's "User Community" page. """ @@ -38,4 +38,4 @@ This script opens the user's default web browser at www.blender3d.org's # -------------------------------------------------------------------------- import webbrowser -webbrowser.open('http://www.blender3d.org/Community') +webbrowser.open('http://www.blender.org/community/user-community/') diff --git a/release/scripts/import_web3d.py b/release/scripts/import_web3d.py index 06cde898ef2..28bc1a40ef0 100755 --- a/release/scripts/import_web3d.py +++ b/release/scripts/import_web3d.py @@ -36,6 +36,8 @@ __bpydoc__ = """\ This script is an importer for the X3D and VRML97 file formats. """ +DEBUG = False + # This should work without a blender at all try: from Blender.sys import exists @@ -50,11 +52,11 @@ def dirName(path): def imageConvertCompat(path): - try: import os - except: - return path + try: import os + except: return path + if os.sep=='\\': return path # assime win32 has quicktime, dont convert - if path.endswith('.gif'): + if path.lower().endswith('.gif'): path_to = path[:-3] + 'png' ''' @@ -145,13 +147,12 @@ def vrmlFormat(data): data = data[:start] + data[end:] ok = True # keep looking - last_i = end - len(item) + 1 + 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#') @@ -173,13 +174,14 @@ def vrmlFormat(data): while ok: ok = False i = data.find(search + '"', last_i) - + # print i if i != -1: start = i + len(search) # first char after end of search item = string_ls.pop(0) + # print item data = data[:start] + item + data[start:] - last_i = start + len(item) + last_i = start + len(item) + 1 ok = True @@ -201,6 +203,7 @@ def vrmlFormat(data): NODE_NORMAL = 1 # {} NODE_ARRAY = 2 # [] NODE_REFERENCE = 3 # USE foobar +# NODE_PROTO = 4 # lines = [] @@ -211,6 +214,10 @@ def getNodePreText(i, words): if i>=len(lines): break + ''' + elif lines[i].startswith('PROTO'): + return NODE_PROTO, i+1 + ''' elif lines[i]=='{': # words.append(lines[i]) # no need # print "OK" @@ -244,6 +251,23 @@ def is_nodeline(i, words): if not lines[i][0].isalpha(): return 0, 0 + #if lines[i].startswith('field'): + # return 0, 0 + + # Is this a prototype?? + if lines[i].startswith('PROTO'): + words[:] = lines[i].split() + return NODE_NORMAL, i+1 # TODO - assumes the next line is a '[\n', skip that + if lines[i].startswith('EXTERNPROTO'): + words[:] = lines[i].split() + return NODE_ARRAY, i+1 # TODO - assumes the next line is a '[\n', skip that + + ''' + proto_type, new_i = is_protoline(i, words, proto_field_defs) + if new_i != -1: + return proto_type, new_i + ''' + # Simple "var [" type if lines[i+1] == '[': if lines[i].count('"') % 2 == 0: @@ -253,6 +277,7 @@ def is_nodeline(i, words): node_type, new_i = getNodePreText(i, words) if not node_type: + if DEBUG: print "not node_type", lines[i] return 0, 0 # Ok, we have a { after some values @@ -311,10 +336,10 @@ def is_numline(i): return True except: return False - + class vrmlNode(object): - __slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode' + __slots__ = 'id', 'fields', 'proto_node', 'proto_field_defs', 'proto_fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'PROTO_NAMESPACE', 'x3dNode' def __init__(self, parent, node_type, lineno): self.id = None self.node_type = node_type @@ -329,11 +354,17 @@ class vrmlNode(object): # This is only set from the root nodes. # Having a filename also denotes a root node self.filename = None + self.proto_node = None # proto field definition eg: "field SFColor seatColor .6 .6 .1" # Store in the root node because each inline file needs its own root node and its own namespace self.DEF_NAMESPACE = None self.ROUTE_IPO_NAMESPACE = None + ''' self.FIELD_NAMESPACE = None + ''' + + + self.PROTO_NAMESPACE = None self.reference = None @@ -343,16 +374,26 @@ class vrmlNode(object): return self.fields = [] # fields have no order, in some cases rool level values are not unique so dont use a dict + + self.proto_field_defs = [] # proto field definition eg: "field SFColor seatColor .6 .6 .1" + self.proto_fields = [] # proto field usage "diffuseColor IS seatColor" self.children = [] self.array_data = [] # use for arrays of data - should only be for NODE_ARRAY types # Only available from the root node + ''' def getFieldDict(self): if self.FIELD_NAMESPACE != None: return self.FIELD_NAMESPACE else: return self.parent.getFieldDict() + ''' + def getProtoDict(self): + if self.PROTO_NAMESPACE != None: + return self.PROTO_NAMESPACE + else: + return self.parent.getProtoDict() def getDefDict(self): if self.DEF_NAMESPACE != None: @@ -368,9 +409,10 @@ class vrmlNode(object): def setRoot(self, filename): self.filename = filename - self.FIELD_NAMESPACE = {} + # self.FIELD_NAMESPACE = {} self.DEF_NAMESPACE = {} self.ROUTE_IPO_NAMESPACE = {} + self.PROTO_NAMESPACE = {} def isRoot(self): if self.filename == None: @@ -399,20 +441,36 @@ class vrmlNode(object): except: return None + def findSpecRecursive(self, spec): + self_real = self.getRealNode() + if spec == self_real.getSpec(): + return self + + for child in self_real.children: + if child.findSpecRecursive(spec): + return child + + return None + def getPrefix(self): if self.id: return self.id[0] return None - def getDefName(self): + def getSpecialTypeName(self, typename): self_real = self.getRealNode() + try: return self_real.id[ list(self_real.id).index(typename)+1 ] + except: return None + + + def getDefName(self): + return self.getSpecialTypeName('DEF') + + def getProtoName(self): + return self.getSpecialTypeName('PROTO') - if 'DEF' in self_real.id: - # print self_real.id - return self_real.id[ list(self_real.id).index('DEF')+1 ] - else: - return None - + def getExternprotoName(self): + return self.getSpecialTypeName('EXTERNPROTO') def getChildrenBySpec(self, node_spec): # spec could be Transform, Shape, Appearance self_real = self.getRealNode() @@ -449,7 +507,26 @@ class vrmlNode(object): ancestry.append(self) for child in self.getRealNode().children: if child not in ancestry: - child.getSerialized(results, ancestry) + # We dont want to load proto's, they are only references + # We could enforce this elsewhere + + # Only add this in a very special case + # where the parent of this object is not the real parent + # - In this case we have added the proto as a child to a node instancing it. + # This is a bit arbitary, but its how Proto's are done with this importer. + if child.getProtoName() == None and child.getExternprotoName() == None: + child.getSerialized(results, ancestry) + else: + + if DEBUG: print 'getSerialized() is proto:', child.getProtoName(), child.getExternprotoName(), self.getSpec() + + self_spec = self.getSpec() + + if child.getProtoName() == self_spec or child.getExternprotoName() == self_spec: + if DEBUG: "FoundProto!" + child.getSerialized(results, ancestry) + + return results @@ -462,7 +539,7 @@ class vrmlNode(object): child.searchNodeTypeID(node_spec, results) return results - def getFieldName(self, field): + def getFieldName(self, field, ancestry, AS_CHILD=False): self_real = self.getRealNode() # incase we're an instance for f in self_real.fields: @@ -470,14 +547,81 @@ class vrmlNode(object): if f and f[0] == field: # print '\tfound field', f - return f[1:] + if len(f)>=3 and f[1] == 'IS': # eg: 'diffuseColor IS legColor' + field_id = f[2] + + # print "\n\n\n\n\n\nFOND IS!!!" + f_proto_lookup = None + f_proto_child_lookup = None + i = len(ancestry) + while i: + i -= 1 + node = ancestry[i] + node = node.getRealNode() + + # proto settings are stored in "self.proto_node" + if node.proto_node: + # Get the default value from the proto, this can be overwridden by the proto instace + # 'field SFColor legColor .8 .4 .7' + if AS_CHILD: + for child in node.proto_node.children: + #if child.id and len(child.id) >= 3 and child.id[2]==field_id: + if child.id and ('point' in child.id or 'points' in child.id): + f_proto_child_lookup = child + + else: + for f_def in node.proto_node.proto_field_defs: + if len(f_def) >= 4: + if f_def[0]=='field' and f_def[2]==field_id: + f_proto_lookup = f_def[3:] + + # Node instance, Will be 1 up from the proto-node in the ancestry list. but NOT its parent. + # This is the setting as defined by the instance, including this setting is optional, + # and will override the default PROTO value + # eg: 'legColor 1 0 0' + if AS_CHILD: + for child in node.children: + if child.id and child.id[0]==field_id: + f_proto_child_lookup = child + else: + for f_def in node.fields: + if len(f_def) >= 2: + if f_def[0]==field_id: + if DEBUG: print "getFieldName(), found proto", f_def + f_proto_lookup = f_def[1:] + + + if AS_CHILD: + if f_proto_child_lookup: + if DEBUG: + print "getFieldName() - AS_CHILD=True, child found" + print f_proto_child_lookup + return f_proto_child_lookup + else: + return f_proto_lookup + else: + if AS_CHILD: + return None + else: + # Not using a proto + return f[1:] + # print '\tfield not found', field + + + # See if this is a proto name + if AS_CHILD: + child_array = None + for child in self_real.children: + if child.id and len(child.id) == 1 and child.id[0] == field: + return child + return None - def getFieldAsInt(self, field, default): + def getFieldAsInt(self, field, default, ancestry): self_real = self.getRealNode() # incase we're an instance - f = self_real.getFieldName(field) + f = self_real.getFieldName(field, ancestry) if f==None: return default if ',' in f: f = f[:f.index(',')] # strip after the comma @@ -491,10 +635,10 @@ class vrmlNode(object): print '\tvalue "%s" could not be used as an int for field "%s"' % (f[0], field) return default - def getFieldAsFloat(self, field, default): + def getFieldAsFloat(self, field, default, ancestry): self_real = self.getRealNode() # incase we're an instance - f = self_real.getFieldName(field) + f = self_real.getFieldName(field, ancestry) if f==None: return default if ',' in f: f = f[:f.index(',')] # strip after the comma @@ -508,10 +652,10 @@ class vrmlNode(object): print '\tvalue "%s" could not be used as a float for field "%s"' % (f[0], field) return default - def getFieldAsFloatTuple(self, field, default): + def getFieldAsFloatTuple(self, field, default, ancestry): self_real = self.getRealNode() # incase we're an instance - f = self_real.getFieldName(field) + f = self_real.getFieldName(field, ancestry) if f==None: return default # if ',' in f: f = f[:f.index(',')] # strip after the comma @@ -532,10 +676,10 @@ class vrmlNode(object): print '\tvalue "%s" could not be used as a float tuple for field "%s"' % (f, field) return default - def getFieldAsBool(self, field, default): + def getFieldAsBool(self, field, default, ancestry): self_real = self.getRealNode() # incase we're an instance - f = self_real.getFieldName(field) + f = self_real.getFieldName(field, ancestry) if f==None: return default if ',' in f: f = f[:f.index(',')] # strip after the comma @@ -551,10 +695,10 @@ class vrmlNode(object): print '\t"%s" could not be used as a bool for field "%s"' % (f[1], field) return default - def getFieldAsString(self, field, default=None): + def getFieldAsString(self, field, default, ancestry): self_real = self.getRealNode() # incase we're an instance - f = self_real.getFieldName(field) + f = self_real.getFieldName(field, ancestry) if f==None: return default if len(f) < 1: print '\t"%s" wrong length for string conversion for field "%s"' % (f, field) @@ -576,24 +720,22 @@ class vrmlNode(object): print '\tvalue "%s" could not be used as a string for field "%s"' % (f[0], field) return default - def getFieldAsArray(self, field, group): + def getFieldAsArray(self, field, group, ancestry): ''' For this parser arrays are children ''' self_real = self.getRealNode() # incase we're an instance - 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 + child_array = self_real.getFieldName(field, ancestry, True) + #if type(child_array)==list: # happens occasionaly + # array_data = child_array + if child_array==None: # For x3d, should work ok with vrml too # for x3d arrays are fields, vrml they are nodes, annoying but not tooo bad. - data_split = self.getFieldName(field) + data_split = self.getFieldName(field, ancestry) if not data_split: return [] array_data = ' '.join(data_split) @@ -660,7 +802,7 @@ class vrmlNode(object): return new_array - def getFieldAsStringArray(self, field): + def getFieldAsStringArray(self, field, ancestry): ''' Get a list of strings ''' @@ -698,7 +840,6 @@ class vrmlNode(object): def __repr__(self): level = self.getLevel() ind = ' ' * level - if self.node_type==NODE_REFERENCE: brackets = '' elif self.node_type==NODE_NORMAL: @@ -717,14 +858,25 @@ class vrmlNode(object): text += ind + "(reference node)\n" return text - text += ind + 'FIELDS:\n' + if self.proto_node: + text += ind + 'PROTO NODE...\n' + text += str(self.proto_node) + text += ind + 'PROTO NODE_DONE\n' + + text += ind + 'FIELDS:' + str(len(self.fields)) + '\n' for i,item in enumerate(self.fields): text += ind + 'FIELD:\n' text += ind + str(item) +'\n' + + text += ind + 'PROTO_FIELD_DEFS:' + str(len(self.proto_field_defs)) + '\n' - #text += ind + 'ARRAY: ' + str(len(self.array_data)) + ' ' + str(self.array_data) + '\n' - text += ind + 'ARRAY: ' + str(len(self.array_data)) + '[...] \n' + for i,item in enumerate(self.proto_field_defs): + text += ind + 'PROTO_FIELD:\n' + text += ind + str(item) +'\n' + + text += ind + 'ARRAY: ' + str(len(self.array_data)) + ' ' + str(self.array_data) + '\n' + #text += ind + 'ARRAY: ' + str(len(self.array_data)) + '[...] \n' text += ind + 'CHILDREN: ' + str(len(self.children)) + '\n' for i, child in enumerate(self.children): @@ -735,21 +887,57 @@ class vrmlNode(object): return text - def parse(self, i): - new_i = self.__parse(i) + def parse(self, i, IS_PROTO_DATA=False): + new_i = self.__parse(i, IS_PROTO_DATA) # print self.id, self.getFilename() - # If we were an inline then try load the file + # Check if this node was an inline or externproto + + url_ls = [] + if self.node_type == NODE_NORMAL and self.getSpec() == 'Inline': + ancestry = [] # Warning! - PROTO's using this wont work at all. + url = self.getFieldAsString('url', None, ancestry) + if url: + url_ls = [(url, None)] + del ancestry + + elif self.getExternprotoName(): + # externproto + url_ls = [] + for f in self.fields: + + if type(f)==str: + f = [f] + + for ff in f: + for f_split in ff.split('"'): + # print f_split + # "someextern.vrml#SomeID" + if '#' in f_split: + + f_split, f_split_id = f_split.split('#') # there should only be 1 # anyway + + url_ls.append( (f_split, f_split_id) ) + else: + url_ls.append( (f_split, None) ) + + + # Was either an Inline or an EXTERNPROTO + if url_ls: - url = self.getFieldAsString('url', None) + # print url_ls - if url != None: + for url, extern_key in url_ls: + print url urls = [] urls.append( url ) urls.append( BPySys.caseInsensitivePath(urls[-1]) ) + urls.append( dirName(self.getFilename()) + url ) + urls.append( BPySys.caseInsensitivePath(urls[-1]) ) + urls.append( dirName(self.getFilename()) + baseName(url) ) urls.append( BPySys.caseInsensitivePath(urls[-1]) ) @@ -786,7 +974,7 @@ class vrmlNode(object): lines.insert(0, 'root_node____') lines.append('}') ''' - ff = open('/test.txt', 'w') + ff = open('/tmp/test.txt', 'w') ff.writelines([l+'\n' for l in lines]) ''' @@ -794,15 +982,36 @@ class vrmlNode(object): child.setRoot(url) # initialized dicts child.parse(0) + # if self.getExternprotoName(): + if self.getExternprotoName(): + if not extern_key: # if none is spesified - use the name + extern_key = self.getSpec() + + if extern_key: + + self.children.remove(child) + child.parent = None + + extern_child = child.findSpecRecursive(extern_key) + + if extern_child: + self.children.append(extern_child) + extern_child.parent = self + + if DEBUG: print "\tEXTERNPROTO ID found!:", extern_key + else: + print "\tEXTERNPROTO ID not found!:", extern_key + # Watch it! - restore lines lines[:] = lines_old - return new_i - def __parse(self, i): - # print 'parsing at', i, - # print i, self.id, self.lineno + def __parse(self, i, IS_PROTO_DATA=False): + ''' + print 'parsing at', i, + print i, self.id, self.lineno + ''' l = lines[i] if l=='[': @@ -811,9 +1020,11 @@ class vrmlNode(object): i+=1 else: words = [] + node_type, new_i = is_nodeline(i, words) if not node_type: # fail for parsing new node. - raise "error" + print "Failed to parse new node" + raise ValueError if self.node_type==NODE_REFERENCE: # Only assign the reference and quit @@ -827,40 +1038,72 @@ class vrmlNode(object): # fill in DEF/USE key = self.getDefName() - if key != None: self.getDefDict()[ key ] = self + key = self.getProtoName() + if not key: key = self.getExternprotoName() + + proto_dict = self.getProtoDict() + if key != None: + proto_dict[ key ] = self + + # Parse the proto nodes fields + self.proto_node = vrmlNode(self, NODE_ARRAY, new_i) + new_i = self.proto_node.parse(new_i) + + self.children.remove(self.proto_node) + + # print self.proto_node + + new_i += 1 # skip past the { + + + else: # If we're a proto instance, add the proto node as our child. + spec = self.getSpec() + try: + self.children.append( proto_dict[spec] ) + #pass + except: + pass + + del spec + + del proto_dict, key + i = new_i # print self.id ok = True while ok: + if i>=len(lines): + return len(lines)-1 + l = lines[i] - # print '\t', i, l + # print '\tDEBUG:', i, self.node_type, l if l=='': i+=1 continue if l=='}': - if self.node_type != NODE_NORMAL: - print 'wrong node ending, expected an } ' + str(i) - raise "" + if self.node_type != NODE_NORMAL: # also ends proto nodes, we may want a type for these too. + print 'wrong node ending, expected an } ' + str(i) + ' ' + str(self.node_type) + if DEBUG: + raise ValueError ### print "returning", i return i+1 if l==']': if self.node_type != NODE_ARRAY: - print 'wrong node ending, expected a ] ' + str(i) - raise "" + print 'wrong node ending, expected a ] ' + str(i) + ' ' + str(self.node_type) + if DEBUG: + raise ValueError ### print "returning", i return i+1 node_type, new_i = is_nodeline(i, []) if node_type: # check text\n{ - ### print '\t\tgroup', i child = vrmlNode(self, node_type, i) i = child.parse(i) - # print child.id, 'YYY' elif l=='[': # some files have these anonymous lists child = vrmlNode(self, NODE_ARRAY, i) @@ -943,6 +1186,7 @@ class vrmlNode(object): # this IS a key but the previous value was not a key, ot it was a defined field. if (not iskey(field_context[-1])) or ((len(field_context)==3 and field_context[1]=='IS')): field_list.append(field_context) + field_context = [value[j]] else: # The last item was not a value, multiple keys are needed in some cases. @@ -965,18 +1209,9 @@ class vrmlNode(object): if value[0]=='field': # field SFFloat creaseAngle 4 - self.getFieldDict()[value[2]] = value[3:] # skip the first 3 values + self.proto_field_defs.append(value) else: - # Get referenced field - if len(value) >= 3 and value[1]=='IS': - try: - value = [ value[0] ] + self.getFieldDict()[ value[2] ] - except: - print '\tWarning, field could not be found:', value, 'TODO add support for exposedField' - print '\t', self.getFieldDict() - self.fields.append(value) - else: - self.fields.append(value) + self.fields.append(value) i+=1 def gzipOpen(path): @@ -1015,8 +1250,9 @@ def vrml_parse(path): # Use for testing our parsed output, so we can check on line numbers. ''' - ff = open('/test.txt', 'w') + ff = open('/tmp/test.txt', 'w') ff.writelines([l+'\n' for l in lines]) + ff.close() ''' # Now evaluate it @@ -1036,9 +1272,8 @@ def vrml_parse(path): root.parse(0) # This prints a load of text - ''' - print root - ''' + if DEBUG: + print root return root, '' @@ -1055,7 +1290,7 @@ class x3dNode(vrmlNode): vrmlNode.__init__(self, parent, node_type, -1) self.x3dNode = x3dNode - def parse(self): + def parse(self, IS_PROTO_DATA=False): # print self.x3dNode.tagName define = self.x3dNode.getAttributeNode('DEF') @@ -1195,12 +1430,12 @@ def translateScale(sca): mat[2][2] = sca[2] return mat -def translateTransform(node): - cent = node.getFieldAsFloatTuple('center', None) # (0.0, 0.0, 0.0) - rot = node.getFieldAsFloatTuple('rotation', None) # (0.0, 0.0, 1.0, 0.0) - sca = node.getFieldAsFloatTuple('scale', None) # (1.0, 1.0, 1.0) - scaori = node.getFieldAsFloatTuple('scaleOrientation', None) # (0.0, 0.0, 1.0, 0.0) - tx = node.getFieldAsFloatTuple('translation', None) # (0.0, 0.0, 0.0) +def translateTransform(node, ancestry): + cent = node.getFieldAsFloatTuple('center', None, ancestry) # (0.0, 0.0, 0.0) + rot = node.getFieldAsFloatTuple('rotation', None, ancestry) # (0.0, 0.0, 1.0, 0.0) + sca = node.getFieldAsFloatTuple('scale', None, ancestry) # (1.0, 1.0, 1.0) + scaori = node.getFieldAsFloatTuple('scaleOrientation', None, ancestry) # (0.0, 0.0, 1.0, 0.0) + tx = node.getFieldAsFloatTuple('translation', None, ancestry) # (0.0, 0.0, 0.0) if cent: cent_mat = TranslationMatrix(Vector(cent)).resize4x4() @@ -1232,11 +1467,11 @@ def translateTransform(node): return new_mat -def translateTexTransform(node): - cent = node.getFieldAsFloatTuple('center', None) # (0.0, 0.0) - rot = node.getFieldAsFloat('rotation', None) # 0.0 - sca = node.getFieldAsFloatTuple('scale', None) # (1.0, 1.0) - tx = node.getFieldAsFloatTuple('translation', None) # (0.0, 0.0) +def translateTexTransform(node, ancestry): + cent = node.getFieldAsFloatTuple('center', None, ancestry) # (0.0, 0.0) + rot = node.getFieldAsFloat('rotation', None, ancestry) # 0.0 + sca = node.getFieldAsFloatTuple('scale', None, ancestry) # (1.0, 1.0) + tx = node.getFieldAsFloatTuple('translation', None, ancestry) # (0.0, 0.0) if cent: @@ -1279,17 +1514,17 @@ def getFinalMatrix(node, mtx, ancestry): mtx = Matrix() for node_tx in transform_nodes: - mat = translateTransform(node_tx) + mat = translateTransform(node_tx, ancestry) mtx = mtx * mat return mtx -def importMesh_IndexedFaceSet(geom, bpyima): +def importMesh_IndexedFaceSet(geom, bpyima, ancestry): # print geom.lineno, geom.id, vrmlNode.DEF_NAMESPACE.keys() - ccw = geom.getFieldAsBool('ccw', True) - ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True) # per vertex or per face - ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True) + ccw = geom.getFieldAsBool('ccw', True, ancestry) + ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True, ancestry) # per vertex or per face + ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry) # This is odd how point is inside Coordinate @@ -1298,14 +1533,14 @@ def importMesh_IndexedFaceSet(geom, bpyima): coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - if coord: ifs_points = coord.getFieldAsArray('point', 3) + if coord: ifs_points = coord.getFieldAsArray('point', 3, ancestry) else: coord = [] if not coord: print '\tWarnint: IndexedFaceSet has no points' return None, ccw - ifs_faces = geom.getFieldAsArray('coordIndex', 0) + ifs_faces = geom.getFieldAsArray('coordIndex', 0, ancestry) coords_tex = None if ifs_faces: # In rare cases this causes problems - no faces but UVs??? @@ -1315,8 +1550,8 @@ def importMesh_IndexedFaceSet(geom, bpyima): coords_tex = geom.getChildBySpec('TextureCoordinate') if coords_tex: - ifs_texpoints = coords_tex.getFieldAsArray('point', 2) - ifs_texfaces = geom.getFieldAsArray('texCoordIndex', 0) + ifs_texpoints = coords_tex.getFieldAsArray('point', 2, ancestry) + ifs_texfaces = geom.getFieldAsArray('texCoordIndex', 0, ancestry) if not ifs_texpoints: # IF we have no coords, then dont bother @@ -1329,11 +1564,11 @@ def importMesh_IndexedFaceSet(geom, bpyima): vcolor_spot = None # spot color when we dont have an array of colors if vcolor: # float to char - ifs_vcol = [[int(c*256) for c in col] for col in vcolor.getFieldAsArray('color', 3)] - ifs_color_index = geom.getFieldAsArray('colorIndex', 0) + ifs_vcol = [[int(c*256) for c in col] for col in vcolor.getFieldAsArray('color', 3, ancestry)] + ifs_color_index = geom.getFieldAsArray('colorIndex', 0, ancestry) if not ifs_vcol: - vcolor_spot = [int(c*256) for c in vcolor.getFieldAsFloatTuple('color', [])] + vcolor_spot = [int(c*256) for c in vcolor.getFieldAsFloatTuple('color', [], ancestry)] # Convert faces into somthing blender can use edges = [] @@ -1516,7 +1751,12 @@ def importMesh_IndexedFaceSet(geom, bpyima): fv = f.verts for i,c in enumerate(fcol): color_index = fv[i].index # color index is vert index - if ifs_color_index: color_index = ifs_color_index[color_index] + if ifs_color_index: + try: + color_index = ifs_color_index[color_index] + except: + print '\tWarning: per vertex color index out of range' + continue if len(ifs_vcol) < color_index: c.r, c.g, c.b = ifs_vcol[color_index] @@ -1540,24 +1780,27 @@ def importMesh_IndexedFaceSet(geom, bpyima): col = ifs_vcol[color_index] for i,c in enumerate(fcol): - c.r, c.g, c.b = col + try: + c.r, c.g, c.b = col + except: + pass # incase its not between 0 and 255 bpymesh.verts.delete([0,]) # EEKADOODLE return bpymesh, ccw -def importMesh_IndexedLineSet(geom): +def importMesh_IndexedLineSet(geom, ancestry): # VRML not x3d #coord = geom.getChildByName('coord') # 'Coordinate' coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - if coord: points = coord.getFieldAsArray('point', 3) + if coord: points = coord.getFieldAsArray('point', 3, ancestry) else: points = [] if not points: print '\tWarning: IndexedLineSet had no points' return None - ils_lines = geom.getFieldAsArray('coordIndex', 0) + ils_lines = geom.getFieldAsArray('coordIndex', 0, ancestry) lines = [] line = [] @@ -1596,11 +1839,11 @@ def importMesh_IndexedLineSet(geom): return bpycurve -def importMesh_PointSet(geom): +def importMesh_PointSet(geom, ancestry): # VRML not x3d #coord = geom.getChildByName('coord') # 'Coordinate' coord = geom.getChildBySpec('Coordinate') # works for x3d and vrml - if coord: points = coord.getFieldAsArray('point', 3) + if coord: points = coord.getFieldAsArray('point', 3, ancestry) else: points = [] # vcolor = geom.getChildByName('color') # blender dosnt have per vertex color @@ -1614,26 +1857,26 @@ GLOBALS['CIRCLE_DETAIL'] = 12 MATRIX_Z_TO_Y = RotationMatrix(90, 4, 'x') -def importMesh_Sphere(geom): +def importMesh_Sphere(geom, ancestry): # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('radius', 0.5) * 2 # * 2 for the diameter + diameter = geom.getFieldAsFloat('radius', 0.5, ancestry) * 2 # * 2 for the diameter bpymesh = Mesh.Primitives.UVsphere(GLOBALS['CIRCLE_DETAIL'], GLOBALS['CIRCLE_DETAIL'], diameter) bpymesh.transform(MATRIX_Z_TO_Y) return bpymesh -def importMesh_Cylinder(geom): +def importMesh_Cylinder(geom, ancestry): # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('radius', 1.0) * 2 # * 2 for the diameter - height = geom.getFieldAsFloat('height', 2) + diameter = geom.getFieldAsFloat('radius', 1.0, ancestry) * 2 # * 2 for the diameter + height = geom.getFieldAsFloat('height', 2, ancestry) bpymesh = Mesh.Primitives.Cylinder(GLOBALS['CIRCLE_DETAIL'], diameter, height) bpymesh.transform(MATRIX_Z_TO_Y) # Warning - Rely in the order Blender adds verts # not nice design but wont change soon. - bottom = geom.getFieldAsBool('bottom', True) - side = geom.getFieldAsBool('side', True) - top = geom.getFieldAsBool('top', True) + bottom = geom.getFieldAsBool('bottom', True, ancestry) + side = geom.getFieldAsBool('side', True, ancestry) + top = geom.getFieldAsBool('top', True, ancestry) if not top: # last vert is top center of tri fan. bpymesh.verts.delete([(GLOBALS['CIRCLE_DETAIL']+GLOBALS['CIRCLE_DETAIL'])+1]) @@ -1647,18 +1890,18 @@ def importMesh_Cylinder(geom): return bpymesh -def importMesh_Cone(geom): +def importMesh_Cone(geom, ancestry): # bpymesh = bpy.data.meshes.new() - diameter = geom.getFieldAsFloat('bottomRadius', 1.0) * 2 # * 2 for the diameter - height = geom.getFieldAsFloat('height', 2) + diameter = geom.getFieldAsFloat('bottomRadius', 1.0, ancestry) * 2 # * 2 for the diameter + height = geom.getFieldAsFloat('height', 2, ancestry) bpymesh = Mesh.Primitives.Cone(GLOBALS['CIRCLE_DETAIL'], diameter, height) bpymesh.transform(MATRIX_Z_TO_Y) # Warning - Rely in the order Blender adds verts # not nice design but wont change soon. - bottom = geom.getFieldAsBool('bottom', True) - side = geom.getFieldAsBool('side', True) + bottom = geom.getFieldAsBool('bottom', True, ancestry) + side = geom.getFieldAsBool('side', True, ancestry) if not bottom: # last vert is on the bottom bpymesh.verts.delete([GLOBALS['CIRCLE_DETAIL']+1]) @@ -1667,10 +1910,10 @@ def importMesh_Cone(geom): return bpymesh -def importMesh_Box(geom): +def importMesh_Box(geom, ancestry): # bpymesh = bpy.data.meshes.new() - size = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0)) + size = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0), ancestry) bpymesh = Mesh.Primitives.Cube(1.0) # Scale the box to the size set @@ -1714,7 +1957,7 @@ def importShape(node, ancestry): textx = appr.getChildBySpec('TextureTransform') if textx: - texmtx = translateTexTransform(textx) + texmtx = translateTexTransform(textx, ancestry) @@ -1726,28 +1969,28 @@ def importShape(node, ancestry): # all values between 0.0 and 1.0, defaults from VRML docs bpymat = bpy.data.materials.new() - bpymat.amb = mat.getFieldAsFloat('ambientIntensity', 0.2) - bpymat.rgbCol = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8]) + bpymat.amb = mat.getFieldAsFloat('ambientIntensity', 0.2, ancestry) + bpymat.rgbCol = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8], ancestry) # NOTE - blender dosnt support emmisive color # Store in mirror color and approximate with emit. - emit = mat.getFieldAsFloatTuple('emissiveColor', [0.0, 0.0, 0.0]) + emit = mat.getFieldAsFloatTuple('emissiveColor', [0.0, 0.0, 0.0], ancestry) bpymat.mirCol = emit bpymat.emit = (emit[0]+emit[1]+emit[2])/3.0 - bpymat.hard = int(1+(510*mat.getFieldAsFloat('shininess', 0.2))) # 0-1 -> 1-511 - bpymat.specCol = mat.getFieldAsFloatTuple('specularColor', [0.0, 0.0, 0.0]) - bpymat.alpha = 1.0 - mat.getFieldAsFloat('transparency', 0.0) + bpymat.hard = int(1+(510*mat.getFieldAsFloat('shininess', 0.2, ancestry))) # 0-1 -> 1-511 + bpymat.specCol = mat.getFieldAsFloatTuple('specularColor', [0.0, 0.0, 0.0], ancestry) + bpymat.alpha = 1.0 - mat.getFieldAsFloat('transparency', 0.0, ancestry) if bpymat.alpha < 0.999: bpymat.mode |= Material.Modes.ZTRANSP if ima: - ima_url = ima.getFieldAsString('url') + ima_url = ima.getFieldAsString('url', None, ancestry) if ima_url==None: - try: ima_url = ima.getFieldAsStringArray('url')[0] # in some cases we get a list of images. + try: ima_url = ima.getFieldAsStringArray('url', ancestry)[0] # in some cases we get a list of images. except: ima_url = None if ima_url==None: @@ -1772,8 +2015,8 @@ def importShape(node, ancestry): else: bpymat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) - ima_repS = ima.getFieldAsBool('repeatS', True) - ima_repT = ima.getFieldAsBool('repeatT', True) + ima_repS = ima.getFieldAsBool('repeatS', True, ancestry) + ima_repT = ima.getFieldAsBool('repeatT', True, ancestry) # To make this work properly we'd need to scale the UV's too, better to ignore th # texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512) @@ -1785,19 +2028,19 @@ def importShape(node, ancestry): geom_spec = geom.getSpec() ccw = True if geom_spec == 'IndexedFaceSet': - bpydata, ccw = importMesh_IndexedFaceSet(geom, bpyima) + bpydata, ccw = importMesh_IndexedFaceSet(geom, bpyima, ancestry) elif geom_spec == 'IndexedLineSet': - bpydata = importMesh_IndexedLineSet(geom) + bpydata = importMesh_IndexedLineSet(geom, ancestry) elif geom_spec == 'PointSet': - bpydata = importMesh_PointSet(geom) + bpydata = importMesh_PointSet(geom, ancestry) elif geom_spec == 'Sphere': - bpydata = importMesh_Sphere(geom) + bpydata = importMesh_Sphere(geom, ancestry) elif geom_spec == 'Box': - bpydata = importMesh_Box(geom) + bpydata = importMesh_Box(geom, ancestry) elif geom_spec == 'Cylinder': - bpydata = importMesh_Cylinder(geom) + bpydata = importMesh_Cylinder(geom, ancestry) elif geom_spec == 'Cone': - bpydata = importMesh_Cone(geom) + bpydata = importMesh_Cone(geom, ancestry) else: print '\tWarning: unsupported type "%s"' % geom_spec return @@ -1810,8 +2053,8 @@ def importShape(node, ancestry): bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpydata) if type(bpydata) == Types.MeshType: - is_solid = geom.getFieldAsBool('solid', True) - creaseAngle = geom.getFieldAsFloat('creaseAngle', None) + is_solid = geom.getFieldAsBool('solid', True, ancestry) + creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry) if creaseAngle != None: bpydata.maxSmoothAngle = 1+int(min(79, creaseAngle * RAD_TO_DEG)) @@ -1852,17 +2095,17 @@ def importShape(node, ancestry): bpyob.setMatrix( getFinalMatrix(node, None, ancestry) ) -def importLamp_PointLight(node): +def importLamp_PointLight(node, ancestry): vrmlname = node.getDefName() if not vrmlname: vrmlname = 'PointLight' - # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0) # TODO - # attenuation = node.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0)) # TODO - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0)) - intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. - location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0)) - # is_on = node.getFieldAsBool('on', True) # TODO - radius = node.getFieldAsFloat('radius', 100.0) + # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0, ancestry) # TODO + # attenuation = node.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0), ancestry) # TODO + color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) + intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. + location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0), ancestry) + # is_on = node.getFieldAsBool('on', True, ancestry) # TODO + radius = node.getFieldAsFloat('radius', 100.0, ancestry) bpylamp = bpy.data.lamps.new() bpylamp.setType('Lamp') @@ -1874,15 +2117,15 @@ def importLamp_PointLight(node): return bpylamp, mtx -def importLamp_DirectionalLight(node): +def importLamp_DirectionalLight(node, ancestry): vrmlname = node.getDefName() if not vrmlname: vrmlname = 'DirectLight' # ambientIntensity = node.getFieldAsFloat('ambientIntensity', 0.0) # TODO - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0)) - direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0)) - intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. - # is_on = node.getFieldAsBool('on', True) # TODO + color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) + direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0), ancestry) + intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. + # is_on = node.getFieldAsBool('on', True, ancestry) # TODO bpylamp = bpy.data.lamps.new(vrmlname) bpylamp.setType('Sun') @@ -1896,20 +2139,20 @@ def importLamp_DirectionalLight(node): # looks like default values for beamWidth and cutOffAngle were swapped in VRML docs. -def importLamp_SpotLight(node): +def importLamp_SpotLight(node, ancestry): vrmlname = node.getDefName() if not vrmlname: vrmlname = 'SpotLight' - # ambientIntensity = geom.getFieldAsFloat('ambientIntensity', 0.0) # TODO - # attenuation = geom.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0)) # TODO - beamWidth = node.getFieldAsFloat('beamWidth', 1.570796) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0)) - cutOffAngle = node.getFieldAsFloat('cutOffAngle', 0.785398) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0)) - intensity = node.getFieldAsFloat('intensity', 1.0) # max is documented to be 1.0 but some files have higher. - location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0)) - # is_on = node.getFieldAsBool('on', True) # TODO - radius = node.getFieldAsFloat('radius', 100.0) + # ambientIntensity = geom.getFieldAsFloat('ambientIntensity', 0.0, ancestry) # TODO + # attenuation = geom.getFieldAsFloatTuple('attenuation', (1.0, 0.0, 0.0), ancestry) # TODO + beamWidth = node.getFieldAsFloat('beamWidth', 1.570796, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. + color = node.getFieldAsFloatTuple('color', (1.0, 1.0, 1.0), ancestry) + cutOffAngle = node.getFieldAsFloat('cutOffAngle', 0.785398, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. + direction = node.getFieldAsFloatTuple('direction', (0.0, 0.0, -1.0), ancestry) + intensity = node.getFieldAsFloat('intensity', 1.0, ancestry) # max is documented to be 1.0 but some files have higher. + location = node.getFieldAsFloatTuple('location', (0.0, 0.0, 0.0), ancestry) + # is_on = node.getFieldAsBool('on', True, ancestry) # TODO + radius = node.getFieldAsFloat('radius', 100.0, ancestry) bpylamp = bpy.data.lamps.new(vrmlname) bpylamp.setType('Spot') @@ -1935,14 +2178,14 @@ def importLamp_SpotLight(node): def importLamp(node, spec, ancestry): if spec=='PointLight': - bpylamp,mtx = importLamp_PointLight(node) + bpylamp,mtx = importLamp_PointLight(node, ancestry) elif spec=='DirectionalLight': - bpylamp,mtx = importLamp_DirectionalLight(node) + bpylamp,mtx = importLamp_DirectionalLight(node, ancestry) elif spec=='SpotLight': - bpylamp,mtx = importLamp_SpotLight(node) + bpylamp,mtx = importLamp_SpotLight(node, ancestry) else: print "Error, not a lamp" - raise "" + raise ValueError bpyob = node.blendObject = bpy.data.scenes.active.objects.new(bpylamp) bpyob.setMatrix( getFinalMatrix(node, mtx, ancestry) ) @@ -1952,11 +2195,11 @@ def importViewpoint(node, ancestry): name = node.getDefName() if not name: name = 'Viewpoint' - fieldOfView = node.getFieldAsFloat('fieldOfView', 0.785398) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. - # jump = node.getFieldAsBool('jump', True) - orientation = node.getFieldAsFloatTuple('orientation', (0.0, 0.0, 1.0, 0.0)) - position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 0.0)) - description = node.getFieldAsString('description', '') + fieldOfView = node.getFieldAsFloat('fieldOfView', 0.785398, ancestry) * RAD_TO_DEG # max is documented to be 1.0 but some files have higher. + # jump = node.getFieldAsBool('jump', True, ancestry) + orientation = node.getFieldAsFloatTuple('orientation', (0.0, 0.0, 1.0, 0.0), ancestry) + position = node.getFieldAsFloatTuple('position', (0.0, 0.0, 0.0), ancestry) + description = node.getFieldAsString('description', '', ancestry) bpycam = bpy.data.cameras.new(name) @@ -1976,63 +2219,80 @@ def importTransform(node, ancestry): bpyob = node.blendObject = bpy.data.scenes.active.objects.new('Empty', name) # , name) bpyob.setMatrix( getFinalMatrix(node, None, ancestry) ) + # so they are not too annoying + bpyob.emptyShape= Blender.Object.EmptyShapes.AXES + bpyob.drawSize= 0.2 + #def importTimeSensor(node): -def translatePositionInterpolator(node, ipo): - 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') +def translatePositionInterpolator(node, ipo, ancestry): + key = node.getFieldAsArray('key', 0, ancestry) + keyValue = node.getFieldAsArray('keyValue', 3, ancestry) + try: + loc_x = ipo.addCurve('LocX') + loc_y = ipo.addCurve('LocY') + loc_z = ipo.addCurve('LocZ') + except ValueError: + return + loc_x.interpolation = loc_y.interpolation = loc_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR for i, time in enumerate(key): - x,y,z = keyValue[i] + try: x,y,z = keyValue[i] + except: continue loc_x.append((time,x)) loc_y.append((time,y)) loc_z.append((time,z)) -def translateOrientationInterpolator(node, ipo): - key = node.getFieldAsArray('key', 0) - keyValue = node.getFieldAsArray('keyValue', 4) +def translateOrientationInterpolator(node, ipo, ancestry): + key = node.getFieldAsArray('key', 0, ancestry) + keyValue = node.getFieldAsArray('keyValue', 4, ancestry) - rot_x = ipo.addCurve('RotX') - rot_y = ipo.addCurve('RotY') - rot_z = ipo.addCurve('RotZ') + try: + rot_x = ipo.addCurve('RotX') + rot_y = ipo.addCurve('RotY') + rot_z = ipo.addCurve('RotZ') + except ValueError: + return rot_x.interpolation = rot_y.interpolation = rot_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR for i, time in enumerate(key): + try: x,y,z,w = keyValue[i] + except: continue - mtx = translateRotation(keyValue[i]) + mtx = translateRotation((x,y,z,w)) eul = mtx.toEuler() rot_x.append((time,eul.x/10.0)) rot_y.append((time,eul.y/10.0)) rot_z.append((time,eul.z/10.0)) # Untested! -def translateScalarInterpolator(node, ipo): - key = node.getFieldAsArray('key', 0) - keyValue = node.getFieldAsArray('keyValue', 4) +def translateScalarInterpolator(node, ipo, ancestry): + key = node.getFieldAsArray('key', 0, ancestry) + keyValue = node.getFieldAsArray('keyValue', 4, ancestry) - sca_x = ipo.addCurve('SizeX') - sca_y = ipo.addCurve('SizeY') - sca_z = ipo.addCurve('SizeZ') + try: + sca_x = ipo.addCurve('ScaleX') + sca_y = ipo.addCurve('ScaleY') + sca_z = ipo.addCurve('ScaleZ') + except ValueError: + return sca_x.interpolation = sca_y.interpolation = sca_z.interpolation = Blender.IpoCurve.InterpTypes.LINEAR for i, time in enumerate(key): - x,y,z = keyValue[i] + try: x,y,z = keyValue[i] + except: continue sca_x.append((time,x/10.0)) sca_y.append((time,y/10.0)) sca_z.append((time,z/10.0)) -def translateTimeSensor(node, ipo): +def translateTimeSensor(node, ipo, ancestry): ''' Apply a time sensor to an IPO, VRML has many combinations of loop/start/stop/cycle times to give different results, for now just do the basics @@ -2041,15 +2301,15 @@ def translateTimeSensor(node, ipo): time_cu = ipo.addCurve('Time') time_cu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR - cycleInterval = node.getFieldAsFloat('cycleInterval', None) + cycleInterval = node.getFieldAsFloat('cycleInterval', None, ancestry) - startTime = node.getFieldAsFloat('startTime', 0.0) - stopTime = node.getFieldAsFloat('stopTime', 250.0) + startTime = node.getFieldAsFloat('startTime', 0.0, ancestry) + stopTime = node.getFieldAsFloat('stopTime', 250.0, ancestry) if cycleInterval != None: stopTime = startTime+cycleInterval - loop = node.getFieldAsBool('loop', False) + loop = node.getFieldAsBool('loop', False, ancestry) time_cu.append((1+startTime, 0.0)) time_cu.append((1+stopTime, 1.0/10.0))# anoying, the UI uses /10 @@ -2059,11 +2319,14 @@ def translateTimeSensor(node, ipo): time_cu.extend = Blender.IpoCurve.ExtendTypes.CYCLIC # or - EXTRAP, CYCLIC_EXTRAP, CONST, -def importRoute(node): +def importRoute(node, ancestry): ''' Animation route only at the moment ''' + if not hasattr(node, 'fields'): + return + routeIpoDict = node.getRouteIpoDict() def getIpo(id): @@ -2093,29 +2356,33 @@ ROUTE champFly001.bindTime TO vpTs.set_startTime 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('.') + try: + from_id, from_type = field[1].split('.') + to_id, to_type = field[3].split('.') + except: + print "Warning, invalid ROUTE", field + continue if from_type == 'value_changed': if to_type == 'set_position': ipo = getIpo(to_id) set_data_from_node = defDict[from_id] - translatePositionInterpolator(set_data_from_node, ipo) + translatePositionInterpolator(set_data_from_node, ipo, ancestry) - if to_type == 'set_orientation': + if to_type in ('set_orientation', 'rotation'): ipo = getIpo(to_id) set_data_from_node = defDict[from_id] - translateOrientationInterpolator(set_data_from_node, ipo) + translateOrientationInterpolator(set_data_from_node, ipo, ancestry) if to_type == 'set_scale': ipo = getIpo(to_id) set_data_from_node = defDict[from_id] - translateScalarInterpolator(set_data_from_node, ipo) + translateScalarInterpolator(set_data_from_node, ipo, ancestry) - elif from_type == 'bindTime': + elif from_type =='bindTime': ipo = getIpo(from_id) time_node = defDict[to_id] - translateTimeSensor(time_node, ipo) + translateTimeSensor(time_node, ipo, ancestry) @@ -2147,6 +2414,16 @@ def load_web3d(path, PREF_FLAT=False, PREF_CIRCLE_DIV=16, HELPER_FUNC = None): # continue spec = node.getSpec() + ''' + prefix = node.getPrefix() + if prefix=='PROTO': + pass + else + ''' + if HELPER_FUNC and HELPER_FUNC(node, ancestry): + # Note, include this function so the VRML/X3D importer can be extended + # by an external script. - gets first pick + pass if spec=='Shape': importShape(node, ancestry) elif spec in ('PointLight', 'DirectionalLight', 'SpotLight'): @@ -2163,18 +2440,12 @@ def load_web3d(path, PREF_FLAT=False, PREF_CIRCLE_DIV=16, HELPER_FUNC = None): 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) + importRoute(node, ancestry) for node, ancestry in all_nodes: if node.isRoot(): @@ -2289,24 +2560,32 @@ if __name__ == '__main__': # load_web3d('/fe/x3d/www.web3d.org/x3d/content/examples/Basic/StudentProjects/PlayRoom.x3d') # invalid UVs -''' -import os -# files = os.popen('find /fe/wrl -iname "*.wrl"').readlines() -# files = os.popen('find /fe/x3d -iname "*.x3d"').readlines() -files = os.popen('find /fe/x3d/X3dExamplesSavage -iname "*.x3d"').readlines() -files.sort() -tot = len(files) -for i, f in enumerate(files): - if i < 12803 or i > 1000000: - continue - #if i != 12686: - # continue + +def test(): + import os - f = f.strip() - print f, i, tot - sce = bpy.data.scenes.new(f.split('/')[-1]) - bpy.data.scenes.active = sce - # Window. - load_web3d(f, PREF_FLAT=True) -'''
\ No newline at end of file + files = os.popen('find /fe/wrl -iname "*.wrl"').readlines() + # files = os.popen('find /fe/x3d -iname "*.x3d"').readlines() + # files = os.popen('find /fe/x3d/X3dExamplesSavage -iname "*.x3d"').readlines() + + files.sort() + tot = len(files) + for i, f in enumerate(files): + if i < 124 or i > 1000000: + continue + + #if i != 1068: + # continue + + #if i != 12686: + # continue + + f = f.strip() + print f, i, tot + sce = bpy.data.scenes.new(str(i) + '_' + f.split('/')[-1]) + bpy.data.scenes.active = sce + # Window. + load_web3d(f, PREF_FLAT=True) + +# test() diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py index 006bdf10b49..670165dda51 100644 --- a/release/scripts/mesh_edges2curves.py +++ b/release/scripts/mesh_edges2curves.py @@ -112,7 +112,7 @@ def mesh2polys(): Window.EditMode(0) me = meshOb.getData(mesh=1) polygons= polysFromMesh(me) - w=t=1 + w = 1.0 cu= Curve.New() cu.name = me.name cu.setFlag(1) @@ -128,7 +128,7 @@ def mesh2polys(): vIdx= 0 v= poly[vIdx] - cu.appendNurb([v.co.x, v.co.y, v.co.z, w, t]) + cu.appendNurb((v.co.x, v.co.y, v.co.z, w)) vIdx += 1 cu[i].type= 0 # Poly Line @@ -139,7 +139,7 @@ def mesh2polys(): # Add all the points in the polyline. while vIdx<len(poly): v= poly[vIdx] - cu.appendPoint(i, [v.co.x, v.co.y, v.co.z, w]) + cu.appendPoint(i, (v.co.x, v.co.y, v.co.z, w)) vIdx+=1 i+=1 Window.WaitCursor(0) diff --git a/release/scripts/scripttemplate_background_job.py b/release/scripts/scripttemplate_background_job.py new file mode 100644 index 00000000000..86b58991849 --- /dev/null +++ b/release/scripts/scripttemplate_background_job.py @@ -0,0 +1,124 @@ +#!BPY +""" +Name: 'Background Job Example' +Blender: 248 +Group: 'ScriptTemplate' +Tooltip: 'Script template for automating tasks from the command line with blender' +""" + +from Blender import Window +import bpy + +script_data = \ +'''# This script is an example of how you can run blender from the command line (in background mode with no interface) +# to automate tasks, in this example it creates a text object, camera and light, then renders and/or saves it. +# This example also shows how you can parse command line options to python scripts. +# +# Example usage for this test. +# blender -b -P $HOME/background_job.py -- --text="Hello World" --render="/tmp/hello" --save="/tmp/hello.blend" +# +# Notice all python args are after the '--' argument. + +import Blender +import bpy + +def example_function(body_text, save_path, render_path): + + sce= bpy.data.scenes.active + + txt_data= bpy.data.curves.new('MyText', 'Text3d') + + # Text Object + txt_ob = sce.objects.new(txt_data) # add the data to the scene as an object + txt_data.setText(body_text) # set the body text to the command line arg given + txt_data.setAlignment(Blender.Text3d.MIDDLE)# center text + + # Camera + cam_data= bpy.data.cameras.new('MyCam') # create new camera data + cam_ob= sce.objects.new(cam_data) # add the camera data to the scene (creating a new object) + sce.objects.camera= cam_ob # set the active camera + cam_ob.loc= 0,0,10 + + # Lamp + lamp_data= bpy.data.lamps.new('MyLamp') + lamp_ob= sce.objects.new(lamp_data) + lamp_ob.loc= 2,2,5 + + if save_path: + try: + f= open(save_path, 'w') + f.close() + ok= True + except: + print 'Cannot save to path "%s"' % save_path + ok= False + + if ok: + Blender.Save(save_path, 1) + + if render_path: + render= sce.render + render.extensions= True + render.renderPath = render_path + render.sFrame= 1 + render.eFrame= 1 + render.renderAnim() + + + +import sys # to get command line args +import optparse # to parse options for us and print a nice help message + +script_name= 'background_job.py' + +def main(): + + # get the args passed to blender after "--", all of which are ignored by blender specifically + # so python may receive its own arguments + argv= sys.argv + + if '--' not in argv: + argv = [] # as if no args are passed + else: + argv = argv[argv.index('--')+1: ] # get all args after "--" + + # When --help or no args are given, print this help + usage_text = 'Run blender in background mode with this script:\n' + usage_text += ' blender -b -P ' + script_name + ' -- [options]' + + parser = optparse.OptionParser(usage = usage_text) + + + # Example background utility, add some text and renders or saves it (with options) + # Possible types are: string, int, long, choice, float and complex. + parser.add_option('-t', '--text', dest='body_text', help='This text will be used to render an image', type='string') + + parser.add_option('-s', '--save', dest='save_path', help='Save the generated file to the specified path', metavar='FILE') + parser.add_option('-r', '--render', dest='render_path', help='Render an image to the specified path', metavar='FILE') + + options, args = parser.parse_args(argv) # In this example we wont use the args + + if not argv: + parser.print_help() + return + + if not options.body_text: + print 'Error: --text="some string" argument not given, aborting.\n' + parser.print_help() + return + + # Run the example function + example_function(options.body_text, options.save_path, options.render_path) + + print 'batch job finished, exiting' + + +if __name__ == '__main__': + main() +''' + +new_text = bpy.data.texts.new('background_job.py') +new_text.write(script_data) +bpy.data.texts.active = new_text +Window.RedrawAll() + diff --git a/release/scripts/uvcalc_follow_active_coords.py b/release/scripts/uvcalc_follow_active_coords.py index 79a445329cc..83df200991f 100644 --- a/release/scripts/uvcalc_follow_active_coords.py +++ b/release/scripts/uvcalc_follow_active_coords.py @@ -42,28 +42,15 @@ from Blender import * import bpy import BPyMesh -def extend(): - sce = bpy.data.scenes.active - ob = sce.objects.active - - # print ob, ob.type - if ob == None or ob.type != 'Mesh': - Draw.PupMenu('ERROR: No mesh object.') +def extend(EXTEND_MODE,ob): + if EXTEND_MODE == -1: return - - # Toggle Edit mode + me = ob.getData(mesh=1) + me_verts = me.verts + # Toggle Edit mode is_editmode = Window.EditMode() if is_editmode: Window.EditMode(0) - - me = ob.getData(mesh=1) - me_verts = me.verts - - # 0:normal extend, 1:edge length - EXTEND_MODE = Draw.PupMenu("Use Face Area%t|Loop Average%x2|None%x0") - if EXTEND_MODE == -1: - return - Window.WaitCursor(1) t = sys.time() edge_average_lengths = {} @@ -153,8 +140,7 @@ def extend(): uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] + (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]]) if not me.faceUV: - Draw.PupMenu('ERROR: Mesh has no face UV coords.') - return + me.faceUV= True face_act = me.activeFace if face_act == -1: @@ -247,7 +233,22 @@ def extend(): Window.RedrawAll() Window.WaitCursor(0) -if __name__ == '__main__': - extend() + +def main(): + sce = bpy.data.scenes.active + ob = sce.objects.active + + # print ob, ob.type + if ob == None or ob.type != 'Mesh': + Draw.PupMenu('ERROR: No mesh object.') + return -
\ No newline at end of file + + + # 0:normal extend, 1:edge length + EXTEND_MODE = Draw.PupMenu("Use Face Area%t|Loop Average%x2|None%x0") + extend(EXTEND_MODE,ob) + +if __name__ == '__main__': + main() + diff --git a/release/scripts/uvcalc_quad_clickproj.py b/release/scripts/uvcalc_quad_clickproj.py index 0bba747e010..130a7e5af77 100644 --- a/release/scripts/uvcalc_quad_clickproj.py +++ b/release/scripts/uvcalc_quad_clickproj.py @@ -171,6 +171,9 @@ def main(): f_uv = f.uv return [(v.co-face_corner_main, f_uv[i]) for i,v in enumerate(f.v)] + if me.faceUV==False: + me.faceUV= True + coords = [ (co,uv) for f in me.faces if f.sel for co, uv in get_face_coords(f)] coords_orig = [uv.copy() for co, uv in coords] @@ -264,4 +267,5 @@ def main(): if __name__=='__main__': main() - Window.DrawProgressBar(1.0, '')
\ No newline at end of file + Window.DrawProgressBar(1.0, '') + diff --git a/release/scripts/vertexpaint_from_material.py b/release/scripts/vertexpaint_from_material.py index 2df5b7e721f..9668c521f3a 100644 --- a/release/scripts/vertexpaint_from_material.py +++ b/release/scripts/vertexpaint_from_material.py @@ -27,6 +27,7 @@ def matcol(mat): int(mat.R*255),\ int(mat.G*255),\ int(mat.B*255) + else: return None def mat2vcol(PREF_SEL_FACES_ONLY, PREF_ACTOB_ONLY, PREF_MULTIPLY_COLOR): @@ -47,7 +48,7 @@ def mat2vcol(PREF_SEL_FACES_ONLY, PREF_ACTOB_ONLY, PREF_MULTIPLY_COLOR): me= ob.getData(mesh=1) try: - me.faceUV=True + me.vertexColors=True except: # no faces continue |