diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py index 85d1ac5ceff..b9b7b8e5ae6 100644 --- a/release/scripts/ac3d_export.py +++ b/release/scripts/ac3d_export.py @@ -10,7 +10,7 @@ Tip: 'Export selected meshes to AC3D (.ac) format' __author__ = "Willian P. Germano" __url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", "PLib 3d gaming lib, http://plib.sf.net") -__version__ = "2.36 2005-04-14" +__version__ = "2.37a 2005-06-09" __bpydoc__ = """\ This script exports selected Blender meshes to AC3D's .ac file format. @@ -47,6 +47,8 @@ left without mats -- it's better to always add your own materials;
- set texture dir: override the actual textures path with a given default path (or simply export the texture names, without dir info, if the path is empty);
+ - only selected: only consider selected objects when looking for meshes +to export (read notes below about tokens, too);
strings: - export dir: default dir to export to;
- texture dir: override textures path with this path if 'set texture dir' @@ -118,6 +120,7 @@ SET_TEX_DIR = True TEX_DIR = '' AC3D_4 = True # export crease value, compatible with AC3D 4 loaders NO_SPLIT = False +ONLY_SELECTED = True EXPORT_DIR = '' tooltips = { @@ -130,6 +133,7 @@ tooltips = { 'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)", 'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support", 'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)", + 'ONLY_SELECTED': "export only selected objects" } def update_RegistryInfo(): @@ -143,6 +147,7 @@ def update_RegistryInfo(): d['AC3D_4'] = AC3D_4 d['NO_SPLIT'] = NO_SPLIT d['EXPORT_DIR'] = EXPORT_DIR + d['ONLY_SELECTED'] = ONLY_SELECTED d['tooltips'] = tooltips Blender.Registry.SetKey(REG_KEY, d, True) @@ -159,6 +164,7 @@ if rd: SET_TEX_DIR = rd['SET_TEX_DIR'] TEX_DIR = rd['TEX_DIR'] EXPORT_DIR = rd['EXPORT_DIR'] + ONLY_SELECTED = rd['ONLY_SELECTED'] NO_SPLIT = rd['NO_SPLIT'] except KeyError: update_RegistryInfo() @@ -673,10 +679,13 @@ def fs_callback(filename): # -- End of definitions -OBJS = Blender.Object.GetSelected() +if ONLY_SELECTED: + OBJS = Blender.Object.GetSelected() +else: + OBJS = Blender.Scene.GetCurrent().getChildren() if not OBJS: - Blender.Draw.PupMenu('ERROR: No objects selected') + Blender.Draw.PupMenu('ERROR: no objects selected') else: fname = bsys.makename(ext=".ac") if EXPORT_DIR: diff --git a/release/scripts/bpymodules/svg2obj.py b/release/scripts/bpymodules/svg2obj.py index e7837b9bb15..11d21991bc5 100644 --- a/release/scripts/bpymodules/svg2obj.py +++ b/release/scripts/bpymodules/svg2obj.py @@ -42,8 +42,19 @@ Yet done: c : relative curve to 2004/08/03 s : relative curve to with only one handle -To do: A,S,V,H,Q,T, - a,s, m, v, h, q,t + + A : courbe_vers_a, + V : ligne_tracee_v, + H : ligne_tracee_h, + Z : boucle_z, + Q : courbe_vers_q, + T : courbe_vers_t, + a : courbe_vers_a, + v : ligne_tracee_v, + h : ligne_tracee_h, + z : boucle_z, + q : courbe_vers_q, + Changelog: 0.1.1 : - control file without extension @@ -53,11 +64,13 @@ Changelog: instead of x,y,width and height 0.2.2 : - read compact path data from Illustrator 10 0.2.3 : - read a few new relative displacements - 0.2.4 : - better hash for command with followed by a lone data + 0.2.4 : - better hash for command followed by a lone data (h,v) or uncommun number (a) 0.2.5 : - correction for gimp import 0.2.6 : - correction for illustrator 10 SVG 0.2.7 : - correction for inskape 0.40 cvs SVG + 0.2.8 : - correction for inskape plain SVG + ================================================================================== ==================================================================================""" @@ -290,15 +303,17 @@ def contruit_SYMETRIC(l): def mouvement_vers(c, D, n0,CP): global DEBUG,TAGcourbe - #print c,D[c[1]+1] + print 'c',c,'D[c[1]+1]',D[c[1]+1] l=filtre_DATA(c,D,1) - #print l + print 'l',l if n0 in courbes.ITEM.keys(): n0+=1 - CP=[l[0],l[1]] - else: - CP=[l[0],l[1]] + # + # CP=[l[0],l[1]] + #else: + # CP=[l[0],l[1]] + CP=[l[0],l[1]] courbes.ITEM[n0]=ITEM() courbes.ITEM[n0].Origine=[l[0],l[1]] @@ -522,10 +537,19 @@ def get_BOUNDBOX(BOUNDINGBOX,SVG,viewbox): return BOUNDINGBOX +# 0.2.8 : - correction for inskape 0.40 cvs SVG +def repack_DATA(DATA): + for d in Actions.keys(): + DATA=DATA.replace(d,d+' ') + return DATA + + def unpack_DATA(DATA): DATA[0]=DATA[0].replace('-',',-') + for d in Actions.keys(): DATA[0]=DATA[0].replace(d,','+d+',') + DATA[0]=DATA[0].replace(',,',',') if DATA[0][0]==',':DATA[0]=DATA[0][1:] if DATA[0][-1]==',':DATA[0]=DATA[0][:-1] @@ -575,9 +599,12 @@ def format_PATH(t): if PATH.find(' d="')!=-1: PATH,D=get_content('d',PATH) - - #print "D0= :",D - + + # 0.2.8 : - correction for inskape plain SVG + if D.find(',')==-1: + D=repack_DATA(D) + # 0.2.8 : end + D=D.split(' ') try: @@ -586,17 +613,12 @@ def format_PATH(t): except: pass - #print len(D) - #for D0 in D: - #print " ----> D = :", D0 - if len(D)==1 or len(D[0])>1: D1=[] for D0 in D: D1+=unpack_DATA([D0])[:] D=D1 - - #print "D2= :",D + return t,D @@ -627,8 +649,6 @@ def scan_FILE(nom): else: BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,SVG,viewbox) - #print t - while t.find('path')!=-1: t,D=format_PATH(t) cursor=0 @@ -670,4 +690,3 @@ def fonctionSELECT(nom): if DEVELOPPEMENT==1: Blender.Window.FileSelector (fonctionSELECT, 'SELECT a .SVG FILE') - #sys.path=oldpath diff --git a/release/scripts/console.py b/release/scripts/console.py index 1fbf7908c7a..e95d6bc34b1 100644 --- a/release/scripts/console.py +++ b/release/scripts/console.py @@ -2,22 +2,24 @@ """ Name: 'Interactive Console' -Blender: 236 +Blender: 237 Group: 'System' Tooltip: 'Interactive Python Console' """ + __author__ = "Campbell Barton AKA Ideasman" -__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] +__url__ = ["Author's homepage, http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] __bpydoc__ = """\ This is an interactive console, similar to Python's own command line interpreter. Since it is embedded in Blender, it has access to all Blender Python modules. -Those completely new to Python can check the link button above that points to -its official homepage, with news, downloads and documentation. +Those completely new to Python are recommended to check the link button above +that points to its official homepage, with news, downloads and documentation. Usage:
Type your code and hit "Enter" to get it executed.
- - Right mouse click: Save output;
+ - Right mouse click: Console Menu (Save output, etc);
- Arrow keys: command history and cursor;
+ - Shift + arrow keys: jump words;
- Ctrl + Tab: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;
- Ctrl + Enter: multiline functions -- delays executing code until only Enter is pressed. """ @@ -31,9 +33,13 @@ import types # Constants __DELIMETERS__ = '. ,=+-*/%<>&~][{}():' __LINE_HISTORY__ = 200 + +global __LINE_HEIGHT__ __LINE_HEIGHT__ = 14 +global __FONT_SIZE__ __FONT_SIZE__ = "normal" + ''' # Generic Blender functions def getActScriptWinRect(): @@ -255,8 +261,10 @@ def handle_event(evt, val): cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd def actionRightMouse(): - choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Quit') - print choice + global __FONT_SIZE__ + global __LINE_HEIGHT__ + choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Help|%l|Quit') + # print choice if choice == 1: writeCmdData(cmdBuffer, 0) # type 0 user elif choice == 2: @@ -267,7 +275,26 @@ def handle_event(evt, val): writeCmdData(cmdBuffer, 3) # All elif choice == 6: insertCmdData(cmdBuffer) # All - elif choice == 8: # Exit + elif choice == 8: + # Fontsize. + font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny') + if font_choice != -1: + if font_choice == 1: + __FONT_SIZE__ = 'large' + __LINE_HEIGHT__ = 16 + elif font_choice == 2: + __FONT_SIZE__ = 'normal' + __LINE_HEIGHT__ = 14 + elif font_choice == 3: + __FONT_SIZE__ = 'small' + __LINE_HEIGHT__ = 12 + elif font_choice == 4: + __FONT_SIZE__ = 'tiny' + __LINE_HEIGHT__ = 10 + Draw.Redraw() + elif choice == 10: + Blender.ShowHelp('console.py') + elif choice == 12: # Exit Draw.Exit() @@ -356,12 +383,52 @@ def handle_event(evt, val): if (evt == Draw.UPARROWKEY and val): actionUpKey() elif (evt == Draw.DOWNARROWKEY and val): actionDownKey() - elif (evt == Draw.RIGHTARROWKEY and val): - cursor +=1 - if cursor > -1: - cursor = -1 + elif (evt == Draw.RIGHTARROWKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor+1 + while newCursor<0: + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__: + newCursor+=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -1 # end of line + else: + cursor +=1 + if cursor > -1: + cursor = -1 + elif (evt == Draw.LEFTARROWKEY and val): - cursor -=1 + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor-1 + while abs(newCursor) < len(cmdBuffer[-1].cmd): + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__ or\ + newCursor == cursor: + newCursor-=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -len(cmdBuffer[-1].cmd) # Start of line + + else: + if len(cmdBuffer[-1].cmd) > abs(cursor): + cursor -=1 + + elif (evt == Draw.HOMEKEY and val): + cursor = -len(cmdBuffer[-1].cmd) + + elif (evt == Draw.ENDKEY and val): + cursor = -1 elif (evt == Draw.TABKEY and val): if Window.GetKeyQualifiers() & Window.Qual.CTRL: @@ -391,7 +458,6 @@ def draw_gui(): BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__) __CONSOLE_RECT__= __CONSOLE_RECT__.list - # Clear the screen BGL.glClearColor(0.0, 0.0, 0.0, 1.0) BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer @@ -399,7 +465,10 @@ def draw_gui(): # Draw cursor location colour cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZE__) BGL.glColor3f(0.8, 0.2, 0.2) - BGL.glRecti(cmd2curWidth-1,4,cmd2curWidth+1, 20) + if cmd2curWidth == 0: + BGL.glRecti(0,2,2, __LINE_HEIGHT__+2) + else: + BGL.glRecti(cmd2curWidth-2,2,cmd2curWidth, __LINE_HEIGHT__+2) BGL.glColor3f(1,1,1) # Draw the set of cammands to the buffer @@ -469,8 +538,9 @@ __CONSOLE_VAR_DICT__ = {} # Initialize var dict # Print Startup lines cmdBuffer = [cmdLine("Welcome to Ideasman's Blender Console", 1, None),\ - cmdLine(' * Right Click: Save output', 1, None),\ + cmdLine(' * Right Click: Console Menu (Save output, etc.)', 1, None),\ cmdLine(' * Arrow Keys: Command history and cursor', 1, None),\ + cmdLine(' * Shift With Arrow Keys: Jump words', 1, None),\ cmdLine(' * Ctrl + Tab: Auto compleate based on variable names and modules loaded, multiple choices popup a menu', 1, None),\ cmdLine(' * Ctrl + Enter: Multiline functions, delays executing code until only Enter is pressed.', 1, None)] diff --git a/release/scripts/fixfromarmature.py b/release/scripts/fixfromarmature.py index a9fea501b87..b43cdb0a1e2 100644 --- a/release/scripts/fixfromarmature.py +++ b/release/scripts/fixfromarmature.py @@ -11,14 +11,14 @@ __author__ = "Jean-Michel Soler (jms)" __url__ = ("blender", "elysiun", "Script's homepage, http://jmsoler.free.fr/util/blenderfile/py/fixfromarmature.py", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "05/2005" +__version__ = "06/2005" __bpydoc__ = """\ This script creates a copy of the active mesh with deformations fixed. Usage: -Select the mesh and run this script. A fixed copy of it will be created. +Select the deformed mesh and run this script. A fixed copy of it will be created. """ # $Id$ @@ -72,21 +72,21 @@ def fix_mesh(nomdelobjet): Obis.setMatrix(Ozero.getMatrix()) scene = Blender.Scene.getCurrent() scene.link (Obis) - - Mesh2=Obis.getData() - Mesh1=Ozero.getData() - - if len(Mesh2.verts)==len(Mesh1.verts): - for VertGroupName in Mesh1.getVertGroupNames(): - VertexList = Mesh1.getVertsFromGroup(VertGroupName, True) - Mesh2.addVertGroup(VertGroupName) - for Vertex in VertexList: - Mesh2.assignVertsToGroup(VertGroupName, [Vertex[0]], Vertex[1], 'add') - else: - for vgroupname in Mesh1.getVertGroupNames(): - Mesh2.addVertGroup(vgroupname) - Mesh2.update() - + try : + Mesh2=Obis.getData() + Mesh1=Ozero.getData() + if len(Mesh2.verts)==len(Mesh1.verts): + for VertGroupName in Mesh1.getVertGroupNames(): + VertexList = Mesh1.getVertsFromGroup(VertGroupName, True) + Mesh2.addVertGroup(VertGroupName) + for Vertex in VertexList: + Mesh2.assignVertsToGroup(VertGroupName, [Vertex[0]], Vertex[1], 'add') + else: + for vgroupname in Mesh1.getVertGroupNames(): + Mesh2.addVertGroup(vgroupname) + Mesh2.update() + except: + print "mesh has no vertex group " Ozero=Blender.Object.GetSelected()[0] @@ -110,5 +110,5 @@ else: elif softbodies==1: for f in range(1, curframe + 1): Blender.Set('curframe',f) + Blender.Window.RedrawAll() if fix: fix_mesh(Ozero.getName()) - diff --git a/release/scripts/help_browser.py b/release/scripts/help_browser.py index aa05c988207..d321ffa6256 100644 --- a/release/scripts/help_browser.py +++ b/release/scripts/help_browser.py @@ -71,7 +71,7 @@ Hotkeys:
# -------------------------------------------------------------------------- import Blender -from Blender import sys as bsys, Draw, Window +from Blender import sys as bsys, Draw, Window, Registry WEBBROWSER = True try: @@ -390,7 +390,7 @@ def parse_help_info(script): fname = bsys.join(path, script.fname) if not bsys.exists(fname): - Draw.PupMenu('IO Error: Couldn\'t find script %s' % fname) + Draw.PupMenu('IO Error: couldn\'t find script %s' % fname) return None f = file(fname, 'r') @@ -545,7 +545,7 @@ def gui(): # drawing the screen global SCRIPT_INFO, AllGroups, GROUP_MENUS global BEVT_EMAIL, BEVT_LINK global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU - global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS + global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE theme = Theme.Get()[0] tui = theme.get('ui') @@ -667,7 +667,7 @@ 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)') - 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)') BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) BGL.glRasterPos2i(x, 5) @@ -686,12 +686,12 @@ def fit_scroll(): def event(evt, val): # input events global SCREEN, START_SCREEN, SCRIPT_SCREEN - global SCROLL_DOWN + global SCROLL_DOWN, FMODE if not val: return if evt == Draw.ESCKEY: - if SCREEN == START_SCREEN: Draw.Exit() + if SCREEN == START_SCREEN or FMODE: Draw.Exit() else: SCREEN = START_SCREEN SCROLL_DOWN = 0 @@ -719,7 +719,7 @@ def button_event(evt): # gui button events global SCREEN, START_SCREEN, SCRIPT_SCREEN global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO - global SCROLL_DOWN + global SCROLL_DOWN, FMODE if evt >= 100: # group menus for i in range(len(BUT_GMENU)): @@ -754,10 +754,36 @@ def button_event(evt): # gui button events Draw.Exit() return elif evt == BEVT_BACK: - if SCREEN == SCRIPT_SCREEN: + if SCREEN == SCRIPT_SCREEN and not FMODE: SCREEN = START_SCREEN SCRIPT_INFO = None SCROLL_DOWN = 0 Draw.Redraw() -Draw.Register(gui, event, button_event) +keepon = True +FMODE = False # called by Blender.ShowHelp(name) API function ? + +KEYNAME = '__help_browser' +rd = Registry.GetKey(KEYNAME) +if rd: + rdscript = rd['script'] + keepon = False + Registry.RemoveKey(KEYNAME) + for group in AllGroups: + for script in group.get_scripts(): + if rdscript == script.fname: + parseit = parse_help_info(script) + if parseit == True: + keepon = True + SCREEN = SCRIPT_SCREEN + BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) + BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) + FMODE = True + elif parseit == False: + Draw.PupMenu("ERROR: script doesn't have proper help data") + break + +if not keepon: + Draw.PupMenu("ERROR: couldn't find script") +else: + Draw.Register(gui, event, button_event) diff --git a/release/scripts/obj_export.py b/release/scripts/obj_export.py index d51658b2598..b6ef15a47e3 100644 --- a/release/scripts/obj_export.py +++ b/release/scripts/obj_export.py @@ -57,10 +57,10 @@ NULL_IMG = '(null)' # from docs at http://astronomy.swin.edu.au/~pbourke/geomfor def save_mtl(filename): file = open(filename, "w") for mat in Material.Get(): - + file.write('newmtl %s\n' % (mat.getName())) # Define a new material - # Hardness, convert blenders 1-511 to MTL's + # Hardness, convert blenders 1-511 to MTL's file.write('Ns %s\n' % ((mat.getHardness()-1) * 1.9607843137254901 ) ) col = mat.getRGBCol() @@ -163,7 +163,7 @@ def save_obj(filename): if f.image.filename != currentImgName: currentImgName = f.image.filename # Set a new image for all following faces - file.write( 'usemapusemap %s\n' % currentImgName.split('\\')[-1].split('/')[-1] ) + file.write( 'usemap %s\n' % currentImgName.split('\\')[-1].split('/')[-1] ) elif currentImgName != NULL_IMG: # Not using an image so set to NULL_IMG currentImgName = NULL_IMG diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index 2913cc015ec..6930ef86ef5 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -2,7 +2,7 @@ """ Name: 'Wavefront (.obj)...' -Blender: 237 +Blender: 232 Group: 'Import' Tooltip: 'Load a Wavefront OBJ File' """ @@ -76,17 +76,7 @@ def stripName(name): # name is a string from Blender import * - -#==================================================================================# -# This gets a mat or creates one of the requested name if none exist. # -#==================================================================================# -def getMat(matName): - # Make a new mat - try: - return Material.Get(matName) - except: - return Material.New(matName) - +import sys as py_sys #==================================================================================# # This function sets textures defined in .mtl file # @@ -99,8 +89,8 @@ def getImg(img_fileName): # if we are this far it means the image hasnt been loaded. try: return Image.Load(img_fileName) - except: - print "unable to open", img_fileName + except IOError: + print '\tunable to open image file: "%s"' % img_fileName return @@ -108,48 +98,56 @@ def getImg(img_fileName): #==================================================================================# # This function sets textures defined in .mtl file # #==================================================================================# -def load_mat_image(mat, img_fileName, type, mesh): - try: - image = Image.Load(img_fileName) - except: - print "unable to open", img_fileName - return +def load_mat_image(mat, img_fileName, type, meshDict): + texture = Texture.New(type) texture.setType('Image') - texture.image = image + + image = getImg(img_fileName) + if image: + texture.image = image # adds textures to faces (Textured/Alt-Z mode) # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. if type == 'Kd': - for f in mesh.faces: - if mesh.materials[f.mat].name == mat.name: - - # the inline usemat command overides the material Image - if not f.image: - f.image = image - + for meshPair in meshDict.values(): + for f in meshPair[0].faces: + if meshPair[0].materials[f.mat].name == mat.name: + # the inline usemat command overides the material Image + if not f.image: + f.image = image + # adds textures for materials (rendering) - if type == 'Ka': + elif type == 'Ka': mat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) - if type == 'Kd': + elif type == 'Kd': mat.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.COL) - if type == 'Ks': + elif type == 'Ks': mat.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) #==================================================================================# # This function loads materials from .mtl file (have to be defined in obj file) # #==================================================================================# -def load_mtl(dir, mtl_file, mesh): - # Remove ./ - if mtl_file.endswith('./'): - mtl_file= mtl_file[2:] +def load_mtl(dir, mtl_file, meshDict): + #===============================================================================# + # This gets a mat or creates one of the requested name if none exist. # + #===============================================================================# + def getMat(matName): + # Make a new mat + try: + return Material.Get(matName) + except NameError: + return Material.New(matName) + + mtl_file = stripPath(mtl_file) mtl_fileName = dir + mtl_file + try: fileLines= open(mtl_fileName, 'r').readlines() - except: - print "unable to open", mtl_fileName + except IOError: + print '\tunable to open referenced material file: "%s"' % mtl_fileName return lIdx=0 @@ -162,7 +160,7 @@ def load_mtl(dir, mtl_file, mesh): elif l[0] == '#' or len(l) == 0: pass elif l[0] == 'newmtl': - currentMat = getMat(' '.join(l[1:])) + currentMat = getMat('_'.join(l[1:])) # Material should alredy exist. elif l[0] == 'Ka': currentMat.setMirCol(float(l[1]), float(l[2]), float(l[3])) elif l[0] == 'Kd': @@ -177,56 +175,59 @@ def load_mtl(dir, mtl_file, mesh): currentMat.setAlpha(float(l[1])) elif l[0] == 'map_Ka': img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ka', mesh) + load_mat_image(currentMat, img_fileName, 'Ka', meshDict) elif l[0] == 'map_Ks': img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ks', mesh) + load_mat_image(currentMat, img_fileName, 'Ks', meshDict) elif l[0] == 'map_Kd': img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Kd', mesh) + load_mat_image(currentMat, img_fileName, 'Kd', meshDict) lIdx+=1 #===========================================================================# # Returns unique name of object/mesh (preserve overwriting existing meshes) # #===========================================================================# def getUniqueName(name): + newName = name uniqueInt = 0 while 1: try: - ob = Object.Get(name) + ob = Object.Get(newName) # Okay, this is working, so lets make a new name - name = '%s.%d' % (name, uniqueInt) + newName = '%s.%d' % (name, uniqueInt) uniqueInt +=1 - except: - if name not in NMesh.GetNames(): - return name + except AttributeError: + if newName not in NMesh.GetNames(): + return newName else: - name = '%s.%d' % (name, uniqueInt) + newName = '%s.%d' % (name, uniqueInt) uniqueInt +=1 + +# Gets the meshs index for this material, -1 if its not in the list +def getMeshMaterialIndex(mesh, material): + meshMatIndex = -1 + matIdx = 0 + meshMatList = mesh.materials + while matIdx < len(meshMatList): + if meshMatList[matIdx].name == material.name: + meshMatIndex = matIdx # The current mat index. + break + matIdx+=1 + # -1 if not found + return meshMatIndex + + + + #==================================================================================# # This loads data from .obj file # #==================================================================================# def load_obj(file): time1 = sys.time() - def applyMat(mesh, f, mat): - # Check weather the 16 mat limit has been met. - if len( meshList[objectName][0].materials ) >= MATLIMIT: - print 'Warning, max material limit reached, using an existing material' - return meshList[objectName][0] - - mIdx = 0 - for m in meshList[objectName][0].materials: - if m.getName() == mat.getName(): - break - mIdx+=1 - - if mIdx == len(mesh.materials): - meshList[objectName][0].addMaterial(mat) - - f.mat = mIdx - return f - + + TEX_OFF_FLAG = ~NMesh.FaceModes['TEX'] + # Get the file name with no path or .obj fileName = stripName( stripPath(file) ) @@ -235,56 +236,76 @@ def load_obj(file): DIR = pathName(file, stripPath(file)) fileLines = open(file, 'r').readlines() - - - + uvMapList = [(0,0)] # store tuple uv pairs here # This dummy vert makes life a whole lot easier- # pythons index system then aligns with objs, remove later vertList = [NMesh.Vert(0, 0, 0)] - - nullMat = getMat(NULL_MAT) + + # Store all imported materials in a dict, names are key + materiaDict = {} + + # Store all imported images in a dict, names are key + imageDict = {} + + # This stores the index that the current mesh has for the current material. + # if the mesh does not have the material then set -1 + contextMeshMatIdx = -1 + + # Keep this out of the dict for easy accsess. + nullMat = Material.New(NULL_MAT) currentMat = nullMat # Use this mat. currentImg = NULL_IMG # Null image is a string, otherwise this should be set to an image object.\ - currentSmooth = 0 + currentSmooth = 1 - #==================================================================================# - # Make split lines, ignore blenk lines or comments. # - #==================================================================================# - lIdx = 0 - while lIdx < len(fileLines): - fileLines[lIdx] = fileLines[lIdx].split() - lIdx+=1 + # Store a list of unnamed names + currentUnnamedGroupIdx = 0 + currentUnnamedObjectIdx = 0 + + quadList = (0, 1, 2, 3) #==================================================================================# # Load all verts first (texture verts too) # #==================================================================================# + nonVertFileLines = [] lIdx = 0 - print 'file length: %d' % len(fileLines) + print '\tfile length: %d' % len(fileLines) while lIdx < len(fileLines): - l = fileLines[lIdx] - if len(l) == 0: - fileLines.pop(lIdx) - lIdx-=1 - - elif l[0] == 'v': - # This is a new vert, make a new mesh - vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) ) - fileLines.pop(lIdx) - lIdx-=1 - + # Dont Bother splitting empty or comment lines. + if len(fileLines[lIdx]) == 0: + pass + elif fileLines[lIdx][0] == '\n': + pass + elif fileLines[lIdx][0] == '#': + pass - # UV COORDINATE - elif l[0] == 'vt': - # This is a new vert, make a new mesh - uvMapList.append( (float(l[1]), float(l[2])) ) - fileLines.pop(lIdx) - lIdx-=1 + else: + fileLines[lIdx] = fileLines[lIdx].split() + l = fileLines[lIdx] + + # Splitting may + if len(l) == 0: + pass + # Verts + elif l[0] == 'v': + vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) ) + + # UV COORDINATE + elif l[0] == 'vt': + uvMapList.append( (float(l[1]), float(l[2])) ) + else: + nonVertFileLines.append(l) lIdx+=1 + del fileLines + fileLines = nonVertFileLines + del nonVertFileLines + + # Make a list of all unused vert indicies that we can copy from + VERT_USED_LIST = [-1]*len(vertList) # Here we store a boolean list of which verts are used or not # no we know weather to add them to the current mesh @@ -295,10 +316,13 @@ def load_obj(file): # objectName has a char in front of it that determins weather its a group or object. # We ignore it when naming the object. objectName = 'omesh' # If we cant get one, use this - meshList = {} - meshList[objectName] = (NMesh.GetRaw(), [-1]*len(vertList)) # Mesh/meshList[objectName][1] - meshList[objectName][0].verts.append(vertList[0]) - meshList[objectName][0].hasFaceUV(1) + + meshDict = {} + currentMesh = NMesh.GetRaw() + meshDict[objectName] = (currentMesh, VERT_USED_LIST[:]) # Mesh/meshDict[objectName][1] + currentMesh.verts.append(vertList[0]) + currentMesh.hasFaceUV(1) + #==================================================================================# # Load all faces into objects, main loop # @@ -308,29 +332,21 @@ def load_obj(file): while lIdx < len(fileLines): l = fileLines[lIdx] - # VERTEX - if l[0] == 'v': - pass - - # Comment - if l[0] == '#': - pass - - # VERTEX NORMAL - elif l[0] == 'vn': - pass - - # UV COORDINATE - elif l[0] == 'vt': - pass - # FACE - elif l[0] == 'f': + if l[0] == 'f': # Make a face with the correct material. f = NMesh.Face() - f = applyMat(meshList[objectName][0], f, currentMat) - f.smooth = currentSmooth - if currentImg != NULL_IMG: f.image = currentImg + + # Add material to mesh + if contextMeshMatIdx == -1: + tmpMatLs = currentMesh.materials + + if len(tmpMatLs) == MATLIMIT: + contextMeshMatIdx = 0 # Use first material + print 'material overflow, attempting to use > 16 materials. defaulting to first.' + else: + contextMeshMatIdx = len(tmpMatLs) + currentMesh.addMaterial(currentMat) # Set up vIdxLs : Verts # Set up vtIdxLs : UV @@ -341,7 +357,7 @@ def load_obj(file): for v in l[1:]: # OBJ files can have // or / to seperate vert/texVert/normal # this is a bit of a pain but we must deal with it. - objVert = v.split('/', -1) + objVert = v.split('/') # Vert Index - OBJ supports negative index assignment (like python) @@ -349,8 +365,9 @@ def load_obj(file): if fHasUV: # UV if len(objVert) == 1: - vtIdxLs.append(int(objVert[0])) # Sticky UV coords - elif objVert[1] != '': # Its possible that theres no texture vert just he vert and normal eg 1//2 + #vtIdxLs.append(int(objVert[0])) # replace with below. + vtIdxLs.append(vIdxLs[-1]) # Sticky UV coords + elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2 vtIdxLs.append(int(objVert[1])) # Seperate UV coords else: fHasUV = 0 @@ -365,13 +382,13 @@ def load_obj(file): # Quads only, we could import quads using the method below but it polite to import a quad as a quad. if len(vIdxLs) == 4: - for i in [0,1,2,3]: - if meshList[objectName][1][vIdxLs[i]] == -1: - meshList[objectName][0].verts.append(vertList[vIdxLs[i]]) - f.v.append(meshList[objectName][0].verts[-1]) - meshList[objectName][1][vIdxLs[i]] = len(meshList[objectName][0].verts)-1 + for i in quadList: # quadList == [0,1,2,3] + if meshDict[objectName][1][vIdxLs[i]] == -1: + currentMesh.verts.append(vertList[vIdxLs[i]]) + f.v.append(currentMesh.verts[-1]) + meshDict[objectName][1][vIdxLs[i]] = len(currentMesh.verts)-1 else: - f.v.append(meshList[objectName][0].verts[meshList[objectName][1][vIdxLs[i]]]) + f.v.append(currentMesh.verts[meshDict[objectName][1][vIdxLs[i]]]) # UV MAPPING if fHasUV: @@ -380,44 +397,53 @@ def load_obj(file): # f.uv.append( uvMapList[ vtIdxLs[i] ] ) if f.v > 0: - f = applyMat(meshList[objectName][0], f, currentMat) + f.mat = contextMeshMatIdx if currentImg != NULL_IMG: - f.image = currentImg - meshList[objectName][0].faces.append(f) # move the face onto the mesh - if len(meshList[objectName][0].faces[-1]) > 0: - meshList[objectName][0].faces[-1].smooth = currentSmooth - + f.image = currentImg + else: + f.mode &= TEX_OFF_FLAG + currentMesh.faces.append(f) # move the face onto the mesh + if len(f) > 0: + f.smooth = currentSmooth + elif len(vIdxLs) >= 3: # This handles tri's and fans for i in range(len(vIdxLs)-2): f = NMesh.Face() - f = applyMat(meshList[objectName][0], f, currentMat) + for ii in [0, i+1, i+2]: - if meshList[objectName][1][vIdxLs[ii]] == -1: - meshList[objectName][0].verts.append(vertList[vIdxLs[ii]]) - f.v.append(meshList[objectName][0].verts[-1]) - meshList[objectName][1][vIdxLs[ii]] = len(meshList[objectName][0].verts)-1 + if meshDict[objectName][1][vIdxLs[ii]] == -1: + currentMesh.verts.append(vertList[vIdxLs[ii]]) + f.v.append(currentMesh.verts[-1]) + meshDict[objectName][1][vIdxLs[ii]] = len(currentMesh.verts)-1 else: - f.v.append(meshList[objectName][0].verts[meshList[objectName][1][vIdxLs[ii]]]) + f.v.append(currentMesh.verts[meshDict[objectName][1][vIdxLs[ii]]]) # UV MAPPING if fHasUV: f.uv.extend([uvMapList[ vtIdxLs[0] ], uvMapList[ vtIdxLs[i+1] ], uvMapList[ vtIdxLs[i+2] ]]) - + if f.v > 0: - f = applyMat(meshList[objectName][0], f, currentMat) + f.mat = contextMeshMatIdx if currentImg != NULL_IMG: - f.image = currentImg - meshList[objectName][0].faces.append(f) # move the face onto the mesh - if len(meshList[objectName][0].faces[-1]) > 0: - meshList[objectName][0].faces[-1].smooth = currentSmooth + f.image = currentImg + else: + f.mode |= TEX_OFF_FLAG + currentMesh.faces.append(f) # move the face onto the mesh + if len(f) > 0: + f.smooth = currentSmooth # FACE SMOOTHING elif l[0] == 's': - if l[1] == 'off': currentSmooth = 0 - else: currentSmooth = 1 - # print "smoothing", currentSmooth + # No value? then turn on. + if len(l) == 1: + currentSmooth = 1 + else: + if l[1] == 'off': + currentSmooth = 0 + else: + currentSmooth = 1 # OBJECT / GROUP elif l[0] == 'o' or l[0] == 'g': @@ -426,51 +452,93 @@ def load_obj(file): # Only make a new group.object name if the verts in the existing object have been used, this is obscure # but some files face groups seperating verts and faces which results in silly things. (no groups have names.) - if len(l) == 1 and len( meshList[objectName][0].faces ) == 0: - pass + if len(l) > 1: + objectName = '_'.join(l[1:]) + else: # No name given + # Make a new empty name + if l[0] == 'g': # Make a blank group name + objectName = 'unnamed_grp_%d' % currentUnnamedGroupIdx + currentUnnamedGroupIdx +=1 + else: # is an object. + objectName = 'unnamed_ob_%d' % currentUnnamedObjectIdx + currentUnnamedObjectIdx +=1 - else: - newObjectName = l[0] + '_' - - # if there is no groups name then make gp_1, gp_2, gp_100 etc - - if len(l) == 1: # No name given, make a unique name up. - - unique_count = 0 - while newObjectName in meshList.keys(): - newObjectName = '%s_%d' % (l[0], unique_count) - unique_count +=1 - else: # The the object/group name given - newObjectName += '_'.join(l[1:]) - - # Assign the new name - objectName = newObjectName - - # If we havnt written to this mesh before then do so. - # if we have then we'll just keep appending to it, this is required for soem files. - if objectName not in meshList.keys(): - meshList[objectName] = (NMesh.GetRaw(), [-1]*len(vertList)) - meshList[objectName][0].hasFaceUV(1) - meshList[objectName][0].verts.append( vertList[0] ) + + # If we havnt written to this mesh before then do so. + # if we have then we'll just keep appending to it, this is required for soem files. + + # If we are new, or we are not yet in the list of added meshes + # then make us new mesh. + if len(l) == 1 or objectName not in meshDict.keys(): + currentMesh = NMesh.GetRaw() + meshDict[objectName] = (currentMesh, VERT_USED_LIST[:]) + currentMesh.hasFaceUV(1) + currentMesh.verts.append( vertList[0] ) + contextMeshMatIdx = -1 + else: + # Since we have this in Blender then we will check if the current Mesh has the material. + # set the contextMeshMatIdx to the meshs index but only if we have it. + currentMesh = meshDict[objectName] + contextMeshMatIdx = getMeshMaterialIndex(currentMesh, currentMat) + + # MATERIAL elif l[0] == 'usemtl': - if len(l) == 1 or l[1] == '(null)': - currentMat = getMat(NULL_MAT) + if len(l) == 1 or l[1] == NULL_MAT: + #~ currentMat = getMat(NULL_MAT) + newMatName = NULL_MAT + currentMat = nullMat else: - currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces - - # MATERIAL + #~ currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces + newMatName = '_'.join(l[1:]) + + + try: # Add to material list if not there + currentMat = materiaDict[newMatName] + newMatName = currentMat.name # Make sure we are up to date, Blender might have incremented the name. + + # Since we have this in Blender then we will check if the current Mesh has the material. + matIdx = 0 + tmpMeshMaterials = currentMesh.materials + while matIdx < len(tmpMeshMaterials): + if tmpMeshMaterials[matIdx].name == newMatName: + contextMeshMatIdx = matIdx # The current mat index. + break + matIdx+=1 + + + + except KeyError: # Not added yet, add now. + currentMat = Material.New(newMatName) + materiaDict[newMatName] = currentMat + contextMeshMatIdx = -1 # Mesh cant possibly have the material. + + # IMAGE elif l[0] == 'usemat' or l[0] == 'usemap': if len(l) == 1 or l[1] == '(null)' or l[1] == 'off': currentImg = NULL_IMG else: - currentImg = getImg('%s%s' % (DIR, ' '.join(l[1:]).replace('./', '') ) ) # Use join in case of spaces + # Load an image. + newImgName = stripPath(' '.join(l[1:])) + + try: + # Assume its alredy set in the dict (may or maynot be loaded) + currentImg = imageDict[newImgName] + + except KeyError: # Not in dict, add for first time. + try: # Image has not been added, Try and load the image + currentImg = Image.Load( '%s%s' % (DIR, newImgName) ) # Use join in case of spaces + imageDict[newImgName] = currentImg + + except IOError: # Cant load, just set blank. + imageDict[newImgName] = NULL_IMG + currentImg = NULL_IMG # MATERIAL FILE elif l[0] == 'mtllib': - mtl_fileName = ' '.join(l[1:]) + mtl_fileName = ' '.join(l[1:]) # SHOULD SUPPORT MULTIPLE MTL? lIdx+=1 @@ -479,22 +547,24 @@ def load_obj(file): # Write all meshs in the dictionary # #==============================================# for ob in Scene.GetCurrent().getChildren(): # Deselect all - ob.sel = 0 + ob.sel = 0 + + + # Applies material properties to materials alredy on the mesh as well as Textures. + if mtl_fileName != '': + load_mtl(DIR, mtl_fileName, meshDict) + importedObjects = [] - for mk in meshList.keys(): - # Applies material properties to materials alredy on the mesh as well as Textures. - if mtl_fileName != '': - load_mtl(DIR, mtl_fileName, meshList[mk][0]) - - meshList[mk][0].verts.pop(0) + for mk in meshDict.keys(): + meshDict[mk][0].verts.pop(0) # Ignore no vert meshes. - if not meshList[mk][0].verts: + if not meshDict[mk][0].verts: continue name = getUniqueName(mk) - ob = NMesh.PutRaw(meshList[mk][0], name) + ob = NMesh.PutRaw(meshDict[mk][0], name) ob.name = name importedObjects.append(ob) @@ -507,8 +577,10 @@ def load_obj(file): Window.FileSelector(load_obj, 'Import Wavefront OBJ') -''' + # For testing compatibility +''' +TIME = sys.time() import os for obj in os.listdir('/obj/'): if obj.lower().endswith('obj'): @@ -517,3 +589,5 @@ for obj in os.listdir('/obj/'): newScn.makeCurrent() load_obj('/obj/' + obj) ''' +#print "TOTAL IMPORT TIME: ", sys.time() - TIME +#load_obj('/obj/her.obj') diff --git a/release/scripts/save_theme.py b/release/scripts/save_theme.py index ba0b9bbcf8f..79205c0d478 100644 --- a/release/scripts/save_theme.py +++ b/release/scripts/save_theme.py @@ -2,14 +2,14 @@ """ Name: 'Save Current Theme...' -Blender: 236 +Blender: 237 Group: 'Export' Tooltip: 'Save current theme as a bpython script' """ __author__ = "Willian P. Germano" __url__ = ("blender", "elysiun") -__version__ = "1.2 2005/05/17" +__version__ = "2.37 2005/06/06" __bpydoc__ = """\ This script saves the current Theme in Blender as a Blender Python script. @@ -39,7 +39,6 @@ some information on it before sharing it with others. # $Id$ # # -------------------------------------------------------------------------- -# save_theme version 2.34 Sep 20, 2004 # Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br # -------------------------------------------------------------------------- # Released under the Blender Artistic License (BAL): @@ -71,13 +70,13 @@ def write_theme(filename): # \"\"\" # Name: '%s' -# Blender: 236 +# Blender: 237 # Group: 'Themes' # Tooltip: 'Change current theme' # \"\"\" __%s__ = "????" -__%s__ = "1.2" +__%s__ = "2.37" __%s__ = ["blender"] __%s__ = \"\"\"\\ You can edit this section to write something about your script that can diff --git a/release/scripts/tex2uvbaker.py b/release/scripts/tex2uvbaker.py index 1e46e06475c..326f852d53d 100644 --- a/release/scripts/tex2uvbaker.py +++ b/release/scripts/tex2uvbaker.py @@ -2,20 +2,19 @@ """ Registration info for Blender menus: Name: 'Texture Baker' -Blender: 233 +Blender: 237 Group: 'UV' Tooltip: 'Procedural to uvmapped texture baker' """ __author__ = "Jean-Michel Soler (jms)" __url__ = ("blender", "elysiun", -"Script online, http://jmsoler.free.fr/util/blenderfile/py/text2uvbaker.py", +"Official Page, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm", "Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") -__version__ = "0.2.3 2004/12/30" +__version__ = "0.2.6 2005/5/29" __bpydoc__ = """\ -This script "bakes" Blender procedural materials (including textures): it saves -them as 2d uv-mapped images. +Texture Baker "bakes" Blender procedural materials (including textures): it saves them as 2d uv-mapped images. This script saves an uv texture layout of the chosen mesh, that can be used as an uv map for it. It is a way to export procedurals from Blender as normal @@ -24,24 +23,47 @@ with the mesh in games and other 3d applications. Usage: -a) Enter face mode and define uv coordinates for your mesh;
-b) Define its materials and textures and set "Map Input" coordinates to UV; +a) Enter face mode and define uv coordinates for your mesh (do not forget to choose a development shape);
+b) Define its materials and textures;
c) Run this script and check the console. +Global variables: + +a) FRAME (integer): the last frame of the animation, autodocumented.
+b) LIMIT (integer): 0 or 1, uvcoords may exceed limits 0.0 to 1.0, this variable obliges the script to do a complete framing of the uvcoord. + Notes:
- This script was based on a suggestion by Martin (Theeth) Poirier;
+ This script was based on a suggestion by Martin (Theeth) Poirier. """ #--------------------------------------------- -# Last release : 0.2.3 , 2004/12/30 , 22h13 +# Last release : 0.2.6 , 2005/05/29 , 22h00 #--------------------------------------------- #--------------------------------------------- # (c) jm soler 07/2004 : 'Procedural Texture Baker' -# Based on a Martin Theeth' Poirier's really -# good idea : -# it makes a rvk mesh with uv coords of the -# original mesh. -# released under Blender Artistic Licence +# Based on a Martin 'Theeth' Poirier's really +# good idea : makes a rvk mesh with uv coords +# of the original mesh. +# +# Released under Blender Artistic Licence +# +# 0.2.6 +# -- Creation of LAMP object is removed and replaced +# by the use of the shadeless option in material object +# +# -- helpmsg corrected : the aim of the script +# is to bake any type of textures so we have not +# to mapinput its textures on UV . +# +# --'pers' camera was replaced by an 'ortho' one. +# +# 0.2.5 +# -- if a image file with the same name exits the +# system returns an error +# +# 0.2.4 +# -- a LIMIT variable is added to unlock the uvcoords +# autoframing # # # 0.2.3 : @@ -85,7 +107,7 @@ Notes:
# #--------------------------------------------- # Official Page : -# http://jmsoler.free.fr/util/blenderfile/py/text2uvbaker.py +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm # For problems and errors: # http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender #--------------------------------------------- @@ -93,9 +115,69 @@ Notes:
import Blender from Blender import NMesh, Draw, Object, Scene, Camera -FRAME = 100 -XYLIMIT = [0.0, 0.] +#----------------------------------- +# Last release : 0.2.5 , 2005/05/22 , 20h00 +#----------------------------------- +# la fonction Blender.sys.dirname pose un +# probleme lorsque la memoire est trop encombree +# --- +# It seems that the Blender.sys.dirname function +# poses a problem when the memory is too much encumbered +#----------------------------------- +try: + import nt + os = nt + os.sep='\\' +except: + import posix + os = posix + os.sep='/' +DIRNAME=Blender.Get('filename') +#----------------------------------- +# decoupage de la chaine en fragment +# de façon a isoler le nom du fichier +# du repertoire +# --- +# split string in fragments to isolate +# the file name from the path name +#----------------------------------- + +if DIRNAME.find(os.sep): + k0=DIRNAME.split(os.sep) +else: + k0=DIRNAME.split('/') +DIRNAME=DIRNAME.replace(k0[-1],'') +#----------------------------------- +# Last release : 0.2.5 , 2005/05/22 , end +#----------------------------------- + +#----------------------------------- +# Last release : 0.2.4 , 2005/05/22 , 15h00 +#----------------------------------- +FRAME = Blender.Get('endframe') +#----------------------------------- +# Last release : 0.2.4 , 2005/05/22 , end +#----------------------------------- + +#----------------------------------- +# Last release : 0.2.4 , 2005/05/18 , 11h00 +# +# Si LIMIT == 0 le script n'essaye pas de realiser +# un nouveau cadrage pour que l'image presente toute les +# coordonnées uv. +# --- +# if LIMIT == 0 the script do not try to make +# a new framing with all the uvcoord in only one +# shoot... +#----------------------------------- +LIMIT=0 +#----------------------------------- +# Last release : 0.2.4 , 2005/05/18 , END +#----------------------------------- + +XYLIMIT = [0.0, 0.0,1.0,1.0] OBJPOS = 100.0 +DEBUG=1 helpmsg = """ Texture Baker: @@ -106,23 +188,79 @@ normal image textures that can be edited with a 2d image manipulation program or used with the mesh in games and other 3d applications. Basic instructions: -- Enter face mode and define uv coordinates for your mesh; -- Define its materials and textures and set "Map Input" coordinates to UV; +- Enter face mode and define uv coordinates for your mesh (do not forget to + choose a development shape); +- Define its materials and textures ; - Run this script and check the console. + """ def GET_newobject (TYPE,NAME): + """ +# --------------------------- +# Function GET_newobject +# +# IN : TYPE string , object type ('Mesh','Empty',...) +# NAME string , name object +# OUT: OBJECT Blender objetc described in teh string TYPE +# SCENE Blender current scene object +# --------------------------- + Return and object and the current scene + """ SCENE = Blender.Scene.getCurrent() OBJECT = Blender.Object.New(TYPE,NAME) SCENE.link(OBJECT) return OBJECT, SCENE +def RenameImage(RDIR, MYDIR, FILENAME, name): + """ +# --------------------------- +# Function RenameImage +# +# IN : RDIR string , current render directory +# MYDIR string , new render dir for this shoot +# FILENAME string , last rendered image filename +# name string , new name for this image +# OUT: nothing +# --------------------------- + Rename the file pointed by the string name + recall the function if the file yet exists + """ + newfname = RDIR + MYDIR + name + if newfname.find('.png', -4) < 0 : newfname += '.png' + if not Blender.sys.exists(newfname): + os.rename(FILENAME, newfname) + else: + name = Draw.PupStrInput ('ReName Image, please :', name, 32) + RenameImage(RDIR, MYDIR, FILENAME, name) + def SAVE_image (rc, name, FRAME): + """ +# --------------------------- +# Function SAVE_image +# +# IN : rc current render context object +# name string , image name +# FRAME integer, last numbre of the curent animation +# OUT: nothing +# --------------------------- + """ + rc.enableExtensions(1) MYDIR = '' - RENDERDIR = rc.getRenderPath() + RENDERDIR = rc.getRenderPath().replace('\\','/') + if RENDERDIR.find('//')==0 : + print 'filename', Blender.Get('filename'),'/n', Blender.sys.dirname(Blender.Get('filename')) + RDIR=RENDERDIR.replace('//',DIRNAME) + else: + RDIR=RENDERDIR[:] + if DEBUG : print 'RDIR : ', RDIR + + HOMEDIR=Blender.Get('homedir') + if DEBUG : print 'HOMEDIR', HOMEDIR rc.setRenderPath(RENDERDIR + MYDIR) - print "Render folder:", RENDERDIR + MYDIR + if DEBUG : print "Render folder:", RENDERDIR + MYDIR IMAGETYPE = Blender.Scene.Render.PNG + if DEBUG : print 'IMAGETYPE : ',IMAGETYPE rc.setImageType(IMAGETYPE) NEWFRAME = FRAME OLDEFRAME = rc.endFrame() @@ -130,39 +268,37 @@ def SAVE_image (rc, name, FRAME): rc.startFrame(NEWFRAME) rc.endFrame(NEWFRAME) rc.renderAnim() - - try: - import nt - os = nt - - except: - import posix - os = posix + Blender.Scene.Render.CloseRenderWindow() FILENAME = "%04d" % NEWFRAME FILENAME = FILENAME.replace (' ', '0') - FILENAME = RENDERDIR + MYDIR + FILENAME + '.png' + FILENAME = RDIR + MYDIR + FILENAME + '.png' - try: - TRUE = os.stat(FILENAME) - newfname = RENDERDIR + MYDIR + name - if newfname.find('.png', -4) < 0: newfname += '.png' - os.rename(FILENAME, newfname) - print "Renamed to:", newfname - - except: - pass + RenameImage(RDIR, MYDIR, FILENAME, name) rc.endFrame(OLDEFRAME) rc.startFrame(OLDSFRAME) rc.setRenderPath(RENDERDIR) def SHOOT (XYlimit, frame, obj, name, FRAME): + """ +# --------------------------- +# Function SHOOT +# +# IN : XYlimit list of 4 floats, smallest and biggest +# uvcoords +# frame cureente frame +# obj for object location +# name image name +# FRAME the last animation's frame +# OUT: nothing +# --------------------------- + render and save the baked textures picture + """ try: CAM = Blender.Object.Get('UVCAMERA') Cam = CAM.getData() SC = Blender.Scene.getCurrent() - except: Cam = Blender.Camera.New() Cam.name = 'UVCamera' @@ -172,45 +308,29 @@ def SHOOT (XYlimit, frame, obj, name, FRAME): Cam.lens = 30 Cam.name = 'UVCamera' + Cam.setType('ortho') + Cam.setScale(1.0) + CAM.setLocation(obj.getLocation()) - CAM.LocX += XYlimit[0] / 2.0 - CAM.LocY += XYlimit[1] / 2.0 - CAM.LocZ += max (XYlimit[0], XYlimit[1]) + CAM.LocX += XYlimit[2] * 0.500 + CAM.LocY += XYlimit[3] * 0.500 + CAM.LocZ += max (XYlimit[2], XYlimit[3]) CAM.setEuler (0.0, 0.0, 0.0) - try: - LAMP = Blender.Object.Get('ECLAIRAGE') - lampe = LAMP.getData() - SC = Blender.Scene.getCurrent() - - except: - lampe = Blender.Lamp.New() - lampe.name = 'lumin' - LAMP, SC = GET_newobject('Lamp','ECLAIRAGE') - LAMP.link(lampe) - LAMP.setName('ECLAIRAGE') - - LAMP.setLocation(obj.getLocation()) - LAMP.LocX += XYlimit[0] / 2.0 - LAMP.LocY += XYlimit[1] / 2.0 - LAMP.LocZ += max (XYlimit[0], XYlimit[1]) - LAMP.setEuler (0.0, 0.0, 0.0) - context = SC.getRenderingContext() Camold = SC.getCurrentCamera() SC.setCurrentCamera(CAM) + OLDy = context.imageSizeY() OLDx = context.imageSizeX() - tres = Draw.PupMenu('TEXTURE OUT RESOLUTION : %t | 256 %x1 | 512 %x2 | 768 %x3 | 1024 %x4') + + tres = Draw.PupMenu('TEXTURE OUT RESOLUTION : %t | 256 %x1 | 512 %x2 | 768 %x3 | 1024 %x4 | 2048 %x5 ') if (tres) == 1: res = 256 - elif (tres) == 2: res = 512 - elif (tres) == 3: res = 768 - elif (tres) == 4: res = 1024 - + elif (tres) == 5: res = 2048 else: res = 512 context.imageSizeY(res) @@ -223,10 +343,58 @@ def SHOOT (XYlimit, frame, obj, name, FRAME): Blender.Set ('curframe', frame) -def Mesh2UVCoord (): - if 1:#try: - MESH3D = Object.GetSelected()[0] +#----------------------------------- +# release : 0.2.6 , 2005/05/29 , 00h00 +#----------------------------------- +def PROV_Shadeless(MATList): + """ +# --------------------------- +# Function PROV_Shadeless +# +# IN : MATList a list of the mesh's materials +# OUT: SHADEDict a dictionnary of the materials' shadeles value +# --------------------------- + """ + SHADEDict={} + for mat in MATList: + SHADEDict[mat.name]=mat.mode + mat.mode |= Blender.Material.Modes.SHADELESS + return SHADEDict +#----------------------------------- +# Last release : 0.2.6 , 2005/05/29 , end +#----------------------------------- + +#----------------------------------- +# release : 0.2.6 , 2005/05/29 , 00h00 +#----------------------------------- +def REST_Shadeless(SHADEDict): + """ +# --------------------------- +# Function REST_Shadeless +# +# IN : SHADEDict a dictionnary of the materials' shadeles value +# OUT : nothing +# --------------------------- + """ + for m in SHADEDict.keys(): + mat=Blender.Material.Get(m) + mat.mode=SHADEDict[m] +#----------------------------------- +# release : 0.2.6 , 2005/05/29 , end +#----------------------------------- + +def Mesh2UVCoord (LIMIT): + """ +# --------------------------- +# Function Mesh2UVCoord +# +# IN : LIMIT integer, create or not a new framing for uvcoords +# OUT: nothing +# --------------------------- + """ + try: + MESH3D = Object.GetSelected()[0] if MESH3D.getType() == 'Mesh': MESH = MESH3D.getData() @@ -234,12 +402,12 @@ def Mesh2UVCoord (): NewOBJECT=Blender.Object.Get('UVOBJECT') CurSCENE=Blender.Scene.getCurrent() MESH2 = NewOBJECT.getData() - MESH2.faces=[] - + except: NewOBJECT, CurSCENE = GET_newobject('Mesh','UVOBJECT') MESH2 = Blender.NMesh.GetRaw() + MESH2.faces=[] for f in MESH.faces: f1 = Blender.NMesh.Face() @@ -258,55 +426,73 @@ def Mesh2UVCoord (): MESH2.materials = MESH.materials[:] - - #NewOBJECT.link(MESH2) - NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0) NewOBJECT.setEuler (0.0, 0.0, 0.0) MESH2.removeAllKeys() - - for f in MESH2.faces: - for v in f.v: - for n in [0, 1]: - v.co[n] = f.uv[f.v.index(v)][n] - exec "if v.co[%s] > XYLIMIT[%s]: XYLIMIT[%s] = v.co[%s]" % (n, n, n, n) - - v.co[2] = 0.0 - - print XYLIMIT - MESH2.update() MESH2.insertKey (1, 'absolute') MESH2.update() + for f in MESH2.faces: + for v in f.v: + for n in [0,1]: + v.co[n] = f.uv[f.v.index(v)][n] + exec "if v.co[%s] > XYLIMIT[%s]: XYLIMIT[%s] = v.co[%s]" % (n, n+2, n+2, n) + exec "if v.co[%s] < XYLIMIT[%s]: XYLIMIT[%s] = v.co[%s]" % (n, n, n, n) + v.co[2] = 0.0 + + if DEBUG: print XYLIMIT + MESH2.update() MESH2.insertKey (FRAME, 'absolute') MESH2.update() + imagename = 'uvtext' - name = "CHANGE IMAGE NAME ? %t | Replace it | No replace | Script help" + name = "CHANGE IMAGE NAME ? %t | Replace it | No replacing | Script help" result = Draw.PupMenu(name) if result == 1: imagename = Draw.PupStrInput ('Image Name:', imagename, 32) if result != 3: - SHOOT (XYLIMIT, FRAME, NewOBJECT, imagename, FRAME) + #----------------------------------- + # release : 0.2.6 , 2005/05/29 , 00h00 + #----------------------------------- + SHADEDict=PROV_Shadeless(MESH2.materials) + #----------------------------------- + # release : 0.2.6 , 2005/05/29 , end + #----------------------------------- + + if LIMIT : + SHOOT(XYLIMIT, FRAME, NewOBJECT, imagename, FRAME) + else : + SHOOT([0.0,0.0,1.0,1.0], FRAME, NewOBJECT, imagename, FRAME) + #----------------------------------- + # release : 0.2.6, 2005/05/29 , 00h00 + #----------------------------------- + REST_Shadeless(SHADEDict) + #----------------------------------- + # release : 0.2.6 , 2005/05/29 , end + #----------------------------------- + Blender.Redraw() + else: - Draw.PupMenu("Ready%t|Please check console for instructions") - print helpmsg + Blender.ShowHelp('tex2uvbaker.py') + #Draw.PupMenu("Ready%t|Please check console for instructions") + if DEBUG: print helpmsg else: - name = "Error%t|Active object is not a mesh or has no UV coordinates" + name = "ERROR: active object is not a mesh or has no UV coordinates" result = Draw.PupMenu(name) print 'problem : no object selected or not mesh' - #except: - # name = "Error%t|Active object is not a mesh or has no UV coordinates" - # result = Draw.PupMenu(name) + except: + name = "ERROR: active object is not a mesh or has no UV coordinates" + result = Draw.PupMenu(name) print 'problem : no object selected or not mesh' -Mesh2UVCoord() +Mesh2UVCoord(LIMIT) diff --git a/source/blender/include/BPI_script.h b/source/blender/include/BPI_script.h index 243e50ecfa4..80ac8b46900 100644 --- a/source/blender/include/BPI_script.h +++ b/source/blender/include/BPI_script.h @@ -47,6 +47,7 @@ typedef struct Script { void *py_draw; void *py_event; void *py_button; + void *py_browsercallback; void *py_globaldict; int flags, lastspace; diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 912a479eef9..f79cb2065ec 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -527,6 +527,7 @@ int BPY_txt_do_python_Text( struct Text *text ) script->py_draw = NULL; script->py_event = NULL; script->py_button = NULL; + script->py_browsercallback = NULL; py_dict = CreateGlobalDictionary( ); @@ -756,6 +757,7 @@ int BPY_menu_do_python( short menutype, int event ) script->py_draw = NULL; script->py_event = NULL; script->py_button = NULL; + script->py_browsercallback = NULL; py_dict = CreateGlobalDictionary( ); @@ -915,6 +917,7 @@ void BPY_clear_script( Script * script ) Py_XDECREF( ( PyObject * ) script->py_draw ); Py_XDECREF( ( PyObject * ) script->py_event ); Py_XDECREF( ( PyObject * ) script->py_button ); + Py_XDECREF( ( PyObject * ) script->py_browsercallback ); dict = script->py_globaldict; diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c index 0c75ee22ab6..f6c5aff0db8 100644 --- a/source/blender/python/api2_2x/Draw.c +++ b/source/blender/python/api2_2x/Draw.c @@ -70,6 +70,11 @@ #include "interface.h" #include "mydevice.h" /*@ for all the event constants */ +/* these delimit the free range for button events */ +#define EXPP_BUTTON_EVENTS_OFFSET 1001 +#define EXPP_BUTTON_EVENTS_MIN 0 +#define EXPP_BUTTON_EVENTS_MAX 15382 /* 16384 - 1 - OFFSET */ + /* pointer to main dictionary defined in Blender.c */ extern PyObject *g_blenderdict; @@ -510,18 +515,6 @@ static void spacescript_do_pywin_buttons( SpaceScript * sc, void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, short val, char ascii ) { - static int menu_hack = 0; - - /* about menu_hack above: when a menu returns after an entry is chosen, - * two events are generated, the second one with val = 4. We don't want - * this second one to be passed to Python, because it can be confused with - * some event with same number defined by the script. - * What we do is set menu_hack to 1 if a button event occurs. - * Then if the next one is also a button event, w/ val = 4, we discard it. */ - - if( event != UI_BUT_EVENT || !val ) - menu_hack = 0; - if( event == QKEY && G.qual & ( LR_ALTKEY | LR_CTRLKEY ) ) { /* finish script: user pressed ALT+Q or CONTROL+Q */ Script *script = sc->script; @@ -533,27 +526,20 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, return; } - if( val ) { - if( uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING ) - event = 0; + if (val) { - if( event == UI_BUT_EVENT ) { - if( menu_hack && val == UI_RETURN_OK ) { /* "false" event? */ - if ( menu_hack == 2 ) /* was last event UI_RETURN_OUT? */ - spacescript_do_pywin_buttons( sc, UI_RETURN_OUT ); /* if so, send */ - menu_hack = 0; /* clear menu_hack */ - } - else if( val == UI_RETURN_OUT ) /* possible cancel */ - menu_hack = 2; - else { - menu_hack = 1; - spacescript_do_pywin_buttons( sc, val ); - } + if (uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING) event = 0; + if (event == UI_BUT_EVENT) { + /* check that event is in free range for script button events; + * read the comment before check_button_event() below to understand */ + if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000) + spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET); + return; } } - /* Using the "event" main module var, used by scriptlinks, to pass the ascii + /* We use the "event" main module var, used by scriptlinks, to pass the ascii * value to event callbacks (gui/event/button callbacks are not allowed * inside scriptlinks, so this is ok) */ if( sc->script->py_event ) { @@ -756,6 +742,21 @@ static uiBlock *Get_uiBlock( void ) return uiGetBlock( butblock, curarea ); } +/* We restrict the acceptable event numbers to a proper "free" range + * according to other spaces in Blender. + * winqread***space() (space events callbacks) use short for events + * (called 'val' there) and we also translate by EXPP_BUTTON_EVENTS_OFFSET + * to get rid of unwanted events (check BPY_do_pywin_events above for + * explanation). This function takes care of that and proper checking: */ +static int check_button_event(int *event) { + if ((*event < EXPP_BUTTON_EVENTS_MIN) || + (*event > EXPP_BUTTON_EVENTS_MAX)) { + return -1; + } + *event += EXPP_BUTTON_EVENTS_OFFSET; + return 0; +} + static PyObject *Method_Button( PyObject * self, PyObject * args ) { uiBlock *block; @@ -768,6 +769,10 @@ static PyObject *Method_Button( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, five ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + block = Get_uiBlock( ); if( block ) @@ -790,6 +795,10 @@ static PyObject *Method_Menu( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, six ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); but->type = 1; but->val.asint = def; @@ -815,6 +824,10 @@ static PyObject *Method_Toggle( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, six ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); but->type = 1; but->val.asint = def; @@ -873,6 +886,10 @@ static PyObject *Method_Slider( PyObject * self, PyObject * args ) "expected a string, five ints, three PyObjects\n\ and optionally another int and string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) { @@ -932,14 +949,18 @@ static PyObject *Method_Scrollbar( PyObject * self, PyObject * args ) if( !PyArg_ParseTuple( args, "iiiiiOOO|is", &event, &x, &y, &w, &h, &inio, &mino, &maxo, &realtime, &tip ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected five ints, three PyObjects and optionally\n\ - another int and string as arguments" ); + "expected five ints, three PyObjects and optionally\n\ +another int and string as arguments" ); if( !PyNumber_Check( inio ) || !PyNumber_Check( inio ) || !PyNumber_Check( inio ) ) return EXPP_ReturnPyObjError( PyExc_AttributeError, "expected numbers for initial, min, and max" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) @@ -995,6 +1016,10 @@ static PyObject *Method_Number( PyObject * self, PyObject * args ) "expected a string, five ints, three PyObjects and\n\ optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) { @@ -1045,6 +1070,10 @@ static PyObject *Method_String( PyObject * self, PyObject * args ) "expected a string, five ints, a string, an int and\n\ optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + if (len > (UI_MAX_DRAW_STR - 1)) { len = UI_MAX_DRAW_STR - 1; newstr[len] = '\0'; diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index 41a7ad7c910..236275742be 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -68,9 +68,6 @@ /* See Draw.c */ extern int EXPP_disable_force_draw; -/* Callback used by the file and image selector access functions */ -static PyObject *EXPP_FS_PyCallback = NULL; - /*****************************************************************************/ /* Python API function prototypes for the Window module. */ /*****************************************************************************/ @@ -453,24 +450,42 @@ static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args ) static void getSelectedFile( char *name ) { - PyObject *callback; - PyObject *result; - - callback = EXPP_FS_PyCallback; - result = PyObject_CallFunction( EXPP_FS_PyCallback, "s", name ); - if ((!result) && (G.f & G_DEBUG)) { - fprintf(stderr, "BPy error: Callback call failed!\n"); + PyObject *pycallback; + PyObject *result; + Script *script; + + /* let's find the script that owns this callback */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; } - Py_XDECREF(result); - /* Catch changes of EXPP_FS_PyCallback during the callback call - * due to calls to Blender.Window.FileSelector or - * Blender.Window.ImageSelector inside the python callback. */ - if (callback == EXPP_FS_PyCallback) { - Py_DECREF(EXPP_FS_PyCallback); - EXPP_FS_PyCallback = NULL; - } else { - Py_DECREF(callback); - } + + if (!script) { + if (curarea->spacetype == SPACE_SCRIPT) { + SpaceScript *sc = curarea->spacedata.first; + script = sc->script; + } + } + + pycallback = script->py_browsercallback; + + if (pycallback) { + result = PyObject_CallFunction( pycallback, "s", name ); + + if (!result) { + if (G.f & G_DEBUG) + fprintf(stderr, "BPy error: Callback call failed!\n"); + } + else Py_DECREF(result); + + if (script->py_browsercallback == pycallback) + script->py_browsercallback = NULL; + /* else another call to selector was made inside pycallback */ + + Py_DECREF(pycallback); + } + return; } @@ -480,6 +495,7 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) char *filename = G.sce; SpaceScript *sc; Script *script = NULL; + PyObject *pycallback = NULL; int startspace = 0; if (during_scriptlink()) @@ -490,13 +506,13 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError(PyExc_RuntimeError, "the file selector is not available in background mode"); - if((!PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename)) - || (!PyCallable_Check(EXPP_FS_PyCallback))) + if((!PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename)) + || (!PyCallable_Check(pycallback))) return EXPP_ReturnPyObjError( PyExc_AttributeError, "\nexpected a callback function (and optionally one or two strings) " "as argument(s)" ); - Py_XINCREF(EXPP_FS_PyCallback); + Py_INCREF(pycallback); /* trick: we move to a spacescript because then the fileselector will properly * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the @@ -527,6 +543,12 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) script->flags |= SCRIPT_FILESEL; + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; + activate_fileselect( FILE_BLENDER, title, filename, getSelectedFile ); Py_INCREF( Py_None ); @@ -539,6 +561,7 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) char *filename = G.sce; SpaceScript *sc; Script *script = NULL; + PyObject *pycallback = NULL; int startspace = 0; if (during_scriptlink()) @@ -549,14 +572,13 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError(PyExc_RuntimeError, "the image selector is not available in background mode"); - if( !PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename ) - || (!PyCallable_Check(EXPP_FS_PyCallback))) - return ( EXPP_ReturnPyObjError - ( PyExc_AttributeError, - "\nexpected a callback function (and optionally one or two strings) " - "as argument(s)" ) ); + if( !PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename ) + || (!PyCallable_Check(pycallback))) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "\nexpected a callback function (and optionally one or two strings) " + "as argument(s)" ); - Py_XINCREF(EXPP_FS_PyCallback); + Py_INCREF(pycallback); /* trick: we move to a spacescript because then the fileselector will properly * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the @@ -586,6 +608,11 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) } script->flags |= SCRIPT_FILESEL; /* same flag as filesel */ + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; activate_imageselect( FILE_BLENDER, title, filename, getSelectedFile ); @@ -610,12 +637,11 @@ static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args ) if( !PyArg_ParseTuple( args, "fs", &done, &info ) ) return ( EXPP_ReturnPyObjError( PyExc_AttributeError, - "expected a float and a string as arguments" ) ); + "expected a float and a string as arguments" ) ); - if( !G.background ) - retval = progress_bar( done, info ); + retval = progress_bar( done, info ); - curarea = sa; + areawinset(sa->win); return Py_BuildValue( "i", retval ); } diff --git a/source/blender/python/api2_2x/doc/Theme.py b/source/blender/python/api2_2x/doc/Theme.py index e2e9c74c8ed..d8be2074741 100644 --- a/source/blender/python/api2_2x/doc/Theme.py +++ b/source/blender/python/api2_2x/doc/Theme.py @@ -183,6 +183,11 @@ class Theme: @cvar face_select: theme rgba var. @cvar face_dot: theme rgba var. @cvar normal: theme rgba var. + @cvar syntaxl: theme rgba var. + @cvar syntaxn: theme rgba var. + @cvar syntaxb: theme rgba var. + @cvar syntaxv: theme rgba var. + @cvar syntaxc: theme rgba var. @type vertex_size: int @cvar vertex_size: size of the vertices dots on screen in the range [1, 10]. @type facedot_size: int diff --git a/source/blender/python/api2_2x/windowTheme.c b/source/blender/python/api2_2x/windowTheme.c index 5f2e06024da..7ee6cd80a1c 100644 --- a/source/blender/python/api2_2x/windowTheme.c +++ b/source/blender/python/api2_2x/windowTheme.c @@ -134,9 +134,9 @@ static void ThemeSpace_dealloc( BPy_ThemeSpace * self ) else if (!strcmp(name, #attr))\ attrib = charRGBA_New(&tsp->attr[0]); -/* Example: ELSEIF_TSP_RGBA(outline) becomes: +/* Example: ELSEIF_TSP_RGBA(back) becomes: * else if (!strcmp(name, "back") - * attr = charRGBA_New(&tsp->back[0]) + * attrib = charRGBA_New(&tsp->back[0]) */ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) @@ -146,7 +146,7 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) if( !strcmp( name, "theme" ) ) attrib = PyString_FromString( self->theme->name ); - ELSEIF_TSP_RGBA( back ) + ELSEIF_TSP_RGBA( back ) ELSEIF_TSP_RGBA( text ) ELSEIF_TSP_RGBA( text_hi ) ELSEIF_TSP_RGBA( header ) @@ -169,19 +169,26 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( syntaxl ) + ELSEIF_TSP_RGBA( syntaxn ) + ELSEIF_TSP_RGBA( syntaxb ) + ELSEIF_TSP_RGBA( syntaxv ) + ELSEIF_TSP_RGBA( syntaxc ) else if( !strcmp( name, "vertex_size" ) ) attrib = Py_BuildValue( "i", tsp->vertex_size ); else if( !strcmp( name, "facedot_size" ) ) attrib = Py_BuildValue( "i", tsp->facedot_size ); else if( !strcmp( name, "__members__" ) ) - attrib = Py_BuildValue( "[ssssssssssssssssssssssssss]", "theme", + attrib = Py_BuildValue( "[sssssssssssssssssssssssssssssss]", "theme", "back", "text", "text_hi", "header", "panel", "shade1", "shade2", "hilite", "grid", "wire", "select", "active", "transform", "vertex", "vertex_select", "edge", "edge_select", "edge_seam", "edge_facesel", "face", "face_select", - "face_dot", "normal", "vertex_size", "facedot_size" ); + "face_dot", "normal", + "syntaxl", "syntaxn", "syntaxb", "syntaxv", "syntaxc", + "vertex_size", "facedot_size" ); if( attrib != Py_None ) return attrib; @@ -199,7 +206,6 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, if( !strcmp( name, "back" ) ) attrib = charRGBA_New( &tsp->back[0] ); - ELSEIF_TSP_RGBA( back ) ELSEIF_TSP_RGBA( text ) ELSEIF_TSP_RGBA( text_hi ) ELSEIF_TSP_RGBA( header ) @@ -222,6 +228,11 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( syntaxl ) + ELSEIF_TSP_RGBA( syntaxn ) + ELSEIF_TSP_RGBA( syntaxb ) + ELSEIF_TSP_RGBA( syntaxv ) + ELSEIF_TSP_RGBA( syntaxc ) else if( !strcmp( name, "vertex_size" ) ) { int val; diff --git a/source/blender/src/drawscript.c b/source/blender/src/drawscript.c index c4ec1a4db3a..30c3e11f00b 100644 --- a/source/blender/src/drawscript.c +++ b/source/blender/src/drawscript.c @@ -85,13 +85,14 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * void drawscriptspace(ScrArea *sa, void *spacedata) { SpaceScript *sc = curarea->spacedata.first; + Script *script = NULL; glClearColor(0.6, 0.6, 0.6, 1.0); glClear(GL_COLOR_BUFFER_BIT); myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5); if (!sc->script) { - Script *script = G.main->script.first; + script = G.main->script.first; while (script) { @@ -105,7 +106,16 @@ void drawscriptspace(ScrArea *sa, void *spacedata) if (!sc->script) return; - BPY_spacescript_do_pywin_draw(sc); + script = sc->script; + + if (script->py_draw) { + BPY_spacescript_do_pywin_draw(sc); + } + /* quick hack for 2.37a for scripts that call the progress bar inside a + * file selector callback, to show previous space after finishing, w/o + * needing an event */ + else if (!script->flags && !script->py_event && !script->py_button) + addqueue(curarea->win, MOUSEX, 0); } void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt) @@ -117,7 +127,15 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * Script *script = sc->script; if (script) { - BPY_spacescript_do_pywin_event(sc, event, val, ascii); + if (script->py_event || script->py_button) + BPY_spacescript_do_pywin_event(sc, event, val, ascii); + + /* for file/image sel scripts: if user leaves file/image selection space, + * this frees the script (since it can't be accessed anymore): */ + else if (script->flags == SCRIPT_FILESEL) { + script->flags = 0; + script->lastspace = SPACE_SCRIPT; + } if (!script->flags) {/* finished with this script, let's free it */ if (script->lastspace != SPACE_SCRIPT)