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
.mle
;
12 import cc
.squirreljme
.jvm
.mle
.PencilShelf
;
13 import cc
.squirreljme
.jvm
.mle
.brackets
.PencilBracket
;
14 import cc
.squirreljme
.jvm
.mle
.constants
.PencilCapabilities
;
15 import cc
.squirreljme
.jvm
.mle
.constants
.UIPixelFormat
;
16 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
17 import javax
.microedition
.lcdui
.Font
;
18 import javax
.microedition
.lcdui
.Graphics
;
19 import javax
.microedition
.lcdui
.Image
;
20 import javax
.microedition
.lcdui
.Text
;
21 import javax
.microedition
.lcdui
.game
.Sprite
;
24 * This delegates drawing operations to either the hardware graphics layer
25 * or the software graphics layer.
27 * This utilizes both {@link PencilShelf} and {@link PencilBracket} for native
32 public final class PencilGraphics
36 * {@squirreljme.property cc.squirreljme.lcdui.software=boolean
37 * If set to {@code true} then software graphics will be forced to be
40 private static final String _FORCE_SOFTWARE_PROPERTY
=
41 "cc.squirreljme.lcdui.software";
43 /** Forcing software rasterization */
44 private static final boolean _IS_FORCE_SOFTWARE
;
46 /** Software graphics backend. */
47 protected final Graphics software
;
49 /** The hardware bracket reference. */
50 protected final PencilBracket hardware
;
52 /** The capabilities of the graphics hardware. */
53 protected final int capabilities
;
56 protected final int surfaceW
;
58 /** Surface height. */
59 protected final int surfaceH
;
61 /** Does this have alpha channel support? */
62 protected final boolean hasAlpha
;
64 /** The current alpha color. */
65 private int _argbColor
;
67 /** The current blending mode. */
68 private int _blendingMode
;
70 /** The clip height. */
71 private int _clipHeight
;
73 /** The clip width. */
74 private int _clipWidth
;
76 /** The clip X position. */
79 /** The clip Y position. */
82 /** The current font used. */
85 /** The current stroke style. */
86 private int _strokeStyle
;
88 /** The current X translation. */
91 /** The current Y translation. */
97 Boolean
.getBoolean(PencilGraphics
._FORCE_SOFTWARE_PROPERTY
);
101 * Initializes the pencil graphics system.
103 * @param __caps Capabilities of the hardware, this determines the
104 * functions that are available.
105 * @param __software The fallback software graphics rasterizer.
106 * @param __sw The surface width.
107 * @param __sh The surface height.
108 * @param __hardware The hardware bracket reference for drawing.
109 * @param __pf The pixel format used.
110 * @throws IllegalArgumentException If hardware graphics are not capable
111 * enough to be used at all.
112 * @throws NullPointerException On null arguments.
115 private PencilGraphics(int __caps
, Graphics __software
, int __sw
, int __sh
,
116 PencilBracket __hardware
, int __pf
)
117 throws IllegalArgumentException
, NullPointerException
119 if (__software
== null || __hardware
== null)
120 throw new NullPointerException("NARG");
122 // {@squirreljme.error EB3g Hardware graphics not capable enough.}
123 if ((__caps
& PencilCapabilities
.MINIMUM
) == 0)
124 throw new IllegalArgumentException("EB3g " + __caps
);
126 this.software
= __software
;
127 this.hardware
= __hardware
;
128 this.capabilities
= __caps
;
130 // These are used to manage the clip
131 this.surfaceW
= __sw
;
132 this.surfaceH
= __sh
;
134 // Does this use alpha?
135 this.hasAlpha
= (__pf
== UIPixelFormat
.INT_RGBA8888
||
136 __pf
== UIPixelFormat
.SHORT_ABGR1555
||
137 __pf
== UIPixelFormat
.SHORT_RGBA4444
);
139 // Set initial parameters for the graphics and make sure they are
140 // properly forwarded as well
141 this.setAlphaColor(0xFF000000);
142 this.setBlendingMode(Graphics
.SRC_OVER
);
143 this.setStrokeStyle(Graphics
.SOLID
);
152 public void clipRect(int __x
, int __y
, int __w
, int __h
)
154 throw Debugging
.todo();
162 public void copyArea(int __sx
, int __sy
, int __w
, int __h
, int __dx
,
163 int __dy
, int __anchor
)
164 throws IllegalArgumentException
, IllegalStateException
166 if (0 == (this.capabilities
& PencilCapabilities
.COPY_AREA
))
168 this.software
.copyArea(__sx
, __sy
, __w
, __h
, __dx
, __dy
, __anchor
);
172 throw Debugging
.todo();
180 public void drawArc(int __x
, int __y
, int __w
, int __h
, int __sa
,
183 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_ARC
))
185 this.software
.drawArc(__x
, __y
, __w
, __h
, __sa
, __aa
);
189 throw Debugging
.todo();
197 public void drawARGB16(short[] __data
, int __off
, int __scanlen
,
198 int __x
, int __y
, int __w
, int __h
)
199 throws NullPointerException
201 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_XRGB16_SIMPLE
))
203 this.software
.drawARGB16(__data
, __off
, __scanlen
, __x
, __y
, __w
,
208 throw Debugging
.todo();
216 public void drawChar(char __s
, int __x
, int __y
, int __anchor
)
218 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
220 this.software
.drawChar(__s
, __x
, __y
, __anchor
);
224 throw Debugging
.todo();
232 public void drawChars(char[] __s
, int __o
, int __l
, int __x
, int __y
,
234 throws NullPointerException
236 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
238 this.software
.drawChars(__s
, __o
, __l
, __x
, __y
, __anchor
);
242 throw Debugging
.todo();
250 public void drawImage(Image __i
, int __x
, int __y
, int __anchor
)
251 throws IllegalArgumentException
, NullPointerException
253 // This is a duplicate function, so it gets forwarded
254 this.drawRegion(__i
, 0, 0,
255 __i
.getWidth(), __i
.getHeight(), 0,
264 public void drawLine(int __x1
, int __y1
, int __x2
, int __y2
)
266 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_LINE
))
268 this.software
.drawLine(__x1
, __y1
, __x2
, __y2
);
272 PencilShelf
.hardwareDrawLine(this.hardware
, __x1
, __y1
, __x2
, __y2
);
280 public void drawRGB(int[] __data
, int __off
, int __scanlen
, int __x
,
281 int __y
, int __w
, int __h
, boolean __alpha
)
282 throws NullPointerException
284 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_XRGB32_REGION
))
286 this.software
.drawRGB(__data
, __off
, __scanlen
, __x
, __y
, __w
,
292 this.__drawRegion(__data
, __off
, __scanlen
, __alpha
,
293 0, 0, __w
, __h
, Sprite
.TRANS_NONE
,
294 __x
, __y
, Graphics
.TOP
| Graphics
.LEFT
, __w
, __h
,
295 __scanlen
, (__data
.length
- __off
) / __scanlen
);
303 public void drawRGB16(short[] __data
, int __off
, int __scanlen
,
304 int __x
, int __y
, int __w
, int __h
)
305 throws NullPointerException
307 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_XRGB16_SIMPLE
))
309 this.software
.drawRGB16(__data
, __off
, __scanlen
, __x
, __y
,
314 throw Debugging
.todo();
322 public void drawRect(int __x
, int __y
, int __w
, int __h
)
324 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_RECT
))
326 this.software
.drawRect(__x
, __y
, __w
, __h
);
330 throw Debugging
.todo();
338 public void drawRegion(Image __src
, int __xsrc
, int __ysrc
,
339 int __wsrc
, int __hsrc
, int __trans
, int __xdest
, int __ydest
,
341 throws IllegalArgumentException
, NullPointerException
344 this.drawRegion(__src
, __xsrc
, __ysrc
, __wsrc
, __hsrc
,
345 __trans
, __xdest
, __ydest
, __anch
, __wsrc
, __hsrc
);
353 public void drawRegion(Image __src
, int __xsrc
, int __ysrc
,
354 int __wsrc
, int __hsrc
, int __trans
, int __xdest
, int __ydest
,
355 int __anch
, int __wdest
, int __hdest
)
356 throws IllegalArgumentException
, NullPointerException
359 throw new NullPointerException("NARG");
361 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_XRGB32_REGION
))
363 this.software
.drawRegion(__src
, __xsrc
, __ysrc
, __wsrc
, __hsrc
,
364 __trans
, __xdest
, __ydest
, __anch
, __wdest
, __hdest
);
368 // If the image is direct, use the buffer that is inside rather than
369 // a copy, so we do not waste time copying from it!
373 if (__src
.squirreljmeIsDirect())
375 buf
= __src
.squirreljmeDirectRGBInt();
376 offset
= __src
.squirreljmeDirectOffset();
377 scanLen
= __src
.squirreljmeDirectScanLen();
380 // Image is not directly accessible, so get a copy of it
383 // Obtain image properties
384 int iW
= __src
.getWidth();
385 int iH
= __src
.getHeight();
386 int totalPixels
= iW
* iH
;
389 buf
= new int[totalPixels
];
392 __src
.getRGB(buf
, offset
, scanLen
, 0, 0, iW
, iH
);
395 // Perform the internal draw
396 this.__drawRegion(buf
, offset
, scanLen
, __src
.hasAlpha(),
397 __xsrc
, __ysrc
, __wsrc
, __hsrc
, __trans
,
398 __xdest
, __ydest
, __anch
,
399 __wdest
, __hdest
, __src
.getWidth(), __src
.getHeight());
407 public void drawRoundRect(int __x
, int __y
, int __w
, int __h
,
410 if (0 == (this.capabilities
& PencilCapabilities
.DRAW_ROUND_RECT
))
412 this.software
.drawRoundRect(__x
, __y
, __w
, __h
, __aw
, __ah
);
416 throw Debugging
.todo();
424 public void drawString(String __s
, int __x
, int __y
, int __anchor
)
425 throws NullPointerException
427 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
429 this.software
.drawString(__s
, __x
, __y
, __anchor
);
433 throw Debugging
.todo();
441 public void drawSubstring(String __s
, int __o
, int __l
,
442 int __x
, int __y
, int __anchor
)
443 throws NullPointerException
, StringIndexOutOfBoundsException
445 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
447 this.software
.drawSubstring(__s
, __o
, __l
, __x
, __y
, __anchor
);
451 throw Debugging
.todo();
459 public void drawText(Text __t
, int __x
, int __y
)
461 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
463 this.software
.drawText(__t
, __x
, __y
);
467 throw Debugging
.todo();
475 public void fillArc(int __x
, int __y
, int __w
, int __h
, int __sa
,
478 if (0 == (this.capabilities
& PencilCapabilities
.FILL_ARC
))
480 this.software
.fillArc(__x
, __y
, __w
, __h
, __sa
, __aa
);
484 throw Debugging
.todo();
492 public void fillRect(int __x
, int __y
, int __w
, int __h
)
494 if (0 == (this.capabilities
& PencilCapabilities
.FILL_RECT
))
496 this.software
.fillRect(__x
, __y
, __w
, __h
);
500 // Forward to hardware
501 PencilShelf
.hardwareFillRect(this.hardware
, __x
, __y
, __w
, __h
);
509 public void fillRoundRect(int __x
, int __y
, int __w
, int __h
,
512 if (0 == (this.capabilities
& PencilCapabilities
.FILL_ROUND_RECT
))
514 this.software
.fillRoundRect(__x
, __y
, __w
, __h
, __aw
, __ah
);
518 throw Debugging
.todo();
526 public void fillTriangle(int __x1
, int __y1
, int __x2
, int __y2
,
529 if (0 == (this.capabilities
& PencilCapabilities
.FILL_TRIANGLE
))
531 this.software
.fillTriangle(__x1
, __y1
, __x2
, __y2
, __x3
, __y3
);
535 throw Debugging
.todo();
543 public int getAlpha()
545 return (this._argbColor
>> 24) & 0xFF;
553 public int getAlphaColor()
555 return this._argbColor
;
563 public int getBlendingMode()
565 return this._blendingMode
;
573 public int getBlueComponent()
575 return (this._argbColor
) & 0xFF;
583 public int getClipHeight()
585 return this._clipHeight
;
593 public int getClipWidth()
595 return this._clipWidth
;
603 public int getClipX()
605 return this._clipX
- this._transX
;
613 public int getClipY()
615 return this._clipY
- this._transY
;
623 public int getColor()
625 return this._argbColor
& 0xFFFFFF;
633 public int getDisplayColor(int __rgb
)
635 // We can just ask the software graphics for the color we are using
636 // since it should hopefully match the hardware one.
637 return this.software
.getDisplayColor(__rgb
);
645 public Font
getFont()
647 if (0 == (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
648 return this.software
.getFont();
658 public int getGrayScale()
660 return (((this._argbColor
>> 16) & 0xFF) +
661 ((this._argbColor
>> 8) & 0xFF) +
662 ((this._argbColor
) & 0xFF)) / 3;
670 public int getGreenComponent()
672 return (this._argbColor
>> 8) & 0xFF;
680 public int getRedComponent()
682 return (this._argbColor
>> 16) & 0xFF;
690 public int getStrokeStyle()
692 return this._strokeStyle
;
700 public int getTranslateX()
710 public int getTranslateY()
720 public void setAlpha(int __a
)
721 throws IllegalArgumentException
723 this.setAlphaColor(__a
,
724 this.getRedComponent(),
725 this.getGreenComponent(),
726 this.getBlueComponent());
734 public void setAlphaColor(int __argb
)
737 this._argbColor
= __argb
;
739 // Set on the remote software and hardware graphics
740 this.software
.setAlphaColor(__argb
);
741 PencilShelf
.hardwareSetAlphaColor(this.hardware
, __argb
);
749 public void setAlphaColor(int __a
, int __r
, int __g
, int __b
)
750 throws IllegalArgumentException
752 // {@squirreljme.error EB3t Color out of range. (Alpha; Red; Green;
754 if (__a
< 0 || __a
> 255 || __r
< 0 || __r
> 255 ||
755 __g
< 0 || __g
> 255 || __b
< 0 || __b
> 255)
756 throw new IllegalArgumentException(String
.format(
757 "EB3t %d %d %d %d", __a
, __r
, __g
, __b
));
760 this.setAlphaColor((__a
<< 24) | (__r
<< 16) | (__g
<< 8) | __b
);
768 public void setBlendingMode(int __m
)
769 throws IllegalArgumentException
771 // {@squirreljme.error EB3u Invalid blending mode. (The mode)}
772 if ((__m
!= Graphics
.SRC
&& __m
!= Graphics
.SRC_OVER
) ||
773 (__m
== Graphics
.SRC
&& !this.hasAlpha
))
774 throw new IllegalArgumentException("EB3u " + __m
);
777 this._blendingMode
= __m
;
779 // Forward to both software and hardware graphics
780 this.software
.setBlendingMode(__m
);
781 PencilShelf
.hardwareSetBlendingMode(this.hardware
, __m
);
789 public void setClip(int __x
, int __y
, int __w
, int __h
)
791 // Calculate the base clip coordinates
792 int startX
= __x
+ this._transX
;
793 int startY
= __y
+ this._transY
;
794 int endX
= startX
+ __w
;
795 int endY
= startY
+ __h
;
813 // Determine the bounds of all of these
814 int clipX
= Math
.min(this.surfaceW
, Math
.max(0, startX
));
815 int clipY
= Math
.min(this.surfaceH
, Math
.max(0, startY
));
816 int clipEndX
= Math
.min(this.surfaceW
, Math
.max(0, endX
));
817 int clipEndY
= Math
.min(this.surfaceH
, Math
.max(0, endY
));
822 this._clipWidth
= clipEndX
- clipX
;
823 this._clipHeight
= clipEndY
- clipY
;
825 // Forward to both software and hardware graphics
826 this.software
.setClip(__x
, __y
, __w
, __h
);
827 PencilShelf
.hardwareSetClip(this.hardware
, __x
, __y
, __w
, __h
);
834 @SuppressWarnings("MagicNumber")
836 public void setColor(int __rgb
)
838 this.setAlphaColor((this.getAlphaColor() & 0xFF_
000000) |
839 (__rgb
& 0x00_FFFFFF
));
847 public void setColor(int __r
, int __g
, int __b
)
848 throws IllegalArgumentException
850 this.setAlphaColor(this.getAlpha(), __r
, __g
, __b
);
858 public void setFont(Font __font
)
863 // This is always set in software
864 this.software
.setFont(__font
);
866 // If supported by hardware, set it here
867 if (0 != (this.capabilities
& PencilCapabilities
.FONT_TEXT
))
868 throw Debugging
.todo();
876 public void setGrayScale(int __v
)
878 this.setAlphaColor(this.getAlpha(), __v
, __v
, __v
);
886 public void setStrokeStyle(int __style
)
887 throws IllegalArgumentException
889 // {@squirreljme.error EB3v Illegal stroke style.}
890 if (__style
!= Graphics
.SOLID
&& __style
!= Graphics
.DOTTED
)
891 throw new IllegalArgumentException("EB3v");
894 this._strokeStyle
= __style
;
896 // Forward to both software and hardware graphics
897 this.software
.setStrokeStyle(__style
);
898 PencilShelf
.hardwareSetStrokeStyle(this.hardware
, __style
);
906 public void translate(int __x
, int __y
)
912 // Forward to both software and hardware graphics
913 this.software
.translate(__x
, __y
);
914 PencilShelf
.hardwareTranslate(this.hardware
, __x
, __y
);
918 * Draws a direct RGB region of an image.
920 * @param __data The source buffer.
921 * @param __off The offset into the buffer.
922 * @param __scanlen The scanline length.
923 * @param __alpha Drawing with the alpha channel?
924 * @param __xsrc The source X position.
925 * @param __ysrc The source Y position.
926 * @param __wsrc The width of the source region.
927 * @param __hsrc The height of the source region.
928 * @param __trans Sprite translation and/or rotation, see {@link Sprite}.
929 * @param __xdest The destination X position, is translated.
930 * @param __ydest The destination Y position, is translated.
931 * @param __anch The anchor point.
932 * @param __wdest The destination width.
933 * @param __hdest The destination height.
934 * @param __origImgWidth Original image width.
935 * @param __origImgHeight Original image height.
936 * @throws NullPointerException On null arguments.
939 private void __drawRegion(int[] __data
, int __off
, int __scanlen
,
940 boolean __alpha
, int __xsrc
, int __ysrc
, int __wsrc
, int __hsrc
,
941 int __trans
, int __xdest
, int __ydest
, int __anch
, int __wdest
,
942 int __hdest
, int __origImgWidth
, int __origImgHeight
)
943 throws NullPointerException
946 throw new NullPointerException("NARG");
948 // Forward to the native region drawing method
949 PencilShelf
.hardwareDrawXRGB32Region(this.hardware
,
950 __data
, __off
, __scanlen
,
951 __alpha
, __xsrc
, __ysrc
, __wsrc
, __hsrc
,
952 __trans
, __xdest
, __ydest
, __anch
,
953 __wdest
, __hdest
, __origImgWidth
, __origImgHeight
);
957 * Creates a graphics that is capable of drawing on hardware if it is
958 * supported, but falling back to software level graphics.
960 * @param __pf The {@link UIPixelFormat} used for the draw.
961 * @param __bw The buffer width, this is the scanline width of the buffer.
962 * @param __bh The buffer height.
963 * @param __buf The target buffer to draw to, this is cast to the correct
965 * @param __offset The offset to the start of the buffer.
966 * @param __pal The color palette, may be {@code null}.
967 * @param __sx Starting surface X coordinate.
968 * @param __sy Starting surface Y coordinate.
969 * @param __sw Surface width.
970 * @param __sh Surface height.
971 * @throws NullPointerException On null arguments.
974 public static Graphics
hardwareGraphics(int __pf
, int __bw
,
975 int __bh
, Object __buf
, int __offset
, int[] __pal
, int __sx
, int __sy
,
977 throws NullPointerException
979 // Setup software graphics
980 Graphics software
= SoftwareGraphicsFactory
.softwareGraphics(__pf
,
981 __bw
, __bh
, __buf
, __offset
, __pal
, __sx
, __sy
, __sw
, __sh
);
983 // Get the capabilities of the native system, if it is not supported
984 // then operations will purely be implemented in software
985 // It can also be disabled via a system property
986 int caps
= PencilShelf
.capabilities(__pf
);
987 if (PencilGraphics
._IS_FORCE_SOFTWARE
||
988 (caps
& PencilCapabilities
.MINIMUM
) == 0)
991 return new PencilGraphics(caps
, software
, __sw
, __sh
,
992 PencilShelf
.hardwareGraphics(__pf
,
993 __bw
, __bh
, __buf
, __offset
, __pal
, __sx
, __sy
, __sw
, __sh
), __pf
);