bugfix
[pyworlds.git] / src / pyworlds / worlds.py
blobfbbce2f95f940e2e980f898ab3830623c23d7e15
1 import sys, os, os.path, soya
2 import soya.widget as widget
3 from soya import sdlconst
4 import soya.widget
5 import math
7 from utils import *
8 import pyworlds.basics.scene
10 global scene,camera,light
11 global MOUSE_WHEEL
14 scene = None
15 camera = None
16 light = None
17 pyworlds_engine = ""
18 # TODO: Create a full-camera class to handle several kinds of performance for cameras
20 animated_meshes = {}
21 meshes = {}
22 KEY = {}
23 MOUSE_X = 0
24 MOUSE_Y = 0
25 MOUSE_BUTTON = {}
26 MOUSE_BUTTONUP = []
27 MOUSE_WHEEL = 0
29 # TODO: Place functions to access KEY, and return float or bool values. x>0.5 => True
30 callback_round = None
31 callback_advance = None
32 # TODO: Add the user-callback
33 scene_body = None
34 # TODO: Delete scene_body and use main Soya callbacks
36 enable_fps = False
38 # Import Psyco if available
39 try:
40 import psyco
41 psyco.full()
42 print "Psyco found and started -- Python code accelerated."
43 except ImportError:
44 print "I can't find PsyCo -- install it to get more speed"
45 pass
49 def is_pyWorlds_installed():
50 print "pyWorlds seem to be installed and working."
51 return True
54 def init(width = 1020,height = 760,title="PyWorlds (Soya3D)",create_basic=True):
55 global scene,mainloop,pyworlds_engine
56 pyworlds_engine = "soya"
57 soya.init(width=width, height= height,title=title)
58 soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
59 scene = pyworlds.basics.scene.scene
60 mainloop=soya.MainLoop(scene)
61 scene.mainloop=mainloop
62 scene.round_duration=.04
63 mainloop.round_duration=.04
64 if create_basic:
65 init_basicscene()
67 def init_basicscene():
68 global scene, light, camera, scene_body
69 scene_body = SceneBody(scene,None)
71 light = soya.Light(scene)
72 light.directional = 1
73 light.rotate_x(-90)
75 camera = soya.Camera(scene)
76 #camera.set_xyz(0,2,5)
77 #camera.rotate_x(-15)
78 camera.back = 200
79 #camera = soya.TravelingCamera(scene)
82 def begin_loop(callbackround=None, callbackadvance=None, engine="soya" ):
83 global scene, callback_round, callback_advance, camera,mainloop
84 import soya.pudding as pudding
85 callback_round = callbackround
86 callback_advance = callbackadvance
87 if engine=="soya":
88 soya.set_root_widget(camera)
89 elif engine=="pudding":
90 pass
91 else:
92 print "error engine %s unknown" % engine
93 #soya.set_root_widget(soya.widget.Group())
94 #soya.root_widget.add(camera)
95 #if enable_fps: soya.root_widget.add(soya.widget.FPSLabel())
96 return mainloop.main_loop()
98 def init_gui():
99 global root,viewport
100 import soya.gui
102 root = soya.gui.RootLayer(None)
103 viewport = soya.gui.CameraViewport(root, camera)
106 def init_pudding(width = 1020,height = 760,title="PyWorlds (Soya3D)", options = {}):
107 global root,viewport,camera,scene,mainloop, pyworlds_engine
108 soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
109 pyworlds_engine = "pudding"
110 import soya.pudding as pudding
111 soya.init(width=width, height= height, title=title)
112 pudding.init()
113 scene = pyworlds.basics.scene.scene
114 mainloop=pudding.main_loop.MainLoop(scene)
115 scene.mainloop=mainloop
116 scene.round_duration=.04
117 mainloop.round_duration=.04
120 if 'nobasics' not in options: init_basicscene()
121 soya.set_root_widget(pudding.core.RootWidget(width = width,height = height))
122 if 'nochild' not in options: soya.root_widget.add_child(camera)
126 def begin_guiloop(callbackround=None, callbackadvance=None ):
127 global root, mainloop
128 global scene, callback_round, callback_advance, camera, scene_body
129 callback_round = callbackround
130 callback_advance = callbackadvance
133 soya.set_root_widget(root)
134 scene_body = SceneBody(scene,None)
135 mainloop.main_loop()
137 def clearScene(fullClear = False):
138 global scene,camera,light,scene_body
140 validObj=[scene_body,camera,light]
141 if fullClear: validObj=[]
142 toRemove=[]
143 for body in scene.children:
144 if body not in validObj: toRemove.append(body)
146 for body in toRemove:
147 #print body
148 scene.children.remove(body)
152 class SceneBody(soya.Body):
153 def advance_time(self, proportion):
154 global callback_advance
155 soya.Body.advance_time(self, proportion)
156 if callback_advance: callback_advance(proportion)
158 def begin_round(self):
159 global MOUSE_WHEEL
160 global KEY,callback_round, MOUSE_X, MOUSE_Y, MOUSE_BUTTON,MOUSE_BUTTONUP, mainloop
161 soya.Body.begin_round(self)
162 array_events = []
163 if pyworlds_engine == "soya":
164 array_events = soya.process_event()
165 elif pyworlds_engine == "pudding":
166 import soya.pudding as pudding
167 # Use mainloop.events instead of pudding.process_event() :
168 # array_events = pudding.process_event()
169 array_events = mainloop.events
171 for ev1 in MOUSE_BUTTONUP:
172 if MOUSE_BUTTON.has_key(ev1):
173 del MOUSE_BUTTON[ev1]
174 MOUSE_BUTTONUP = []
176 for event in array_events:
178 if event[0] == soya.sdlconst.KEYDOWN:
179 if event[1] == soya.sdlconst.K_ESCAPE: soya.MAIN_LOOP.stop()
180 else:
181 KEY[event[1]]=event[:]
183 elif event[0] == sdlconst.KEYUP:
184 if event[1] in KEY: del KEY[event[1]]
186 elif event[0] == sdlconst.QUIT:
187 soya.MAIN_LOOP.stop()
189 elif event[0] == soya.sdlconst.MOUSEBUTTONDOWN:
190 MOUSE_BUTTON[event[1]]=event[:]
191 MOUSE_X = event[2]
192 MOUSE_Y = event[3]
193 a,b,c,d = MOUSE_BUTTON[event[1]]
194 if a == 5 and (b==4 or b==5): MOUSE_WHEEL = b
196 elif event[0] == soya.sdlconst.MOUSEBUTTONUP:
197 #print "Up: ",MOUSE_BUTTON[event[1]]
198 MOUSE_BUTTONUP.append(event[1])
199 #if MOUSE_BUTTON.has_key(event[1]):
200 # del MOUSE_BUTTON[event[1]]
201 MOUSE_X = event[2]
202 MOUSE_Y = event[3]
204 elif event[0] == soya.sdlconst.MOUSEMOTION:
205 MOUSE_X = event[1]
206 MOUSE_Y = event[2]
209 if callback_round: callback_round()
212 class Body(soya.Body):
213 def __init__(self,filename):
214 global scene
215 if type(filename) == type(''):
216 if filename in meshes:
217 mesh = meshes[filename]
218 else:
219 mesh = soya.Model.get(filename)
220 meshes[filename] = mesh
221 else:
222 # if it's not a text it is a mesh.
223 mesh = filename
225 self.mesh = mesh
226 soya.Body.__init__(self,scene,mesh)
227 self.velocity = soya.Vector(self,0,0,0)
228 self.rotation = [0,0,0]
230 def advance_time(self, proportion):
231 global mainloop
232 soya.Body.advance_time(self, proportion)
233 elapsed = mainloop.round_duration * proportion
234 if elapsed==0: elapsed=0.001
236 self.add_mul_vector(elapsed, self.velocity)
237 self.rotate_x(elapsed * self.rotation[0])
238 self.rotate_y(elapsed * self.rotation[1])
239 self.rotate_z(elapsed * self.rotation[2])
244 #class Character(soya.Body):
245 #def __init__(self,filename):
246 #global scene
247 #if type(filename) == type(''):
248 #if filename in animated_meshes:
249 #mesh = animated_meshes[filename]
250 #else:
251 #mesh = soya.AnimatedModel.get(filename)
252 #animated_meshes[filename] = mesh
253 #else:
254 ## if it's not a text it is a animated-mesh.
255 #mesh = filename
256 #self.mesh = mesh
257 ## print "Available meshes :", sorcerer_model.meshes .keys()
258 ## print "Available animations:", mesh.animations.keys()
259 ## -> Available animations: ['marche', 'tourneD', 'chute', 'tourneG', 'attente', 'recule']
261 #soya.Body.__init__(self,scene,mesh)
262 #self.states = {
263 #"stop" : ["garde","attente"],
264 #"walk" : ["marche"],
266 #self.state = None
267 #self.statecycle = None
268 #self.character_setstate("stop")
269 #self.velocity = soya.Vector(self,0,0,0)
270 #self.rotation = [0,0,0]
271 #self.desiredangle = 0
272 #self.look_at_speed = 10
274 #def advance_time(self, proportion):
275 #soya.Body.advance_time(self, proportion)
276 #elapsed = mainloop.round_duration * proportion
277 #if elapsed==0: elapsed=0.001
278 #self.angle = self.get_absoluteangleXZ()
279 #if self.desiredangle >= 360: self.desiredangle-=360
280 #if self.desiredangle < 0: self.desiredangle+=360
282 #anglediff = self.desiredangle - self.angle
283 #if anglediff > 180: anglediff-=360
284 #if anglediff < -180: anglediff+=360
285 #factor = self.look_at_speed
286 #if factor > 1/elapsed : factor = 1/elapsed
287 #anglemov = anglediff * factor
289 #if abs(self.rotation[1])>abs(anglemov):
290 #self.rotation[1]=(self.rotation[1]-anglemov)/2.0
291 #else:
292 #self.rotation[1]=(self.rotation[1]*5-anglemov)/6.0
293 #if abs(anglediff)<1:
294 #self.rotation[1]=-anglediff
296 #self.add_mul_vector(elapsed , self.velocity)
297 #self.rotate_x(elapsed * self.rotation[0])
298 #self.rotate_y(elapsed * self.rotation[1])
299 #self.rotate_z(elapsed * self.rotation[2])
301 #def get_absoluteangleXZ(self,vector=None):
302 #if vector == None:
303 #vector = soya.Vector(self,0,0,-1)
305 #q=vector % scene # I mean an upper container.
307 #return xy_toangle(q.x,q.z)
309 #def character_setstate(self,newstate):
310 #if newstate==self.state: return False
311 #if not hasattr(self.mesh,"animations"): return False
312 #if len(self.states[newstate])<1: raise
313 #newstatecycle=None
314 #try:
315 #for statecycle in self.states[newstate]:
316 #if statecycle in self.mesh.animations:
317 #newstatecycle=statecycle
318 #break;
319 #except:
320 #raise
321 #if not newstatecycle:
322 #print "Not found any animation for %s: " % newstate, self.states[newstate]
323 #print "Available animations:", self.mesh.animations.keys()
324 #raise
326 #if self.statecycle:
327 #self.animate_clear_cycle(self.statecycle)
328 #self.statecycle = None
329 #self.animate_blend_cycle(newstatecycle)
330 #self.statecycle = newstatecycle
331 #self.state=newstate
332 #return True
339 class FollowBody(Body):
340 def __init__(self,filename,target):
341 Body.__init__(self,filename)
342 self.x=target.x
343 self.y=target.y
344 self.z=target.z
345 self.target = target
346 self.target_distance = [0.5,1.0,2]
347 self.set_springfactor(16)
348 self.target_velocity = 1
350 for i in range(25):
351 self.begin_round()
352 self.advance_time(0.5)
354 def set_springfactor(self,factor):
355 self.target_springfactor = factor / 100.0
357 def begin_round(self):
358 Body.begin_round(self)
360 distance = self.distance_to(self.target)
361 _min = self.target_distance[0]
362 _med = self.target_distance[1]
363 _max = self.target_distance[2]
364 factor = 1
365 Q = 1
366 if distance <= _min: factor = 0.0
367 elif distance >= _max: factor = 0.0
368 else:
369 Q = (_med - distance)
370 if distance < _med:
371 Q /= math.sqrt(_med - _min)
372 factor = (distance - _min) / (_med - _min)
373 else:
374 Q /= math.sqrt(_max - _med)
375 factor = (_max - distance) / (_max - _med)
379 factor2 = (_med - distance) / (_max - _min)
380 if factor2 < 1: factor2 = 1
381 if self.velocity.z>1:
382 factor/=self.velocity.z
384 vel = self.target_velocity
385 # self.velocity.z = (self.velocity.z * self.target_springfactor * factor + Q * vel ) / (self.target_springfactor * factor + 1 )
386 self.velocity.z = (self.velocity.z * self.target_springfactor * factor + (_med - distance) * vel ) / (self.target_springfactor * factor + 1 )
387 #self.velocity.z *= factor2
388 if distance<_max:
389 look_at_elastic(self,self.target, sqrt_from=360, factor=(1-factor)+.3)
390 else:
391 self.look_at(self.target)
393 def advance_time(self, proportion):
394 Body.advance_time(self, proportion)
395 distance = self.distance_to(self.target)
396 _min = self.target_distance[0]
397 _med = self.target_distance[1]
398 _max = self.target_distance[2]
399 f3 = (distance - _med) / (_max - _med)
400 f1 = self.target_springfactor * 100 + 1
401 if f3>1:
402 f3=1
404 f3*=proportion
405 self.x = (self.x * f1 + self.target.x * f3) / (f1+f3)
406 self.y = (self.y * f1 + self.target.y * f3) / (f1+f3)
407 self.z = (self.z * f1 + self.target.z * f3) / (f1+f3)