diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py index d5b25486937..35880682afa 100644 --- a/release/scripts/ac3d_export.py +++ b/release/scripts/ac3d_export.py @@ -2,7 +2,7 @@ """ Registration info for Blender menus: Name: 'AC3D (.ac)...' -Blender: 232 +Blender: 233 Group: 'Export' Submenu: 'All meshes...' all Submenu: 'Only selected...' sel @@ -13,8 +13,9 @@ Tip: 'Export to AC3D (.ac) format.' # $Id$ # # -------------------------------------------------------------------------- -# AC3DExport version 2.32-1 Jan 21, 2004 -# Program versions: Blender 2.32+ and AC3Db files (means version 0xb) +# AC3DExport version 2.34 +# Program versions: Blender 2.34 and AC3Db files (means version 0xb) +# new: minor tweaks, exporter didn't change # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -420,4 +421,5 @@ def fs_callback(filename): if __script__['arg'] == 'config': Draw.Register(gui, event, b_event) else: - Blender.Window.FileSelector(fs_callback, "Export AC3D") + fname = Blender.sys.makename(ext=".ac") + Blender.Window.FileSelector(fs_callback, "Export AC3D", fname) diff --git a/release/scripts/knife.py b/release/scripts/knife.py new file mode 100644 index 00000000000..d1df1007f1d --- /dev/null +++ b/release/scripts/knife.py @@ -0,0 +1,690 @@ +#!BPY + +""" +Name: 'Blender Knife Tool' +Blender: 232 +Group: 'Modifiers' +Tooltip: 'Cut a mesh along a plane w/o creating doubles' +""" + +# $Id$ +# +################################################################### +# # +# Blender Knife Tool # +# # +# v. 0.0.0 - 0.0.6 (C) December 2002 Stefano Selleri # +# v. 0.0.7 (C) March 2004 Wim Van Hoydonck # +# v. 0.0.8 (C) March 2004 Wim Van Hoydonck & Stefano Selleri# +# # +# Released under the Blender Artistic Licence (BAL) # +# See www.blender.org # +# # +# Works in Blender 2.32 and higher # +# # +# this script can be found online at: # +# http://users.pandora.be/tuinbels/scripts/knife-0.0.8.py # +# http://www.selleri.org/Blender # +# # +# email: tuinbels@hotmail.com # +# selleri@det.unifi.it # +################################################################### +# History # +# V: 0.0.0 - 08-12-02 - The script starts to take shape, a # +# history is now deserved :) # +# 0.0.1 - 09-12-02 - The faces are correctly selected and # +# assigned to the relevant objects now the # +# hard (splitting) part... # +# 0.0.2 - 14-12-02 - Still hacking on the splitting... # +# It works, but I have to de-globalize # +# the intersection coordinates # +# 0.0.3 - 15-12-02 - First Alpha version # +# 0.0.4 - 17-12-02 - Upgraded accordingly to eeshlo tips # +# Use Matrices for coordinate transf. # +# Add a GUI # +# Make it Run on 2.23 # +# 0.0.5 - 17-12-02 - Eeshlo solved some problems.... # +# Theeth too adviced me # +# 0.0.6 - 18-12-02 - Better error messages # +# 0.0.7 - 26-03-04 - Developer team doubles! # +# This version is by Wim! # +# Doesn't create doubles (AFAIK) # +# - Faster (for small meshes), global # +# coordinates of verts are calculated only # +# once # +# - Editing the CutPlane in editmode (move) # +# shouldn't cause problems anymore # +# - Menu button added to choose between the # +# different Edit Methods # +# - If a mesh is cut twice at the same place, # +# this gives errors :( (also happened in # +# previous versions) # +# - Willian Padovani Germano solved # +# a problem, many thanks :) # +# - Stefano Selleri made some good # +# suggestions, thanks :) # +# 0.0.8 - 26-03-04 - General Interface rewrite (Stefano) # +# 0.0.8a- 31-03-04 - Added some error messages # +# - Cut multiple meshes at once # +# # +################################################################### + +import Blender +from Blender import * +from Blender.sys import time +from math import * + +Epsilon = 0.00001 +msg = '' +RBmesh0 = Draw.Create(0) +RBmesh1 = Draw.Create(0) +RBmesh2 = Draw.Create(1) + +VERSION = '0.0.8' + +# see if time module is available +#try: +# import time +# timport = 1 +#except: +# timport = 0 + + +BL_VERSION = Blender.Get('version') +if (BL_VERSION<=223): + import Blender210 + +#=================================# +# Vector and matrix manipulations # +#=================================# + +# vector addition +def vecadd(a, b): + return [a[0] - b[0], a[1] - b[1], a[2] + b[2]] + +# vector substration +def vecsub(a, b): + return [a[0] - b[0], a[1] - b[1], a[2] - b[2]] + +# vector crossproduct +def veccross(x, y): + v = [0, 0, 0] + v[0] = x[1]*y[2] - x[2]*y[1] + v[1] = x[2]*y[0] - x[0]*y[2] + v[2] = x[0]*y[1] - x[1]*y[0] + return v + +# vector dotproduct +def vecdot(x, y): + return x[0]*y[0] + x[1]*y[1] + x[2]*y[2] + +# vector length +def length(v): + return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) + +# vector multiplied by constant s +def vecmul(a, s): + return[a[0]*s, a[1]*s, a[2]*s] + +# vector divided by constant s +def vecdiv(a, s): + if s!=0.0: s = 1.0/s + return vecmul(a, s) + +# matrix(4x3) vector multiplication +def mulmatvec4x3(a, b): + # a is vector, b is matrix + r = [0, 0, 0] + r[0] = a[0]*b[0][0] + a[1]*b[1][0] + a[2]*b[2][0] + b[3][0] + r[1] = a[0]*b[0][1] + a[1]*b[1][1] + a[2]*b[2][1] + b[3][1] + r[2] = a[0]*b[0][2] + a[1]*b[1][2] + a[2]*b[2][2] + b[3][2] + return r + +# Normalization of a vector +def Normalize(a): + lengte = length(a) + return vecdiv(a, lengte) + +# calculate normal from 3 verts +def Normal(v0, v1, v2): + return veccross(vecsub(v0, v1),vecsub(v0, v2)) + +#===========================# +# Coordinatetransformations # +#===========================# + +def GlobalPosition(P, Obj): + + if (BL_VERSION<=223): + m = Obj.matrix + else: + m = Obj.getMatrix() + + return mulmatvec4x3(P, m) + +def LocalPosition(P, Obj): + + if (BL_VERSION<=223): + m = Blender210.getObject(Obj.name).inverseMatrix + else: + m = Obj.getInverseMatrix() + + return mulmatvec4x3(P, m) + +#================# +# Get Plane Data # +#================# + +def PlaneData(Plane): + global msg + # + # Calculate: + # - the normal of the plane, + # - the offset of the plane wrt the global coordinate system + # in the direction of the normal of the plane + # + PlaneMesh = NMesh.GetRawFromObject(Plane.name) + + if (len(PlaneMesh.faces)>1): + msg = "ERROR: Active object must be a single face plane" + return ((0,0,0),(0,0,0),1) + else: + if (len(PlaneMesh.verts)<3): + msg = "ERROR: 3 vertices needed to define a plane" + return ((0,0,0),(0,0,0),1) + else: + v0 = GlobalPosition(PlaneMesh.faces[0].v[0].co, Plane) + v1 = GlobalPosition(PlaneMesh.faces[0].v[1].co, Plane) + v2 = GlobalPosition(PlaneMesh.faces[0].v[2].co, Plane) + + # the normal of the plane, calculated from the first 3 verts + PNormal = Normalize(Normal(v0,v1,v2)) + + # offset of the plane, using 1st vertex instead of Plane.getLocaction() + POffset = vecdot(v0,PNormal) + + return PNormal, POffset, 0 + +#====================================# +# Position with respect to Cut Plane # +#====================================# + +def Distance(P, N, d0): + # + # distance from a point to a plane + # + return vecdot(P, N) - d0 + +def FacePosition(dist): + # + # position of a face wrt to the plane + # + np, nn, nz = 0, 0, 0 + + for d in dist: + + # the distances are calculated in advance + if d > 0: + np += 1 + elif d < 0: + nn += 1 + else: + nz += 1 + + if np == 0: + return -1 + if nn == 0: + return 1 + return 0 + +#==========================================# +# Append existing faces / create new faces # +#==========================================# + +def FaceAppend(me, fidx): + # + # append a face to a mesh based on a list of vertex-indices + # + nf = NMesh.Face() + + for i in fidx: + nf.v.append(me.verts[i]) + me.faces.append(nf) + +def FaceMake(me, vl): + # + # make one or two new faces based on a list of vertex-indices + # + idx = len(me.verts) + + if len(vl) <= 4: + nf = NMesh.Face() + for i in range(len(vl)): + nf.v.append(me.verts[vl[i]]) + me.faces.append(nf) + else: + nf = NMesh.Face() + nf.v.append(me.verts[vl[0]]) + nf.v.append(me.verts[vl[1]]) + nf.v.append(me.verts[vl[2]]) + nf.v.append(me.verts[vl[3]]) + me.faces.append(nf) + + nf = NMesh.Face() + nf.v.append(me.verts[vl[3]]) + nf.v.append(me.verts[vl[4]]) + nf.v.append(me.verts[vl[0]]) + me.faces.append(nf) + +#=====================================# +# Generate vertex lists for new faces # +#=====================================# + +def Split(Obj, MeshPos, MeshNeg, Vglob, Vidx, N, d0, newvidx, newvcoo, totverts, d): + # + # - calculate intersectionpoints of the plane with faces + # - see if this intersectionpoint already exists (look for vertices close to the new vertex) + # - if it does not yet exist, append a vertex to the mesh, + # remember its index and location and append the index to the appropriate vertex-lists + # - if it does, use that vertex (and its index) to create the face + # + + vp = [] + vn = [] + + # distances of the verts wrt the plane are calculated in main part of script + + for i in range(len(d)): + # the previous vertex + dim1 = d[int(fmod(i-1,len(d)))] + Vim1 = Vglob[int(fmod(i-1,len(d)))] + + if abs(d[i]) < Epsilon: + # if the vertex lies in the cutplane + vp.append(Vidx[i]) + vn.append(Vidx[i]) + else: + if abs(dim1) < Epsilon: + # if the previous vertex lies in cutplane + if d[i] > 0: + vp.append(Vidx[i]) + else: + vn.append(Vidx[i]) + else: + if d[i]*dim1 > 0: + # if they are on the same side of the plane + if d[i] > 0: + vp.append(Vidx[i]) + else: + vn.append(Vidx[i]) + else: + # the vertices are not on the same side of the plane, so we have an intersection + + Den = vecdot(vecsub(Vglob[i],Vim1),N) + + Vi = [] + Vi.append ( ((Vim1[0]*Vglob[i][1]-Vim1[1]*Vglob[i][0])*N[1]+(Vim1[0]*Vglob[i][2]-Vim1[2]*Vglob[i][0])*N[2]+(Vglob[i][0]-Vim1[0])*d0)/Den) + Vi.append ( ((Vim1[1]*Vglob[i][0]-Vim1[0]*Vglob[i][1])*N[0]+(Vim1[1]*Vglob[i][2]-Vim1[2]*Vglob[i][1])*N[2]+(Vglob[i][1]-Vim1[1])*d0)/Den) + Vi.append ( ((Vim1[2]*Vglob[i][0]-Vim1[0]*Vglob[i][2])*N[0]+(Vim1[2]*Vglob[i][1]-Vim1[1]*Vglob[i][2])*N[1]+(Vglob[i][2]-Vim1[2])*d0)/Den) + + ViL = LocalPosition(Vi, Obj) + + if newvidx == []: + # if newvidx is empty (the first time Split is called), append a new vertex + # to the mesh and remember its vertex-index and location + ViLl = NMesh.Vert(ViL[0],ViL[1],ViL[2]) + + if MeshPos == MeshNeg: + MeshPos.verts.append(ViLl) + + else: + MeshPos.verts.append(ViLl) + MeshNeg.verts.append(ViLl) + + nvidx = totverts + newvidx.append(nvidx) + newvcoo.append(ViL) + + vp.append(nvidx) + vn.append(nvidx) + else: + # newvidx is not empty + dist1 = [] + tlr = 0 + for j in range(len(newvidx)): + # calculate the distance from the new vertex to the vertices + # in the list with new vertices + dist1.append(length(vecsub(ViL, newvcoo[j]))) + for k in range(len(dist1)): + if dist1[k] < Epsilon: + # if distance is smaller than epsilon, use the other vertex + # use newvidx[k] as vert + vp.append(newvidx[k]) + vn.append(newvidx[k]) + break # get out of closest loop + else: + tlr += 1 + + if tlr == len(newvidx): + nvidx = totverts + len(newvidx) + ViLl = NMesh.Vert(ViL[0],ViL[1],ViL[2]) + + if MeshPos == MeshNeg: + MeshPos.verts.append(ViLl) + + else: + MeshPos.verts.append(ViLl) + MeshNeg.verts.append(ViLl) + + newvidx.append(nvidx) + newvcoo.append(ViL) + vp.append(nvidx) + vn.append(nvidx) + + if d[i] > 0: + vp.append(Vidx[i]) + else: + vn.append(Vidx[i]) + + return vp, vn, newvidx, newvcoo + +#===========# +# Main part # +#===========# + +def CutMesh(): + global msg + global RBmesh0,RBmesh1,RBmesh2 + #if timport == 1: + # start = time.clock() + start = time() + + selected_obs = Object.GetSelected() + + total = len(selected_obs) + + NoErrors=0 + + meshes = 0 + + # check to see if every selected object is a mesh + for ob in selected_obs: + type = ob.getType() + if type == 'Mesh': + meshes += 1 + + # at least select two objects + if meshes <= 1: + msg = "ERROR: At least two objects should be selected" + NoErrors = 1 + + # if not every object is a mesh + if meshes != total: + msg = "ERROR: You should only select meshobjects" + NoErrors=1 + + # everything is ok + if NoErrors == 0: + Pln = selected_obs[0] + PNormal, POffset, NoErrors = PlaneData(Pln) + + # loop to cut multiple meshes at once + for o in range(1, total): + + Obj = selected_obs[o] + + if (NoErrors == 0) : + + m = Obj.getData() + + if RBmesh1.val == 1: + + MeshNew = NMesh.GetRaw() + + if RBmesh2.val == 1: + + MeshPos = NMesh.GetRaw() + MeshNeg = NMesh.GetRaw() + + # get the indices of the faces of the mesh + idx = [] + for i in range(len(m.faces)): + idx.append(i) + + # if idx is not reversed, this results in a list index out of range if + # the original mesh is used (RBmesh1 == 0) + idx.reverse() + + lenface, vertglob, vertidx, vertdist = [], [], [], [] + + # total number of vertices + totverts = len(m.verts) + + # for every face: calculate global coordinates of the vertices + # append the vertex-index to a list + # calculate distance of vertices to cutplane in advance + + for i in idx: + fvertidx, Ve, dist = [], [], [] + fa = m.faces[i] + lenface.append(len(fa)) + for v in fa.v: + globpos = GlobalPosition(v.co, Obj) + Ve.append(globpos) + fvertidx.append(v.index) + dist.append(Distance(globpos, PNormal, POffset)) + vertidx.append(fvertidx) + vertglob.append(Ve) + vertdist.append(dist) + + + # append the verts of the original mesh to the new mesh + if RBmesh1.val == 1: + for v in m.verts: + MeshNew.verts.append(v) + + if RBmesh2.val == 1: + idx2 = [] + dist2 = [] + for v in m.verts: + MeshPos.verts.append(v) + MeshNeg.verts.append(v) + idx2.append(v.index) + dist2.append(Distance(GlobalPosition(v.co, Obj), PNormal, POffset)) + + # remove all faces of m if the original object has to be used + + if RBmesh0.val == 1: + m.faces = [] + + newvidx, newvcoo = [], [] + testidxpos, testidxneg = [], [] + + # what its all about... + for i in idx: + fp = FacePosition(vertdist[i]) + + # no intersection + if fp > 0: + if RBmesh0.val == 1: + FaceAppend(m, vertidx[i]) + + elif RBmesh1.val == 1: + FaceAppend(MeshNew, vertidx[i]) + + elif RBmesh2.val == 1: + FaceAppend(MeshPos, vertidx[i]) + + if testidxpos == []: + testidxpos = vertidx[i] + elif fp < 0: + if RBmesh0.val == 1: + FaceAppend(m, vertidx[i]) + elif RBmesh1.val == 1: + FaceAppend(MeshNew, vertidx[i]) + + elif RBmesh2.val == 1: + FaceAppend(MeshNeg, vertidx[i]) + + if testidxneg == []: + testidxneg = vertidx[i] + + # intersected faces + else: + # make new mesh + if RBmesh1.val == 1: + vlp, vln, newvidx, newvcoo = Split(Obj, MeshNew, MeshNew, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i]) + + if vlp != 0 and vln != 0: + FaceMake(MeshNew, vlp) + FaceMake(MeshNew, vln) + # two new meshes + elif RBmesh2.val == 1: + vlp, vln, newvidx, newvcoo = Split(Obj, MeshPos, MeshNeg, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i]) + + if vlp != 0 and vln != 0: + FaceMake(MeshPos, vlp) + FaceMake(MeshNeg, vln) + + # use old mesh + elif RBmesh0.val == 1: + + vlp, vln, newvidx, newvcoo = Split(Obj, m, m, vertglob[i], vertidx[i], PNormal, POffset, newvidx, newvcoo, totverts, vertdist[i]) + + if vlp != 0 and vln != 0: + FaceMake(m, vlp) + FaceMake(m, vln) + + if RBmesh1.val == 1: + + ObOne = NMesh.PutRaw(MeshNew) + + ObOne.LocX, ObOne.LocY, ObOne.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ + ObOne.RotX, ObOne.RotY, ObOne.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ + ObOne.SizeX, ObOne.SizeY, ObOne.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ + + elif RBmesh2.val == 1: + + # remove verts that do not belong to a face + idx2.reverse() + dist2.reverse() + + for i in range(len(idx2)): + if dist2[i] < 0: + v = MeshPos.verts[idx2[i]] + MeshPos.verts.remove(v) + if dist2[i] > 0: + v = MeshNeg.verts[idx2[i]] + MeshNeg.verts.remove(v) + + ObPos = NMesh.PutRaw(MeshPos) + + ObPos.LocX, ObPos.LocY, ObPos.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ + ObPos.RotX, ObPos.RotY, ObPos.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ + ObPos.SizeX, ObPos.SizeY, ObPos.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ + + ObNeg = NMesh.PutRaw(MeshNeg) + + ObNeg.LocX, ObNeg.LocY, ObNeg.LocZ = Obj.LocX, Obj.LocY, Obj.LocZ + ObNeg.RotX, ObNeg.RotY, ObNeg.RotZ = Obj.RotX, Obj.RotY, Obj.RotZ + ObNeg.SizeX, ObNeg.SizeY, ObNeg.SizeZ = Obj.SizeX, Obj.SizeY, Obj.SizeZ + + elif RBmesh0.val == 1: + m.update() + + + #if timport == 1: + #end = time.clock() + #total = end - start + #print "mesh(es) cut in", total, "seconds" + + end = time() + total = end - start + print "mesh(es) cut in", total, "seconds" + +############################################################# +# Graphics # +############################################################# +def Warn(): + BGL.glRasterPos2d(115, 23) + Blender.Window.Redraw(Blender.Window.Const.TEXT) + +def draw(): + global msg + global RBmesh0,RBmesh1,RBmesh2 + global VERSION + + BGL.glClearColor(0.5, 0.5, 0.5, 0.0) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) + BGL.glColor3f(0, 0, 0) # Black + BGL.glRectf(2, 2, 482, 220) + BGL.glColor3f(0.48, 0.4, 0.57) # Light Purple + BGL.glRectf(4, 179, 480, 210) + BGL.glRectf(4, 34, 480, 150) + BGL.glColor3f(0.3, 0.27, 0.35) # Dark purple + BGL.glRectf(4, 151,480, 178) + BGL.glRectf(4, 4, 480, 33) + + + BGL.glColor3f(1, 1, 1) + BGL.glRasterPos2d(8, 200) + Draw.Text("Blender Knife Tool - V. 0.0.8a - 26 March 2004") + BGL.glRasterPos2d(8, 185) + Draw.Text("by Wim Van Hoydonck & Stefano Selleri") + Draw.Button("Exit", 1, 430, 185, 40, 20) + + RBmesh0 = Draw.Toggle("Edit Object", 10,10,157,153,18,RBmesh0.val, "The knife creates new vertices in the selected object."); + RBmesh1 = Draw.Toggle("New Object", 11,165,157,153,18,RBmesh1.val, "The knife duplicates the object and creates new vertices in the new object."); + RBmesh2 = Draw.Toggle("Two New Objects",12,320,157,153,18,RBmesh2.val, "The knife creates two new separate objects."); + + BGL.glRasterPos2d(8, 128) + Draw.Text("1 - Draw a Mesh Plane defining the Cut Plane") + BGL.glRasterPos2d(8, 108) + Draw.Text("2 - Select the Meshes to be Cut and the Cut Plane") + BGL.glRasterPos2d(8, 88) + Draw.Text(" (Meshes Dark Purple, Plane Light Purple)") + BGL.glRasterPos2d(8, 68) + Draw.Text("3 - Choose the Edit Method (Radio Buttons above)") + BGL.glRasterPos2d(8, 48) + Draw.Text("4 - Push the 'CUT' button (below)") + #Create Buttons + Draw.Button("CUT", 4, 10, 10, 465, 18, "Cut the selected mesh along the plane") + + + BGL.glRasterPos2d(10, 223) + BGL.glColor3f(1,0,0) + Draw.Text(msg) + msg = '' + +def event(evt, val): + if evt == Draw.QKEY and not val: + Draw.Exit() + if evt == Draw.CKEY and not val: + CutMesh() + Draw.Redraw() + +def bevent(evt): + global RBmesh0,RBmesh1,RBmesh2 + + if evt == 1: + Draw.Exit() + elif evt == 4: + CutMesh() + Draw.Redraw() + elif evt == 10: + RBmesh0.val = 1 + RBmesh1.val = 0 + RBmesh2.val = 0 + Draw.Redraw() + elif evt == 11: + RBmesh0.val = 0 + RBmesh1.val = 1 + RBmesh2.val = 0 + Draw.Redraw() + elif evt == 12: + RBmesh0.val = 0 + RBmesh1.val = 0 + RBmesh2.val = 1 + Draw.Redraw() + +Draw.Register(draw, event, bevent) diff --git a/source/blender/python/api2_2x/Scene.c b/source/blender/python/api2_2x/Scene.c index 8fa1802fe24..218610a67e5 100644 --- a/source/blender/python/api2_2x/Scene.c +++ b/source/blender/python/api2_2x/Scene.c @@ -37,6 +37,7 @@ #include /* for copy_scene */ #include /* for set_scene */ #include /* for copy_view3d_lock() */ +#include #include /* for MEM_callocN */ #include /* for #define REDRAW */ @@ -97,6 +98,7 @@ static PyObject *Scene_getChildren(BPy_Scene *self); static PyObject *Scene_getCurrentCamera(BPy_Scene *self); static PyObject *Scene_setCurrentCamera(BPy_Scene *self, PyObject *args); static PyObject *Scene_getRenderingContext(BPy_Scene *self); +static PyObject *Scene_getScriptlinks(BPy_Scene *self, PyObject *args); //deprecated methods static PyObject *Scene_currentFrame(BPy_Scene *self, PyObject *args); @@ -140,6 +142,9 @@ static PyMethodDef BPy_Scene_methods[] = { "() - Return list of all objects linked to scene self"}, {"getCurrentCamera", (PyCFunction)Scene_getCurrentCamera, METH_NOARGS, "() - Return current active Camera"}, + {"getScriptlinks", (PyCFunction)Scene_getScriptlinks, METH_VARARGS, + "(eventname) - Get a list of this scene's scriptlinks (Text names) of the given type\n" + "(eventname) - string: FrameChanged, OnLoad or Redraw."}, {"setCurrentCamera", (PyCFunction)Scene_setCurrentCamera, METH_VARARGS, "() - Set the currently active Camera"}, //DEPRECATED @@ -693,7 +698,7 @@ static PyObject *Scene_setCurrentCamera (BPy_Scene *self, PyObject *args) { Object *object; BPy_Object *cam_obj; - Scene *scene = self->scene; + Scene *scene = self->scene; if (!scene) return EXPP_ReturnPyObjError (PyExc_RuntimeError, @@ -725,6 +730,55 @@ static PyObject *Scene_getRenderingContext (BPy_Scene *self) return RenderData_CreatePyObject(self->scene); } + +/* Scene.getScriptlinks */ +static PyObject *Scene_getScriptlinks (BPy_Scene *self, PyObject *args) +{ + Scene *scene = self->scene; + char *eventname = NULL; + int event = 0; + ScriptLink *slink = &(scene)->scriptlink; + + if (!scene) + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "Blender Scene was deleted!"); + + if (!PyArg_ParseTuple(args, "s", &eventname)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected event name (string) as argument"); + + if (!strcmp(eventname, "FrameChanged")) + event = SCRIPT_FRAMECHANGED; + else if (!strcmp(eventname, "OnLoad")) + event = SCRIPT_ONLOAD; + else if (!strcmp(eventname, "Redraw")) + event = SCRIPT_REDRAW; + else + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "unknown event"); + + /* actually !scriptlink shouldn't happen ... */ + if (!slink || !slink->totscript) { + Py_INCREF(Py_None); + return Py_None; + } + else { + PyObject *list = PyList_New(0); + int i; + + if (!list) + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyList!"); + + for (i = 0; i < slink->totscript; i++) { + if ((slink->flag[i] == event) && slink->scripts[i]) + PyList_Append(list, PyString_FromString(slink->scripts[i]->name+2)); + } + + return list; + } +} + /*****************************************************************************/ // DEPRECATED /*****************************************************************************/ diff --git a/source/blender/python/api2_2x/Sys.c b/source/blender/python/api2_2x/Sys.c index 81488c2c676..b2c133d6881 100644 --- a/source/blender/python/api2_2x/Sys.c +++ b/source/blender/python/api2_2x/Sys.c @@ -42,6 +42,7 @@ static PyObject *M_sys_basename (PyObject *self, PyObject *args); static PyObject *M_sys_dirname (PyObject *self, PyObject *args); static PyObject *M_sys_splitext (PyObject *self, PyObject *args); +static PyObject *M_sys_makename (PyObject *self, PyObject *args, PyObject *kw); static PyObject *M_sys_exists (PyObject *self, PyObject *args); static PyObject *M_sys_time (PyObject *self); @@ -69,6 +70,17 @@ static char M_sys_splitext_doc[] = /this/that/file.ext -> ('/this/that/file','.ext').\n\ Return the pair (root, extension)."; +static char M_sys_makename_doc[] = +"(path = Blender.Get('filename'), ext = \"\", strip = 0) -\n\ +Strip dir and extension from path, leaving only a name, then append 'ext'\n\ +to it (if given) and return the resulting string.\n\n\ +(path) - string: a pathname -- Blender.Get('filename') if 'path' isn't given;\n\ +(ext = \"\") - string: the extension to append.\n\ +(strip = 0) - int: strip dirname from 'path' if given and non-zero.\n\ +Ex: makename('/path/to/file/myfile.foo','-01.abc') returns 'myfile-01.abc'\n\ +Ex: makename(ext='.txt') returns 'untitled.txt' if Blender.Get('filename')\n\ +returns a path to the file 'untitled.blend'"; + static char M_sys_time_doc[] = "() - Return a float representing time elapsed in seconds.\n\ Each successive call is garanteed to return values greater than or\n\ @@ -84,6 +96,8 @@ struct PyMethodDef M_sys_methods[] = { {"basename", M_sys_basename, METH_VARARGS, M_sys_basename_doc}, {"dirname", M_sys_dirname, METH_VARARGS, M_sys_dirname_doc}, {"splitext", M_sys_splitext, METH_VARARGS, M_sys_splitext_doc}, + {"makename", (PyCFunction)M_sys_makename, METH_VARARGS|METH_KEYWORDS, + M_sys_makename_doc}, {"exists", M_sys_exists, METH_VARARGS, M_sys_exists_doc}, {"time", (PyCFunction)M_sys_time, METH_NOARGS, M_sys_time_doc}, {NULL, NULL, 0, NULL} @@ -145,7 +159,7 @@ static PyObject *M_sys_basename (PyObject *self, PyObject *args) return EXPP_ReturnPyObjError(PyExc_RuntimeError, "path too long"); strncpy(basename, p+1, n); /* + 1 to skip the sep */ - basename[n] = 0; + basename[n] = '\0'; return Py_BuildValue("s", basename); } @@ -177,11 +191,11 @@ static PyObject *M_sys_dirname (PyObject *self, PyObject *args) return EXPP_ReturnPyObjError (PyExc_RuntimeError, "path too long"); strncpy(dirname, name, n); - dirname[n] = 0; + dirname[n] = '\0'; return Py_BuildValue("s", dirname); } - return Py_BuildValue("s", "."); /* XXX need to fix this? (is crossplatform?)*/ + return Py_BuildValue("s", "."); } static PyObject *M_sys_splitext (PyObject *self, PyObject *args) @@ -220,13 +234,71 @@ static PyObject *M_sys_splitext (PyObject *self, PyObject *args) EXPP_ReturnPyObjError(PyExc_RuntimeError, "path too long"); strncpy(ext, dot, n); - ext[n] = 0; + ext[n] = '\0'; strncpy(path, name, dot - name); - path[dot - name] = 0; + path[dot - name] = '\0'; return Py_BuildValue("ss", path, ext); } +static PyObject *M_sys_makename(PyObject *self, PyObject *args, PyObject *kw) +{ + char *path = G.sce, *ext = NULL; + int strip = 0; + static char *kwlist[] = {"path", "ext", "strip", NULL}; + char *dot = NULL, *p = NULL, basename[FILE_MAXFILE]; + char sep; + int n, len, lenext = 0; + PyObject *c; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|ssi", kwlist, + &path, &ext, &strip)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected one or two strings and an int (or nothing) as arguments"); + + len = strlen(path); + if (ext) lenext = strlen(ext); + + if ((len + lenext) > FILE_MAXFILE) + return EXPP_ReturnPyObjError(PyExc_RuntimeError, "path too long"); + + c = PyObject_GetAttrString (g_sysmodule, "dirsep"); + sep = PyString_AsString(c)[0]; + Py_DECREF(c); + + p = strrchr(path, sep); + + if (p && strip) { + n = path + len - p - 1; /* - 1 because we don't want the sep */ + + strncpy(basename, p+1, n); /* + 1 to skip the sep */ + basename[n] = 0; + } + else { + strncpy(basename, path, len); + n = len; + basename[n] = '\0'; + } + + dot = strrchr(basename, '.'); + + /* now the extension: always remove the one in basename */ + if (dot || ext) { + if (!ext) + basename[dot - basename] = '\0'; + else { /* if user gave an ext, append it */ + + if (dot) n = dot - basename; + else n = strlen(basename); + + strncpy(basename + n, ext, lenext); + basename[n+lenext] = '\0'; + } + } + + return PyString_FromString(basename); +} + static PyObject *M_sys_time (PyObject *self) { double t = PIL_check_seconds_timer(); diff --git a/source/blender/python/api2_2x/doc/Sys.py b/source/blender/python/api2_2x/doc/Sys.py index 515bc6e3fee..d969fe545b4 100644 --- a/source/blender/python/api2_2x/doc/Sys.py +++ b/source/blender/python/api2_2x/doc/Sys.py @@ -68,6 +68,35 @@ def splitext (path): @return: (root, ext) """ +def makename (path = "Blender.Get('filename')", ext = "", strip = 0): + """ + Remove extension from 'path', append extension 'ext' (if given) + to the result and return it. If 'strip' is non-zero, also remove + dirname from path. + + Example:: + import Blender + from Blender.sys import * + print makename('/path/to/myfile.txt','.abc', 1) # returns 'myfile.abc' + + print makename('/path/to/myfile.obj', '-01.obj') # '/path/to/myfile-01.obj' + + print makename('/path/to/myfile.txt', strip = 1) # 'myfile' + + # note that: + print makename(ext = '.txt') + # is equivalent to: + print sys.splitext(Blender.Get('filename'))[0]) + '.txt' + + @type path: string + @param path: a path name or Blender.Get('filename'), if not given. + @type ext: string + @param ext: an extension to append. For flexibility, a dot ('.') is + not automatically included. + @rtype: string + @return: the resulting string + """ + def exists(path): """ Tell if the given pathname (file or dir) exists.