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