Few fixes with multitouch. I think the code is solid now.
[rokon:rokon.git] / src / com / stickycoding / rokon / Scene.java
1 package com.stickycoding.rokon;\r
2 \r
3 import java.lang.reflect.InvocationTargetException;\r
4 import java.lang.reflect.Method;\r
5 import java.util.Arrays;\r
6 \r
7 import javax.microedition.khronos.opengles.GL10;\r
8 \r
9 import android.view.KeyEvent;\r
10 import android.view.MotionEvent;\r
11 \r
12 import com.badlogic.gdx.physics.box2d.Contact;\r
13 import com.badlogic.gdx.physics.box2d.ContactListener;\r
14 import com.badlogic.gdx.physics.box2d.World;\r
15 import com.stickycoding.rokon.background.Background;\r
16 import com.stickycoding.rokon.device.Graphics;\r
17 import com.stickycoding.rokon.device.OS;\r
18 \r
19 /**\r
20  * Scene.java\r
21  * A Scene holds and prepares drawable objects or object groups\r
22  * \r
23  * @author Richard\r
24  */\r
25 public class Scene {\r
26         \r
27         public static final int SCENE_TEXTURE_COUNT = 32;\r
28         public static final int DEFAULT_LAYER_COUNT = 1;\r
29         public static final int DEFAULT_LAYER_OBJECT_COUNT = 32;\r
30 \r
31         protected Layer[] layer;\r
32         protected boolean loadedTextures;\r
33         protected int layerCount;\r
34         protected Window window = null;\r
35         protected Texture[] texturesToLoad;\r
36         protected Texture[] texturesOnHardware;\r
37         protected boolean useInvoke;\r
38         protected World world;\r
39         protected boolean usePhysics = false;\r
40         protected ContactListener contactListener;\r
41         protected boolean useContactListener;\r
42         protected Background background;\r
43         \r
44         protected float defaultLineWidth = 1;\r
45 \r
46         public void onPreDraw(GL10 gl) { }\r
47         public void onPostDraw(GL10 gl) { }\r
48         \r
49         public void onPause() { }\r
50         public void onResume() { }\r
51         \r
52         public void onTouchDown(Drawable object, float x, float y, MotionEvent event, int pointerId) { }\r
53         public void onTouchUp(Drawable object, float x, float y, MotionEvent event, int pointerId) { }\r
54         public void onTouchMove(Drawable object, float x, float y, MotionEvent event, int pointerId) { }\r
55         public void onTouch(Drawable object, float x, float y, MotionEvent event, int pointerId) { }\r
56         public void onTouchDown(float x, float y, MotionEvent event, int pointerId) { }\r
57         public void onTouchMove(float x, float y, MotionEvent event, int pointerId) { }\r
58         public void onTouch(float x, float y, MotionEvent event, int pointerId) { }\r
59         public void onTouchUp(float x, float y, MotionEvent event, int pointerId) { }\r
60         \r
61         public void onTouchDownReal(float x, float y, MotionEvent event, int pointerId) { }\r
62         public void onTouchMoveReal(float x, float y, MotionEvent event, int pointerId) { }\r
63         public void onTouchUpReal(float x, float y, MotionEvent event, int pointerId) { }\r
64         public void onTouchReal(float x, float y, MotionEvent event, int pointerId) { }\r
65 \r
66         public void onKeyDown(int keyCode, KeyEvent event) { }\r
67         public void onKeyUp(int keyCode, KeyEvent event) { }\r
68         public void onTrackballEvent(MotionEvent event) { }\r
69         \r
70         /**\r
71          * Sets a World for the physics in this Scene\r
72          * Automatically flags usePhysics\r
73          * \r
74          * @param world valid World object\r
75          */\r
76         public void setWorld(World world) {\r
77                 this.world = world;\r
78                 Physics.world = world;\r
79                 usePhysics = true;\r
80         }\r
81         \r
82         /**\r
83          * Returns the World associated with this Scene\r
84          * \r
85          * @return NULL if no World set\r
86          */\r
87         public World getWorld() {\r
88                 return world;\r
89         }\r
90         \r
91         /**\r
92          * Flags to use physics in this Scene\r
93          */\r
94         public void usePhysics() {\r
95                 usePhysics = true;\r
96         }\r
97         \r
98         /**\r
99          * Flags to not use physics\r
100          */\r
101         public void noPhysics() {\r
102                 usePhysics = false;\r
103         }\r
104         \r
105         /**\r
106          * Removes the World from this Scene\r
107          */\r
108         public void removeWorld() {\r
109                 this.world = null;\r
110                 Physics.world = null;\r
111                 usePhysics = false;\r
112         }\r
113         \r
114         /**\r
115          * Triggers the Scene to begin invoking methods on certain events, this is not set by default.\r
116          * If the methods that are to be invoked don't exist, no exceptions will be raised.\r
117          */\r
118         public void useInvoke() {\r
119                 useInvoke = true;\r
120         }\r
121         \r
122         /**\r
123          * Stops the Scene from invoking methods on events, this is the default state\r
124          */\r
125         public void stopInvoke() {\r
126                 useInvoke = false;\r
127         }\r
128         \r
129         /**\r
130          * Invokes a method inside the Scene class, defined by given parameters.\r
131          * If no parameters exist, use the alternative invoke method\r
132          * \r
133          * @param methodName String\r
134          * @param params Class[]\r
135          * @param paramValues Object[]\r
136          * \r
137          * @return TRUE if successful, FALSE otherwise\r
138          */\r
139         public boolean invoke(String methodName, Class<?>[] params, Object[] paramValues) {\r
140                 for(Method m : this.getClass().getDeclaredMethods()) {\r
141                         if(m.getName().equals(methodName)) {\r
142                                 if(Arrays.equals(params, m.getParameterTypes())) {\r
143                                         try {\r
144                                                 m.invoke(this, paramValues);\r
145                                                 return true;\r
146                                         } catch (IllegalArgumentException e) {\r
147                                                 Debug.error("Invoking, IllegalArgument");\r
148                                                 e.printStackTrace();\r
149                                                 return false;\r
150                                         } catch (IllegalAccessException e) {\r
151                                                 Debug.error("Invoking, IllegalAccess");\r
152                                                 e.printStackTrace();\r
153                                                 return false;\r
154                                         } catch (InvocationTargetException e) {\r
155                                                 Debug.error("Invoking, IllegalTarget");\r
156                                                 e.printStackTrace();\r
157                                                 return false;\r
158                                         }\r
159                                 }\r
160                         }\r
161                 }\r
162                 return false;\r
163         }\r
164         \r
165         /**\r
166          * Invokes a method by parameters inside a Callback object\r
167          * \r
168          * @param callback valid Callback object\r
169          * @return TRUE if successful, FALSE otherwise\r
170          */\r
171         public boolean invoke(Callback callback) {\r
172                 if(callback.parameters == null) {\r
173                         return invoke(callback.methodName);\r
174                 } \r
175                 if(callback.parameterTypes == null) {\r
176                         return invoke(callback.methodName, callback.parameters);\r
177                 }\r
178                 return invoke(callback.methodName, callback.parameterTypes, callback.parameters);\r
179         }\r
180         \r
181         /**\r
182          * USE AT YOUR OWN RISK\r
183          * Invokes a method inside the Scene class, it selects the first matching method name and tries to pass on given parameters\r
184          * An error will be raised if this isn't the correct method. This routine is simply for those too lazy (or wanting to save\r
185          * on a little processing time) and are 100% sure there are no name conflicts.\r
186          * \r
187          * IllegalArgumentException may be passed to the Debug class, logcat will be notified - but there is no way to test at your end.\r
188          * \r
189          * @param methodName String\r
190          * @param paramValues Object[]\r
191          * \r
192          * @return TRUE if successful, FALSE otherwise\r
193          */\r
194         public boolean invoke(String methodName, Object[] paramValues) {\r
195                 for(Method m : this.getClass().getDeclaredMethods()) {\r
196                         if(m.getName().equals(methodName)) {\r
197                                 try {\r
198                                         m.invoke(this, paramValues);\r
199                                         return true;\r
200                                 } catch (IllegalArgumentException e) {\r
201                                         Debug.error("Invoking, IllegalArgument");\r
202                                         e.printStackTrace();\r
203                                         return false;\r
204                                 } catch (IllegalAccessException e) {\r
205                                         Debug.error("Invoking, IllegalAccess");\r
206                                         e.printStackTrace();\r
207                                         return false;\r
208                                 } catch (InvocationTargetException e) {\r
209                                         Debug.error("Invoking, IllegalTarget");\r
210                                         e.printStackTrace();\r
211                                         return false;\r
212                                 }\r
213                         }\r
214                 }\r
215                 return false;\r
216         }\r
217         \r
218         /**\r
219          * Invokes a method inside the Scene class, assuming there are no parameters to pass\r
220          * \r
221          * @param methodName String\r
222          * \r
223          * @return TRUE if successful, FALSE otherwise\r
224          */\r
225         public boolean invoke(String methodName) {\r
226                 for(Method m : this.getClass().getDeclaredMethods()) {\r
227                         if(m.getName().equals(methodName)) {\r
228                                 if(m.getParameterTypes().length == 0) {\r
229                                         try {\r
230                                                 m.invoke(this);\r
231                                                 return true;\r
232                                         } catch (IllegalArgumentException e) {\r
233                                                 Debug.error("Invoking, IllegalArgument");\r
234                                                 e.printStackTrace();\r
235                                                 return false;\r
236                                         } catch (IllegalAccessException e) {\r
237                                                 Debug.error("Invoking, IllegalAccess");\r
238                                                 e.printStackTrace();\r
239                                                 return false;\r
240                                         } catch (InvocationTargetException e) {\r
241                                                 Debug.error("Invoking, IllegalTarget");\r
242                                                 e.printStackTrace();\r
243                                                 return false;\r
244                                         }\r
245                                 }\r
246                         }\r
247                 }\r
248                 return false;\r
249         }\r
250         \r
251         protected void handleSDK8MultiTouch(MotionEvent event) {\r
252                 for(int idx = 0; idx < event.getPointerCount(); idx++) {\r
253                         int id = event.getPointerId(idx);\r
254                         final float realX = event.getX(idx) * (RokonActivity.gameWidth / Graphics.getWidthPixels());\r
255                         final float realY = event.getY(idx) * (RokonActivity.gameHeight / Graphics.getHeightPixels());\r
256                         float gameX = realX;\r
257                         float gameY = realY;\r
258                         if(window != null) {\r
259                                 float xFraction = event.getX(idx) / Graphics.getWidthPixels();\r
260                                 float yFraction = event.getY(idx) / Graphics.getHeightPixels();\r
261                                 gameX = window.getX() + (window.width * xFraction);\r
262                                 gameY = window.getY() + (window.height * yFraction);\r
263                         }\r
264                         onTouch(gameX, gameY, event, id);\r
265                         onTouchReal(realX, realY, event, id);\r
266                         final int action = event.getAction();\r
267                         switch(action & MotionEvent.ACTION_MASK) {\r
268                                 case MotionEvent.ACTION_DOWN:\r
269                                         onTouchDown(gameX, gameY, event, id);\r
270                                         onTouchDownReal(realX, realY, event, id);\r
271                                         break;\r
272                                 case MotionEvent.ACTION_UP:\r
273                                         onTouchUp(gameX, gameY, event, id);\r
274                                         onTouchUpReal(realX, realY, event, id);\r
275                                         break;\r
276                                 case MotionEvent.ACTION_MOVE:\r
277                                         onTouchMove(gameX, gameY, event, id);\r
278                                         onTouchMoveReal(realX, realY, event, id);\r
279                                         break;\r
280                                 case MotionEvent.ACTION_POINTER_DOWN:\r
281                                         if((action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == idx) {\r
282                                                 onTouchDown(gameX, gameY, event, id);\r
283                                                 onTouchDownReal(realX, realY, event, id);\r
284                                         }\r
285                                         break;\r
286                                 case MotionEvent.ACTION_POINTER_UP:\r
287                                         if((action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == idx) {\r
288                                                 onTouchUp(gameX, gameY, event, id);\r
289                                                 onTouchUpReal(realX, realY, event, id);\r
290                                         }\r
291                                         break;\r
292                         }\r
293                         for(int i = 0; i < layerCount; i++) {\r
294                                 for(int j = 0; j < layer[i].maximumDrawableObjects; j++) {\r
295                                         float checkX, checkY;\r
296                                         checkX = gameX;\r
297                                         checkY = gameY;\r
298                                         if(layer[i].ignoreWindow) {\r
299                                                 checkX = realX;\r
300                                                 checkY = realY;\r
301                                         }\r
302                                         Drawable object = layer[i].gameObjects.get(j);\r
303                                         if(object != null && object.isTouchable()) {\r
304                                                 if(MathHelper.pointInRect(checkX, checkY, object.getX(), object.getY(), object.getWidth(), object.getHeight())) {\r
305                                                         onTouch(object, checkX, checkY, event, 0);\r
306                                                         if(object.getName() != null) {\r
307                                                                 invoke(object.getName() + "_onTouch", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
308                                                         }\r
309                                                         switch(action & MotionEvent.ACTION_MASK) {\r
310                                                                 case MotionEvent.ACTION_DOWN:\r
311                                                                         onTouchDown(object, checkX, checkY, event, id);\r
312                                                                         if(object.getName() != null) {\r
313                                                                                 invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
314                                                                         }\r
315                                                                         break;\r
316                                                                 case MotionEvent.ACTION_UP:\r
317                                                                         onTouchUp(object, checkX, checkY, event, id);\r
318                                                                         if(object.getName() != null) {\r
319                                                                                 invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
320                                                                         }\r
321                                                                         break;\r
322                                                                 case MotionEvent.ACTION_MOVE:\r
323                                                                         onTouch(object, checkX, checkY, event, id);\r
324                                                                         if(object.getName() != null) {\r
325                                                                                 invoke(object.getName() + "_onTouchMove", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
326                                                                         }\r
327                                                                         break;\r
328                                                                 case MotionEvent.ACTION_POINTER_DOWN:\r
329                                                                         if((action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == idx) {\r
330                                                                                 onTouchDown(object, checkX, checkY, event, id);\r
331                                                                                 if(object.getName() != null) {\r
332                                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
333                                                                                 }\r
334                                                                         }\r
335                                                                         break;\r
336                                                                 case MotionEvent.ACTION_POINTER_UP:\r
337                                                                         if((action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == idx) {\r
338                                                                                 onTouchUp(object, checkX, checkY, event, id);\r
339                                                                                 if(object.getName() != null) {\r
340                                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
341                                                                                 }\r
342                                                                         }\r
343                                                                         break;\r
344                                                         }\r
345                                                 }\r
346                                         }\r
347                                 }\r
348                         }\r
349                 }\r
350         }\r
351         \r
352         protected void handleMultiTouch(MotionEvent event) {\r
353                 final int action = event.getAction();\r
354                 for(int idx = 0; idx < event.getPointerCount(); idx++) {\r
355                         int id = event.getPointerId(idx);\r
356                         final float realX = event.getX(idx) * (RokonActivity.gameWidth / Graphics.getWidthPixels());\r
357                         final float realY = event.getY(idx) * (RokonActivity.gameHeight / Graphics.getHeightPixels());\r
358                         float gameX = realX;\r
359                         float gameY = realY;\r
360                         if(window != null) {\r
361                                 float xFraction = event.getX(idx) / Graphics.getWidthPixels();\r
362                                 float yFraction = event.getY(idx) / Graphics.getHeightPixels();\r
363                                 gameX = window.getX() + (window.width * xFraction);\r
364                                 gameY = window.getY() + (window.height * yFraction);\r
365                         }\r
366                         onTouch(gameX, gameY, event, id);\r
367                         onTouchReal(realX, realY, event, id);\r
368                         switch(action) {\r
369                                 case MotionEvent.ACTION_DOWN:\r
370                                         onTouchDown(gameX, gameY, event, id);\r
371                                         onTouchDownReal(realX, realY, event, id);\r
372                                         break;\r
373                                 case MotionEvent.ACTION_UP:\r
374                                         onTouchUp(gameX, gameY, event, id);\r
375                                         onTouchUpReal(realX, realY, event, id);\r
376                                         break;\r
377                                 case MotionEvent.ACTION_MOVE:\r
378                                         onTouchMove(gameX, gameY, event, id);\r
379                                         onTouchMoveReal(realX, realY, event, id);\r
380                                         break;\r
381                                 case MotionEvent.ACTION_POINTER_1_DOWN:\r
382                                         if(idx == 0) {\r
383                                                 onTouchDown(gameX, gameY, event, id);\r
384                                                 onTouchDownReal(realX, realY, event, id);\r
385                                         }\r
386                                         break;\r
387                                 case MotionEvent.ACTION_POINTER_1_UP:\r
388                                         if(idx == 0) {\r
389                                                 onTouchUp(gameX, gameY, event, id);\r
390                                                 onTouchUpReal(realX, realY, event, id);\r
391                                         }\r
392                                         break;\r
393                                 case MotionEvent.ACTION_POINTER_2_DOWN:\r
394                                         if(idx == 1) {\r
395                                                 onTouchDown(gameX, gameY, event, id);\r
396                                                 onTouchDownReal(realX, realY, event, id);\r
397                                         }\r
398                                         break;\r
399                                 case MotionEvent.ACTION_POINTER_2_UP:\r
400                                         if(idx == 1) {\r
401                                                 onTouchUp(gameX, gameY, event, id);\r
402                                                 onTouchUpReal(realX, realY, event, id);\r
403                                         }\r
404                                         break;\r
405                                 case MotionEvent.ACTION_POINTER_3_DOWN:\r
406                                         if(idx == 2) {\r
407                                                 onTouchDown(gameX, gameY, event, id);\r
408                                                 onTouchDownReal(realX, realY, event, id);\r
409                                         }\r
410                                         break;\r
411                                 case MotionEvent.ACTION_POINTER_3_UP:\r
412                                         if(idx == 2) {\r
413                                                 onTouchUp(gameX, gameY, event, id);\r
414                                                 onTouchUpReal(realX, realY, event, id);\r
415                                         }\r
416                                         break;\r
417                         }\r
418                         for(int i = 0; i < layerCount; i++) {\r
419                                 for(int j = 0; j < layer[i].maximumDrawableObjects; j++) {\r
420                                         float checkX, checkY;\r
421                                         checkX = gameX;\r
422                                         checkY = gameY;\r
423                                         if(layer[i].ignoreWindow) {\r
424                                                 checkX = realX;\r
425                                                 checkY = realY;\r
426                                         }\r
427                                         Drawable object = layer[i].gameObjects.get(j);\r
428                                         if(object != null && object.isTouchable()) {\r
429                                                 if(MathHelper.pointInRect(checkX, checkY, object.getX(), object.getY(), object.getWidth(), object.getHeight())) {\r
430                                                         onTouch(object, checkX, checkY, event, id);\r
431                                                         if(object.getName() != null) {\r
432                                                                 invoke(object.getName() + "_onTouch", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
433                                                         }\r
434                                                         switch(action) {\r
435                                                                 case MotionEvent.ACTION_DOWN:\r
436                                                                         onTouchDown(object, checkX, checkY, event, id);\r
437                                                                         if(object.getName() != null) {\r
438                                                                                 invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
439                                                                         }\r
440                                                                         break;\r
441                                                                 case MotionEvent.ACTION_UP:\r
442                                                                         onTouchUp(object, checkX, checkY, event, id);\r
443                                                                         if(object.getName() != null) {\r
444                                                                                 invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
445                                                                         }\r
446                                                                         break;\r
447                                                                 case MotionEvent.ACTION_MOVE:\r
448                                                                         onTouch(object, checkX, checkY, event, id);\r
449                                                                         if(object.getName() != null) {\r
450                                                                                 invoke(object.getName() + "_onTouchMove", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
451                                                                         }\r
452                                                                         break;\r
453                                                                 case MotionEvent.ACTION_POINTER_1_DOWN:\r
454                                                                         if(idx == 0) {\r
455                                                                                 onTouchDown(object, checkX, checkY, event, id);\r
456                                                                                 if(object.getName() != null) {\r
457                                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
458                                                                                 }\r
459                                                                         }\r
460                                                                         break;\r
461                                                                 case MotionEvent.ACTION_POINTER_1_UP:\r
462                                                                         if(idx == 0) {\r
463                                                                                 onTouchUp(object, checkX, checkY, event, id);\r
464                                                                                 if(object.getName() != null) {\r
465                                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
466                                                                                 }\r
467                                                                         }\r
468                                                                         break;\r
469                                                                 case MotionEvent.ACTION_POINTER_2_DOWN:\r
470                                                                         if(idx == 1) {\r
471                                                                                 onTouchDown(object, checkX, checkY, event, id);\r
472                                                                                 if(object.getName() != null) {\r
473                                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
474                                                                                 }\r
475                                                                         }\r
476                                                                         break;\r
477                                                                 case MotionEvent.ACTION_POINTER_2_UP:\r
478                                                                         if(idx == 1) {\r
479                                                                                 onTouchUp(object, checkX, checkY, event, id);\r
480                                                                                 if(object.getName() != null) {\r
481                                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
482                                                                                 }\r
483                                                                         }\r
484                                                                         break;\r
485                                                                 case MotionEvent.ACTION_POINTER_3_DOWN:\r
486                                                                         if(idx == 2) {\r
487                                                                                 onTouchDown(object, checkX, checkY, event, id);\r
488                                                                                 if(object.getName() != null) {\r
489                                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
490                                                                                 }\r
491                                                                         }\r
492                                                                         break;\r
493                                                                 case MotionEvent.ACTION_POINTER_3_UP:\r
494                                                                         if(idx == 2) {\r
495                                                                                 onTouchUp(object, checkX, checkY, event, id);\r
496                                                                                 if(object.getName() != null) {\r
497                                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, id });\r
498                                                                                 }\r
499                                                                         }\r
500                                                                         break;\r
501                                                         }\r
502                                                 }\r
503                                         }\r
504                                 }\r
505                         }\r
506                 }\r
507         }\r
508         \r
509         protected void handleTouch(MotionEvent event) {\r
510                 if(OS.API_LEVEL >= 5) {\r
511                         if(OS.API_LEVEL >= 8) {\r
512                                 handleSDK8MultiTouch(event);\r
513                                 return;\r
514                         }\r
515                         handleMultiTouch(event);\r
516                         return;\r
517                 }\r
518                 final float realX = event.getX() * (RokonActivity.gameWidth / Graphics.getWidthPixels());\r
519                 final float realY = event.getY() * (RokonActivity.gameHeight / Graphics.getHeightPixels());\r
520                 float gameX = realX;\r
521                 float gameY = realY;\r
522                 if(window != null) {\r
523                         float xFraction = event.getX() / Graphics.getWidthPixels();\r
524                         float yFraction = event.getY() / Graphics.getHeightPixels();\r
525                         gameX = window.getX() + (window.width * xFraction);\r
526                         gameY = window.getY() + (window.height * yFraction);\r
527                 }\r
528                 onTouch(gameX, gameY, event, 0);\r
529                 onTouchReal(realX, realY, event, 0);\r
530                 final int action = event.getAction();\r
531                 switch(action) {\r
532                         case MotionEvent.ACTION_DOWN:\r
533                                 onTouchDown(gameX, gameY, event, 0);\r
534                                 onTouchDownReal(realX, realY, event, 0);\r
535                                 break;\r
536                         case MotionEvent.ACTION_UP:\r
537                                 onTouchUp(gameX, gameY, event, 0);\r
538                                 onTouchUpReal(realX, realY, event, 0);\r
539                                 break;\r
540                         case MotionEvent.ACTION_MOVE:\r
541                                 onTouchMove(gameX, gameY, event, 0);\r
542                                 onTouchMoveReal(realX, realY, event, 0);\r
543                                 break;\r
544                 }\r
545                 for(int i = 0; i < layerCount; i++) {\r
546                         for(int j = 0; j < layer[i].maximumDrawableObjects; j++) {\r
547                                 float checkX, checkY;\r
548                                 checkX = gameX;\r
549                                 checkY = gameY;\r
550                                 if(layer[i].ignoreWindow) {\r
551                                         checkX = realX;\r
552                                         checkY = realY;\r
553                                 }\r
554                                 Drawable object = layer[i].gameObjects.get(j);\r
555                                 if(object != null && object.isTouchable()) {\r
556                                         if(MathHelper.pointInRect(checkX, checkY, object.getX(), object.getY(), object.getWidth(), object.getHeight())) {\r
557                                                 onTouch(object, checkX, checkY, event, 0);\r
558                                                 if(object.getName() != null) {\r
559                                                         invoke(object.getName() + "_onTouch", new Class[] { float.class, float.class, MotionEvent.class }, new Object[] { gameX, gameY, event, 0 });\r
560                                                 }\r
561                                                 switch(event.getAction()) {\r
562                                                         case MotionEvent.ACTION_DOWN:\r
563                                                                 onTouchDown(object, checkX, checkY, event, 0);\r
564                                                                 if(object.getName() != null) {\r
565                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, 0 });\r
566                                                                 }\r
567                                                                 break;\r
568                                                         case MotionEvent.ACTION_UP:\r
569                                                                 onTouchUp(object, checkX, checkY, event, 0);\r
570                                                                 if(object.getName() != null) {\r
571                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, 0 });\r
572                                                                 }\r
573                                                                 break;\r
574                                                         case MotionEvent.ACTION_MOVE:\r
575                                                                 onTouch(object, checkX, checkY, event, 0);\r
576                                                                 if(object.getName() != null) {\r
577                                                                         invoke(object.getName() + "_onTouchMove", new Class[] { float.class, float.class, MotionEvent.class, int.class }, new Object[] { gameX, gameY, event, 0 });\r
578                                                                 }\r
579                                                                 break;\r
580                                                 }\r
581                                         }\r
582                                 }\r
583                         }\r
584                 }\r
585         }\r
586         \r
587         /**\r
588          * Creates a new Scene with given layer count, and a corresponding maximum DrawableObject count \r
589          * \r
590          * @param layerCount maximum number of layers\r
591          * @param layerObjectCount maximum number of DrawableObjects per layer, the array length must match layerCount\r
592          */\r
593         public Scene(int layerCount, int[] layerObjectCount) {\r
594                 this.layerCount = layerCount;\r
595                 layer = new Layer[layerCount];\r
596                 for(int i = 0; i < layerCount; i++) {\r
597                         layer[i] = new Layer(this, layerObjectCount[i]);\r
598                 }\r
599                 prepareNewScene();\r
600         }\r
601         \r
602         /**\r
603          * Creates a new Scene with given layer count, all layers will have the same maximum number of DrawableObjects\r
604          * \r
605          * @param layerCount maximum number of layers\r
606          * @param layerObjectCount maximum number of DrawableObjects per layer\r
607          */\r
608         public Scene(int layerCount, int layerObjectCount) {\r
609                 this.layerCount = layerCount;\r
610                 layer = new Layer[layerCount];\r
611                 for(int i = 0; i < layerCount; i++) {\r
612                         layer[i] = new Layer(this, layerObjectCount);\r
613                 }\r
614                 prepareNewScene();\r
615         }\r
616         \r
617         /**\r
618          * Creates a new Scene with given layer count, and a default maximum DrawableObject count of DEFAULT_LAYER_OBJECT_COUNT\r
619          * \r
620          * @param layerCount maximum number of layers\r
621          */\r
622         public Scene(int layerCount) {\r
623                 this(layerCount, DEFAULT_LAYER_OBJECT_COUNT);\r
624         }\r
625         \r
626         /**\r
627          * Creates a new Scene with defaults, DEFAULT_LAYER_COUNT and DEFAULT_LAYER_OBJECT_COUNT\r
628          */\r
629         public Scene() {\r
630                 this(DEFAULT_LAYER_COUNT, DEFAULT_LAYER_OBJECT_COUNT);\r
631                 \r
632         }\r
633         \r
634         private void prepareNewScene() {\r
635                 texturesToLoad = new Texture[SCENE_TEXTURE_COUNT];\r
636                 texturesOnHardware = new Texture[SCENE_TEXTURE_COUNT];\r
637         }\r
638         \r
639         /**\r
640          * Flags a Texture to be loaded into this Scene\r
641          * This must be called before RokonActivity.setScene\r
642          * \r
643          * @param texture valid Texture object\r
644          */\r
645         public void useTexture(Texture texture) {\r
646                 for(int i = 0; i < texturesToLoad.length; i++) {\r
647                         if(texturesToLoad[i] == texture) return;\r
648                         if(texturesToLoad[i] == null) {\r
649                                 texturesToLoad[i] = texture;\r
650                                 return;\r
651                         }\r
652                 }\r
653                 Debug.warning("Scene.useTexture", "Tried loading too many Textures onto the Scene, max is " + texturesToLoad.length);\r
654         }\r
655         \r
656         /**\r
657          * Defines the active Window for this Scene\r
658          * If no Window is given, a default static view will be rendered \r
659          * \r
660          * @param window\r
661          */\r
662         public void setWindow(Window window) {\r
663                 if(window == null) {\r
664                         Debug.warning("Scene.setWindow", "Tried setting a NULL Window");\r
665                         return;\r
666                 }\r
667                 this.window = window;\r
668         }\r
669         \r
670         /**\r
671          * Removes the current active Window, returning it to NULL\r
672          */\r
673         public void removeWindow() {\r
674                 window = null;\r
675         }\r
676         \r
677         /**\r
678          * @return NULL if there is no Window associated with this Scene\r
679          */\r
680         public Window getWindow() {\r
681                 if(window == null)\r
682                         return null;\r
683                 return window;\r
684         }\r
685         \r
686         /**\r
687          * Fetches the Layer object associated with the given index\r
688          * \r
689          * @param index the index of the Layer\r
690          * @return NULL if invalid index is given\r
691          */\r
692         public Layer getLayer(int index) {\r
693                 if(index < 0 || index > layerCount) {\r
694                         Debug.warning("Scene.getLayer", "Tried fetching invalid layer (" + index + "), maximum is " + layerCount);\r
695                         return null;\r
696                 }\r
697                 return layer[index];\r
698         }\r
699         \r
700         /**\r
701          * Clears the DrawableObjects from all Layers\r
702          */\r
703         public void clear() {\r
704                 for(int i = 0; i < layerCount; i++) {\r
705                         layer[i].clear();\r
706                 }\r
707         }\r
708         \r
709         /**\r
710          * Clears all the DrawableObjects from a specified Layer\r
711          * \r
712          * @param index the index of the Layer\r
713          */\r
714         public void clearLayer(int index) {\r
715                 if(index <= 0 || index > layerCount) {\r
716                         Debug.warning("Scene.clearLayer", "Tried clearing invalid layer (" + index + "), maximum is " + layerCount);\r
717                         return;\r
718                 }\r
719                 layer[index].clear();\r
720         }\r
721         \r
722         /**\r
723          * Moves a Layer from one index to another, and shuffles the others up or down to accomodate\r
724          * \r
725          * @param startIndex the current index of the Layer\r
726          * @param endIndex the desired final index of the Layer\r
727          */\r
728         public void moveLayer(int startIndex, int endIndex) {\r
729                 if(startIndex == endIndex) {\r
730                         Debug.warning("Scene.moveLayer", "Tried moving a Layer to its own position, stupid");\r
731                         return;\r
732                 }\r
733                 if(startIndex <= 0 || startIndex > layerCount) {\r
734                         Debug.warning("Scene.moveLayer", "Tried moving an invalid Layer, startIndex=" + startIndex + ", maximum is " + layerCount);\r
735                         return;\r
736                 }\r
737                 if(endIndex <= 0 || endIndex > layerCount) {\r
738                         Debug.warning("Scene.moveLayer", "Tried moving an invalid Layer, endIndex=" + endIndex + ", maximum is " + layerCount);\r
739                         return;\r
740                 }\r
741                 Layer temporaryLayer = layer[startIndex];\r
742                 if(endIndex < startIndex) {\r
743                         for(int i = endIndex; i < startIndex; i++) {\r
744                                 layer[i + 1] = layer[i];\r
745                         }\r
746                         layer[endIndex] = temporaryLayer;\r
747                 }\r
748                 if(endIndex > startIndex) { \r
749                         for(int i = startIndex; i < endIndex; i++) {\r
750                                 layer[i] = layer[i + 1];\r
751                         }\r
752                         layer[endIndex] = temporaryLayer;\r
753                 }\r
754         }\r
755         \r
756         /**\r
757          * Switches the position of one Layer with another\r
758          * \r
759          * @param layer1 the index of the first Layer\r
760          * @param layer2 the index of the second Layer\r
761          */\r
762         public void switchLayers(int layer1, int layer2) {\r
763                 if(layer1 == layer2) {\r
764                         Debug.warning("Scene.switchLayers", "Tried switching the same Layer");\r
765                         return;\r
766                 }\r
767                 if(layer1 < 0 || layer1 > layerCount) {\r
768                         Debug.warning("Scene.switchLayers", "Tried switch an invalid Layer, layer1=" + layer1 + ", maximum is " + layerCount);\r
769                         return;\r
770                 }\r
771                 if(layer2 < 0 || layer2 > layerCount) {\r
772                         Debug.warning("Scene.switchLayers", "Tried switch an invalid Layer, layer2=" + layer2 + ", maximum is " + layerCount);\r
773                         return;\r
774                 }\r
775                 Layer temporaryLayer = layer[layer1];\r
776                 layer[layer1] = layer[layer2];\r
777                 layer[layer2] = temporaryLayer;\r
778         }\r
779         \r
780         /**\r
781          * Replaces a Layer object in this Scene\r
782          * \r
783          * @param index a valid index for a Layer, less than getLayerCount\r
784          * @param layer a valid Layer object to replace the existing Layer\r
785          */\r
786         public void setLayer(int index, Layer layer) {\r
787                 if(layer == null) {\r
788                         Debug.warning("Scene.setLayer", "Tried setting to a null Layer");\r
789                         return;\r
790                 }\r
791                 if(index < 0 || index > layerCount) {\r
792                         Debug.warning("Scene.setLayer", "Tried setting an invalid Layer, index=" + index + ", maximum is " + layerCount);\r
793                         return;\r
794                 }\r
795                 this.layer[index] = layer;\r
796         }\r
797         \r
798         /**\r
799          * Adds a DrawableObject to the first (0th) Layer\r
800          * \r
801          * @param drawableObject a valid DrawableObject\r
802          */\r
803         public void add(GameObject drawableObject) {\r
804                 layer[0].add(drawableObject);\r
805         }\r
806         \r
807         /**\r
808          * Adds a DrawableObject to a given Layer\r
809          * \r
810          * @param layerIndex a valid index of a Layer\r
811          * @param drawableObject a valid DrawableObject\r
812          */\r
813         public void add(int layerIndex, GameObject drawableObject) {\r
814                 if(layerIndex < 0 || layerIndex > layerCount) {\r
815                         Debug.warning("Scene.add", "Tried adding to an invalid Layer, layerIndex=" + layerIndex + ", maximum is " + layerCount);\r
816                         return;\r
817                 }\r
818                 if(drawableObject == null) {\r
819                         Debug.warning("Scene.add", "Tried adding a NULL DrawableObject");\r
820                         return;\r
821                 }\r
822                 layer[layerIndex].add(drawableObject);\r
823         }\r
824         \r
825         /**\r
826          * Removes a DrawableObject from the Scene\r
827          * \r
828          * @param drawableObject a valid DrawableObject\r
829          */\r
830         public void remove(DrawableObject drawableObject) {\r
831                 drawableObject.remove();\r
832         }\r
833         \r
834         protected void onUpdate() {\r
835                 \r
836         }\r
837         \r
838         protected void onGameLoop() {\r
839                 \r
840         }\r
841         \r
842         protected void onSetScene() {\r
843                 loadedTextures = false;\r
844         }\r
845         \r
846         protected void onEndScene() {\r
847                 \r
848         }\r
849         \r
850         protected void onLoadTextures(GL10 gl) {\r
851                 Debug.print("Loading textures onto the Scene");\r
852                 for(int i = 0; i < texturesToLoad.length; i++) {\r
853                         if(texturesToLoad[i] != null) {\r
854                                 texturesToLoad[i].onLoadTexture(gl);\r
855                                 boolean foundSpace = false;\r
856                                 for(int j = 0; j < texturesOnHardware.length; j++) {\r
857                                         if(texturesOnHardware[j] == null) {\r
858                                                 Debug.print("found room...");\r
859                                                 texturesOnHardware[j] = texturesToLoad[i];\r
860                                                 foundSpace = true;\r
861                                                 break;\r
862                                         }\r
863                                 }\r
864                                 if(!foundSpace) {\r
865                                         Debug.warning("Loading more textures than we can remember - will not be there if we onPause, may not be destroyed on Scene death");\r
866                                 }\r
867                                 texturesToLoad[i] = null;\r
868                         }\r
869                 }\r
870                 loadedTextures = true;\r
871         }\r
872         \r
873         protected void onReloadTextures(GL10 gl) {\r
874                 texturesToLoad = texturesOnHardware;\r
875                 for(int i = 0; i < texturesOnHardware.length; i++) {\r
876                         texturesOnHardware[i] = null;\r
877                 }\r
878                 onLoadTextures(gl);\r
879         }\r
880         \r
881         protected void onDraw(GL10 gl) {\r
882                 onPreDraw(gl);\r
883                 gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
884                 if(background != null) {\r
885                         background.onDraw(gl);\r
886                 }\r
887                 if(window != null) {\r
888                         window.onUpdate(gl);\r
889                 }\r
890                 if(usePhysics && !pausePhysics) {\r
891                         world.step(Time.getTicksFraction(), 10, 10);\r
892                 }\r
893                 gl.glMatrixMode(GL10.GL_MODELVIEW);\r
894         gl.glLoadIdentity();\r
895                 for(int i = 0; i < layerCount; i++) {\r
896                         layer[i].onDraw(gl);\r
897                 }\r
898                 onPostDraw(gl);\r
899         }\r
900         \r
901         protected boolean pausePhysics = false;\r
902         \r
903         public void pausePhysics() {\r
904                 pausePhysics = true;\r
905         }\r
906         \r
907         public void resumePhysics() {\r
908                 pausePhysics = false;\r
909         }\r
910         \r
911         public void setBackground(Background background) {\r
912                 this.background = background;\r
913                 background.parentScene = this;\r
914         }\r
915         \r
916         public Background getBackground() {\r
917                 return this.background;\r
918         }\r
919         \r
920         \r
921         \r
922         \r
923         \r
924         \r
925         \r
926         \r
927         protected class SceneContactListener implements ContactListener {\r
928 \r
929                 public void beginContact(Contact contact) {\r
930                         // TODO Auto-generated method stub\r
931                         \r
932                 }\r
933 \r
934                 public void endContact(Contact contact) {\r
935                         // TODO Auto-generated method stub\r
936                         \r
937                 }\r
938                 \r
939         }\r
940         \r
941         public void useContactListener() {\r
942                 if(contactListener == null) {\r
943                         contactListener = new SceneContactListener();\r
944                 }\r
945                 useContactListener = true;\r
946         }\r
947         \r
948         public void stopContactListener() {\r
949                 useContactListener = false;\r
950         }\r
951         \r
952         public void setContactListener(ContactListener contactListener) {\r
953                 this.contactListener = contactListener;\r
954         }\r
955         \r
956         public void setDefaultLineWidth(float lineWidth) {\r
957                 defaultLineWidth = lineWidth;\r
958         }\r
959         \r
960         public float getDefaultLineWidth() {\r
961                 return defaultLineWidth;\r
962         }\r
963         \r
964         \r
965         \r
966 }\r