View Javadoc

1   /*
2    *  MicroEmulator
3    *  Copyright (C) 2005 Andres Navarro
4    *
5    *  This library is free software; you can redistribute it and/or
6    *  modify it under the terms of the GNU Lesser General Public
7    *  License as published by the Free Software Foundation; either
8    *  version 2.1 of the License, or (at your option) any later version.
9    *
10   *  This library is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   *  Lesser General Public License for more details.
14   *
15   *  You should have received a copy of the GNU Lesser General Public
16   *  License along with this library; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package javax.microedition.lcdui.game;
21  
22  import javax.microedition.lcdui.Graphics;
23  import javax.microedition.lcdui.Image;
24  
25  /**
26   *
27   * @author Andres Navarro
28   *
29   */
30  
31  // TODO add more synchronization
32  
33  public class Sprite extends Layer {
34      // transform constants
35      public static final int TRANS_NONE = 0;
36      public static final int TRANS_ROT90 = 5;
37      public static final int TRANS_ROT180 = 3;
38      public static final int TRANS_ROT270 = 6;
39      public static final int TRANS_MIRROR = 2;
40      public static final int TRANS_MIRROR_ROT90 = 7;
41      public static final int TRANS_MIRROR_ROT180 = 1;
42      public static final int TRANS_MIRROR_ROT270 = 4;
43  
44      // current frame index (within the sequence, not the absolut index)
45      private int frame;
46      
47      // the frame sequence
48      // null if the default is used
49      private int [] sequence;
50      
51      // coordinate of the reference pixel
52      private int refX;
53      private int refY;
54      
55      // number of cols and rows within the image
56      private int cols;
57      private int rows;
58      
59      // the transform aplied to this sprite
60      private int transform;
61              
62      // the image containg the frames
63      private Image img;
64      
65      // the collision rectangle
66      private int collX;
67      private int collY;
68      private int collWidth;
69      private int collHeight;
70      
71      // arrays for the collision detection at pixel level
72      private int []rgbData;
73      private int []rgbDataAux;
74      
75      public Sprite(Image img) {
76          this(img, img.getWidth(), img.getHeight());
77      }
78      
79      public Sprite(Image img, int frameWidth, int frameHeight) {
80          // initial state is visible, positioned at 0, 0
81          // with a bound rectangle the same as the frame
82          super(0, 0, frameWidth, frameHeight, true);
83          
84          // implicit check for null img
85          if (img.getWidth() % frameWidth != 0 ||
86                  img.getHeight() % frameHeight != 0)
87              throw new IllegalArgumentException();
88          this.img = img;
89          cols = img.getWidth() / frameWidth;
90          rows = img.getHeight() / frameHeight;
91          collX = collY = 0;
92          collWidth = frameWidth;
93          collHeight = frameHeight;
94      }
95      
96      public Sprite(Sprite otherSprite) {
97          // copy the otherSprite
98          super(otherSprite.getX(), otherSprite.getY(), 
99                  otherSprite.getWidth(), otherSprite.getHeight(),
100                 otherSprite.isVisible());
101         this.frame = otherSprite.frame;
102         this.sequence = otherSprite.sequence;
103         this.refX = otherSprite.refX;
104         this.refY = otherSprite.refY;
105         this.cols = otherSprite.cols;
106         this.rows = otherSprite.rows;
107         this.transform = otherSprite.transform;
108         this.img = otherSprite.img;
109         this.collX = otherSprite.collX;
110         this.collY = otherSprite.collY;
111         this.collWidth = otherSprite.collWidth;
112         this.collHeight = otherSprite.collHeight;
113     }
114     
115     public final boolean collidesWith(Image image, int iX, int iY, boolean pixelLevel) {
116         if (image == null)
117             throw new IllegalArgumentException();
118         
119         // only check collision if visible
120         if (!this.isVisible())
121                 return false;
122 
123         if (pixelLevel)
124             return collidesWithPixelLevel(image, iX, iY);
125         else
126             return collidesWith(image, iX, iY);
127     }
128 
129 
130     
131     public final boolean collidesWith(TiledLayer layer, boolean pixelLevel) {
132         int sX, sY;
133         int sW, sH;
134 
135         if (layer == null) {
136             throw new NullPointerException();
137         }
138         
139         // only check collision if visible
140         if (!this.isVisible())
141                 return false;
142 
143         // only check collision if both are visible
144         if (!layer.isVisible() || !this.isVisible())
145             return false;
146             
147         if (pixelLevel) // second and third parameters are dont care
148             return collidesWithPixelLevel(layer, 0, 0);
149         else 
150             return collidesWith(layer, 0, 0);
151     }
152 
153     public final boolean collidesWith(Sprite otherSprite, boolean pixelLevel) {
154         int sX, sY;
155         int sW, sH;
156 
157         if (otherSprite == null) {
158             throw new NullPointerException();
159         }
160         
161         // only check collision if both are visible
162         if (!otherSprite.isVisible() || !this.isVisible())
163             return false;
164         
165         if (pixelLevel) // second and third parameters are dont care
166             return collidesWithPixelLevel(otherSprite, 0, 0);
167         else 
168             return collidesWith(otherSprite, 0, 0);
169     }
170     
171     public void defineReferencePixel(int x, int y) {
172         refX = x;
173         refY = y;
174     }
175     
176     public int getRefPixelX() {
177         return getX() + refX;
178     }
179     
180     public int getRefPixelY() {
181         return getY() + refY;
182     }
183 
184     public void setRefPixelPosition(int x, int y) {
185         int curRefX, curRefY;
186         int width = getWidth();
187         int height = getHeight();
188 
189         switch(transform) {
190             case TRANS_NONE:
191                 curRefX = refX;
192                 curRefY = refY;
193                 break;
194             case TRANS_MIRROR_ROT180:
195                 curRefX = width - refX;
196                 curRefY = height - refY;
197                 break;
198             case TRANS_MIRROR:
199                 curRefX = width - refX;
200                 curRefY = refY;
201                 break;
202             case TRANS_ROT180:
203                 curRefX = refX;
204                 curRefY = height - refY;
205                 break;
206             case TRANS_MIRROR_ROT270:
207                 curRefX = height - refY;
208                 curRefY = refX;
209                 break;
210             case TRANS_ROT90:
211                 curRefX = height - refY;
212                 curRefY = width - refX;
213                 break;
214             case TRANS_ROT270:
215                 curRefX = refY;
216                 curRefY = refX;
217                 break;
218             case TRANS_MIRROR_ROT90:
219                 curRefX = refY;
220                 curRefY = width - refX;
221                 break;
222             default: // cant really happen, but the return keeps the
223                     // compiler happy (otherwise it'll report variable
224                     // may not be initialized)
225                 return;
226         }
227 
228         setPosition(x - curRefX, y - curRefY);
229     }
230    
231     public void defineCollisionRectangle(int x, int y, int width, int height) {
232         if (width < 0 || height < 0)
233             throw new IllegalArgumentException();
234         collX = x;
235         collY = y;
236         collWidth = width;
237         collHeight = height;
238     }
239     
240     public void setFrameSequence(int []sequence) {
241         if (sequence == null) {
242             // return to default sequence
243             this.sequence = null;
244             return;
245         }
246 
247         int max = (rows*cols)-1;
248 
249         int l = sequence.length;
250         
251         if (l == 0)
252             throw new IllegalArgumentException();
253         
254         for (int i = 0; i < l; i++) {
255             int value = sequence[i];
256             if (value > max || value < 0)
257                 throw new ArrayIndexOutOfBoundsException();
258         }
259             
260         this.sequence = sequence;
261         // the frame number has to be reseted
262         this.frame = 0;
263     }
264     
265     public final int getFrame() {
266 		return frame;
267     }
268     
269     public int getFrameSequenceLength() {
270     	return (sequence == null) ? rows*cols : sequence.length; 
271     }
272     
273     public void setFrame(int frame) {
274         int l = (sequence == null)? rows*cols : sequence.length; 
275         if (frame < 0 || frame >= l) {
276             throw new IndexOutOfBoundsException();
277         }
278         this.frame = frame;
279     }
280     
281     public void nextFrame() {
282         if (frame == ((sequence == null)? rows*cols : sequence.length) - 1)
283             frame = 0;
284         else
285             frame++;
286     }
287     
288     public void prevFrame() {
289         if (frame == 0)
290             frame = ((sequence == null)? rows*cols : sequence.length) - 1;
291         else
292             frame--;
293     }
294  
295     public void setImage(Image img, int frameWidth, int frameHeight) {
296     	synchronized (this) {
297 	        int oldW = getWidth();
298 	        int oldH = getHeight();
299 	        int newW = img.getWidth();
300 	        int newH = img.getHeight();
301 	        
302 	        // implicit size check
303 	        setSize(frameWidth, frameHeight);
304 	
305 	        if (img.getWidth() % frameWidth != 0 ||
306 	                img.getHeight() % frameHeight != 0)
307 	            throw new IllegalArgumentException();
308 	        this.img = img;
309 	        
310 	        int oldFrames = cols*rows;
311 	        cols = img.getWidth() / frameWidth;
312 	        rows = img.getHeight() / frameHeight;
313 	        
314 	        if (rows*cols < oldFrames) {
315 	            // there are fewer frames
316 	            // reset frame number and sequence
317 	            sequence = null;
318 	            frame = 0;
319 	        }
320 	        
321 	        if (frameWidth != getWidth() || frameHeight != getHeight()) {
322 	            // size changed
323 	            // reset collision rectangle and collision detection array
324 	            defineCollisionRectangle(0, 0, frameWidth, frameHeight);
325 	            rgbData = rgbDataAux = null;
326 	            
327 	            // if necessary change position to keep the reference pixel in place
328 	            
329 	            if (transform != TRANS_NONE) {
330 	                int dx, dy;
331 	                switch(transform) {
332 	                    case TRANS_MIRROR_ROT180:
333 	                        dx = newW - oldW;
334 	                        dy = newH - oldH;
335 	                        break;
336 	                    case TRANS_MIRROR:
337 	                        dx = newW - oldW;
338 	                        dy = 0;
339 	                        break;
340 	                    case TRANS_ROT180:
341 	                        dx = 0;
342 	                        dy = newH - oldH;
343 	                        break;
344 	                    case TRANS_MIRROR_ROT270:
345 	                        dx = newH - oldH;
346 	                        dy = 0;
347 	                        break;
348 	                    case TRANS_ROT90:
349 	                        dx = newH - oldH;
350 	                        dy = newW - oldW;
351 	                        break;
352 	                    case TRANS_ROT270:
353 	                        dx = 0;
354 	                        dy = 0;
355 	                        break;
356 	                    case TRANS_MIRROR_ROT90:
357 	                        dx = 0;
358 	                        dy = newW - oldW;
359 	                        break;
360 	                    default: // cant really happen, but the return keeps the
361 	                            // compiler happy (otherwise it'll report variable
362 	                            // may not be initialized)
363 	                        return;
364 	                }
365 	                // now change position to keep the refPixel in place
366 	                move(dx, dy);
367 	            }	                
368 	        }
369     	}
370     }
371     
372     public final void paint(Graphics g) {
373         if (!isVisible())
374             return;
375         
376         int f = (sequence == null)? frame : sequence[frame];
377         int w = getWidth();
378         int h = getHeight();
379         int fx = w * (f % cols);
380         int fy = h * (f / cols);        
381         
382         g.drawRegion(img, fx, fy, w, h, transform, getX(), getY(), Graphics.TOP | Graphics.LEFT);
383     }
384     
385     public int getRawFrameCount() {
386         return cols * rows;
387     }
388     
389     public void setTransform (int transform) {
390         if (this.transform == transform)
391             return;
392         
393         int width = getWidth();
394         int height = getHeight();
395         int currentTransform = this.transform;
396         
397         // calculate the coordinates of refPixel in the new transform
398         // relative to x, y
399         
400         int newRefX, newRefY;
401 
402         switch(transform) {
403             case TRANS_NONE:
404                 newRefX = refX;
405                 newRefY = refY;
406                 break;
407             case TRANS_MIRROR_ROT180:
408                 newRefX = width - refX;
409                 newRefY = height - refY;
410                 break;
411             case TRANS_MIRROR:
412                 newRefX = width - refX;
413                 newRefY = refY;
414                 break;
415             case TRANS_ROT180:
416                 newRefX = refX;
417                 newRefY = height - refY;
418                 break;
419             case TRANS_MIRROR_ROT270:
420                 newRefX = height - refY;
421                 newRefY = refX;
422                 break;
423             case TRANS_ROT90:
424                 newRefX = height - refY;
425                 newRefY = width - refX;
426                 break;
427             case TRANS_ROT270:
428                 newRefX = refY;
429                 newRefY = refX;
430                 break;
431             case TRANS_MIRROR_ROT90:
432                 newRefX = refY;
433                 newRefY = width - refX;
434                 break;
435             default:
436                 throw new IllegalArgumentException();
437         }
438 
439         // calculate the coordinates of refPixel in the current transform
440         // relative to x, y
441         
442         int curRefX, curRefY;
443 
444         switch(currentTransform) {
445             case TRANS_NONE:
446                 curRefX = refX;
447                 curRefY = refY;
448                 break;
449             case TRANS_MIRROR_ROT180:
450                 curRefX = width - refX;
451                 curRefY = height - refY;
452                 break;
453             case TRANS_MIRROR:
454                 curRefX = width - refX;
455                 curRefY = refY;
456                 break;
457             case TRANS_ROT180:
458                 curRefX = refX;
459                 curRefY = height - refY;
460                 break;
461             case TRANS_MIRROR_ROT270:
462                 curRefX = height - refY;
463                 curRefY = refX;
464                 break;
465             case TRANS_ROT90:
466                 curRefX = height - refY;
467                 curRefY = width - refX;
468                 break;
469             case TRANS_ROT270:
470                 curRefX = refY;
471                 curRefY = refX;
472                 break;
473             case TRANS_MIRROR_ROT90:
474                 curRefX = refY;
475                 curRefY = width - refX;
476                 break;
477             default: // cant really happen, but the return keeps the
478                     // compiler happy (otherwise it'll report variable
479                     // may not be initialized)
480                 return;
481         }
482         
483         // now change position to keep the refPixel in place
484         move(curRefX - newRefX, curRefY - newRefY);
485         this.transform = transform;
486     }
487 
488     
489     /**
490      * Helper methods that check for collisions
491      * They are at the end of the file because of the 
492      * length of the code
493      *
494      * For both methods, the second and third parameters 
495      * are significant only if o is an Image, 
496      * otherwise they are ignored
497      */
498     private synchronized boolean collidesWith(Object o, 
499                 int oX, int oY) {
500     
501         int tX = 0, tY = 0, tW = 0, tH = 0;
502         int oW = 0, oH = 0;
503 
504         Sprite t = this;
505         boolean another = true;
506         
507         
508         while (another) {
509             int sX, sY, sW, sH;
510 
511             int cX = t.collX;
512             int cY = t.collY;
513             int cW = t.collWidth;
514             int cH = t.collHeight;
515             
516             // if there is a zero in a dimension
517             // then it cannot intersect with anything!
518             if (cW == 0 || cH == 0) {
519                 return false;
520             }
521 
522             switch(t.transform) {
523                 case TRANS_NONE:
524                     sX = t.getX() + cX;
525                     sY = t.getY() + cY;
526                     sW = cW;
527                     sH = cH;
528                     break;
529                 case TRANS_MIRROR_ROT180:
530                     sX = t.getX() + cX;
531                     sY = t.getY() + (t.getHeight() - cY - 1) - cH;
532                     sW = cW;
533                     sH = cH;
534                     break;
535                 case TRANS_MIRROR:
536                     sX = t.getX() + (t.getWidth() - cX - 1) - cW;
537                     sY = t.getY() + cY;
538                     sW = cW;
539                     sH = cH;
540                     break;
541                 case TRANS_ROT180:
542                     sX = t.getX() + (t.getWidth() - cX - 1) - cW;
543                     sY = t.getY() + (t.getHeight() - cY - 1) - cH; 
544                     sW = cW;
545                     sH = cH;
546                     break;
547                 case TRANS_MIRROR_ROT270:
548                     sX = t.getX() + cY;
549                     sY = t.getY() + cX;
550                     sW = cH;
551                     sH = cW;
552                     break;
553                 case TRANS_ROT90:
554                     sX = t.getX() + (t.getHeight() - cY - 1) - cH;
555                     sY = t.getY() + cX;
556                     sW = cH;
557                     sH = cW;
558                     break;
559                 case TRANS_MIRROR_ROT90:
560                     sX = t.getX() + (t.getHeight() - cY - 1) - cH;
561                     sY = t.getY() + (t.getWidth() - cX - 1) - cW;
562                     sW = cH;
563                     sH = cW;
564                     break;
565                 case TRANS_ROT270:
566                     sX = t.getX() + cY;
567                     sY = t.getY() + (t.getWidth() - cX - 1) - cW;
568                     sW = cH;
569                     sH = cW;
570                     break;
571                 default: // cant really happen, but the return keeps the
572                         // compiler happy (otherwise it'll report variable
573                         // may not be initialized)
574                     return false;
575             }
576             
577             if (o != t) {
578                 tX = sX;
579                 tY = sY;
580                 tW = sW;
581                 tH = sH;
582                 if (o instanceof Sprite) {
583                     // two sprites first round
584                     // another = true;
585                     t = (Sprite) o;
586                 } else if (o instanceof TiledLayer) {
587                     another = false;
588                     TiledLayer layer = (TiledLayer) o;
589                     oX = layer.getX();
590                     oY = layer.getY();
591                     oW = layer.getWidth();
592                     oH = layer.getHeight();
593                 } else { // o instanceof lcdui.Image
594                     another = false;
595                     Image img = (Image) o;
596                     oW = img.getWidth();
597                     oH = img.getHeight();
598                 }
599             } else {
600                 another = false;
601                 // two sprites
602                 // second round
603                 oX = sX;
604                 oY = sY;
605                 oW = sW;
606                 oH = sH;
607             }
608         }
609 
610         // if there is no intersection
611         // we know there is no collision
612         if (tX > oX && tX >= oX + oW)
613             return false;
614         else if (tX < oX && tX + tW <= oX)
615             return false;
616         else if (tY > oY && tY >= oY + oH)
617             return false;
618         else if (tY < oY && tY + tH <= oY)
619             return false;
620 
621         if (o instanceof TiledLayer) {
622             // if o is a tiledLayer then
623             // it is possible to have not a
624             // collision if every intersection tile
625             // has a zero value 
626             TiledLayer layer = (TiledLayer) o;
627             // this is the intersection of the two rectangles
628             int rX, rY, rW, rH;
629 
630             if (oX > tX) {
631                 rX = oX;
632                 rW = ((oX + oW < tX + tW)? oX + oW : tX + tW) - rX;
633             } else {
634                 rX = tX;
635                 rW = ((tX + tW < oX + oW)? tX + tW : oX + oW) - rX;
636             }
637             if (oY > tY) {
638                 rY = oY;
639                 rH = ((oY + oH < tY + tH)? oY + oH : tY + tH) - rY;
640             } else {
641                 rY = tY;
642                 rH = ((tY + tH < oY + oH)? tY + tH : oY + oH) - rY;
643             }
644             
645             Image img = layer.img;
646 
647             int lW = layer.getCellWidth();
648             int lH = layer.getCellHeight();
649 
650             int minC = (rX - oX) / lW;
651             int minR = (rY - oY) / lH;
652             int maxC = (rX - oX + rW - 1) / lW;
653             int maxR = (rY - oY + rH - 1) / lH;
654 
655             // travel across all cells in the collision
656             // rectangle
657             for (int row = minR; row <= maxR; row++) {
658                 for (int col = minC; col <= maxC; col++) {
659                     int cell = layer.getCell(col, row);
660                     // if cell is animated get current
661                     // associated static tile
662                     if (cell < 0)
663                         cell = layer.getAnimatedTile(cell);
664 
665                     if (cell != 0)
666                         return true;
667                 }
668             }
669 
670             // if no non zero cell was found
671             // there is no collision
672             return false;
673         } else {
674             // if the other object is an image or sprite
675             // collision happened
676             return true;
677         }
678     }    
679 
680     private synchronized boolean collidesWithPixelLevel(Object o, 
681                 int oX, int oY) {
682         
683         
684         boolean another = true;
685         Sprite t = this;
686 
687         // the compiler bitchs if we dont initialize this
688         int tX = 0, tY = 0, tW = 0, tH = 0;
689         int oW = 0, oH = 0;
690         
691         while (another) {
692             // first calculate the actual rectangle we must check 
693             // for this sprite
694             // this are for the reduced collision rectangle
695             int cX, cY, cW, cH;
696             // this are for the intersection of the bounds rectangle 
697             // and collision rectangle, taking into account
698             // position and transform
699             int sX, sY, sW, sH;
700 
701 
702             
703             // take the collision rectangle in account
704             // but since the pixels outside the frame are
705             // considered transparent, first we have to
706             // take the intersection between the collision
707             // rectangle and the frame bounds
708 
709             if (t.collX >= t.getWidth() || t.collX + t.collWidth <= 0 
710                         || t.collY >= t.getHeight() || t.collY + t.collHeight <= 0)
711             // collision rectangle outside frame bounds
712                 return false;
713 
714             cX = (t.collX >= 0)? t.collX : 0;
715             cY = (t.collY >= 0)? t.collY : 0;
716             cW = (t.collX + t.collWidth < t.getWidth())? t.collX + t.collWidth - cX : t.getWidth() - cX;
717             cH = (t.collY + t.collHeight < t.getHeight())? t.collY + t.collHeight - cY : t.getHeight() - cY;
718 
719             switch(t.transform) {
720                 case TRANS_NONE:
721                     sX = t.getX() + cX;
722                     sY = t.getY() + cY;
723                     sW = cW;
724                     sH = cH;
725                     break;
726                 case TRANS_MIRROR_ROT180:
727                     sX = t.getX() + cX;
728                     sY = t.getY() + (t.getHeight() - cY - 1) - cH;
729                     sW = cW;
730                     sH = cH;
731                     break;
732                 case TRANS_MIRROR:
733                     sX = t.getX() + (t.getWidth() - cX - 1) - cW;
734                     sY = t.getY() + cY;
735                     sW = cW;
736                     sH = cH;
737                     break;
738                 case TRANS_ROT180:
739                     sX = t.getX() + (t.getWidth() - cX - 1) - cW;
740                     sY = t.getY() + (t.getHeight() - cY - 1) - cH; 
741                     sW = cW;
742                     sH = cH;
743                     break;
744                 case TRANS_MIRROR_ROT270:
745                     sX = t.getX() + cY;
746                     sY = t.getY() + cX;
747                     sW = cH;
748                     sH = cW;
749                     break;
750                 case TRANS_ROT90:
751                     sX = t.getX() + (t.getHeight() - cY) - cH;
752                     sY = t.getY() + cX;
753                     sW = cH;
754                     sH = cW;
755                     break;
756                 case TRANS_MIRROR_ROT90:
757                     sX = t.getX() + (t.getHeight() - cY) - cH;
758                     sY = t.getY() + (t.getWidth() - cX) - cW;
759                     sW = cH;
760                     sH = cW;
761                     break;
762                 case TRANS_ROT270:
763                     sX = t.getX() + cY;
764                     sY = t.getY() + (t.getWidth() - cX) - cW;
765                     sW = cH;
766                     sH = cW;
767                     break;
768                 default: // cant really happen, but the return keeps the
769                         // compiler happy (otherwise it'll report variable
770                         // may not be initialized)
771                     return false;
772             }
773             
774             if (o != t) {
775                 tX = sX;
776                 tY = sY;
777                 tW = sW;
778                 tH = sH;
779                 if (o instanceof Sprite) {
780                     // two sprites first round
781                     // another = true;
782                     t = (Sprite) o;
783                 } else if (o instanceof TiledLayer) {
784                     another = false;
785                     TiledLayer layer = (TiledLayer) o;
786                     oX = layer.getX();
787                     oY = layer.getY();
788                     oW = layer.getWidth();
789                     oH = layer.getHeight();
790                 } else { // o instanceof lcdui.Image
791                     another = false;
792                     Image img = (Image) o;
793                     oW = img.getWidth();
794                     oH = img.getHeight();
795                 }
796             } else {
797                 another = false;
798                 // two sprites
799                 // second round
800                 oX = sX;
801                 oY = sY;
802                 oW = sW;
803                 oH = sH;
804             }
805         }
806  
807         // if there is no intersection
808         // we know there is no collision
809         if (tX > oX && tX >= oX + oW)
810             return false;
811         else if (tX < oX && tX + tW <= oX)
812             return false;
813         else if (tY > oY && tY >= oY + oH)
814             return false;
815         else if (tY < oY && tY + tH <= oY)
816             return false;
817 
818         // variables keep popping out of nowhere...
819         // this is the intersection of the two rectangles
820         int rX, rY, rW, rH;
821 
822         
823         if (oX > tX) {
824             rX = oX;
825             rW = ((oX + oW < tX + tW)? oX + oW : tX + tW) - rX ;
826         } else {
827             rX = tX;
828             rW = ((tX + tW < oX + oW)? tX + tW : oX + oW) - rX;
829         }
830         if (oY > tY) {
831             rY = oY;
832             rH = ((oY + oH < tY + tH)? oY + oH : tY + tH) - rY ;
833         } else {
834             rY = tY;
835             rH = ((tY + tH < oY + oH)? tY + tH : oY + oH) - rY;
836         }
837 
838         // ...and a lot more..
839         int tColIncr = 0, tRowIncr = 0, tOffset = 0;
840         int oColIncr = 0, oRowIncr = 0, oOffset = 0;
841 
842         int f = (sequence == null)? frame : sequence[frame];
843 
844         int fW = getWidth();
845         int fH = getHeight();
846         int fX = fW * (f % rows);
847         int fY = fH * (f / rows);
848 
849         if (rgbData == null) {
850             rgbData = new int[fW*fH];
851             rgbDataAux = new int[fW*fH];
852         }
853 
854         t = this;
855         another = true;
856         int[] tRgbData = this.rgbData;
857         
858         while (another) {
859             int sOffset;
860             int sColIncr;
861             int sRowIncr;
862                     
863             switch(t.transform) {
864                 case TRANS_NONE:
865                     t.img.getRGB(tRgbData, 0, rW, fX + rX - t.getX(), fY + rY - t.getY(), rW, rH); 
866                     sOffset = 0;
867                     sColIncr = 1;
868                     sRowIncr = 0;
869                     break;
870                 case TRANS_ROT180:
871                     t.img.getRGB(tRgbData, 0, rW, fX + fW - (rX - t.getX()) - rW - 1, fY + fH - (rY - t.getY()) - rH - 1, rW, rH); 
872                     sOffset = (rH * rW) - 1;
873                     sColIncr = -1;
874                     sRowIncr =  0;
875                     break;
876                 case TRANS_MIRROR:
877                     t.img.getRGB(tRgbData, 0, rW, fX + fW - (rX - t.getX()) - rW - 1, fY + rY - t.getY(), rW, rH); 
878                     sOffset = rW - 1;
879                     sColIncr = -1;
880                     sRowIncr =  rW << 1;
881                     break;
882                 case TRANS_MIRROR_ROT180:
883                     t.img.getRGB(tRgbData, 0, rW, fX + rX - t.getX(), fY + fH - (rY - t.getY()) - rH - 1, rW, rH); 
884                     sOffset = (rH - 1) * rW;
885                     sColIncr = 1;
886                     sRowIncr =  -(rW << 1);
887                     break;
888                 case TRANS_ROT90:
889                     t.img.getRGB(tRgbData, 0, rH, fX + rY - t.getY(), fY + fH - (rX - t.getX()) - rW, rH, rW); 
890                     sOffset = (rW - 1) * rH;
891                     sColIncr = -rH;
892                     sRowIncr = (rH * rW) + 1;
893                     break;
894                 case TRANS_MIRROR_ROT90:
895                     t.img.getRGB(tRgbData, 0, rH, fX + fW - (rY - t.getY()) - rH, fY + fH - (rX - t.getX()) - rW, rH, rW); 
896                     sOffset = (rH * rW) - 1;
897                     sColIncr = -rH;
898                     sRowIncr = (rH * rW) - 1;
899                     break;
900                 case TRANS_MIRROR_ROT270:
901                     t.img.getRGB(tRgbData, 0, rH, fX + rY - t.getY(), fY + rX - t.getX(), rH, rW); 
902                     sOffset = 0;
903                     sColIncr = rH;
904                     sRowIncr = -(rH * rW) + 1;
905                     break;
906                 case TRANS_ROT270:
907                     t.img.getRGB(tRgbData, 0, rH, fX + fW - (rY - t.getY()) - rH, fY + rX - t.getX(), rH, rW); 
908                     sOffset = rH - 1;
909                     sColIncr = rH;
910                     sRowIncr =  -(rH * rW) - 1;
911                     break;
912                 default: // cant really happen, but the return keeps the
913                         // compiler happy (otherwise it'll report variable
914                         // may not be initialized)
915                     return false;
916             }
917 
918             if (o != t) {
919                 tOffset = sOffset;
920                 tRowIncr = sRowIncr;
921                 tColIncr = sColIncr;
922 
923                 if (o instanceof Sprite) {
924                     // two sprites first round
925                     // another = true;
926                     t = (Sprite) o;
927                     tRgbData = this.rgbDataAux;
928           
929                     f = (t.sequence == null)? t.frame : t.sequence[t.frame];
930 
931                     fW = t.getWidth();
932                     fH = t.getHeight();
933                     fX = fW * (f % t.rows);
934                     fY = fH * (f / t.rows);
935                 } else if (o instanceof TiledLayer) {
936                     another = false;
937                     TiledLayer layer = (TiledLayer) o;
938                     Image img = layer.img;
939 
940                     oOffset = 0;
941                     oColIncr = 1;
942                     oRowIncr = 0;
943                     
944                     int lW = layer.getCellWidth();
945                     int lH = layer.getCellHeight();
946                     
947                     int minC = (rX - oX) / lW;
948                     int minR = (rY - oY) / lH;
949                     int maxC = (rX - oX + rW - 1) / lW;
950                     int maxR = (rY - oY + rH - 1) / lH;
951                     
952                     // travel across all cells in the collision
953                     // rectangle
954                     for (int row = minR; row <= maxR; row++) {
955                         for (int col = minC; col <= maxC; col++) {
956                             int cell = layer.getCell(col, row);
957                             // if cell is animated get current
958                             // associated static tile
959                             if (cell < 0)
960                                 cell = layer.getAnimatedTile(cell);
961                             
962                             int minX = (col == minC)? (rX - oX) % lW : 0;
963                             int minY = (row == minR)? (rY - oY) % lH : 0;
964                             int maxX = (col == maxC)? (rX + rW - oX - 1) % lW : lW-1;
965                             int maxY = (row == maxR)? (rY + rH - oY - 1) % lH : lH-1;
966                             
967                             
968                             int c = (row - minR) * lH * rW + (col - minC) * lW -
969                                     ((col == minC)? 0 : (rX - oX) % lW) -
970                                     ((row == minR)? 0 : (rY - oY) % lH) * rW;
971 
972                             // if cell is invisible we should still set
973                             // all points as transparent to prevent
974                             // fake positives caused by residual data
975                             // on the rgb array
976                             if (cell == 0) {
977                                 
978                                 for (int y = minY; y <= maxY; y++, 
979                                             c += rW - (maxX - minX + 1)) {
980                                     for (int x = minX; x <= maxX; x++, c++) {
981                                         rgbDataAux[c] = 0;
982                                     }
983                                 }
984                             } else {
985                                 // make cell 0-based
986                                 cell--;
987                                 
988                                 int imgCols = img.getWidth() / layer.getCellWidth();
989                                 int xSrc = lW * (cell % imgCols);
990                                 int ySrc = (cell / imgCols) * lH;
991                                 img.getRGB(rgbDataAux, c, rW, xSrc + minX, 
992                                         ySrc + minY, maxX - minX + 1, 
993                                         maxY - minY + 1);
994       
995                             }
996                         }
997                     }
998                 } else { // o instanceof lcdui.Image
999                     another = false;
1000                     Image img = (Image) o;
1001                     // get the image rgb data, and the increments
1002                     img.getRGB(rgbDataAux, 0, rW, rX - oX, rY - oY, rW, rH);
1003                     oOffset = 0;
1004                     oColIncr = 1;
1005                     oRowIncr = 0;
1006                 }
1007             } else {
1008                 // two sprites
1009                 // second round, exit the loop
1010                 another = false;
1011                 oOffset = sOffset;
1012                 oRowIncr = sRowIncr;
1013                 oColIncr = sColIncr;
1014             }
1015         }
1016         
1017         for (int row = 0; row < rH; row++, tOffset += tRowIncr, oOffset += oRowIncr) {
1018             for (int col = 0; col < rW; col++, tOffset += tColIncr, oOffset += oColIncr) {
1019                 int rgb = rgbData[tOffset];
1020                 int rgbA = rgbDataAux[oOffset];
1021                 // look for two opaque pixels
1022                 if (((rgb & rgbA) >> 24) == -1)
1023                     return true;
1024             }
1025         }
1026         return false;
1027     }
1028 
1029 }
1030 
1031