1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.runtime
.lcdui
.gfx
;
12 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
13 import cc
.squirreljme
.runtime
.lcdui
.font
.SQFFont
;
14 import javax
.microedition
.lcdui
.Font
;
15 import javax
.microedition
.lcdui
.Graphics
;
16 import javax
.microedition
.lcdui
.Image
;
17 import javax
.microedition
.lcdui
.Text
;
18 import javax
.microedition
.lcdui
.game
.Sprite
;
21 * This class contains the advanced graphics functions which uses
22 * pre-determined functions to determine how to draw something.
24 * This class will eventually be replaced by generic auto-generated classes
25 * which can handle every pixel format.
29 public class AdvancedGraphics
32 /** Clipping above. */
33 private static final int _CLIP_ABOVE
=
36 /** Clipping below. */
37 private static final int _CLIP_BELOW
=
41 private static final int _CLIP_RIGHT
=
45 private static final int _CLIP_LEFT
=
48 /** The array buffer. */
49 protected final int[] buffer
;
51 /** The length of the buffer. */
52 protected final int bufferlen
;
54 /** The width of the image. */
55 protected final int width
;
57 /** The height of the image. */
58 protected final int height
;
60 /** The pitch of the image. */
61 protected final int pitch
;
63 /** The buffer offset. */
64 protected final int offset
;
66 /** The number of elements that consist of pixel data. */
67 protected final int numelements
;
69 /** Physical end of the buffer. */
70 protected final int lastelement
;
72 /** Is there an alpha channel? */
73 protected final boolean hasalphachannel
;
75 /** Absolute translated X coordinate. */
76 protected final int abstransx
;
78 /** Absolute translated Y coordinate. */
79 protected final int abstransy
;
81 /** The current stroke style. */
82 protected int strokestyle
;
84 /** Is a dot stroke being used? */
85 protected boolean dotstroke
;
87 /** Translated X coordinate. */
90 /** Translated Y coordinate. */
93 /** The starting X clip. */
96 /** The starting Y clip. */
99 /** The ending X clip. */
100 protected int clipex
;
102 /** The ending Y clip. */
103 protected int clipey
;
105 /** The clip width. */
108 /** The clip height. */
111 /** The current font, null means default. */
114 /** The current blending mode. */
115 protected int blendmode
;
117 /** Could blending be done? */
118 protected boolean candoblending
;
120 /** Is blending actually going to be done? */
121 protected boolean doblending
;
123 /** The current color. */
126 /** The painting alpha color. */
127 protected int paintalpha
;
129 /** The color to use for painting. */
130 protected int paintcolor
;
132 /** Paint color with the alpha channel set to the max. */
133 protected int paintcolorhigh
;
135 /** The alpha color and normal color for painting. */
136 protected int paintalphacolor
;
138 /** Function for filled rectangle. */
139 protected AdvancedFunction funcfillrect
;
141 /** Function for drawing characters. */
142 protected AdvancedFunction funccharbmp
;
144 /** Function for drawing lines. */
145 protected AdvancedFunction funcline
;
148 protected AdvancedFunction funcrgbtile
;
151 protected AdvancedFunction funcargbtile
;
154 * Initializes the graphics.
156 * @param __buf The buffer.
157 * @param __alpha Does the buffer actually use the alpha channel?
158 * @param __aba Advanced buffer adapter, used to translate the internal
159 * integer based buffer to other formats.
160 * @param __w The image width.
161 * @param __h The image height.
162 * @param __p The image pitch.
163 * @param __o The buffer offset.
164 * @param __atx Absolute X translation.
165 * @param __aty Absolute Y translation.
166 * @throws IllegalArgumentException If the input parameters are not
168 * @throws NullPointerException On null arguments.
171 public AdvancedGraphics(int[] __buf
, boolean __alpha
,
172 AdvancedBufferAdapter __aba
,
173 int __w
, int __h
, int __p
, int __o
, int __atx
, int __aty
)
174 throws IllegalArgumentException
, NullPointerException
177 throw new NullPointerException("NARG");
179 // {@squirreljme.error EB0b Invalid width and/or height specified.}
180 if (__w
<= 0 || __h
<= 0)
181 throw new IllegalArgumentException("EB0b");
183 // {@squirreljme.error EB0c The pitch is less than the width.}
185 throw new IllegalArgumentException("EB0c");
187 // {@squirreljme.error EB0d The specified parameters exceed the bounds
188 // of the array. (The width; The height; The offset; The pitch;
189 // The array length; The number of elements in the image)}
190 int numelements
= (__p
* __h
),
191 lastelement
= __o
+ numelements
,
192 buflen
= __buf
.length
;
193 if (__o
< 0 || lastelement
> buflen
)
194 throw new ArrayIndexOutOfBoundsException(
195 String
.format("EB0d %d %d %d %d %d %d", __w
, __h
,
196 __o
, __p
, buflen
, numelements
));
200 this.bufferlen
= buflen
;
205 this.numelements
= numelements
;
206 this.lastelement
= lastelement
;
207 this.hasalphachannel
= __alpha
;
209 // Setup absolute translation and initialize the base translation
210 // which is at the absolute origin
211 this.abstransx
= __atx
;
212 this.abstransy
= __aty
;
216 // Initial clipping rectangle has the image bounds
224 // Reset all initial functions
225 this.resetParameters(true);
233 public void clipRect(int __x
, int __y
, int __w
, int __h
)
239 // Get right end coordinates
259 // Never go past the end of the viewport because pixels will never
260 // be drawn in negative regions
266 // Additionally do not go past the edge ever that way the end
267 // clipping point is always valid
268 int width
= this.width
,
269 height
= this.height
;
275 // Get the old clipping bounds
276 int oldclipsx
= this.clipsx
,
277 oldclipsy
= this.clipsy
,
278 oldclipex
= this.clipex
,
279 oldclipey
= this.clipey
;
281 // Only set the clipping bounds if they exceed the previous ones
283 this.clipsx
= (oldclipsx
= __x
);
285 this.clipsy
= (oldclipsy
= __y
);
287 this.clipex
= (oldclipex
= ex
);
289 this.clipey
= (oldclipey
= ey
);
292 this.clipw
= this.clipex
- oldclipsx
;
293 this.cliph
= this.clipey
- oldclipsy
;
301 public void copyArea(int __sx
, int __sy
, int __w
, int __h
,
302 int __dx
, int __dy
, int __anchor
)
303 throws IllegalArgumentException
, IllegalStateException
305 // Need translation coordinates
306 int tx
= this.transx
,
313 // Translate all coordinates
319 // Perform needed anchoring
320 if ((__anchor
& Graphics
.HCENTER
) != 0)
322 else if ((__anchor
& Graphics
.RIGHT
) != 0)
324 if ((__anchor
& Graphics
.VCENTER
) != 0)
326 else if ((__anchor
& Graphics
.BOTTOM
) != 0)
329 // End coordinates for both
330 int sex
= __sx
+ __w
,
335 // {@squirreljme.error EB0e Source region for area copy is out of
337 if (__sx
< 0 || __sy
< 0 || sex
> iw
|| sey
> ih
)
338 throw new IllegalArgumentException("EB0e");
340 this.__unimplemented(__dx
, __dy
, "copyArea");
348 public void drawArc(int __x
, int __y
, int __w
, int __h
, int __sa
,
351 this.__unimplemented(__x
, __y
, "drawArc");
359 public void drawARGB16(short[] __data
, int __off
, int __scanlen
,
360 int __x
, int __y
, int __w
, int __h
)
361 throws NullPointerException
363 this.__unimplemented(__x
, __y
, "drawARGB16");
371 public void drawChar(char __s
, int __x
, int __y
, int __anchor
)
373 // Same as drawing strings
374 this.drawString(new String(new char[]{__s
}, 0, 1),
383 public void drawChars(char[] __s
, int __o
, int __l
, int __x
,
384 int __y
, int __anchor
)
385 throws NullPointerException
388 throw new NullPointerException("NARG");
390 // Same as drawing string
391 this.drawString(new String(__s
, __o
, __l
),
400 public void drawImage(Image __i
, int __x
, int __y
, int __anchor
)
401 throws IllegalArgumentException
, NullPointerException
404 throw new NullPointerException("NARG");
406 this.drawRegion(__i
, 0, 0, __i
.getWidth(), __i
.getHeight(), 0,
415 public void drawLine(int __x1
, int __y1
, int __x2
, int __y2
)
417 // Translate all coordinates
418 int transx
= this.transx
,
419 transy
= this.transy
;
425 // Get clipping region
426 int clipsx
= this.clipsx
,
427 clipsy
= this.clipsy
,
428 clipex
= this.clipex
,
429 clipey
= this.clipey
;
431 // Perform Cohen-Sutherland line clipping
434 // Determine points that lie outside the box
435 int outa
= AdvancedGraphics
.__csOut(__x1
, __y1
,
436 clipsx
, clipsy
, clipex
- 1,clipey
- 1),
437 outb
= AdvancedGraphics
.__csOut(__x2
, __y2
, clipsx
,
438 clipsy
, clipex
- 1, clipey
- 1);
440 // Both points are outside the box, do nothing
441 if ((outa
& outb
) != 0)
444 // Both points are inside the box, use this line
445 if (outa
== 0 && outb
== 0)
448 // Only the second point is outside, swap the points so that the
449 // first point is outside and the first is not
468 // The point is clipped
471 // Differences of points
472 int dx
= __x2
- __x1
,
475 // Clips above the box
476 if ((outa
& AdvancedGraphics
._CLIP_ABOVE
) != 0)
478 __x1
+= dx
* (clipey
- __y1
) / dy
;
483 else if ((outa
& AdvancedGraphics
._CLIP_BELOW
) != 0)
485 __x1
+= dx
* (clipsy
- __y1
) / dy
;
489 // Clips the right side
490 else if ((outa
& AdvancedGraphics
._CLIP_RIGHT
) != 0)
492 __y1
+= dy
* (clipex
- __x1
) / dx
;
496 // Clips the left side
497 else if ((outa
& AdvancedGraphics
._CLIP_LEFT
) != 0)
499 __y1
+= dy
* (clipsx
- __x1
) / dx
;
505 // Have lines which always go to the right
516 // The resulting line should never be out of bounds
517 if (__x1
< clipsx
|| __x2
< clipsx
|| __y1
< clipsy
|| __y2
< clipsy
||
518 __x1
> clipex
|| __x2
> clipex
|| __y1
> clipey
|| __y2
> clipey
)
521 // Forward depending on blending and/or dots
524 this.funcline
.function(this,
525 new int[]{__x1
, __y1
, __x2
, __y2
},
529 // Exception happened when drawing a line
530 catch (IndexOutOfBoundsException e
)
532 Debugging
.debugNote("Line (%d, %d) -> (%d, %d)", __x1
, __y1
,
542 public void drawRGB(int[] __data
, int __off
, int __scanlen
,
543 int __x
, int __y
, int __w
, int __h
, boolean __alpha
)
544 throws NullPointerException
547 throw new NullPointerException("NARG");
553 // Determine ending position
557 // Get clipping region
558 int clipsx
= this.clipsx
;
559 int clipsy
= this.clipsy
;
560 int clipex
= this.clipex
;
561 int clipey
= this.clipey
;
563 // Box is completely outside the bounds of the clip, do not draw
564 if (ex
< clipsx
|| __x
>= clipex
|| ey
< clipsy
|| __y
>= clipey
)
567 // Determine sub-clipping area
568 int subX
= Math
.max(0, clipsx
- __x
);
569 int subY
= Math
.max(0, clipsy
- __y
);
577 // Check end coordinate
587 // We might have multiplied alpha blending, or just normal blending
588 // If __alpha is true then this is 32-bit RGBA!
592 this.funcargbtile
.function(this,
593 new int[]{__off
, __scanlen
, __x
, __y
, tw
, th
, subX
, subY
},
594 new Object
[]{__data
});
596 this.funcrgbtile
.function(this,
597 new int[]{__off
, __scanlen
, __x
, __y
, tw
, th
, subX
, subY
},
598 new Object
[]{__data
});
600 catch (IndexOutOfBoundsException e
)
603 "drawRGBTile(buffer[%d]=%s, bufferlen=%d, w=%d, h=%d, " +
604 "pitch=%d, offset=%d -> " +
605 "data[%d]=%s, w=%d, h=%d, off=%d, " +
607 "x=%d, y=%d, tw=%d, th=%d, subX=%d, subY=%d)",
608 this.buffer
.length
, this.buffer
, this.bufferlen
,
609 this.width
, this.height
, this.pitch
, this.offset
,
610 __data
.length
, __data
, __w
, __h
, __off
, __scanlen
, __x
, __y
,
620 public void drawRGB16(short[] __data
, int __off
, int __scanlen
,
621 int __x
, int __y
, int __w
, int __h
)
622 throws NullPointerException
624 this.__unimplemented(__x
, __y
, "drawRGB16");
632 public void drawRect(int __x
, int __y
, int __w
, int __h
)
634 // The width and height are increased by a single pixel
638 // For now just cheat and draw four lines
642 this.drawLine(__x
, __y
, ex
, __y
);
643 this.drawLine(__x
, ey
, ex
, ey
);
644 this.drawLine(__x
, __y
, __x
, ey
);
645 this.drawLine(ex
, __y
, ex
, ey
);
653 public void drawRegion(Image __src
, int __xsrc
, int __ysrc
,
654 int __wsrc
, int __hsrc
, int __trans
, int __xdest
, int __ydest
,
656 throws IllegalArgumentException
, NullPointerException
659 throw new NullPointerException("NARG");
661 this.__drawRegion(__src
, __xsrc
, __ysrc
, __wsrc
, __hsrc
, __trans
,
662 __xdest
, __ydest
, __anch
, __wsrc
, __hsrc
, true);
670 public void drawRegion(Image __src
, int __xsrc
, int __ysrc
,
671 int __wsrc
, int __hsrc
, int __trans
, int __xdest
, int __ydest
,
672 int __anch
, int __wdest
, int __hdest
)
673 throws IllegalArgumentException
, NullPointerException
676 throw new NullPointerException("NARG");
678 this.__drawRegion(__src
, __xsrc
, __ysrc
, __wsrc
, __hsrc
, __trans
,
679 __xdest
, __ydest
, __anch
, __wdest
, __hdest
, false);
687 public void drawRoundRect(int __x
, int __y
, int __w
, int __h
,
690 this.__unimplemented(__x
, __y
, "drawRoundRect");
698 public void drawString(String __s
, int __x
, int __y
,
700 throws NullPointerException
703 throw new NullPointerException("NARG");
705 this.__drawText(this.__buildText(__s
), __x
, __y
, __anchor
);
713 public void drawSubstring(String __s
, int __o
, int __l
, int __x
,
714 int __y
, int __anchor
)
715 throws NullPointerException
, StringIndexOutOfBoundsException
718 throw new NullPointerException("NARG");
719 if (__o
< 0 || __l
< 0 || (__o
+ __l
) > __s
.length())
720 throw new StringIndexOutOfBoundsException("IOOB");
722 this.__drawText(this.__buildText(__s
.substring(__o
, __o
+ __l
)),
731 public void drawText(Text __t
, int __x
, int __y
)
733 this.__drawText(__t
, __x
, __y
, 0);
741 public void fillArc(int __x
, int __y
, int __w
, int __h
, int __sa
,
744 this.__unimplemented(__x
, __y
, "fillArc");
752 public void fillRect(int __x
, int __y
, int __w
, int __h
)
754 // Get actual end points
758 // Translate all coordinates
759 int transx
= this.transx
,
760 transy
= this.transy
;
782 // Get clipping region
783 int clipsx
= this.clipsx
,
784 clipsy
= this.clipsy
,
785 clipex
= this.clipex
- 1,
786 clipey
= this.clipey
- 1;
788 // Never clip past the left/top
794 // Never clip past the right/bottom
800 // Calculate actual dimensions used
805 this.funcfillrect
.function(this,
806 new int[]{__x
, __y
, ex
, ey
, __w
, __h
},
815 public void fillRoundRect(int __x
, int __y
, int __w
, int __h
,
818 this.__unimplemented(__x
, __y
, "fillRoundRect");
826 public void fillTriangle(int __x1
, int __y1
, int __x2
, int __y2
,
829 this.__unimplemented(__x1
, __y1
, "fillTriangle");
837 public int getAlpha()
839 return (this.color
>> 24) & 0xFF;
847 public int getAlphaColor()
857 public int getBlendingMode()
859 return this.blendmode
;
867 public int getBlueComponent()
869 return (this.color
) & 0xFF;
873 * Returns the element in the input array which represents the end of the
874 * clipping rectangle.
876 * @return The element which contains the end of the clipping rectangle.
879 public final int getClipElementEnd()
881 // Subtract one from the Y because it is on the next row
882 return this.offset
+ (((this.pitch
* (this.clipey
- 1)) +
887 * Returns the element in the input array which represents the start of
888 * the clipping rectangle.
890 * @return The element which contains the start of the clipping rectangle.
893 public final int getClipElementStart()
895 return this.offset
+ (((this.pitch
* this.clipsy
) + this.clipsx
));
903 public int getClipHeight()
913 public int getClipWidth()
923 public int getClipX()
925 return this.clipsx
- this.transx
;
933 public int getClipY()
935 return this.clipsy
- this.transy
;
943 public int getColor()
945 return this.color
& 0xFFFFFF;
953 public int getDisplayColor(int __rgb
)
955 // Just use the original input color, without the alpha channel
956 return __rgb
& 0xFFFFFF;
964 public Font
getFont()
968 rv
= Font
.getDefaultFont();
977 public int getGrayScale()
979 return (this.getRedComponent() + this.getGreenComponent() + this
980 .getBlueComponent()) / 3;
988 public int getGreenComponent()
990 return (this.color
>> 8) & 0xFF;
998 public int getRedComponent()
1000 return (this.color
>> 16) & 0xFF;
1008 public int getStrokeStyle()
1010 return this.strokestyle
;
1018 public int getTranslateX()
1020 return this.transx
- this.abstransx
;
1028 public int getTranslateY()
1030 return this.transy
- this.abstransy
;
1034 * Resets all parameters of the graphics output.
1036 * @param __clip If {@code true} then the clip is also reset.
1039 public void resetParameters(boolean __clip
)
1041 // Clear translation
1042 this.transx
= this.abstransx
;
1043 this.transy
= this.abstransy
;
1048 int width
= this.width
,
1049 height
= this.height
;
1053 this.clipex
= width
;
1054 this.clipey
= height
;
1056 this.cliph
= height
;
1059 // Always reset these
1060 this.setAlphaColor(0xFF000000);
1061 this.setBlendingMode(Graphics
.SRC_OVER
);
1062 this.setStrokeStyle(Graphics
.SOLID
);
1071 public void setAlpha(int __a
)
1072 throws IllegalArgumentException
1074 this.setAlphaColor(__a
, this.getRedComponent(), this.getGreenComponent(),
1075 this.getBlueComponent());
1083 public void setAlphaColor(int __argb
)
1085 // Set the original color directly
1086 this.color
= __argb
;
1088 // Determine if blending is to be performed or it is just directly
1089 // setting values, blending is only performed if the alpha channel
1090 // is not fully opaque and blending is permitted
1091 int alpha
= (__argb
>>> 24);
1092 boolean doblending
= (this.candoblending
&& alpha
!= 0xFF);
1094 // Set internal blend mode
1095 this.doblending
= doblending
;
1097 // Set painting colors
1098 this.paintalpha
= alpha
;
1099 this.paintcolor
= __argb
& 0xFFFFFF;
1100 this.paintcolorhigh
= __argb
| 0xFF000000;
1101 this.paintalphacolor
= __argb
;
1104 this.__updateFunctions();
1112 public void setAlphaColor(int __a
, int __r
, int __g
, int __b
)
1113 throws IllegalArgumentException
1115 // {@squirreljme.error EB0f Color out of range. (Alpha; Red; Green;
1117 if (__a
< 0 || __a
> 255 || __r
< 0 || __r
> 255 ||
1118 __g
< 0 || __g
> 255 || __b
< 0 || __b
> 255)
1119 throw new IllegalArgumentException(String
.format(
1120 "EB0f %d %d %d %d", __a
, __r
, __g
, __b
));
1123 this.setAlphaColor((__a
<< 24) | (__r
<< 16) | (__g
<< 8) | __b
);
1131 public void setBlendingMode(int __m
)
1132 throws IllegalArgumentException
1134 boolean candoblending
,
1135 oldcandoblending
= this.candoblending
;
1137 // Just use source pixels
1138 if (__m
== Graphics
.SRC
)
1140 // {@squirreljme.error EB0g Cannot set the overlay blending mode
1141 // because this graphics context does not have the alpha channel.}
1142 if (!this.hasalphachannel
)
1143 throw new IllegalArgumentException("EB0g");
1145 candoblending
= false;
1148 // Perform blending since this is the default mode
1149 else if (__m
== Graphics
.SRC_OVER
)
1151 candoblending
= true;
1154 // {@squirreljme.error EB0h Unknown blending mode.}
1156 throw new IllegalArgumentException("EB0h");
1159 this.blendmode
= __m
;
1160 this.candoblending
= candoblending
;
1162 // If the blending mode has changed then possible blending tables
1163 // need to be recalculated accordingly
1164 if (candoblending
!= oldcandoblending
)
1165 this.setAlphaColor(this.getAlphaColor());
1168 this.__updateFunctions();
1176 public void setClip(int __x
, int __y
, int __w
, int __h
)
1182 // Get right end coordinates
1202 // Never go past the end of the viewport because pixels will never
1203 // be drawn in negative regions
1209 // Additionally do not go past the edge ever that way the end
1210 // clipping point is always valid
1211 int width
= this.width
,
1212 height
= this.height
;
1225 this.clipw
= ex
- __x
;
1226 this.cliph
= ey
- __y
;
1234 public void setColor(int __rgb
)
1236 this.setAlphaColor((this.getAlphaColor() & 0xFF_
000000) |
1237 (__rgb
& 0x00_FFFFFF
));
1245 public void setColor(int __r
, int __g
, int __b
)
1246 throws IllegalArgumentException
1248 this.setAlphaColor(this.getAlpha(), __r
, __g
, __b
);
1256 public void setFont(Font __font
)
1267 public void setGrayScale(int __v
)
1269 this.setAlphaColor(this.getAlpha(), __v
, __v
, __v
);
1278 public void setStrokeStyle(int __style
)
1279 throws IllegalArgumentException
1281 // {@squirreljme.error EB0i Illegal stroke style.}
1282 if (__style
!= Graphics
.SOLID
&& __style
!= Graphics
.DOTTED
)
1283 throw new IllegalArgumentException("EB0i");
1286 this.strokestyle
= __style
;
1287 this.dotstroke
= (__style
== Graphics
.DOTTED
);
1290 this.__updateFunctions();
1298 public void translate(int __x
, int __y
)
1305 * Builds and returns a text object for usage.
1307 * @param __s The string used.
1308 * @return A new text object.
1309 * @throws NullPointerException On null arguments.
1312 private Text
__buildText(String __s
)
1313 throws NullPointerException
1316 throw new NullPointerException("NARG");
1318 // Get the font, or fallback to the default if it was not set
1319 Font font
= this.getFont();
1321 // Setup, use a zero height for now since it will be calculated after
1322 // the font and such has been set
1323 Text rv
= new Text(__s
,
1324 font
.stringWidth(__s
), 0);
1326 // Set text properties
1329 rv
.setForegroundColor(this.color
);
1331 // Set the height to the required height of the box now that the
1332 // parameters have been set
1333 rv
.setHeight(rv
.getRequiredHeight());
1341 * @param __src Source image.
1342 * @param __xsrc X source.
1343 * @param __ysrc Y source.
1344 * @param __wsrc W source.
1345 * @param __hsrc H source.
1346 * @param __trans Translation.
1347 * @param __xdest X destination.
1348 * @param __ydest Y destination.
1349 * @param __anch Anchor.
1350 * @param __wdest W destination.
1351 * @param __hdest H destination.
1352 * @param __dswap Swap destinations on rotate?
1353 * @throws IllegalArgumentException If the input is not valid.
1354 * @throws NullPointerException On null arguments.
1357 private void __drawRegion(Image __src
, int __xsrc
, int __ysrc
,
1358 int __wsrc
, int __hsrc
, int __trans
, int __xdest
, int __ydest
,
1359 int __anch
, int __wdest
, int __hdest
, boolean __dswap
)
1360 throws IllegalArgumentException
, NullPointerException
1363 throw new NullPointerException("NARG");
1366 boolean alpha
= __src
.hasAlpha();
1368 // Extract image pixel data
1369 int numpixels
= __wsrc
* __hsrc
;
1370 int[] data
= new int[numpixels
];
1371 __src
.getRGB(data
, 0, __wsrc
, __xsrc
, __ysrc
, __wsrc
, __hsrc
);
1373 // Perform the transformation, possibly returning a new data buffer
1374 int[] transdim
= new int[]{__wsrc
, __hsrc
, __wdest
, __hdest
};
1375 data
= __transform(__trans
, data
, __wsrc
, __hsrc
, transdim
,
1378 // Re-read the new image sizes!
1379 __wsrc
= transdim
[0];
1380 __hsrc
= transdim
[1];
1381 __wdest
= transdim
[2];
1382 __hdest
= transdim
[3];
1384 // Anchor horizontally?
1385 if ((__anch
& Graphics
.HCENTER
) == Graphics
.HCENTER
)
1386 __xdest
-= __wdest
>> 1;
1389 else if ((__anch
& Graphics
.RIGHT
) == Graphics
.RIGHT
)
1393 if ((__anch
& Graphics
.VCENTER
) == Graphics
.VCENTER
)
1394 __ydest
-= __hdest
>> 1;
1397 else if ((__anch
& Graphics
.BOTTOM
) == Graphics
.BOTTOM
)
1400 // If this is non-stretched we can just use the standard RGB
1401 // drawing function!
1402 if (__wsrc
== __wdest
&& __hsrc
== __hdest
)
1403 this.drawRGB(data
, 0, __wsrc
, __xdest
, __ydest
,
1404 __wsrc
, __hsrc
, alpha
);
1406 // Use stretchy draw
1408 this.__drawRGBStretched(data
, 0, __wsrc
, __xdest
, __ydest
,
1409 __wsrc
, __hsrc
, alpha
, __wdest
, __hdest
);
1413 * Draws stretched RGB.
1415 * @param __data The data to draw.
1416 * @param __off The offset into the array.
1417 * @param __scanlen The scan length.
1418 * @param __x X position.
1419 * @param __y Y position.
1420 * @param __wsrc Width of source.
1421 * @param __hsrc Height of source.
1422 * @param __alpha Use alpha channel?
1423 * @param __wdest Width of destination.
1424 * @param __hdest Height of destination.
1425 * @throws NullPointerException On null arguments.
1428 private void __drawRGBStretched(int[] __data
, int __off
, int __scanlen
,
1429 int __x
, int __y
, int __wsrc
, int __hsrc
, boolean __alpha
,
1430 int __wdest
, int __hdest
)
1431 throws NullPointerException
1434 throw new NullPointerException("NARG");
1436 this.__unimplemented(__x
, __y
, "drawRGBStretched");
1440 * Draws the given text object.
1442 * @param __t The text object to draw.
1443 * @param __x The X position.
1444 * @param __y The Y position.
1445 * @param __anchor The, this just adjusts determines how the actual text
1446 * box region is drawn. If baseline is used, Y is just offset by the
1447 * baseline for the first character and not the entire block size.
1448 * @throws NullPointerException On null arguments.
1451 final void __drawText(Text __t
, int __x
, int __y
, int __anchor
)
1452 throws NullPointerException
1455 throw new NullPointerException("NARG");
1457 // Translate to the displayed coordinate space
1462 __TextState__ ts
= new __TextState__();
1465 ts
.textw
= __t
.getWidth();
1466 ts
.texth
= __t
.getHeight();
1467 if ((__anchor
& Graphics
.RIGHT
) != 0)
1469 else if ((__anchor
& Graphics
.HCENTER
) != 0)
1470 __x
-= (ts
.textw
>> 1);
1471 if ((__anchor
& Graphics
.BOTTOM
) != 0)
1473 else if ((__anchor
& Graphics
.VCENTER
) != 0)
1474 __y
-= (ts
.texth
>> 1);
1476 // Get clipping region
1477 ts
.clipsx
= this.clipsx
;
1478 ts
.clipsy
= this.clipsy
;
1479 ts
.clipex
= this.clipex
- 1;
1480 ts
.clipey
= this.clipey
- 1;
1482 // Wanting to draw a bunch of text completely out of the clip? Ignore
1483 if (__x
>= ts
.clipex
|| __y
>= ts
.clipey
)
1486 // Trying to draw the text completely out of the clip as well?
1487 ts
.tex
= __x
+ ts
.textw
;
1488 ts
.tey
= __y
+ ts
.texth
;
1489 if (ts
.tex
< ts
.clipsx
|| ts
.tey
< ts
.clipsy
)
1492 // The text box acts as an extra clip, so force everything to clip
1494 if (__x
> ts
.clipsx
)
1496 if (ts
.tex
< ts
.clipex
)
1498 if (__y
> ts
.clipsy
)
1500 if (ts
.tey
< ts
.clipey
)
1503 // Cache the default font in the event it is never changed ever
1504 ts
.lastfont
= __t
.getFont();
1505 ts
.sqf
= SQFFont
.cacheFont(ts
.lastfont
);
1506 ts
.bmp
= new byte[ts
.sqf
.charbitmapsize
];
1507 ts
.pixelheight
= ts
.sqf
.pixelheight
;
1508 ts
.bitsperscan
= ts
.sqf
.bitsperscan
;
1510 // Background color to use
1511 ts
.bgcol
= __t
.getBackgroundColor();
1512 ts
.hasbg
= ((ts
.bgcol
& 0xFF_
000000) != 0);
1514 // Need to store the properties since drawing of the text will
1515 // change how characters are drawn
1516 ts
.oldcolor
= this.getAlphaColor();
1519 // Read in all the text characters
1520 int n
= __t
.getTextLength();
1521 String chars
= __t
.getText(0, n
);
1523 // Draw each character according to their metrics
1524 for (int i
= 0; i
< n
; i
++)
1526 // Ignore certain characters
1527 char c
= chars
.charAt(i
);
1528 if (c
== '\r' || c
== '\n')
1531 // Need to find the SQF for this font again?
1532 Font drawfont
= __t
.getFont(i
);
1533 if (drawfont
!= ts
.lastfont
)
1535 ts
.lastfont
= drawfont
;
1536 ts
.sqf
= SQFFont
.cacheFont(ts
.lastfont
);
1537 ts
.bmp
= new byte[ts
.sqf
.charbitmapsize
];
1538 ts
.pixelheight
= ts
.sqf
.pixelheight
;
1539 ts
.bitsperscan
= ts
.sqf
.bitsperscan
;
1542 // Get the metrics for the character
1543 __t
.getCharExtent(i
, ts
.metrics
);
1545 // Calculate the draw position of the character
1546 int dsx
= __x
+ ts
.metrics
[0];
1547 int dsy
= __y
+ ts
.metrics
[1];
1548 int dex
= dsx
+ ts
.metrics
[2];
1549 int dey
= dsy
+ ts
.metrics
[3];
1551 // Completely out of bounds, ignore because we cannot draw it
1553 if (dsx
>= clipex
|| dex
<= 0 ||
1554 dsy
>= clipey
|| dey
<= 0)
1557 // Map character index to the SQF
1558 char mc
= SQFFont
.mapChar(c
);
1560 // Base scan offsets and such
1562 int scanlen
= ts
.sqf
.charWidth(mc
);
1564 int linelen
= ts
.pixelheight
;
1566 // Off the left side?
1567 if (dsx
< ts
.clipsx
)
1569 int diff
= ts
.clipsx
- dsx
;
1573 // Reset to clip bound
1577 // Off the right side
1578 if (dex
> ts
.clipex
)
1579 scanlen
-= (dex
- ts
.clipex
);
1582 if (dsy
< ts
.clipsy
)
1584 int diff
= ts
.clipsy
- dsy
;
1588 // Reset to clip bound
1593 if (dey
> ts
.clipey
)
1594 linelen
-= (dey
- ts
.clipey
);
1596 // Load the character bitmap
1597 int bps
= ts
.sqf
.loadCharBitmap(mc
, ts
.bmp
);
1603 this.setAlphaColor(ts
.bgcol
);
1605 // Perform draw operation
1606 this.funcfillrect
.function(this, ts
.loadIntArgs(dsx
, dsy
,
1607 dsx
+ (scanlen
- scanoff
), dsy
+ (linelen
- lineoff
),
1608 scanlen
- scanoff
, linelen
- lineoff
), ts
.chobj
);
1611 // Set color to the foreground color of this character
1612 this.setAlphaColor(__t
.getForegroundColor(i
));
1614 // Setup the draw and do it
1615 this.funccharbmp
.function(this, ts
.loadIntArgs(this.color
, dsx
, dsy
,
1616 bps
, scanoff
, scanlen
, lineoff
, linelen
),
1617 ts
.loadObject(ts
.bmp
));
1621 // Just in case revert properties
1624 this.setAlphaColor(ts
.oldcolor
);
1629 * Draw a string which just says not implemented.
1631 * @param __x X Coordinate.
1632 * @param __y Y Coordinate.
1633 * @param __txt The message text.
1636 private void __unimplemented(int __x
, int __y
, String __txt
)
1637 throws NullPointerException
1640 throw new NullPointerException("NARG");
1642 // Just draw crosshair and a string
1643 this.drawLine(__x
- 5, __y
, __x
+ 5, __y
);
1644 this.drawLine(__x
, __y
- 5, __x
, __y
+ 5);
1645 this.drawString(__txt
, __x
, __y
, 0);
1649 * Updates the graphics drawing functions to what is needed.
1653 private void __updateFunctions()
1655 boolean doblending
= this.doblending
,
1656 dotstroke
= this.dotstroke
;
1657 int blendmode
= this.blendmode
;
1662 this.funcfillrect
= AdvancedFunction
.FILLRECT_BLEND
;
1663 this.funccharbmp
= AdvancedFunction
.CHARBITMAP_BLEND
;
1664 this.funcrgbtile
= AdvancedFunction
.RGBTILE_BLEND
;
1665 this.funcargbtile
= AdvancedFunction
.ARGBTILE_BLEND
;
1670 this.funcline
= AdvancedFunction
.LINE_BLEND_DOT
;
1676 this.funcline
= AdvancedFunction
.LINE_BLEND_NODOT
;
1683 this.funcfillrect
= AdvancedFunction
.FILLRECT_NOBLEND
;
1684 this.funccharbmp
= AdvancedFunction
.CHARBITMAP_NOBLEND
;
1685 this.funcrgbtile
= AdvancedFunction
.RGBTILE_NOBLEND
;
1686 this.funcargbtile
= AdvancedFunction
.ARGBTILE_NOBLEND
;
1691 this.funcline
= AdvancedFunction
.LINE_NOBLEND_DOT
;
1697 this.funcline
= AdvancedFunction
.LINE_NOBLEND_NODOT
;
1703 * Determines the Cohen-Sutherland clipping flags.
1705 * @param __x Input X coordinate.
1706 * @param __y Input Y coordinate.
1707 * @param __csx Clipping box starting X.
1708 * @param __csy Clipping box starting Y.
1709 * @param __cex Clipping box ending X.
1710 * @param __cey Clipping box ending Y.
1711 * @return The clipping bit flags.
1714 private static int __csOut(int __x
, int __y
, int __csx
, int __csy
,
1715 int __cex
, int __cey
)
1719 // Clips above or below?
1721 rv
|= AdvancedGraphics
._CLIP_ABOVE
;
1722 else if (__y
< __csy
)
1723 rv
|= AdvancedGraphics
._CLIP_BELOW
;
1725 // Clips right or left?
1727 rv
|= AdvancedGraphics
._CLIP_RIGHT
;
1728 else if (__x
< __csx
)
1729 rv
|= AdvancedGraphics
._CLIP_LEFT
;
1735 * Transforms the data in the buffer.
1737 * @param __trans The transformation to perform.
1738 * @param __data The input data.
1739 * @param __wsrc The width of the source.
1740 * @param __hsrc The width of the destination.
1741 * @param __dimout Output dimensions.
1742 * @param __dswap Swap destinations?
1743 * @return The resulting data is translated, this may be the same as
1745 * @throws NullPointerException On null arguments.
1748 private static int[] __transform(int __trans
, int[] __data
,
1749 int __wsrc
, int __hsrc
, int[] __dimout
, boolean __dswap
)
1750 throws NullPointerException
1752 if (__data
== null || __dimout
== null)
1753 throw new NullPointerException("NARG");
1755 // Destination width and height
1759 // Determine the transformation functions to use. There are just three
1760 // primitive transformation functions: flip horizontally, then
1761 // flip vertically, then rotate 90 degrees clockwise. This handles
1762 // every transformation which fill every single bit.
1766 // These bits represent the stuff to do! == 0b9VH;
1767 case Sprite
.TRANS_NONE
: xform
= 0b000
; break;
1768 case Sprite
.TRANS_MIRROR
: xform
= 0b001
; break;
1769 case Sprite
.TRANS_MIRROR_ROT180
: xform
= 0b010
; break;
1770 case Sprite
.TRANS_ROT180
: xform
= 0b011
; break;
1771 case Sprite
.TRANS_ROT90
: xform
= 0b100
; break;
1772 case Sprite
.TRANS_MIRROR_ROT90
: xform
= 0b101
; break;
1773 case Sprite
.TRANS_MIRROR_ROT270
: xform
= 0b110
; break;
1774 case Sprite
.TRANS_ROT270
: xform
= 0b111
; break;
1775 // These bits represent the stuff to do! == 0b9VH;
1778 // Mirror horizontally?
1779 if ((xform
& 0b001
) != 0)
1780 for (int y
= 0; y
< hdest
; y
++)
1783 de
= (dx
+ wdest
) - 1;
1784 for (int x
= 0, n
= (wdest
>> 1); x
< n
; x
++)
1787 __data
[de
--] = __data
[dx
];
1792 // Mirror vertically?
1793 if ((xform
& 0b010
) != 0)
1794 for (int ya
= 0, yn
= __hsrc
>> 1; ya
< yn
; ya
++)
1796 int ra
= __wsrc
* ya
,
1797 rb
= (__wsrc
* (__hsrc
- ya
)) - __wsrc
;
1800 for (int x
= 0; x
< __wsrc
; x
++)
1803 __data
[rb
++] = __data
[ra
];
1808 // Rotate 90 degrees clockwise
1809 if ((xform
& 0b100
) != 0)
1812 int[] orig
= __data
.clone();
1814 // Swap the X and Y pixels first
1815 int ttop
= hdest
- 1;
1816 for (int y
= 0; y
< hdest
; y
++)
1817 for (int x
= 0; x
< wdest
; x
++)
1819 int ps
= (wdest
* y
) + x
,
1820 pd
= (hdest
* x
) + (ttop
- y
);
1822 __data
[pd
] = orig
[ps
];
1825 // The output width and height are flipped
1826 __dimout
[0] = hdest
;
1827 __dimout
[1] = wdest
;
1829 // Swap destinations as well?
1832 int t
= __dimout
[2];
1833 __dimout
[2] = __dimout
[3];
1838 // Otherwise use the same target dimensions
1841 __dimout
[0] = wdest
;
1842 __dimout
[1] = hdest
;