Correct use of pudding events (removes double event calls)
[pyworlds.git] / src / pyworlds / worlds.py
blobb0255e4214920de3e5016c2c7b2240cb4070cd08
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 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_WHEEL = 0
28 # TODO: Place functions to access KEY, and return float or bool values. x>0.5 => True
29 callback_round = None
30 callback_advance = None
31 # TODO: Add the user-callback
32 scene_body = None
33 # TODO: Delete scene_body and use main Soya callbacks
35 enable_fps = False
37 # Import Psyco if available
38 try:
39 import psyco
40 psyco.full()
41 print "Psyco found and started -- Python code accelerated."
42 except ImportError:
43 print "I can't find PsyCo -- install it to get more speed"
44 pass
48 def is_pyWorlds_installed():
49 print "pyWorlds seem to be installed and working."
50 return True
53 def init(create_basic=True):
54 global scene,mainloop,pyworlds_engine
55 pyworlds_engine = "soya"
56 soya.init()
57 soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
58 scene = basics.scene.scene
59 mainloop=soya.MainLoop(scene)
60 scene.mainloop=mainloop
61 scene.round_duration=.04
62 mainloop.round_duration=.04
63 if create_basic:
64 init_basicscene()
66 def init_basicscene():
67 global scene, light, camera, scene_body
68 scene_body = SceneBody(scene,None)
70 light = soya.Light(scene)
71 light.directional = 1
72 light.rotate_x(-90)
74 camera = soya.Camera(scene)
75 #camera.set_xyz(0,2,5)
76 #camera.rotate_x(-15)
77 camera.back = 200
78 #camera = soya.TravelingCamera(scene)
81 def begin_loop(callbackround=None, callbackadvance=None, engine="soya" ):
82 global scene, callback_round, callback_advance, camera,mainloop
83 import soya.pudding as pudding
84 callback_round = callbackround
85 callback_advance = callbackadvance
86 if engine=="soya":
87 soya.set_root_widget(camera)
88 elif engine=="pudding":
89 pass
90 else:
91 print "error engine %s unknown" % engine
92 #soya.set_root_widget(soya.widget.Group())
93 #soya.root_widget.add(camera)
94 #if enable_fps: soya.root_widget.add(soya.widget.FPSLabel())
95 return mainloop.main_loop()
97 def init_gui():
98 global root,viewport
99 import soya.gui
101 root = soya.gui.RootLayer(None)
102 viewport = soya.gui.CameraViewport(root, camera)
105 def init_pudding(width = 500,height = 500, options = {}):
106 global root,viewport,camera,scene,mainloop, pyworlds_engine
107 soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
108 pyworlds_engine = "pudding"
109 import soya.pudding as pudding
110 soya.init()
111 pudding.init()
112 scene = basics.scene.scene
113 mainloop=pudding.main_loop.MainLoop(scene)
114 scene.mainloop=mainloop
115 scene.round_duration=.04
116 mainloop.round_duration=.04
119 if 'nobasics' not in options: init_basicscene()
120 soya.set_root_widget(pudding.core.RootWidget(width = width,height = height))
121 if 'nochild' not in options: soya.root_widget.add_child(camera)
125 def begin_guiloop(callbackround=None, callbackadvance=None ):
126 global root, mainloop
127 global scene, callback_round, callback_advance, camera, scene_body
128 callback_round = callbackround
129 callback_advance = callbackadvance
132 soya.set_root_widget(root)
133 scene_body = SceneBody(scene,None)
134 mainloop.main_loop()
136 def clearScene(fullClear = False):
137 global scene,camera,light,scene_body
139 validObj=[scene_body,camera,light]
140 if fullClear: validObj=[]
141 toRemove=[]
142 for body in scene.children:
143 if body not in validObj: toRemove.append(body)
145 for body in toRemove:
146 #print body
147 scene.children.remove(body)
151 class SceneBody(soya.Body):
152 def advance_time(self, proportion):
153 global callback_advance
154 soya.Body.advance_time(self, proportion)
155 if callback_advance: callback_advance(proportion)
157 def begin_round(self):
158 global MOUSE_WHEEL
159 global KEY,callback_round, MOUSE_X, MOUSE_Y, MOUSE_BUTTON, mainloop
160 soya.Body.begin_round(self)
161 array_events = []
162 if pyworlds_engine == "soya":
163 array_events = soya.process_event()
164 elif pyworlds_engine == "pudding":
165 import soya.pudding as pudding
166 # Use mainloop.events instead of pudding.process_event() :
167 # array_events = pudding.process_event()
168 array_events = mainloop.events
170 for event in array_events:
172 if event[0] == soya.sdlconst.KEYDOWN:
173 if event[1] == soya.sdlconst.K_ESCAPE: soya.MAIN_LOOP.stop()
174 else:
175 KEY[event[1]]=event[:]
177 elif event[0] == sdlconst.KEYUP:
178 if event[1] in KEY: del KEY[event[1]]
180 elif event[0] == sdlconst.QUIT:
181 soya.MAIN_LOOP.stop()
183 elif event[0] == soya.sdlconst.MOUSEBUTTONDOWN:
184 MOUSE_BUTTON[event[1]]=event[:]
185 MOUSE_X = event[2]
186 MOUSE_Y = event[3]
187 a,b,c,d = MOUSE_BUTTON[event[1]]
188 if a == 5 and (b==4 or b==5): MOUSE_WHEEL = b
190 elif event[0] == soya.sdlconst.MOUSEBUTTONUP:
191 #print "Up: ",MOUSE_BUTTON[event[1]]
192 if MOUSE_BUTTON.has_key(event[1]):
193 del MOUSE_BUTTON[event[1]]
194 MOUSE_X = event[2]
195 MOUSE_Y = event[3]
197 elif event[0] == soya.sdlconst.MOUSEMOTION:
198 MOUSE_X = event[1]
199 MOUSE_Y = event[2]
202 if callback_round: callback_round()
205 class Body(soya.Body):
206 def __init__(self,filename):
207 global scene
208 if type(filename) == type(''):
209 if filename in meshes:
210 mesh = meshes[filename]
211 else:
212 mesh = soya.Model.get(filename)
213 meshes[filename] = mesh
214 else:
215 # if it's not a text it is a mesh.
216 mesh = filename
218 self.mesh = mesh
219 soya.Body.__init__(self,scene,mesh)
220 self.velocity = soya.Vector(self,0,0,0)
221 self.rotation = [0,0,0]
223 def advance_time(self, proportion):
224 global mainloop
225 soya.Body.advance_time(self, proportion)
226 elapsed = mainloop.round_duration * proportion
227 if elapsed==0: elapsed=0.001
229 self.add_mul_vector(elapsed, self.velocity)
230 self.rotate_x(elapsed * self.rotation[0])
231 self.rotate_y(elapsed * self.rotation[1])
232 self.rotate_z(elapsed * self.rotation[2])
237 #class Character(soya.Body):
238 #def __init__(self,filename):
239 #global scene
240 #if type(filename) == type(''):
241 #if filename in animated_meshes:
242 #mesh = animated_meshes[filename]
243 #else:
244 #mesh = soya.AnimatedModel.get(filename)
245 #animated_meshes[filename] = mesh
246 #else:
247 ## if it's not a text it is a animated-mesh.
248 #mesh = filename
249 #self.mesh = mesh
250 ## print "Available meshes :", sorcerer_model.meshes .keys()
251 ## print "Available animations:", mesh.animations.keys()
252 ## -> Available animations: ['marche', 'tourneD', 'chute', 'tourneG', 'attente', 'recule']
254 #soya.Body.__init__(self,scene,mesh)
255 #self.states = {
256 #"stop" : ["garde","attente"],
257 #"walk" : ["marche"],
259 #self.state = None
260 #self.statecycle = None
261 #self.character_setstate("stop")
262 #self.velocity = soya.Vector(self,0,0,0)
263 #self.rotation = [0,0,0]
264 #self.desiredangle = 0
265 #self.look_at_speed = 10
267 #def advance_time(self, proportion):
268 #soya.Body.advance_time(self, proportion)
269 #elapsed = mainloop.round_duration * proportion
270 #if elapsed==0: elapsed=0.001
271 #self.angle = self.get_absoluteangleXZ()
272 #if self.desiredangle >= 360: self.desiredangle-=360
273 #if self.desiredangle < 0: self.desiredangle+=360
275 #anglediff = self.desiredangle - self.angle
276 #if anglediff > 180: anglediff-=360
277 #if anglediff < -180: anglediff+=360
278 #factor = self.look_at_speed
279 #if factor > 1/elapsed : factor = 1/elapsed
280 #anglemov = anglediff * factor
282 #if abs(self.rotation[1])>abs(anglemov):
283 #self.rotation[1]=(self.rotation[1]-anglemov)/2.0
284 #else:
285 #self.rotation[1]=(self.rotation[1]*5-anglemov)/6.0
286 #if abs(anglediff)<1:
287 #self.rotation[1]=-anglediff
289 #self.add_mul_vector(elapsed , self.velocity)
290 #self.rotate_x(elapsed * self.rotation[0])
291 #self.rotate_y(elapsed * self.rotation[1])
292 #self.rotate_z(elapsed * self.rotation[2])
294 #def get_absoluteangleXZ(self,vector=None):
295 #if vector == None:
296 #vector = soya.Vector(self,0,0,-1)
298 #q=vector % scene # I mean an upper container.
300 #return xy_toangle(q.x,q.z)
302 #def character_setstate(self,newstate):
303 #if newstate==self.state: return False
304 #if not hasattr(self.mesh,"animations"): return False
305 #if len(self.states[newstate])<1: raise
306 #newstatecycle=None
307 #try:
308 #for statecycle in self.states[newstate]:
309 #if statecycle in self.mesh.animations:
310 #newstatecycle=statecycle
311 #break;
312 #except:
313 #raise
314 #if not newstatecycle:
315 #print "Not found any animation for %s: " % newstate, self.states[newstate]
316 #print "Available animations:", self.mesh.animations.keys()
317 #raise
319 #if self.statecycle:
320 #self.animate_clear_cycle(self.statecycle)
321 #self.statecycle = None
322 #self.animate_blend_cycle(newstatecycle)
323 #self.statecycle = newstatecycle
324 #self.state=newstate
325 #return True
332 class FollowBody(Body):
333 def __init__(self,filename,target):
334 Body.__init__(self,filename)
335 self.x=target.x
336 self.y=target.y
337 self.z=target.z
338 self.target = target
339 self.target_distance = [0.5,1.0,2]
340 self.set_springfactor(16)
341 self.target_velocity = 1
343 for i in range(25):
344 self.begin_round()
345 self.advance_time(0.5)
347 def set_springfactor(self,factor):
348 self.target_springfactor = factor / 100.0
350 def begin_round(self):
351 Body.begin_round(self)
353 distance = self.distance_to(self.target)
354 _min = self.target_distance[0]
355 _med = self.target_distance[1]
356 _max = self.target_distance[2]
357 factor = 1
358 Q = 1
359 if distance <= _min: factor = 0.0
360 elif distance >= _max: factor = 0.0
361 else:
362 Q = (_med - distance)
363 if distance < _med:
364 Q /= math.sqrt(_med - _min)
365 factor = (distance - _min) / (_med - _min)
366 else:
367 Q /= math.sqrt(_max - _med)
368 factor = (_max - distance) / (_max - _med)
372 factor2 = (_med - distance) / (_max - _min)
373 if factor2 < 1: factor2 = 1
374 if self.velocity.z>1:
375 factor/=self.velocity.z
377 vel = self.target_velocity
378 # self.velocity.z = (self.velocity.z * self.target_springfactor * factor + Q * vel ) / (self.target_springfactor * factor + 1 )
379 self.velocity.z = (self.velocity.z * self.target_springfactor * factor + (_med - distance) * vel ) / (self.target_springfactor * factor + 1 )
380 #self.velocity.z *= factor2
381 if distance<_max:
382 look_at_elastic(self,self.target, sqrt_from=360, factor=(1-factor)+.3)
383 else:
384 self.look_at(self.target)
386 def advance_time(self, proportion):
387 Body.advance_time(self, proportion)
388 distance = self.distance_to(self.target)
389 _min = self.target_distance[0]
390 _med = self.target_distance[1]
391 _max = self.target_distance[2]
392 f3 = (distance - _med) / (_max - _med)
393 f1 = self.target_springfactor * 100 + 1
394 if f3>1:
395 f3=1
397 f3*=proportion
398 self.x = (self.x * f1 + self.target.x * f3) / (f1+f3)
399 self.y = (self.y * f1 + self.target.y * f3) / (f1+f3)
400 self.z = (self.z * f1 + self.target.z * f3) / (f1+f3)