Initial revision
[blender.git] / intern / python / modules / beta / Scenegraph.py
1
2 """This is a basic scenegraph module for Blender
3 It contains low level API calls..."""
4
5 # (c) 2001, Martin Strubel // onk@section5.de
6
7 from utils import quat #quaternions
8
9 from Blender import Object, Lamp, Scene
10
11
12 TOLERANCE = 0.01
13
14 def uniform_scale(vec):
15         v0 = vec[0]
16         d = abs(vec[1] - v0)
17         if d > TOLERANCE:
18                 return 0
19         d = abs(vec[2] - v0) 
20         if d > TOLERANCE:
21                 return 0
22         return v0
23
24 class Transform:
25         """An abstract transform, containing translation, rotation and scale information"""
26         def __init__(self):
27                 self.scale = (1.0, 1.0, 1.0)
28                 self.translation = (0.0, 0.0, 0.0)
29                 self.rotation = quat.Quat()
30                 self.scaleOrientation = quat.Quat() # axis, angle
31                 self.parent = None
32         def __mul__(self, other):
33                 s = uniform_scale(self.scale)
34                 if not s:
35                         raise RuntimeError, "non uniform scale, can't multiply"
36                 t = Transform()
37                 sc = other.scale
38                 t.scale = (s * sc[0], s * sc[1], s * sc[2])
39                 t.rotation = self.rotation * other.rotation
40                 tr = s * apply(quat.Vector, other.translation) 
41                 t.translation = self.rotation.asMatrix() * tr + self.translation
42                 return t
43         def getLoc(self):
44                 t = self.translation
45                 return (t[0], t[1], t[2]) # make sure it's a tuple..silly blender
46         def calcRotfromAxis(self, axisrotation):
47                 self.rotation = apply(quat.fromRotAxis,axisrotation)
48         def getRot(self):
49                 return self.rotation.asEuler()
50         def getSize(self):
51                 s = self.scale
52                 return (s[0], s[1], s[2])
53         def __repr__(self):
54                 return "Transform: rot: %s loc:%s" % (self.getRot(), self.getLoc())
55         def copy(self):
56                 "returns copy of self"
57                 t = Transform()
58                 t.scale = self.scale
59                 t.translation = self.translation
60                 t.rotation = self.rotation
61                 t.scaleOrientation  = self.scaleOrientation
62                 return t
63
64 class BID:
65         "Blender named Object ID"
66         def __init__(self, name):
67                 self.name = name
68                 self.data = None
69
70 class BScene:
71         def __init__(self, name = None):
72                 from Blender import Scene
73                 self.dict = {'Image': {}, 'Object':{}, 'Mesh' : {}}
74                 self.name = name
75         def __getitem__(self, name):
76                 return self.dict[name]
77         def __setitem__(self, name, val):
78                 self.dict[name] = val
79         def has_key(self, name):
80                 if self.dict.has_key(name):
81                         return 1
82                 else:
83                         return 0
84         def getnewID(self, templ):
85                 n = 0
86                 name = templ
87                 while self.dict.has_key(name):
88                         n += 1
89                         name = "%s.%03d" % (templ, n)
90                 return name     
91                         
92 class BSGNode:
93         "Blender Scenegraph node"
94         isRoot = 0
95         def __init__(self, object = None, type = "", name = ""):
96                 self.type = type
97                 self.name = name
98                 self.children = []
99                 self.level = 0
100                 self.object = object
101         def addChildren(self, children):
102                 self.children += children
103         def traverse(self, visitor):
104                 ret = visitor()
105                 for c in self.children:
106                         c.traverse(visitor)
107                 return ret
108         def setDepth(self, level):
109                 self.level = level
110                 for c in self.children:
111                         c.setDepth(level + 1)
112         def update(self):
113                 ob.name = self.name
114         def __repr__(self):
115                 l = self.level
116                 children = ""
117                 pre = l * ' '
118                 return "\n%s%s [%s] ->%s" % (pre, self.name, self.type, self.children)
119
120 class ObjectNode(BSGNode):
121         def __init__(self, object = None, type = "", name = ""):
122                 self.transform = Transform()
123                 self.scene = Scene.getCurrent()
124                 BSGNode.__init__(self, object, type, name)
125         def makeParent(self, child):
126                 self.child = parent
127                 child.parent = self
128         def clone(self):
129                 ob = self.object
130                 newob = ob.copy()
131                 self.scene.link(newob)
132                 new = ObjectNode(newob)
133                 new.transform = self.transform.copy()
134                 return new
135         def insert(self, child):
136                 self.children.append(child)
137                 child.level = self.level + 1
138                 ob = child.object
139                 self.object.makeParent([ob], 1, 1)
140                 # first parent, THEN set local transform
141                 child.update()
142         def applyTransform(self, tf):
143                 self.transform = tf * self.transform
144         def update(self):
145                 ob = self.object
146                 t = self.transform
147                 ob.loc = t.getLoc()
148                 ob.size = t.getSize()
149                 ob.rot = t.getRot()
150                 ob.name = self.name
151
152 def NodefromData(ob, type, name):
153         new = ObjectNode(None, type, name)
154         if ob:
155                 obj = ob
156         else:
157                 obj = Object.New(type)
158                 Scene.getCurrent().link(obj)
159                 if not obj:
160                         raise RuntimeError, "FATAL: could not create object"
161         new.object= obj
162         new.object.name = name
163         #new.fromData(ob)
164         return new
165
166 class RootNode(ObjectNode):
167         """stupid simple scenegraph prototype"""
168         level = 0
169         isRoot = 1
170         type = 'Root'
171         name = 'ROOT'
172
173         def __init__(self, object = None, type = "", name = ""):
174                 from Blender import Scene
175                 self.transform = Transform()
176                 BSGNode.__init__(self, object, type, name)
177                 self.scene = Scene.getCurrent()
178         def insert(self, child):
179                 child.update()
180                 self.children.append(child)
181         def update(self):
182                 self.scene.update()