diff options
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/Axiscopy.py | 78 | ||||
-rw-r--r-- | release/scripts/clean_mesh.py | 188 | ||||
-rw-r--r-- | release/scripts/knife.py | 2 | ||||
-rw-r--r-- | release/scripts/mod_ai2obj.py | 383 | ||||
-rw-r--r-- | release/scripts/mod_eps2obj.py | 390 | ||||
-rw-r--r-- | release/scripts/mod_gimp2obj.py | 320 | ||||
-rw-r--r-- | release/scripts/mod_svg2obj.py | 647 | ||||
-rw-r--r-- | release/scripts/obj_export.py | 232 | ||||
-rw-r--r-- | release/scripts/obj_import.py | 570 | ||||
-rw-r--r-- | release/scripts/paths_import.py | 35 | ||||
-rw-r--r-- | release/scripts/skin.py | 558 | ||||
-rw-r--r-- | release/scripts/tex2uvbaker.py | 254 | ||||
-rw-r--r-- | release/windows/installer/00.blender.nsi | 8 |
13 files changed, 3270 insertions, 395 deletions
diff --git a/release/scripts/Axiscopy.py b/release/scripts/Axiscopy.py new file mode 100644 index 00000000000..bfdb89806cd --- /dev/null +++ b/release/scripts/Axiscopy.py @@ -0,0 +1,78 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Axis Orientation Copy' +Blender: 233 +Group: 'Object' +Tip: 'Copy the axis orientation of the active object to all selected mesh object' +""" + +# $Id$ +# +#---------------------------------------------- +# A Vanpoucke (xand) +#from the previous script realignaxis +#---------------------------------------------- +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003, 2004: A Vanpoucke +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +from Blender import Mathutils +from Blender.Mathutils import * + + +def applyTransform(mesh,mat): + for v in mesh.verts: + vec = VecMultMat(v.co,mat) + v.co[0], v.co[1], v.co[2] = vec[0], vec[1], vec[2] + + + + +oblist =Object.GetSelected() +lenob=len(oblist) + +if lenob<2: + Draw.PupMenu("Select at least 2 objects") +else : + source=oblist[0] + nsource=source.name + texte="Copy axis orientation from : " + nsource + " ?%t|OK" + result=Draw.PupMenu(texte) + + + for cible in oblist[1:]: + if cible.getType()=='Mesh': + if source.rot!=cible.rot: + rotcible=cible.mat.toEuler().toMatrix() + rotsource=source.mat.toEuler().toMatrix() + rotsourcet = CopyMat(rotsource) + rotsourcet.invert() + mat=rotcible*rotsourcet + ncible=cible.name + me=NMesh.GetRaw(ncible) + applyTransform(me,mat) + NMesh.PutRaw(me,ncible) + cible.makeDisplayList() + cible.rot=source.rot diff --git a/release/scripts/clean_mesh.py b/release/scripts/clean_mesh.py new file mode 100644 index 00000000000..7fa3a496b34 --- /dev/null +++ b/release/scripts/clean_mesh.py @@ -0,0 +1,188 @@ +#!BPY + +""" +Name: 'Cleanup Meshes' +Blender: 234 +Group: 'Mesh' +Tooltip: 'Clean unused data from all selected meshes' +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# Mesh Cleaner 1.0 By Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# Made by Ideasman/Campbell 2004/04/25 - ideasman@linuxmail.org + +import Blender +from Blender import * +from math import sqrt + +VRemNum = ERemNum = FRemNum = 0 # Remember for statistics + + +#================# +# Math functions # +#================# +def compare(f1, f2, limit): + if f1 + limit > f2 and f1 - limit < f2: + return 1 + return 0 + +def measure(v1, v2): + return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length + +def triArea2D(v1, v2, v3): + e1 = measure(v1, v2) + e2 = measure(v2, v3) + e3 = measure(v3, v1) + p = e1+e2+e3 + return 0.25 * sqrt(p*(p-2*e1)*(p-2*e2)*(p-2*e3)) + + +#=============================# +# Blender functions/shortcuts # +#=============================# +def error(str): + Draw.PupMenu('ERROR%t|'+str) + +def getLimit(text): + return Draw.PupFloatInput(text, 0.001, 0.0, 1.0, 0.1, 3) + +def faceArea(f): + if len(f.v) == 4: + return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co) + triArea2D(f.v[0].co, f.v[2].co, f.v[3].co) + elif len(f.v) == 3: + return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co) + + + +#================# +# Mesh functions # +#================# +def delFreeVert(mesh): + global VRemNum + usedList = eval('[' + ('False,' * len(mesh.verts) )+ ']') + # Now tag verts that areused + for f in mesh.faces: + for v in f.v: + usedList[mesh.verts.index(v)] = True + vIdx = 0 + for bool in usedList: + if bool == False: + mesh.verts.remove(mesh.verts[vIdx]) + vIdx -= 1 + VRemNum += 1 + vIdx += 1 + mesh.update() + + +def delEdge(mesh): + global ERemNum + fIdx = 0 + while fIdx < len(mesh.faces): + if len(mesh.faces[fIdx].v) == 2: + mesh.faces.remove(mesh.faces[fIdx]) + ERemNum += 1 + fIdx -= 1 + fIdx +=1 + mesh.update() + +def delEdgeLen(mesh, limit): + global ERemNum + fIdx = 0 + while fIdx < len(mesh.faces): + if len(mesh.faces[fIdx].v) == 2: + if measure(mesh.faces[fIdx].v[0].co, mesh.faces[fIdx].v[1].co) <= limit: + mesh.faces.remove(mesh.faces[fIdx]) + ERemNum += 1 + fIdx -= 1 + fIdx +=1 + mesh.update() + +def delFaceArea(mesh, limit): + global FRemNum + fIdx = 0 + while fIdx < len(mesh.faces): + if len(mesh.faces[fIdx].v) > 2: + if faceArea(mesh.faces[fIdx]) <= limit: + mesh.faces.remove(mesh.faces[fIdx]) + FRemNum += 1 + fIdx -= 1 + fIdx +=1 + mesh.update() + + +#====================# +# Make a mesh list # +#====================# + +is_editmode = Window.EditMode() +if is_editmode: Window.EditMode(0) + +meshList = [] +if len(Object.GetSelected()) > 0: + for ob in Object.GetSelected(): + if ob.getType() == 'Mesh': + meshList.append(ob.getData()) + + +#====================================# +# Popup menu to select the functions # +#====================================# +if len(meshList) == 0: + error('no meshes in selection') +else: + method = Draw.PupMenu(\ + 'Clean Mesh, Remove...%t|\ + Verts: free standing|\ + Edges: not in a face|\ + Edges: below a length|\ + Faces: below an area|%l|\ + All of the above|') + + if method >= 3: + limit = getLimit('threshold: ') + + if method != -1: + for mesh in meshList: + if method == 1: + delFreeVert(mesh) + elif method == 2: + delEdge(mesh) + elif method == 3: + delEdgeLen(mesh, limit) + elif method == 4: + delFaceArea(mesh, limit) + elif method == 6: # All of them + delFaceArea(mesh, limit) + delEdge(mesh) + delFreeVert(mesh) + + mesh.update(0) + Redraw() + +if is_editmode: Window.EditMode(1) + +if method != -1: + Draw.PupMenu('Removed from ' + str(len(meshList)) +' Mesh(es)%t|' + 'Verts:' + str(VRemNum) + ' Edges:' + str(ERemNum) + ' Faces:' + str(FRemNum)) diff --git a/release/scripts/knife.py b/release/scripts/knife.py index 4a7943d8902..f9f8aedf72b 100644 --- a/release/scripts/knife.py +++ b/release/scripts/knife.py @@ -4,7 +4,7 @@ Name: 'Blender Knife Tool' Blender: 232 Group: 'Mesh' -Tooltip: 'Cut a mesh along a plane w/o creating doubles' +Tooltip: 'Cut selected mesh(es) along an active plane w/o creating doubles' """ # $Id$ diff --git a/release/scripts/mod_ai2obj.py b/release/scripts/mod_ai2obj.py new file mode 100644 index 00000000000..07342737aad --- /dev/null +++ b/release/scripts/mod_ai2obj.py @@ -0,0 +1,383 @@ +""" +#---------------------------------------------- +# (c) jm soler juillet 2004, released under Blender Artistic Licence +# for the Blender 2.34 Python Scripts Bundle. +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +# +# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative +# +""" +SHARP_IMPORT=0 +SCALE=1 +DEVELOPPEMENT=0 + +import sys +#oldpath=sys.path +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.readlines() + f.close() + + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + + if len(t)>1: + return t + else: + name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Draw.PupMenu(name) + + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ + self.ITEM = {} + +courbes=COURBE() + +PATTERN={} + +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Object.Get() + BO[-1].RotY=0.0 + BO[-1].makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== AI format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + else: + CP=[l[-3].replace('d',''),l[-2]] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def courbe_vers_c(l,l2, n0,CP): #c,C + + B=Bez() + B.co=[l[2],l[3],l[4],l[5],l[0],l[1]] + + if len(courbes.ITEM[n0].beziers_knot)==1: + CP=[l[0],l[1]] + courbes.ITEM[n0].Origine=[l[0],l[1]] + + if l[-1]=='C': + B.ha=[2,2] + else: + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + if len(l2)>1 and l2[-1] in Actions.keys(): + B.co[-2]=l2[0] + B.co[-1]=l2[1] + else: + #B.co[-2]=courbes.ITEM[n0].beziers_knot[-1].co[0] + #B.co[-1]=courbes.ITEM[n0].beziers_knot[-].co[1] + + B.co[-2]=CP[0] + B.co[-1]=CP[1] + return courbes,n0,CP + + +def courbe_vers_v(l,n0,CP): #v-V + B=Bez() + B.co=[l[2],l[3],l[0],l[1],l[2],l[3]] + if l[-1]=='V': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +def courbe_vers_y(l,n0,CP): #y + B=Bez() + B.co=[l[2],l[3],l[0],l[1],l[2],l[3]] + if l[-1]=='Y': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[2],l[3]] + return courbes,n0,CP + + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + if l[-1]=='L': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +Actions= { "C" : courbe_vers_c, + "c" : courbe_vers_c, + "V" : courbe_vers_v, + "v" : courbe_vers_v, + "Y" : courbe_vers_y, + "y" : courbe_vers_y, + "m" : mouvement_vers, + "l" : ligne_tracee_l, + "L" : ligne_tracee_l} + +TAGcourbe=Actions.keys() + +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%BoundingBox:')!=-1: + t[l]=t[l][t[l].find(':')+1:] + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + #print l, + if t[l].find('BeginPattern')!=-1: + nomPattern=t[l][t[l].find('(')+1:t[l].find(')')] + PATTERN[nomPattern]={} + + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[nomPattern][npat]=[] + while t[l].find('EndPatternLayer')==-1: + #print t[l] + PATTERN[nomPattern][npat].append(l) + l+=1 + if l+1<len(t): + l=l+1 + else: + return 1,l + return 1,l + +def scan_FILE(nom): + global CP, courbes, SCALE + dir,name=split(nom) + name=name.split('.') + n0=0 + result=0 + t=filtreFICHIER(nom) + + if nom.upper().find('.AI')!=-1 and t!='false': + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + SCALE = Blender.Draw.PupMenu(warning) + + npat=0 + l=0 + do=0 + while l <len(t)-1 : + if not do: + do,l=pik_pattern(t,l) + #print 'len(t)',len(t) + t[l].replace('\n','') + if t[l][0]!='%': + l0=t[l].split() + if l0[-1] in TAGcourbe: + if l0[-1] in ['C','c']: + l2=t[l+1].split() + courbes,n0,CP=Actions[l0[-1]](l0,l2,n0,CP) + else: + courbes,n0,CP=Actions[l0[-1]](l0,n0,CP) + l=l+1; #print l + t=[] + courbes.number_of_items=len(courbes.ITEM.keys()) + for k in courbes.ITEM.keys(): + courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot) + + if test_egalitedespositions(courbes.ITEM[k].Origine, + [courbes.ITEM[k].beziers_knot[-1].co[-2], + courbes.ITEM[k].beziers_knot[-1].co[-1]]): + courbes.ITEM[k].flagUV[0]=1 + courbes.ITEM[k].pntsUV[0] -=1 + + if courbes.number_of_items>0: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + warning = "Pattern list (for info not used): %t| " + p0=1 + for P in PATTERN.keys(): + warning+="%s %%x%s|"%(P,p0) + p0+=1 + Padd = Blender.Draw.PupMenu(warning) + + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + else: + pass +#===================================================================== +#====================== AI format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +if DEVELOPPEMENT==1: + Blender.Window.FileSelector (fonctionSELECT, 'SELECT AI FILE') +#sys.path=oldpath diff --git a/release/scripts/mod_eps2obj.py b/release/scripts/mod_eps2obj.py new file mode 100644 index 00000000000..8db89892fc6 --- /dev/null +++ b/release/scripts/mod_eps2obj.py @@ -0,0 +1,390 @@ +#---------------------------------------------- +# (c) jm soler juillet 2004, released under Blender Artistic Licence +# for the Blender 2.34 Python Scripts Bundle. +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_eps.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#---------------------------------------------- + +SHARP_IMPORT=0 +SCALE=1 +scale=1 + +import sys +#oldpath=sys.path +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1: + return t + else: + name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Draw.PupMenu(name) + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + global SCALE,BOUNDINGBOX, scale + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Object.Get() + + BO[-1].RotY=3.1416 + BO[-1].RotZ=3.1416 + BO[-1].RotX=3.1416/2.0 + if scale==1: + BO[-1].LocY+=BOUNDINGBOX['rec'][3] + else: + BO[-1].LocY+=BOUNDINGBOX['rec'][3]/SCALE + + BO[-1].makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX,scale + r=BOUNDINGBOX['rec'] + + if scale==1: + SCALE=1.0 + elif scale==2: + SCALE=r[2]-r[0] + elif scale==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + + #name = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(name) + + +#===================================================================== +#===== EPS format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=[l[-3].replace('d',''),l[-2]] + else: + CP=[l[-3].replace('d',''),l[-2]] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def rmouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + else: + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0,CP + +def courbe_vers_c(l, l2, n0,CP): #c,C + """ + B=Bez() + B.co=[l[0],l[1],l[2],l[3],l[4],l[5]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + """ + B=Bez() + B.co=[l[2],l[3],l[4],l[5],l[0],l[1]] + if len(courbes.ITEM[n0].beziers_knot)==1: + CP=[l[0],l[1]] + courbes.ITEM[n0].Origine=[l[0],l[1]] + if l[-1]=='C': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + if len(l2)>1 and l2[-1] in Actions.keys(): + B.co[-2]=l2[0] + B.co[-1]=l2[1] + else: + B.co[-2]=CP[0] + B.co[-1]=CP[1] + return courbes,n0,CP + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +def rligne_tracee_l(l,n0,CP): + B=Bez() + B.co=["%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1]))] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +Actions= { "curveto" : courbe_vers_c, + "curveto" : courbe_vers_c, + "moveto" : mouvement_vers, + "rmoveto" : mouvement_vers, + "lineto" : ligne_tracee_l, + "rlineto" : rligne_tracee_l +} + +TAGcourbe=Actions.keys() + +""" +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%BoundingBox:')!=-1: + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + print l, + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[npat]=[] + while t[l].find('EndPatternLayer')==-1: + print t[l] + PATTERN[npat].append(l) + l+=1 + if l+1<len(t): + l=l+1 + else: + return 1,l + return 1,l +""" + +def scan_FILE(nom): + global CP, courbes, SCALE, scale + dir,name=split(nom) + name=name.split('.') + n0=0 + result=0 + t=filtreFICHIER(nom) + + if nom.upper().find('.EPS')!=-1 or nom.upper().find('.PS')!=-1 and t!='false': + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + scale = Blender.Draw.PupMenu(warning) + npat=0 + l=0 + do=0 + while l <len(t)-1 : + if t[l].find('%%BoundingBox:')!=-1: + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + """ + if not do: + do,l=pik_pattern(t,l) + """ + #print 'len(t)',len(t) + t[l].replace('\n','') + if t[l][0]!='%': + l0=t[l].split() + if l0!=[] and l0[-1] in TAGcourbe: + if l0[-1] in ['curveto']: + l2=t[l+1].split() + courbes,n0,CP=Actions[l0[-1]](l0,l2,n0,CP) + else: + courbes,n0,CP=Actions[l0[-1]](l0,n0,CP) + + l=l+1#; print l + t=[] + + if t!='false': + courbes.number_of_items=len(courbes.ITEM.keys()) + + for k in courbes.ITEM.keys(): + courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot) + + if test_egalitedespositions(courbes.ITEM[k].Origine, + [courbes.ITEM[k].beziers_knot[-1].co[-2], + courbes.ITEM[k].beziers_knot[-1].co[-1]]): + courbes.ITEM[k].flagUV[0]=1 + courbes.ITEM[k].pntsUV[0] -=1 + + if courbes.number_of_items>0: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + pass + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + else: + pass + + +#===================================================================== +#====================== EPS format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +#Blender.Window.FileSelector (fonctionSELECT, 'SELECT .EPS/.PS FILE') +#sys.path=oldpath diff --git a/release/scripts/mod_gimp2obj.py b/release/scripts/mod_gimp2obj.py new file mode 100644 index 00000000000..7128107cfcd --- /dev/null +++ b/release/scripts/mod_gimp2obj.py @@ -0,0 +1,320 @@ +""" +#---------------------------------------------- +# (c) jm soler juillet 2004, released under Blender Artistic Licence +# for the Blender 2.34 Python Scripts Bundle. +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- +""" +SHARP_IMPORT=0 +SCALE=1 + +import sys +#oldpath=sys.path + +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1 and t[1].find('#POINTS:')==0: + return t + else: + warning = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(warning) + return "false" + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + + def echo(self): + #print 'co = ', self.co + #print 'ha = ', self.ha + pass + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in the courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +def MINMAX(b): + global BOUNDINGBOX + r=BOUNDINGBOX['rec'] + for m in range(0,len(b)-2,2): + #print m, m+1 , len(b)-1 + #print b[m], r, r[0] + if float(b[m])<r[0]: + r[0]=float(b[m]) + + if float(b[m])>r[2]: r[2]=float(b[m]) + + if float(b[m+1])<r[1]: r[1]=float(b[m+1]) + if float(b[m+1])>r[3]: r[3]=float(b[m+1]) + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Object.Get() + + BO[-1].LocZ=1.0 + + BO[-1].makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + + t.append("%s\n"%courbes.ITEM[k].type) + + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =0#courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== GIMP format : DEBUT ========================= +#===================================================================== +CLOSED=0 + +def mouvement_vers(l,l1,l2,n0): + global BOUNDINGBOX, CP + if l[1] == '3' : + n0+=1 + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + courbes.ITEM[n0-1].beziers_knot[0].co[0]=CP[0] + courbes.ITEM[n0-1].beziers_knot[0].co[1]=CP[1] + CP=[l2[-3], l2[-1]] + + elif l[1]=='1' and (n0 not in courbes.ITEM.keys()): + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + CP=[l2[-3], l2[-1]] + + B=Bez() + B.co=[ CP[0],CP[1], + l1[-3], l1[-1], + l[-3], l[-1]] + + CP=[l2[-3], l2[-1]] + + if BOUNDINGBOX['rec']==[]: + BOUNDINGBOX['rec']=[float(l2[-3]), float(l2[-1]), float(l[-3]), float(l[-1])] + B.ha=[0,0] + + """ + if len( courbes.ITEM[n0].beziers_knot)>=1: + courbes.ITEM[n0].beziers_knot[-1].co[2]=l1[-3] + courbes.ITEM[n0].beziers_knot[-1].co[3]=l1[-1] + """ + + MINMAX(B.co) + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0 + +Actions= { "1" : mouvement_vers, + "3" : mouvement_vers } + +TAGcourbe=Actions.keys() + +def scan_FILE(nom): + global CP, courbes, SCALE, MAX, MIN, CLOSED + dir,name=split(nom) + name=name.split('.') + #print name + n0=0 + result=0 + t=filtreFICHIER(nom) + if t!="false": + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + SCALE = Blender.Draw.PupMenu(warning) + npat=0 + l=0 + while l <len(t)-1 : + #print 'len(t)',len(t) + t[l].replace('\n','') + if t[l][0]!='%': + l0=t[l].split() + #print l0[0], l0[1] + if l0[0]=='TYPE:' and l0[1] in TAGcourbe: + #print l0[0], l0[1], + l1=t[l+1].split() + l2=t[l+2].split() + courbes,n0=Actions[l0[1]](l0,l1,l2,n0) + elif l0[0]=='#Point': + POINTS= int(l0[0]) + elif l0[0]=='CLOSED:' and l0[1]=='1': + CLOSED=1 + l=l+1; + + courbes.number_of_items=len(courbes.ITEM.keys()) + + courbes.ITEM[n0].beziers_knot[0].co[0]=CP[0] + courbes.ITEM[n0].beziers_knot[0].co[1]=CP[1] + + for k in courbes.ITEM.keys(): + #print k + if CLOSED == 1: + B=Bez() + B.co=courbes.ITEM[k].beziers_knot[0].co[:] + B.ha=courbes.ITEM[k].beziers_knot[0].ha[:] + B.echo() + courbes.ITEM[k].beziers_knot.append(B) + courbes.ITEM[k].flagUV[0]=1 + courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot) + + if courbes.number_of_items>0: + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + else: + pass + +#===================================================================== +#====================== GIMP Path format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +#Blender.Window.FileSelector (fonctionSELECT, 'SELECT a GIMP Path FILE') +#sys.path=oldpath diff --git a/release/scripts/mod_svg2obj.py b/release/scripts/mod_svg2obj.py new file mode 100644 index 00000000000..d180b0d26c5 --- /dev/null +++ b/release/scripts/mod_svg2obj.py @@ -0,0 +1,647 @@ +""" +(c) jm soler juillet 2004, released under Blender Artistic Licence + for the Blender 2.34 Python Scripts Bundle. +#--------------------------------------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------------------------------------- + +-- Concept : translate SVG file in GEO .obj file and try to load it. +-- Real problem : the name of the blender file is changed ... +-- Curiousity : the original matrix must be : + + 0.0 0.0 1.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0 + + and not: + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0 + +-- Options : + SHARP_IMPORT = 0 + choise between "As is", "Devide by height" and "Devide by width" + SHARP_IMPORT = 1 + no choise + +-- Possible bug : sometime, the new curves object's RotY value + jumps to -90.0 degrees without any reason. + +Yet done: + M : absolute move to + Z : close path + L : absolute line to + C : absolute curve to + S : absolute curve to with only one handle + l : relative line to 2004/08/03 + 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 + +Changelog: + 0.1.1 : - control file without extension + 0.2.0 : - improved reading of several data of the same type + following the same command (for gimp import) + 0.2.1 : - better choice for viewboxing ( takes the viewbox if found, + 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 + (h,v) or uncommun number (a) +================================================================================== +==================================================================================""" + +SHARP_IMPORT=0 +SCALE=1 +scale=1 +DEBUG =0 +DEVELOPPEMENT=1 + +import sys +#oldpath=sys.path +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.read() + f.close() + t=t.replace('\r','') + t=t.replace('\n','') + + if t.upper().find('<SVG')==-1: + name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(name) + return "false" + else: + return t + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ + self.ITEM = {} + + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in the curves dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic definition inAI, EPS forma ================ +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + global SCALE,BOUNDINGBOX, scale + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Object.Get() + + BO[-1].RotY=3.1416 + BO[-1].RotZ=3.1416 + BO[-1].RotX=3.1416/2.0 + + if scale==1: + BO[-1].LocY+=BOUNDINGBOX['rec'][3] + else: + BO[-1].LocY+=BOUNDINGBOX['rec'][3]/SCALE + + BO[-1].makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX,scale + r=BOUNDINGBOX['rec'] + + if scale==1: + SCALE=1.0 + elif scale==2: + SCALE=r[2]-r[0] + elif scale==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =0#courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + #k1 =courbes.ITEM[k].beziers_knot[k2] + k1=ajustement(courbes.ITEM[k].beziers_knot[k2], SCALE) + + t.append("%4f 0.0 %4f \n"%(k1[4],k1[5])) + t.append("%4f 0.0 %4f \n"%(k1[0],k1[1])) + t.append("%4f 0.0 %4f \n"%(k1[2],k1[3])) + t.append(str(courbes.ITEM[k].beziers_knot[k2].ha[0])+' '+str(courbes.ITEM[k].beziers_knot[k2].ha[1])+'\n') + + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +def filtre_DATA(c,D,n): + global DEBUG,TAGcourbe + l=[] + + if len(c[0])==1 and D[c[1]+1].find(',')!=-1: + for n2 in range(1,n+1): + ld=D[c[1]+n2].split(',') + for l_ in ld: + l.append(l_) + + elif len(c[0])==1 and D[c[1]+2][0] not in TAGcourbe: + for n2 in range(1,n*2+1): + l.append(D[c[1]+n2]) + if DEBUG==1 : print l + + return l + +#===================================================================== +#===== SVG format : DEBUT ========================= +#===================================================================== + +def contruit_SYMETRIC(l): + L=[float(l[0]), float(l[1]), + float(l[2]),float(l[3])] + X=L[0]-(L[2]-L[0]) + Y=L[1]-(L[3]-L[1]) + l =[l[0],l[1],"%4s"%X,"%4s"%Y,l[2],l[3]] + return l + +def mouvement_vers(c, D, n0,CP): + global DEBUG,TAGcourbe + #print c,D[c[1]+1] + + l=filtre_DATA(c,D,1) + #print l + if n0 in courbes.ITEM.keys(): + n0+=1 + CP=[l[0],l[1]] + else: + CP=[l[0],l[1]] + + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[0],l[1]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + if DEBUG==1: print courbes.ITEM[n0], CP + + + return courbes,n0,CP + +def boucle_z(c,D,n0,CP): #Z,z + #print c, 'close' + courbes.ITEM[n0].flagUV[0]=1 + return courbes,n0,CP + +def courbe_vers_s(c,D,n0,CP): #S,s + l=filtre_DATA(c,D,2) + if c[0]=='s': + l=["%4s"%(float(l[0])+float(CP[0])), + "%4s"%(float(l[1])+float(CP[1])), + "%4s"%(float(l[2])+float(CP[0])), + "%4s"%(float(l[3])+float(CP[1]))] + l=contruit_SYMETRIC(l) + B=Bez() + B.co=[l[4],l[5],l[2],l[3],l[0],l[1]] #plus toucher au 2-3 + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + BP.co[2]=l[2] #4-5 point prec + BP.co[3]=l[3] + + courbes.ITEM[n0].beziers_knot.append(B) + if DEBUG==1: print B.co,BP.co + CP=[l[4],l[5]] + + if D[c[1]+3] not in TAGcourbe : + c[1]+=2 + courbe_vers_c(c, D, n0,CP) + return courbes,n0,CP + +def courbe_vers_a(c,D,n0,CP): #A + #print c + return courbes,n0,CP + +def courbe_vers_q(c,D,n0,CP): #Q + #print c + return courbes,n0,CP + +def courbe_vers_t(c,D,n0,CP): #T + return courbes,n0,CP + +def courbe_vers_c(c, D, n0,CP): #c,C + + l=filtre_DATA(c,D,3) + #print l, c, CP + + if c[0]=='c': + l=["%4s"%(float(l[0])+float(CP[0])), + "%4s"%(float(l[1])+float(CP[1])), + "%4s"%(float(l[2])+float(CP[0])), + "%4s"%(float(l[3])+float(CP[1])), + "%4s"%(float(l[4])+float(CP[0])), + "%4s"%(float(l[5])+float(CP[1]))] + + #print l + + B=Bez() + B.co=[l[4], + l[5], + l[0], + l[1], + l[2], + l[3]] #plus toucher au 2-3 + + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + + BP.co[2]=l[0] + BP.co[3]=l[1] + + courbes.ITEM[n0].beziers_knot.append(B) + if DEBUG==1: print B.co,BP.co + + CP=[l[4],l[5]] + + if D[c[1]+4] not in TAGcourbe : + c[1]+=3 + courbe_vers_c(c, D, n0,CP) + + return courbes,n0,CP + + +def ligne_tracee_l(c, D, n0,CP): #L,l + #print c + + l=filtre_DATA(c,D,1) + if c[0]=='l': + l=["%4s"%(float(l[0])+float(CP[0])), + "%4s"%(float(l[1])+float(CP[1]))] + + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + + CP=[l[0],l[1]] + + if D[c[1]+2] not in TAGcourbe : + c[1]+=1 + ligne_tracee_l(c, D, n0,CP) #L + + return courbes,n0,CP + + +def ligne_tracee_h(c,D,n0,CP): #H,h + + return courbes,n0,CP + +def ligne_tracee_v(c,D,n0,CP): #V + #print c + #CP=[] + return courbes,n0,CP + +def boucle_tracee_z(c,D,n0,CP): #Z + #print c + #CP=[] + return courbes,n0,CP + +Actions= { "C" : courbe_vers_c, + "A" : courbe_vers_a, + "S" : courbe_vers_s, + "M" : mouvement_vers, + "V" : ligne_tracee_v, + "L" : ligne_tracee_l, + "H" : ligne_tracee_h, + "Z" : boucle_z, + "Q" : courbe_vers_q, + "T" : courbe_vers_t, + + "c" : courbe_vers_c, + "a" : courbe_vers_a, + "s" : courbe_vers_s, + "m" : mouvement_vers, + "v" : ligne_tracee_v, + "l" : ligne_tracee_l, + "h" : ligne_tracee_h, + "z" : boucle_z, + "q" : courbe_vers_q, + "T" : courbe_vers_t +} + +TAGcourbe=Actions.keys() + +def get_content(val,t0): + t=t0[:] + if t.find(' '+val+'="')!=-1: + t=t[t.find(' '+val+'="')+len(' '+val+'="'):] + val=t[:t.find('"')] + t=t[t.find('"'):] + #---------------------------------------------------------------- + #print t[:10], val + #wait=raw_input('wait:' ) + + return t0,val + else: + return t0,0 + +def get_tag(val,t): + + t=t[t.find('<'+val):] + val=t[:t.find('>')+1] + t=t[t.find('>')+1:] + + if DEBUG==3 : print t[:10], val + + return t,val + +def get_val(val,t): + d="" + for l in t: + if l.find(val+'="')!=-1: + d=l[l[:-1].rfind('"')+1:-1] + for nn in d : + if '012345670.'.find(nn)==-1: + d=d.replace(nn,"") + d=float(d) + break + d=0.0 + return d + +def get_BOUNDBOX(BOUNDINGBOX,SVG,viewbox): + if viewbox==0: + h=get_val('height',SVG) + w=get_val('width',SVG) + BOUNDINGBOX['rec']=[0.0,0.0,w,h] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=w/h + else: + viewbox=viewbox.split() + BOUNDINGBOX['rec']=[float(viewbox[0]),float(viewbox[1]),float(viewbox[2]),float(viewbox[3])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[2]-r[0])/(r[3]-r[1]) + + return BOUNDINGBOX + +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] + DATA[0]=DATA[0].replace('\n','') + DATA[0]=DATA[0].replace('\t','') + DATA[0]=DATA[0].split(',') + D2=[] + D1=DATA[0] + + for cell in range(len(D1)): + if D1[cell] in Actions.keys(): + D2.append(D1[cell]) + n=1 + if D1[cell] not in ['h','v','H','V','a','A']: + while cell+n+1<len(D1) and (D1[cell+n] not in Actions.keys()): + D2.append(D1[cell+n]+','+D1[cell+n+1]) + n+=2 + elif D1[cell] in ['h','v','H','V']: + while cell+n+1<len(D1) and (D1[cell+n] not in Actions.keys()): + D2.append(D1[cell+n]) + n+=1 + elif D1[cell] in ['a','A']: + #(rx ry rotation-axe-x drapeau-arc-large drapeau-balayage x y) + #150,150 0 1,0 150,-150 + D2.append(D1[cell+n]+','+D1[cell+n+1]) + D2.append(D1[cell+n+2]) + D2.append(D1[cell+n+3]+','+D1[cell+n+4]) + D2.append(D1[cell+n+5]+','+D1[cell+n+6]) + n+=7 + return D2 + +def format_PATH(t): + + t,PATH=get_tag('path',t) + + if PATH.find(' id="')!=-1: + PATH,ID=get_content('id',PATH) + #print 'ident = ', ID + + if PATH.find(' STROKE="')!=-1: + PATH,ID=get_content('stroke',PATH) + #print 'path stroke = ', ID + + if PATH.find(' stroke-width="')!=-1: + PATH,ID=get_content('stroke-width',PATH) + #print 'path stroke-width = ', ID + + if PATH.find(' d="')!=-1: + PATH,D=get_content('d',PATH) + + #print "D0= :",D + + D=D.split(' ') + #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 + + +def scan_FILE(nom): + global CP, courbes, SCALE, DEBUG, BOUNDINGBOX, scale + dir,name=split(nom) + name=name.split('.') + n0=0 + result=0 + + t=filtreFICHIER(nom) + + if t!='false': + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + scale = Blender.Draw.PupMenu(warning) + npat=0 + l=0 + do=0 + t,SVG=get_tag('svg',t) + + SVG,viewbox=get_content('viewBox',SVG) + + SVG=SVG.split(' ') + if viewbox==0: + BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,SVG,0) + else: + BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,SVG,viewbox) + + #print t + + while t.find('path')!=-1: + + t,D=format_PATH(t) + + cursor=0 + for cell in D: + if DEBUG==2 : print 'cell : ',cell ,' --' + #print 'cell',cell + if len(cell)>=1 and cell[0] in TAGcourbe: + courbes,n0,CP=Actions[cell]([cell,cursor], D, n0,CP) + + cursor+=1 + + courbes.number_of_items=len(courbes.ITEM.keys()) + + for k in courbes.ITEM.keys(): + courbes.ITEM[k].pntsUV[0] =len(courbes.ITEM[k].beziers_knot) + + if courbes.number_of_items>0: + if len(PATTERN.keys() )>0: + if DEBUG == 3 : print len(PATTERN.keys() ) + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + else: + pass + +def ajustement(v,s): + + a,b,c,d,e,f=float(v.co[0]),float(v.co[1]),float(v.co[2]),float(v.co[3]),float(v.co[4]),float(v.co[5]) + return [a/s,-b/s,c/s,-d/s,e/s,-f/s] + +#===================================================================== +#====================== SVG format mouvements ======================== +#===================================================================== + +#===================================================================== +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#===================================================================== +def fonctionSELECT(nom): + scan_FILE(nom) + +if DEVELOPPEMENT==0: + Blender.Window.FileSelector (fonctionSELECT, 'SELECT a .SVG FILE') + #sys.path=oldpath diff --git a/release/scripts/obj_export.py b/release/scripts/obj_export.py index 814f9b481a2..12e09828169 100644 --- a/release/scripts/obj_export.py +++ b/release/scripts/obj_export.py @@ -7,8 +7,6 @@ Group: 'Export' Tooltip: 'Save a Wavefront OBJ File' """ -# $Id$ -# # -------------------------------------------------------------------------- # OBJ Export v0.9 by Campbell Barton (AKA Ideasman) # -------------------------------------------------------------------------- @@ -49,19 +47,6 @@ def stripPath(path): return path -#================================================# -# Gets the world matrix of an object # -# by multiplying by parents mat's recursively # -# This only works in some simple situations, # -# needs work.... # -#================================================# -def getWorldMat(ob): - mat = ob.getMatrix() - p = ob.getParent() - if p != None: - mat = mat + getWorldMat(p) - return mat - #==================# # Apply Transform # #==================# @@ -118,119 +103,110 @@ def save_mtl(filename): def save_obj(filename): - - # First output all material - mtlfilename = filename[:-4] + '.mtl' - save_mtl(mtlfilename) - - - - file = open(filename, "w") - - - # Write Header - file.write('# Blender OBJ File: ' + Get('filename') + ' \n') - file.write('# www.blender.org\n') - - # Tell the obj file what file to use. - file.write('mtllib ' + stripPath(mtlfilename) + ' \n') - - - # Get all meshs - for ob in Object.Get(): - if ob.getType() == 'Mesh': - m = ob.getData() - if len(m.verts) > 0: # Make sure there is somthing to write. - - # Set the default mat - currentMatName = NULL_MAT - currentImgName = NULL_IMG - - file.write('o ' + ob.getName() + '_' + m.name + '\n') # Write Object name - - # Dosent work properly, - matrix = getWorldMat(ob) - - smooth = 0 - - # Vert - for v in m.verts: - # Transform the vert - vTx = apply_transform(v.co, matrix) - - file.write('v ') - file.write(saneFloat(vTx[0])) - file.write(saneFloat(vTx[1])) - file.write(saneFloat(vTx[2]) + '\n') - - # UV - for f in m.faces: - if len(f.v) > 2: - for uvIdx in range(len(f.v)): - file.write('vt ') - if f.uv: - file.write(saneFloat(f.uv[uvIdx][0])) - file.write(saneFloat(f.uv[uvIdx][1])) - else: - file.write('0.0 ') - file.write('0.0 ') - - file.write('0.0' + '\n') - - # NORMAL - for f1 in m.faces: - if len(f1.v) > 2: - for v in f1.v: - # Transform the normal - noTx = apply_transform(v.no, matrix) - noTx.normalize() - file.write('vn ') - file.write(saneFloat(noTx[0])) - file.write(saneFloat(noTx[1])) - file.write(saneFloat(noTx[2]) + '\n') + + # First output all material + mtlfilename = filename[:-4] + '.mtl' + save_mtl(mtlfilename) + + file = open(filename, "w") + + # Write Header + file.write('# Blender OBJ File: ' + Get('filename') + ' \n') + file.write('# www.blender.org\n') + + # Tell the obj file what file to use. + file.write('mtllib ' + stripPath(mtlfilename) + ' \n') + + # Initialize totals, these are updated each object + totverts = totuvco = 0 + + + # Get all meshs + for ob in Object.Get(): + if ob.getType() == 'Mesh': + m = ob.getData() + if len(m.verts) > 0: # Make sure there is somthing to write. + + # Set the default mat + currentMatName = NULL_MAT + currentImgName = NULL_IMG + + file.write('o ' + ob.getName() + '_' + m.name + '\n') # Write Object name + + # Works 100% Yay + matrix = ob.getMatrix('worldspace') + + # Vert + for v in m.verts: + # Transform the vert + vTx = apply_transform(v.co, matrix) - uvIdx = 0 - for f in m.faces: - if len(f.v) > 2: - # Check material and change if needed. - if len(m.materials) > f.mat: - if currentMatName != m.materials[f.mat].getName(): - currentMatName = m.materials[f.mat].getName() - file.write('usemtl ' + currentMatName + '\n') - - elif currentMatName != NULL_MAT: - currentMatName = NULL_MAT - file.write('usemtl ' + currentMatName + '\n') + file.write('v ') + file.write(saneFloat(vTx[0])) + file.write(saneFloat(vTx[1])) + file.write(saneFloat(vTx[2]) + '\n') + + # UV + for f in m.faces: + if len(f.v) > 2: + for uvIdx in range(len(f.v)): + file.write('vt ') + if f.uv: + file.write(saneFloat(f.uv[uvIdx][0])) + file.write(saneFloat(f.uv[uvIdx][1])) + else: + file.write('0.0 ') + file.write('0.0 ') + + file.write('0.0' + '\n') + + # NORMAL + for f1 in m.faces: + if len(f1.v) > 2: + for v in f1.v: + # Transform the normal + noTx = apply_transform(v.no, matrix) + noTx.normalize() + file.write('vn ') + file.write(saneFloat(noTx[0])) + file.write(saneFloat(noTx[1])) + file.write(saneFloat(noTx[2]) + '\n') + + uvIdx = 0 + for f in m.faces: + if len(f.v) > 2: + # Check material and change if needed. + if len(m.materials) > f.mat: + if currentMatName != m.materials[f.mat].getName(): + currentMatName = m.materials[f.mat].getName() + file.write('usemtl ' + currentMatName + '\n') - # UV IMAGE - # If the face uses a different image from the one last set then add a usemap line. - if f.image: - if f.image.filename != currentImgName: - currentImgName = f.image.filename - file.write( 'usemat ' + stripPath(currentImgName) +'\n') # Set a new image for all following faces - - elif currentImgName != NULL_IMG: # Not using an image so set to NULL_IMG - currentImgName = NULL_IMG + elif currentMatName != NULL_MAT: + currentMatName = NULL_MAT + file.write('usemtl ' + currentMatName + '\n') + + # UV IMAGE + # If the face uses a different image from the one last set then add a usemap line. + if f.image: + if f.image.filename != currentImgName: + currentImgName = f.image.filename file.write( 'usemat ' + stripPath(currentImgName) +'\n') # Set a new image for all following faces - - if f.smooth == 1: - if smooth == 0: - smooth = 1 - file.write('s 1\n') - - if f.smooth == 0: - if smooth == 1: - smooth = 0 - file.write('s off\n') - - file.write('f ') - for v in f.v: - file.write( str(m.verts.index(v) +1) + '/') # Vert IDX - file.write( str(uvIdx +1) + '/') # UV IDX - file.write( str(uvIdx +1) + ' ') # NORMAL IDX - uvIdx+=1 - file.write('\n') - - file.close() - -Window.FileSelector(save_obj, 'Export OBJ', newFName('obj')) + + elif currentImgName != NULL_IMG: # Not using an image so set to NULL_IMG + currentImgName = NULL_IMG + file.write( 'usemat ' + stripPath(currentImgName) +'\n') # Set a new image for all following faces + + file.write('f ') + for v in f.v: + file.write( str(m.verts.index(v) + totverts +1) + '/') # Vert IDX + file.write( str(uvIdx + totuvco +1) + '/') # UV IDX + file.write( str(uvIdx + totuvco +1) + ' ') # NORMAL IDX + uvIdx+=1 + file.write('\n') + + # Make the indicies global rather then per mesh + totverts += len(m.verts) + totuvco += uvIdx + file.close() + +Window.FileSelector(save_obj, 'Export Wavefront OBJ', newFName('obj')) diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index e19c52b7be1..236b9705d33 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -53,19 +53,18 @@ def pathName(path,name): # Strips the slashes from the back of a string # #==============================================# def stripPath(path): - for CH in range(len(path), 0, -1): - if path[CH-1] == "/" or path[CH-1] == "\\": - path = path[CH:] - break - return path + for CH in range(len(path), 0, -1): + if path[CH-1] == "/" or path[CH-1] == "\\": + path = path[CH:] + break + return path #====================================================# # Strips the prefix off the name before writing # - #====================================================# def stripName(name): # name is a string - prefixDelimiter = '.' - return name[ : name.find(prefixDelimiter) ] + prefixDelimiter = '.' + return name[ : name.find(prefixDelimiter) ] from Blender import * @@ -74,27 +73,27 @@ 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) + # Make a new mat + try: + return Material.Get(matName) + except: + return Material.New(matName) #==================================================================================# # This function sets textures defined in .mtl file # #==================================================================================# def getImg(img_fileName): - for i in Image.Get(): - if i.filename == img_fileName: - return i + for i in Image.Get(): + if i.filename == img_fileName: + return i - # 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 - return + # 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 + return @@ -102,270 +101,309 @@ 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 + try: + image = Image.Load(img_fileName) + except: + print "unable to open", img_fileName + return - texture = Texture.New(type) - texture.setType('Image') - texture.image = image + texture = Texture.New(type) + texture.setType('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 + # 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 - # adds textures for materials (rendering) - if type == 'Ka': - mat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) - if type == 'Kd': - mat.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.COL) - if type == 'Ks': - mat.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + # adds textures for materials (rendering) + if type == 'Ka': + mat.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) + if type == 'Kd': + mat.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.COL) + if 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): - mtl_fileName = dir + mtl_file - try: - fileLines= open(mtl_fileName, 'r').readlines() - except: - print "unable to open", mtl_fileName - return + # Remove ./ + if mtl_file[:2] == './': + mtl_file= mtl_file[2:] + + mtl_fileName = dir + mtl_file + try: + fileLines= open(mtl_fileName, 'r').readlines() + except: + print "unable to open", mtl_fileName + return - lIdx=0 - while lIdx < len(fileLines): - l = fileLines[lIdx].split() + lIdx=0 + while lIdx < len(fileLines): + l = fileLines[lIdx].split() - # Detect a line that will be ignored - if len(l) == 0: - pass - elif l[0] == '#' or len(l) == 0: - pass - elif l[0] == 'newmtl': - currentMat = getMat(' '.join(l[1:])) - elif l[0] == 'Ka': - currentMat.setMirCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Kd': - currentMat.setRGBCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Ks': - currentMat.setSpecCol(eval(l[1]), eval(l[2]), eval(l[3])) - elif l[0] == 'Ns': - currentMat.setHardness( int((eval(l[1])*0.51)) ) - elif l[0] == 'd': - currentMat.setAlpha(eval(l[1])) - elif l[0] == 'Tr': - currentMat.setAlpha(eval(l[1])) - elif l[0] == 'map_Ka': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ka', mesh) - elif l[0] == 'map_Ks': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Ks', mesh) - elif l[0] == 'map_Kd': - img_fileName = dir + l[1] - load_mat_image(currentMat, img_fileName, 'Kd', mesh) - lIdx+=1 + # Detect a line that will be ignored + if len(l) == 0: + pass + elif l[0] == '#' or len(l) == 0: + pass + elif l[0] == 'newmtl': + currentMat = getMat(' '.join(l[1:])) + elif l[0] == 'Ka': + currentMat.setMirCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Kd': + currentMat.setRGBCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Ks': + currentMat.setSpecCol(eval(l[1]), eval(l[2]), eval(l[3])) + elif l[0] == 'Ns': + currentMat.setHardness( int((eval(l[1])*0.51)) ) + elif l[0] == 'd': + currentMat.setAlpha(eval(l[1])) + elif l[0] == 'Tr': + currentMat.setAlpha(eval(l[1])) + elif l[0] == 'map_Ka': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Ka', mesh) + elif l[0] == 'map_Ks': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Ks', mesh) + elif l[0] == 'map_Kd': + img_fileName = dir + l[1] + load_mat_image(currentMat, img_fileName, 'Kd', mesh) + lIdx+=1 #==================================================================================# # This loads data from .obj file # #==================================================================================# def load_obj(file): - def applyMat(mesh, f, mat): - # Check weather the 16 mat limit has been met. - if len( mesh.materials ) >= MATLIMIT: - print 'Warning, max material limit reached, using an existing material' - return mesh, f - - mIdx = 0 - for m in mesh.materials: - if m.getName() == mat.getName(): - break - mIdx+=1 - - if mIdx == len(mesh.materials): - mesh.addMaterial(mat) - - f.mat = mIdx + def applyMat(mesh, f, mat): + # Check weather the 16 mat limit has been met. + if len( mesh.materials ) >= MATLIMIT: + print 'Warning, max material limit reached, using an existing material' return mesh, f - - # Get the file name with no path or .obj - fileName = stripName( stripPath(file) ) - - mtl_fileName = '' - - DIR = pathName(file, stripPath(file)) - - fileLines = open(file, 'r').readlines() - - mesh = NMesh.GetRaw() # new empty mesh - - objectName = 'mesh' # If we cant get one, use this - - uvMapList = [] # store tuple uv pairs here - - nullMat = getMat(NULL_MAT) - - currentMat = nullMat # Use this mat. - currentImg = NULL_IMG # Null image is a string, otherwise this should be set to an image object. + + mIdx = 0 + for m in mesh.materials: + if m.getName() == mat.getName(): + break + mIdx+=1 + + if mIdx == len(mesh.materials): + mesh.addMaterial(mat) + + f.mat = mIdx + return mesh, f + + # Get the file name with no path or .obj + fileName = stripName( stripPath(file) ) + + mtl_fileName = '' + + DIR = pathName(file, stripPath(file)) - smooth = 0 + fileLines = open(file, 'r').readlines() + + mesh = NMesh.GetRaw() # new empty mesh + + objectName = 'mesh' # If we cant get one, use this + + 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)] # store tuple uv pairs here + + # Here we store a boolean list of which verts are used or not + # no we know weather to add them to the current mesh + # This is an issue with global vertex indicies being translated to per mesh indicies + # like blenders, we start with a dummy just like the vert. + # -1 means unused, any other value refers to the local mesh index of the vert. + usedList = [-1] + + nullMat = getMat(NULL_MAT) + + currentMat = nullMat # Use this mat. + currentImg = NULL_IMG # Null image is a string, otherwise this should be set to an image object. - # Main loop - lIdx = 0 - while lIdx < len(fileLines): - l = fileLines[lIdx].split() - - # Detect a line that will be idnored - if len(l) == 0: - pass - elif l[0] == '#' or len(l) == 0: - pass - # VERTEX - elif l[0] == 'v': - # This is a new vert, make a new mesh - mesh.verts.append( NMesh.Vert(eval(l[1]), eval(l[2]), eval(l[3]) ) ) - - elif l[0] == 'vn': - pass - - elif l[0] == 'vt': - # This is a new vert, make a new mesh - uvMapList.append( (eval(l[1]), eval(l[2])) ) - - elif l[0] == 'f': - - # Make a face with the correct material. - f = NMesh.Face() - mesh, f = applyMat(mesh, f, currentMat) - - # Set up vIdxLs : Verts - # Set up vtIdxLs : UV - vIdxLs = [] - vtIdxLs = [] - 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. - # Well try // first and if that has a len of 1 then we'll try / - objVert = v.split('//', -1) - if len(objVert) == 1: - objVert = objVert[0].split('/', -1) - - # VERT INDEX - vIdxLs.append(eval(objVert[0]) -1) - # UV - if len(objVert) == 1: - vtIdxLs.append(eval(objVert[0]) -1) # Sticky UV coords - else: - vtIdxLs.append(eval(objVert[1]) -1) # Seperate UV coords - - # Quads only, we could import quads using the method below but it polite to import a quad as a quad.f - if len(vIdxLs) == 4: - f.v.append(mesh.verts[vIdxLs[0]]) - f.v.append(mesh.verts[vIdxLs[1]]) - f.v.append(mesh.verts[vIdxLs[2]]) - f.v.append(mesh.verts[vIdxLs[3]]) - # SMOTH FACE - f.smooth = smooth - # UV MAPPING - if uvMapList: - if vtIdxLs[0] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[0] ] ) - if vtIdxLs[1] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[1] ] ) - if vtIdxLs[2] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[2] ] ) - if vtIdxLs[3] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[3] ] ) - - mesh.faces.append(f) # move the face onto the mesh - # Apply the current image to the face - if currentImg != NULL_IMG: - mesh.faces[-1].image = currentImg + # Main loop + lIdx = 0 + while lIdx < len(fileLines): + l = fileLines[lIdx].split() + + # Detect a line that will be idnored + if len(l) == 0: + pass + elif l[0] == '#' or len(l) == 0: + pass + # VERTEX + elif l[0] == 'v': + # This is a new vert, make a new mesh + vertList.append( NMesh.Vert(eval(l[1]), eval(l[2]), eval(l[3]) ) ) + usedList.append(-1) # Ad the moment this vert is not used by any mesh. + + elif l[0] == 'vn': + pass + + elif l[0] == 'vt': + # This is a new vert, make a new mesh + uvMapList.append( (eval(l[1]), eval(l[2])) ) - elif len(vIdxLs) >= 3: # This handles tri's and fans - for i in range(len(vIdxLs)-2): - f = NMesh.Face() - mesh, f = applyMat(mesh, f, currentMat) - f.v.append(mesh.verts[vIdxLs[0]]) - f.v.append(mesh.verts[vIdxLs[i+1]]) - f.v.append(mesh.verts[vIdxLs[i+2]]) - # SMOTH FACE - f.smooth = smooth - # UV MAPPING - if uvMapList: - if vtIdxLs[0] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[0] ] ) - if vtIdxLs[1] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[i+1] ] ) - if vtIdxLs[2] < len(uvMapList): - f.uv.append( uvMapList[ vtIdxLs[i+2] ] ) - - mesh.faces.append(f) # move the face onto the mesh - # Apply the current image to the face - if currentImg != NULL_IMG: - mesh.faces[-1].image = currentImg - - - # is o the only vert/face delimeter? - # if not we could be screwed. - elif l[0] == 'o': - # Some material stuff - if mtl_fileName != '': - load_mtl(DIR, mtl_fileName, mesh) + elif l[0] == 'f': + + # Make a face with the correct material. + f = NMesh.Face() + mesh, f = applyMat(mesh, f, currentMat) + + # Set up vIdxLs : Verts + # Set up vtIdxLs : UV + # Start with a dummy objects so python accepts OBJs 1 is the first index. + vIdxLs = [] + vtIdxLs = [] + fHasUV = len(uvMapList)-1 # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0. + 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) - # Make sure the objects is worth puttong - if len(mesh.verts) > 0: - NMesh.PutRaw(mesh, fileName + '_' + objectName) - # Make new mesh - mesh = NMesh.GetRaw() - - # New mesh name - objectName = '_'.join(l[1:]) # Use join in case of spaces - - # New texture list - uvMapList = [] - - # setting smooth surface on or off - elif l[0] == 's': - if l[1] == 'off': - smooth = 0 - else: - smooth = 1 - - elif l[0] == 'usemtl': - if l[1] == '(null)': - currentMat = getMat(NULL_MAT) - else: - currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces + # Vert Index - OBJ supports negative index assignment (like python) + + vIdxLs.append(eval(objVert[0])) + if fHasUV: + # UV + if len(objVert) == 1: + vtIdxLs.append(eval(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(eval(objVert[1])) # Seperate UV coords + else: + fHasUV = 0 + + # Dont add a UV to the face if its larger then the UV coord list + # The OBJ file would have to be corrupt or badly written for thi to happen + # but account for it anyway. + if vtIdxLs[-1] > len(uvMapList): + fHasUV = 0 + print 'badly written OBJ file, invalid references to UV Texture coordinates.' + + # 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 usedList[vIdxLs[i]] == -1: + mesh.verts.append(vertList[vIdxLs[i]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i]]]) + + # UV MAPPING + if fHasUV: + for i in [0,1,2,3]: + f.uv.append( uvMapList[ vtIdxLs[i] ] ) + mesh.faces.append(f) # move the face onto the mesh + # Apply the current image to the face + if currentImg != NULL_IMG: + mesh.faces[-1].image = currentImg + + elif len(vIdxLs) >= 3: # This handles tri's and fans + for i in range(len(vIdxLs)-2): + f = NMesh.Face() + mesh, f = applyMat(mesh, f, currentMat) + + if usedList[vIdxLs[0]] == -1: + mesh.verts.append(vertList[vIdxLs[0]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[0]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[0]]]) + + if usedList[vIdxLs[i+1]] == -1: + mesh.verts.append(vertList[vIdxLs[i+1]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i+1]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i+1]]]) + + if usedList[vIdxLs[i+2]] == -1: + mesh.verts.append(vertList[vIdxLs[i+2]]) + f.v.append(mesh.verts[-1]) + usedList[vIdxLs[i+2]] = len(mesh.verts)-1 + else: + f.v.append(mesh.verts[usedList[vIdxLs[i+2]]]) + + # UV MAPPING + if fHasUV: + f.uv.append( uvMapList[ vtIdxLs[0] ] ) + f.uv.append( uvMapList[ vtIdxLs[i+1] ] ) + f.uv.append( uvMapList[ vtIdxLs[i+2] ] ) + mesh.faces.append(f) # move the face onto the mesh + + # Apply the current image to the face + if currentImg != NULL_IMG: + mesh.faces[-1].image = currentImg + + # Object / Group + elif l[0] == 'o' or l[0] == 'g': + + # Reset the used list + ulIdx = 0 + while ulIdx < len(usedList): + usedList[ulIdx] = -1 + ulIdx +=1 + + # Some material stuff + if mtl_fileName != '': + load_mtl(DIR, mtl_fileName, mesh) + + # Make sure the objects is worth putting + if len(mesh.verts) > 1: + mesh.verts.remove(mesh.verts[0]) + ob = NMesh.PutRaw(mesh, fileName + '_' + objectName) + if ob != None: # Name the object too. + ob.name = fileName + '_' + objectName - elif l[0] == 'usemat': - if l[1] == '(null)': - currentImg = NULL_IMG - else: - currentImg = getImg(DIR + ' '.join(l[1:])) # Use join in case of spaces - - - elif l[0] == 'mtllib': - mtl_fileName = l[1] - - lIdx+=1 + # Make new mesh + mesh = NMesh.GetRaw() + # This dummy vert makes life a whole lot easier- + # pythons index system then aligns with objs, remove later + mesh.verts.append( NMesh.Vert(0, 0, 0) ) + + # New mesh name + objectName = '_'.join(l[1:]) # Use join in case of spaces + + + elif l[0] == 'usemtl': + if l[1] == '(null)': + currentMat = getMat(NULL_MAT) + else: + currentMat = getMat(' '.join(l[1:])) # Use join in case of spaces + + elif l[0] == 'usemat': + if l[1] == '(null)': + currentImg = NULL_IMG + else: + currentImg = getImg(DIR + ' '.join(l[1:])) # Use join in case of spaces + + + elif l[0] == 'mtllib': + mtl_fileName = l[1] + + lIdx+=1 - # Some material stuff - if mtl_fileName != '': - load_mtl(DIR, mtl_fileName, mesh) - - # We need to do this to put the last object. - # All other objects will be put alredy - if len(mesh.verts) > 0: - NMesh.PutRaw(mesh, fileName + '_' + objectName) + # Some material stuff + if mtl_fileName != '': + load_mtl(DIR, mtl_fileName, mesh) + + # We need to do this to put the last object. + # All other objects will be put alredy + if len(mesh.verts) > 1: + mesh.verts.remove(mesh.verts[0]) + ob = NMesh.PutRaw(mesh, fileName + '_' + objectName) + if ob != None: # Name the object too. + ob.name = fileName + '_' + objectName -Window.FileSelector(load_obj, 'Import OBJ') +Window.FileSelector(load_obj, 'Import Wavefront OBJ') diff --git a/release/scripts/paths_import.py b/release/scripts/paths_import.py new file mode 100644 index 00000000000..89535e2b872 --- /dev/null +++ b/release/scripts/paths_import.py @@ -0,0 +1,35 @@ +#!BPY + +""" +Name: 'Paths (.svg, .ps, .eps, .ai, Gimp)' +Blender: 233 +Group: 'Import' +Submenu: 'Gimp 1.0 - 1.2.5' Gimp_1_0 +Submenu: 'Gimp 2.0' Gimp_2_0 +Submenu: 'Illustrator (.ai) PS-Adobe-2.0' AI +Submenu: 'InkScape (.svg)' SVG +Submenu: 'Postscript (.eps/.ps) PS-Adobe-2.0' EPS +Tip: 'Import a path from any of a set of formats (still experimental)' +""" + +import Blender + +argv=__script__['arg'] + +if argv=='SVG': + from mod_svg2obj import * + +elif argv=='AI': + from mod_ai2obj import * + +elif argv=='EPS': + from mod_eps2obj import * + +elif argv=='Gimp_1_0': + from mod_gimp2obj import * + +elif argv=='Gimp_2_0': + from mod_svg2obj import * + +text = 'Import %s' % argv +Blender.Window.FileSelector (fonctionSELECT, text) diff --git a/release/scripts/skin.py b/release/scripts/skin.py new file mode 100644 index 00000000000..77792c1326b --- /dev/null +++ b/release/scripts/skin.py @@ -0,0 +1,558 @@ +#!BPY + +""" +Name: 'Skin Two Vert-loops / Loft Multiple' +Blender: 234 +Group: 'Mesh' +Submenu: 'Loft-loop - shortest edge method' A1 +Submenu: 'Loft-loop - even method' A2 +Submenu: 'Loft-segment - shortest edge' B1 +Submenu: 'Loft-segment - even method' B2 +Tooltip: 'Select 2 or more vert loops, then run this script' +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# Skin Selected edges 1.0 By Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + + +# Made by Ideasman/Campbell 2004/04/25 - ideasman@linuxmail.org + +import Blender +from Blender import * +import math +from math import * +arg = __script__['arg'] + + +#================# +# Math functions # +#================# + +# Measure 2 points +def measure(v1, v2): + return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length + +# Clamp +def clamp(max, number): + while number >= max: + number = number - max + return number + +#=============================================================# +# List func that takes the last item and adds it to the front # +#=============================================================# +def listRotate(ls): + return [ls[-1]] + ls[:-1] + +#=================================================================# +# Recieve a list of locs: [x,y,z] and return the average location # +#=================================================================# +def averageLocation(locList): + avLoc = [0,0,0] + + # Loop through x/y/z + for coordIdx in [0,1,2]: + + # Add all the values from 1 of the 3 coords at the avLoc. + for loc in locList: + avLoc[coordIdx] += loc[coordIdx] + + avLoc[coordIdx] = avLoc[coordIdx] / len(locList) + return avLoc + + + +#=============================# +# Blender functions/shortcuts # +#=============================# +def error(str): + Draw.PupMenu('ERROR%t|'+str) + +# Returns a new face that has the same properties as the origional face +# With no verts though +def copyFace(face): + newFace = NMesh.Face() + # Copy some generic properties + newFace.mode = face.mode + if face.image != None: + newFace.image = face.image + newFace.flag = face.flag + newFace.mat = face.mat + newFace.smooth = face.smooth + return newFace + +#=============================================# +# Find a selected vert that 2 faces share. # +#=============================================# +def selVertBetween2Faces(face1, face2): + for v1 in face1.v: + if v1.sel: + for v2 in face2.v: + if v1 == v2: + return v1 + + +#=======================================================# +# Measure the total distance between all the edges in # +# 2 vertex loops # +#=======================================================# +def measureVloop(mesh, v1loop, v2loop, surplusFaces): + totalDist = 0 + + # Rotate the vertloops to cycle through each pair. + # of faces to compate the distance between the 2 poins + for ii in range(len(v1loop)): + if ii not in surplusFaces: + V1 = selVertBetween2Faces(mesh.faces[v1loop[0]], mesh.faces[v1loop[1]]) + V2 = selVertBetween2Faces(mesh.faces[v2loop[0]], mesh.faces[v2loop[1]]) + + P1 = (V1[0],V1[1],V1[2]) + P2 = (V2[0],V2[1],V2[2]) + + totalDist += measure(P1,P2) + v1loop = listRotate(v1loop) + v2loop = listRotate(v2loop) + + #selVertBetween2Faces(mesh.faces[v2loop[0]], mesh.faces[v2loop[1]]) + return totalDist + +# Remove the shortest edge from a vert loop +def removeSmallestFace(mesh, vloop): + bestDistSoFar = None + bestFIdxSoFar = None + for fIdx in vloop: + vSelLs = [] + for v in mesh.faces[fIdx].v: + if v.sel: + vSelLs.append(v) + + dist = measure(vSelLs[0].co, vSelLs[1].co) + + if bestDistSoFar == None: + bestDistSoFar = dist + bestFIdxSoFar = fIdx + elif dist < bestDistSoFar: + bestDistSoFar = dist + bestFIdxSoFar = fIdx + + # Return the smallest face index of the vloop that was sent + return bestFIdxSoFar + + +#=============================================# +# Take 2 vert loops and skin them # +#=============================================# +def skinVertLoops(mesh, v1loop, v2loop): + + + #=============================================# + # Handle uneven vert loops, this is tricky # + #=============================================# + # Reorder so v1loop is always the biggest + if len(v1loop) < len(v2loop): + v1loop, v2loop = v2loop, v1loop + + # Work out if the vert loops are equel or not, if not remove the extra faces from the larger + surplusFaces = [] + tempv1loop = eval(str(v1loop)) # strip faces off this one, use it to keep track of which we have taken faces from. + if len(v1loop) > len(v2loop): + + # Even face method. + if arg[1] == '2': + remIdx = 0 + faceStepping = len( v1loop) / len(v2loop) + while len(v1loop) - len(surplusFaces) > len(v2loop): + remIdx += faceStepping + surplusFaces.append(tempv1loop[ clamp(len(tempv1loop),remIdx) ]) + tempv1loop.remove(surplusFaces[-1]) + + # Shortest face + elif arg[1] == '1': + while len(v1loop) - len(surplusFaces) > len(v2loop): + surplusFaces.append(removeSmallestFace(mesh, tempv1loop)) + tempv1loop.remove(surplusFaces[-1]) + + + tempv1loop = None + + v2loop = optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces) + + # make Faces from + lenVloop = len(v1loop) + lenSupFaces = len(surplusFaces) + fIdx = 0 + offset = 0 + while fIdx < lenVloop: + + face = copyFace( mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]] ) + + if v1loop[fIdx] in surplusFaces: + # Draw a try, this face does not catch with an edge. + # So we must draw a tri and wedge it in. + + # Copy old faces properties + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) ) + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) ) + + #face.v.append( selVertBetween2Faces(\ + #mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\ + #mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) ) + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) ) + + mesh.faces.append(face) + + # We need offset to work out how much smaller v2loop is at this current index. + offset+=1 + + + else: + # Draw a normal quad between the 2 edges/faces + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v1loop[clamp(lenVloop, fIdx)]],\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]]) ) + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+1)]],\ + mesh.faces[v1loop[clamp(lenVloop, fIdx+2)]]) ) + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset +1 ))]],\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset + 2))]]) ) + + face.v.append( selVertBetween2Faces(\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, (fIdx - offset))]],\ + mesh.faces[v2loop[clamp(lenVloop - lenSupFaces, fIdx - offset + 1)]]) ) + + mesh.faces.append(face) + + fIdx +=1 + + return mesh + + + +#=======================================================# +# Takes a face and returns the number of selected verts # +#=======================================================# +def faceVSel(face): + vSel = 0 + for v in face.v: + if v.sel: + vSel +=1 + return vSel + + + + +#================================================================# +# This function takes a face and returns its selected vert loop # +# it returns a list of face indicies +#================================================================# +def vertLoop(mesh, startFaceIdx, fIgLs): # fIgLs is a list of faces to ignore. + # Here we store the faces indicies that + # are a part of the first vertex loop + vertLoopLs = [startFaceIdx] + + restart = 0 + while restart == 0: + # this keeps the face loop going until its told to stop, + # If the face loop does not find an adjacent face then the vert loop has been compleated + restart = 1 + + # Get my selected verts for the active face/edge. + selVerts = [] + for v in mesh.faces[vertLoopLs[-1]].v: + selVerts.append(v) + + fIdx = 0 + while fIdx < len(mesh.faces) and restart: + # Not already added to the vert list + if fIdx not in fIgLs + vertLoopLs: + # Has 2 verts selected + if faceVSel(mesh.faces[fIdx]) > 1: + # Now we need to find if any of the selected verts + # are shared with our active face. (are we next to ActiveFace) + for v in mesh.faces[fIdx].v: + if v in selVerts: + vertLoopLs.append(fIdx) + restart = 0 # restart the face loop. + break + + fIdx +=1 + + return vertLoopLs + + + + +#================================================================# +# Now we work out the optimum order to 'skin' the 2 vert loops # +# by measuring the total distance of all edges created, # +# test this for every possible series of joins # +# and find the shortest, Once this is done the # +# shortest dist can be skinned. # +# returns only the 2nd-reordered vert loop # +#================================================================# +def optimizeLoopOrded(mesh, v1loop, v2loop): + bestSoFar = None + + # Measure the dist, ii is just a counter + for ii in range(len(v1loop)): + + # Loop twice , Once for the forward test, and another for the revearsed + for iii in [0, 0]: + dist = measureVloop(mesh, v1loop, v2loop) + # Initialize the Best distance recorded + if bestSoFar == None: + bestSoFar = dist + bestv2Loop = eval(str(v2loop)) + + elif dist < bestSoFar: # Update the info if a better vloop rotation is found. + bestSoFar = dist + bestv2Loop = eval(str(v2loop)) + + # We might have got the vert loop backwards, try the other way + v2loop.reverse() + v2loop = listRotate(v2loop) + return bestv2Loop + + + +#================================================================# +# Now we work out the optimum order to 'skin' the 2 vert loops # +# by measuring the total distance of all edges created, # +# test this for every possible series of joins # +# and find the shortest, Once this is done the # +# shortest dist can be skinned. # +# returns only the 2nd-reordered vert loop # +#================================================================# +def optimizeLoopOrdedShortEdge(mesh, v1loop, v2loop, surplusFaces): + bestSoFar = None + + # Measure the dist, ii is just a counter + for ii in range(len(v2loop)): + + # Loop twice , Once for the forward test, and another for the revearsed + for iii in [0, 0]: + dist = measureVloop(mesh, v1loop, v2loop, surplusFaces) + print 'dist', dist + # Initialize the Best distance recorded + if bestSoFar == None: + bestSoFar = dist + bestv2Loop = eval(str(v2loop)) + + elif dist < bestSoFar: # Update the info if a better vloop rotation is found. + bestSoFar = dist + bestv2Loop = eval(str(v2loop)) + + # We might have got the vert loop backwards, try the other way + v2loop.reverse() + v2loop = listRotate(v2loop) + print 'best so far ', bestSoFar + return bestv2Loop + + + + + + +#==============================# +# Find our vert loop list # +#==============================# +# Find a face with 2 verts selected, +#this will be the first face in out vert loop +def findVertLoop(mesh, fIgLs): # fIgLs is a list of faces to ignore. + + startFaceIdx = None + + fIdx = 0 + while fIdx < len(mesh.faces): + if fIdx not in fIgLs: + # Do we have an edge? + if faceVSel(mesh.faces[fIdx]) > 1: + # THIS IS THE STARTING FACE. + startFaceIdx = fIdx + break + fIdx+=1 + + # Here we access the function that generates the real vert loop + if startFaceIdx != None: + return vertLoop(mesh, startFaceIdx, fIgLs) + else: + # We are out'a vert loops, return a None, + return None + +#===================================# +# Get the average loc of a vertloop # +# This is used when working out the # +# order to loft an object # +#===================================# +def vLoopAverageLoc(mesh, vertLoop): + locList = [] # List of vert locations + + fIdx = 0 + while fIdx < len(mesh.faces): + if fIdx in vertLoop: + for v in mesh.faces[fIdx].v: + if v.sel: + locList.append(v.co) + fIdx+=1 + + return averageLocation(locList) + + + +#=================================================# +# Vert loop group functions + +def getAllVertLoops(mesh): + # Make a chain of vert loops. + fIgLs = [] # List of faces to ignore + allVLoops = [findVertLoop(mesh, fIgLs)] + while allVLoops[-1] != None: + + # In future ignore all faces in this vert loop + fIgLs += allVLoops[-1] + + # Add the new vert loop to the list + allVLoops.append( findVertLoop(mesh, fIgLs) ) + + return allVLoops[:-1] # Remove the last Value- None. + + +def reorderCircularVLoops(mesh, allVLoops): + # Now get a location for each vert loop. + allVertLoopLocs = [] + for vLoop in allVLoops: + allVertLoopLocs.append( vLoopAverageLoc(mesh, vLoop) ) + + # We need to find the longest distance between 2 vert loops so we can + reorderedVLoopLocs = [] + + # Start with this one, then find the next closest. + # in doing this make a new list called reorderedVloop + currentVLoop = 0 + reorderedVloopIdx = [currentVLoop] + newOrderVLoops = [allVLoops[0]] # This is a re-ordered allVLoops + while len(reorderedVloopIdx) != len(allVLoops): + bestSoFar = None + bestVIdxSoFar = None + for vLoopIdx in range(len(allVLoops)): + if vLoopIdx not in reorderedVloopIdx + [currentVLoop]: + if bestSoFar == None: + bestSoFar = measure( allVertLoopLocs[vLoopIdx], allVertLoopLocs[currentVLoop] ) + bestVIdxSoFar = vLoopIdx + else: + newDist = measure( allVertLoopLocs[vLoopIdx], allVertLoopLocs[currentVLoop] ) + if newDist < bestSoFar: + bestSoFar = newDist + bestVIdxSoFar = vLoopIdx + + reorderedVloopIdx.append(bestVIdxSoFar) + reorderedVLoopLocs.append(allVertLoopLocs[bestVIdxSoFar]) + newOrderVLoops.append( allVLoops[bestVIdxSoFar] ) + + # Start looking for the next best fit + currentVLoop = bestVIdxSoFar + + # This is not the locicle place to put this but its convieneint. + # Here we find the 2 vert loops that are most far apart + # We use this to work out which 2 vert loops not to skin when making an open loft. + vLoopIdx = 0 + # Longest measured so far - 0 dummy. + bestSoFar = 0 + while vLoopIdx < len(reorderedVLoopLocs): + + + # Skin back to the start if needs be, becuase this is a crcular loft + toSkin2 = vLoopIdx + 1 + if toSkin2 == len(reorderedVLoopLocs): + toSkin2 = 0 + + + newDist = measure( reorderedVLoopLocs[vLoopIdx], reorderedVLoopLocs[toSkin2] ) + + if newDist >= bestSoFar: + bestSoFar = newDist + vLoopIdxNotToSkin = vLoopIdx + 1 + + vLoopIdx +=1 + + return newOrderVLoops, vLoopIdxNotToSkin + + +is_editmode = Window.EditMode() +if is_editmode: Window.EditMode(0) + +# Get a mesh and raise errors if we cant +mesh = None +if len(Object.GetSelected()) > 0: + if Object.GetSelected()[0].getType() == 'Mesh': + mesh = Object.GetSelected()[0].getData() + else: + error('please select a mesh') +else: + error('no mesh object selected') + + +if mesh != None: + allVLoops = getAllVertLoops(mesh) + + # Re order the vert loops + allVLoops, vLoopIdxNotToSkin = reorderCircularVLoops(mesh, allVLoops) + + vloopIdx = 0 + while vloopIdx < len(allVLoops): + #print range(len(allVLoops) ) + #print vloopIdx + #print allVLoops[vloopIdx] + + # Skin back to the start if needs be, becuase this is a crcular loft + toSkin2 = vloopIdx + 1 + if toSkin2 == len(allVLoops): + toSkin2 = 0 + + # Circular loft or not? + if arg[0] == 'B': # B for open + if vloopIdx != vLoopIdxNotToSkin: + mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2]) + elif arg[0] == 'A': # A for closed + mesh = skinVertLoops(mesh, allVLoops[vloopIdx], allVLoops[toSkin2]) + + vloopIdx +=1 + + mesh.update() + +if is_editmode: Window.EditMode(1) diff --git a/release/scripts/tex2uvbaker.py b/release/scripts/tex2uvbaker.py new file mode 100644 index 00000000000..45dbb2e5b11 --- /dev/null +++ b/release/scripts/tex2uvbaker.py @@ -0,0 +1,254 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'Texture Baker' +Blender: 233 +Group: 'UV' +Tooltip: 'Procedural to uvmapped texture baker' +""" + +#--------------------------------------------- +# Last release : 0.2.2 , 2004/08/01 , 22h13 +#--------------------------------------------- +#--------------------------------------------- +# (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 +# +# 0.2.2 : if the uv mesh objet exists it used, +# no creation of a new one. As the lamp and +# the camera +# 0.2.1 : This script automaticaly frame and shoot the +# new uv mesh . The image file is saved ine the +# /render folder. +# +#--------------------------------------------- +# On user-friendly side : +#--------------------------------------------- +#- Tadje Vobovnik adds the Select Image Size Menu +# +#--------------------------------------------- +# Official Page : +# http://jmsoler.free.fr/util/blenderfile/py/text2uvbaker.py +# For problems and errors: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- + +import Blender +from Blender import NMesh, Draw, Object, Scene, Camera + +FRAME = 100 +XYLIMIT = [0.0, 0.] +OBJPOS = 100.0 + +helpmsg = """ +Texture Baker: + +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 procedural textures from Blender as +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; +- Run this script and check the console. +""" + +def GET_newobject (TYPE): + SCENE = Blender.Scene.getCurrent() + OBJECT = Blender.Object.New(TYPE) + SCENE.link(OBJECT) + return OBJECT, SCENE + +def SAVE_image (rc, name, FRAME): + MYDIR = '' + RENDERDIR = rc.getRenderPath() + rc.setRenderPath(RENDERDIR + MYDIR) + print "Render folder:", RENDERDIR + MYDIR + IMAGETYPE = Blender.Scene.Render.PNG + rc.setImageType(IMAGETYPE) + NEWFRAME = FRAME + OLDEFRAME = rc.endFrame() + OLDSFRAME = rc.startFrame() + rc.startFrame(NEWFRAME) + rc.endFrame(NEWFRAME) + rc.renderAnim() + + try: + import nt + os = nt + + except: + import posix + os = posix + + FILENAME = "%04d" % NEWFRAME + FILENAME = FILENAME.replace (' ', '0') + FILENAME = RENDERDIR + 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 + + rc.endFrame(OLDEFRAME) + rc.startFrame(OLDSFRAME) + rc.setRenderPath(RENDERDIR) + +def SHOOT (XYlimit, frame, obj, name, FRAME): + try: + CAM = Blender.Object.Get('UVCAMERA') + Cam = CAM.getData() + SC = Blender.Scene.getCurrent() + + except: + Cam = Blender.Camera.New() + Cam.name = 'UVCamera' + CAM, SC = GET_newobject('Camera') + CAM.link(Cam) + CAM.setName('UVCAMERA') + Cam.lens = 30 + Cam.name = 'UVCamera' + + CAM.setLocation(obj.getLocation()) + CAM.LocX += XYlimit[0] / 2.0 + CAM.LocY += XYlimit[1] / 2.0 + CAM.LocZ += max (XYlimit[0], XYlimit[1]) + 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') + 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') + + if (tres) == 1: res = 256 + + elif (tres) == 2: res = 512 + + elif (tres) == 3: res = 768 + + elif (tres) == 4: res = 1024 + + else: res = 512 + + context.imageSizeY(res) + context.imageSizeX(res) + SAVE_image (context, name, FRAME) + context.imageSizeY(OLDy) + context.imageSizeX(OLDx) + SC.setCurrentCamera(Camold) + Blender.Set ('curframe', frame) + +def Mesh2UVCoord (): + try: + MESH3D = Object.GetSelected()[0] + + if MESH3D.getType() == 'Mesh': + MESH = MESH3D.getData() + MESH2 = Blender.NMesh.GetRaw() + + for f in MESH.faces: + f1 = Blender.NMesh.Face() + + for v in f.v: + v1 = Blender.NMesh.Vert (v.co[0], v.co[1], v.co[2]) + MESH2.verts.append(v1) + f1.v.append(MESH2.verts[len(MESH2.verts) - 1]) + + MESH2.faces.append(f1) + f1.uv = f.uv[:] + f1.col = f.col[:] + f1.smooth = f.smooth + f1.mode = f.mode + f1.flag = f.flag + f1.mat = f.mat + + MESH2.materials = MESH.materials[:] + + try: + NewOBJECT=Blender.Object.Get('UVOBJECT') + CurSCENE=Blender.Scene.getCurrent() + except: + NewOBJECT, CurSCENE = GET_newobject('Mesh') + + NewOBJECT.link(MESH2) + + #NewOBJECT, CurSCENE = GET_newobject('Mesh') + #NewOBJECT.link(MESH2) + + NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0) + NewOBJECT.setEuler (0.0, 0.0, 0.0) + + MESH2.removeAllKeys() + + 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, n, n) + + v.co[2] = 0.0 + + print XYLIMIT + + MESH2.update() + MESH2.insertKey (FRAME, 'absolute') + MESH2.update() + imagename = 'uvtext' + + name = "CHANGE IMAGE NAME ? %t | Replace it | No replace | 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) + Blender.Redraw() + else: + Draw.PupMenu("Ready%t|Please check console for instructions") + print helpmsg + + else: + name = "Error%t|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) + print 'problem : no object selected or not mesh' + +Mesh2UVCoord() diff --git a/release/windows/installer/00.blender.nsi b/release/windows/installer/00.blender.nsi index 2ee972b97b9..86c3c1f8bc6 100644 --- a/release/windows/installer/00.blender.nsi +++ b/release/windows/installer/00.blender.nsi @@ -258,11 +258,13 @@ Section "Blender-VERSION (required)" SecCopyUI File DISTDIR\.blender\scripts\ac3d_export.py File DISTDIR\.blender\scripts\ac3d_import.py File DISTDIR\.blender\scripts\Apply_def.py + File DISTDIR\.blender\scripts\Axiscopy.py File DISTDIR\.blender\scripts\batch_name_edit.py File DISTDIR\.blender\scripts\bevel_center.py File DISTDIR\.blender\scripts\blender2cal3d.py File DISTDIR\.blender\scripts\bvh_export.py File DISTDIR\.blender\scripts\bvh_import.py + File DISTDIR\.blender\scripts\clean_mesh.py File DISTDIR\.blender\scripts\DirectX8Exporter.py File DISTDIR\.blender\scripts\DirectXExporter.py File DISTDIR\.blender\scripts\disp_paint.py @@ -282,8 +284,12 @@ Section "Blender-VERSION (required)" SecCopyUI File DISTDIR\.blender\scripts\knife.py File DISTDIR\.blender\scripts\lightwave_export.py File DISTDIR\.blender\scripts\lightwave_import.py + File DISTDIR\.blender\scripts\mod_ai2obj.py File DISTDIR\.blender\scripts\mod_blender.py + File DISTDIR\.blender\scripts\mod_eps2obj.py + File DISTDIR\.blender\scripts\mod_gimp2obj.py File DISTDIR\.blender\scripts\mod_meshtools.py + File DISTDIR\.blender\scripts\mod_svg2obj.py File DISTDIR\.blender\scripts\nendo_export.py File DISTDIR\.blender\scripts\nendo_import.py File DISTDIR\.blender\scripts\obdatacopier.py @@ -291,6 +297,7 @@ Section "Blender-VERSION (required)" SecCopyUI File DISTDIR\.blender\scripts\obj_import.py File DISTDIR\.blender\scripts\off_export.py File DISTDIR\.blender\scripts\off_import.py + File DISTDIR\.blender\scripts\paths_import.py File DISTDIR\.blender\scripts\radiosity_export.py File DISTDIR\.blender\scripts\radiosity_import.py File DISTDIR\.blender\scripts\raw_export.py @@ -298,6 +305,7 @@ Section "Blender-VERSION (required)" SecCopyUI File DISTDIR\.blender\scripts\renameobjectbyblock.py File DISTDIR\.blender\scripts\rvk1_torvk2.py File DISTDIR\.blender\scripts\sel_same.py + File DISTDIR\.blender\scripts\skin.py File DISTDIR\.blender\scripts\slp_import.py File DISTDIR\.blender\scripts\sysinfo.py File DISTDIR\.blender\scripts\truespace_export.py |