Path: blob/master/SLICK_HOME/src/org/newdawn/slick/Graphics.java
1456 views
package org.newdawn.slick;12import java.nio.ByteBuffer;3import java.nio.DoubleBuffer;4import java.nio.FloatBuffer;5import java.security.AccessController;6import java.security.PrivilegedAction;7import java.util.ArrayList;89import org.lwjgl.BufferUtils;10import org.lwjgl.opengl.GL11;11import org.newdawn.slick.geom.Rectangle;12import org.newdawn.slick.geom.Shape;13import org.newdawn.slick.geom.ShapeRenderer;14import org.newdawn.slick.opengl.TextureImpl;15import org.newdawn.slick.opengl.renderer.LineStripRenderer;16import org.newdawn.slick.opengl.renderer.Renderer;17import org.newdawn.slick.opengl.renderer.SGL;18import org.newdawn.slick.util.FastTrig;19import org.newdawn.slick.util.Log;2021/**22* A graphics context that can be used to render primatives to the accelerated23* canvas provided by LWJGL.24*25* @author kevin26*/27public class Graphics {28/** The renderer to use for all GL operations */29protected static SGL GL = Renderer.get();30/** The renderer to use line strips */31private static LineStripRenderer LSR = Renderer.getLineStripRenderer();3233/** The normal drawing mode */34public static int MODE_NORMAL = 1;3536/** Draw to the alpha map */37public static int MODE_ALPHA_MAP = 2;3839/** Draw using the alpha blending */40public static int MODE_ALPHA_BLEND = 3;4142/** Draw multiplying the source and destination colours */43public static int MODE_COLOR_MULTIPLY = 4;4445/** Draw adding the existing colour to the new colour */46public static int MODE_ADD = 5;4748/** Draw blending the new image into the old one by a factor of it's colour */49public static int MODE_SCREEN = 6;5051/** The default number of segments that will be used when drawing an oval */52private static final int DEFAULT_SEGMENTS = 50;5354/** The last graphics context in use */55protected static Graphics currentGraphics = null;5657/** The default font to use */58protected static Font DEFAULT_FONT;5960/** The last set scale */61private float sx = 1;62/** The last set scale */63private float sy = 1;6465/**66* Set the current graphics context in use67*68* @param current The graphics context that should be considered current69*/70public static void setCurrent(Graphics current) {71if (currentGraphics != current) {72if (currentGraphics != null) {73currentGraphics.disable();74}75currentGraphics = current;76currentGraphics.enable();77}78}7980/** The font in use */81private Font font;8283/** The current color */84private Color currentColor = Color.white;8586/** The width of the screen */87protected int screenWidth;8889/** The height of the screen */90protected int screenHeight;9192/** True if the matrix has been pushed to the stack */93private boolean pushed;9495/** The graphics context clipping */96private Rectangle clip;9798/** Buffer used for setting the world clip */99private DoubleBuffer worldClip = BufferUtils.createDoubleBuffer(4);100101/** The buffer used to read a screen pixel */102private ByteBuffer readBuffer = BufferUtils.createByteBuffer(4);103104/** True if we're antialias */105private boolean antialias;106107/** The world clip recorded since last set */108private Rectangle worldClipRecord;109110/** The current drawing mode */111private int currentDrawingMode = MODE_NORMAL;112113/** The current line width */114private float lineWidth = 1;115116/** The matrix stack */117private ArrayList stack = new ArrayList();118/** The index into the stack we're using */119private int stackIndex;120121/**122* Default constructor for sub-classes123*/124public Graphics() {125}126127/**128* Create a new graphics context. Only the container should be doing this129* really130*131* @param width132* The width of the screen for this context133* @param height134* The height of the screen for this context135*/136public Graphics(int width, int height) {137if (DEFAULT_FONT == null) {138AccessController.doPrivileged(new PrivilegedAction() {139public Object run() {140try {141DEFAULT_FONT = new AngelCodeFont(142"org/newdawn/slick/data/defaultfont.fnt",143"org/newdawn/slick/data/defaultfont.png");144} catch (SlickException e) {145Log.error(e);146}147return null; // nothing to return148}149});150}151152this.font = DEFAULT_FONT;153screenWidth = width;154screenHeight = height;155}156157/**158* Set the dimensions considered by the graphics context159*160* @param width The width of the graphics context161* @param height The height of the graphics context162*/163void setDimensions(int width, int height) {164screenWidth = width;165screenHeight = height;166}167168/**169* Set the drawing mode to use. This mode defines how pixels are drawn to170* the graphics context. It can be used to draw into the alpha map.171*172* The mode supplied should be one of {@link Graphics#MODE_NORMAL} or173* {@link Graphics#MODE_ALPHA_MAP} or {@link Graphics#MODE_ALPHA_BLEND}174*175* @param mode176* The mode to apply.177*/178public void setDrawMode(int mode) {179predraw();180currentDrawingMode = mode;181if (currentDrawingMode == MODE_NORMAL) {182GL.glEnable(SGL.GL_BLEND);183GL.glColorMask(true, true, true, true);184GL.glBlendFunc(SGL.GL_SRC_ALPHA, SGL.GL_ONE_MINUS_SRC_ALPHA);185}186if (currentDrawingMode == MODE_ALPHA_MAP) {187GL.glDisable(SGL.GL_BLEND);188GL.glColorMask(false, false, false, true);189}190if (currentDrawingMode == MODE_ALPHA_BLEND) {191GL.glEnable(SGL.GL_BLEND);192GL.glColorMask(true, true, true, false);193GL.glBlendFunc(GL11.GL_DST_ALPHA, GL11.GL_ONE_MINUS_DST_ALPHA);194}195if (currentDrawingMode == MODE_COLOR_MULTIPLY) {196GL.glEnable(SGL.GL_BLEND);197GL.glColorMask(true, true, true, true);198GL.glBlendFunc(GL11.GL_ONE_MINUS_SRC_COLOR, GL11.GL_SRC_COLOR);199}200if (currentDrawingMode == MODE_ADD) {201GL.glEnable(SGL.GL_BLEND);202GL.glColorMask(true, true, true, true);203GL.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);204}205if (currentDrawingMode == MODE_SCREEN) {206GL.glEnable(SGL.GL_BLEND);207GL.glColorMask(true, true, true, true);208GL.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_COLOR);209}210postdraw();211}212213/**214* Clear the state of the alpha map across the entire screen. This sets215* alpha to 0 everywhere, meaning in {@link Graphics#MODE_ALPHA_BLEND}216* nothing will be drawn.217*/218public void clearAlphaMap() {219pushTransform();220GL.glLoadIdentity();221222int originalMode = currentDrawingMode;223setDrawMode(MODE_ALPHA_MAP);224setColor(new Color(0,0,0,0));225fillRect(0, 0, screenWidth, screenHeight);226setColor(currentColor);227setDrawMode(originalMode);228229popTransform();230}231232/**233* Must be called before all OpenGL operations to maintain context for234* dynamic images235*/236private void predraw() {237setCurrent(this);238}239240/**241* Must be called after all OpenGL operations to maintain context for242* dynamic images243*/244private void postdraw() {245}246247/**248* Enable rendering to this graphics context249*/250protected void enable() {251}252253/**254* Flush this graphics context to the underlying rendering context255*/256public void flush() {257if (currentGraphics == this) {258currentGraphics.disable();259currentGraphics = null;260}261}262263/**264* Disable rendering to this graphics context265*/266protected void disable() {267}268269/**270* Get the current font271*272* @return The current font273*/274public Font getFont() {275return font;276}277278/**279* Set the background colour of the graphics context280*281* @param color282* The background color of the graphics context283*/284public void setBackground(Color color) {285predraw();286GL.glClearColor(color.r, color.g, color.b, color.a);287postdraw();288}289290/**291* Get the current graphics context background color292*293* @return The background color of this graphics context294*/295public Color getBackground() {296predraw();297FloatBuffer buffer = BufferUtils.createFloatBuffer(16);298GL.glGetFloat(SGL.GL_COLOR_CLEAR_VALUE, buffer);299postdraw();300301return new Color(buffer);302}303304/**305* Clear the graphics context306*/307public void clear() {308predraw();309GL.glClear(SGL.GL_COLOR_BUFFER_BIT);310postdraw();311}312313/**314* Reset the transformation on this graphics context315*/316public void resetTransform() {317sx = 1;318sy = 1;319320if (pushed) {321predraw();322GL.glPopMatrix();323pushed = false;324postdraw();325}326}327328/**329* Check if we've pushed the previous matrix, if not then push it now.330*/331private void checkPush() {332if (!pushed) {333predraw();334GL.glPushMatrix();335pushed = true;336postdraw();337}338}339340/**341* Apply a scaling factor to everything drawn on the graphics context342*343* @param sx344* The scaling factor to apply to the x axis345* @param sy346* The scaling factor to apply to the y axis347*/348public void scale(float sx, float sy) {349this.sx = this.sx * sx;350this.sy = this.sy * sy;351352checkPush();353354predraw();355GL.glScalef(sx, sy, 1);356postdraw();357}358359/**360* Apply a rotation to everything draw on the graphics context361*362* @param rx363* The x coordinate of the center of rotation364* @param ry365* The y coordinate of the center of rotation366* @param ang367* The angle (in degrees) to rotate by368*/369public void rotate(float rx, float ry, float ang) {370checkPush();371372predraw();373translate(rx, ry);374GL.glRotatef(ang, 0, 0, 1);375translate(-rx, -ry);376postdraw();377}378379/**380* Apply a translation to everything drawn to the context381*382* @param x383* The amount to translate on the x-axis384* @param y385* The amount of translate on the y-axis386*/387public void translate(float x, float y) {388checkPush();389390predraw();391GL.glTranslatef(x, y, 0);392postdraw();393}394395/**396* Set the font to be used when rendering text397*398* @param font399* The font to be used when rendering text400*/401public void setFont(Font font) {402this.font = font;403}404405/**406* Reset to using the default font for this context407*/408public void resetFont() {409font = DEFAULT_FONT;410}411412/**413* Set the color to use when rendering to this context414*415* @param color416* The color to use when rendering to this context417*/418public void setColor(Color color) {419if (color == null) {420return;421}422423currentColor = new Color(color);424predraw();425currentColor.bind();426postdraw();427}428429/**430* Get the color in use by this graphics context431*432* @return The color in use by this graphics context433*/434public Color getColor() {435return new Color(currentColor);436}437438/**439* Draw a line on the canvas in the current colour440*441* @param x1442* The x coordinate of the start point443* @param y1444* The y coordinate of the start point445* @param x2446* The x coordinate of the end point447* @param y2448* The y coordinate of the end point449*/450public void drawLine(float x1, float y1, float x2, float y2) {451float lineWidth = this.lineWidth - 1;452453if (LSR.applyGLLineFixes()) {454if (x1 == x2) {455if (y1 > y2) {456float temp = y2;457y2 = y1;458y1 = temp;459}460float step = 1 / sy;461lineWidth = lineWidth / sy;462fillRect(x1-(lineWidth/2.0f),y1-(lineWidth/2.0f),lineWidth+step,(y2-y1)+lineWidth+step);463return;464} else if (y1 == y2) {465if (x1 > x2) {466float temp = x2;467x2 = x1;468x1 = temp;469}470float step = 1 / sx;471lineWidth = lineWidth / sx;472fillRect(x1-(lineWidth/2.0f),y1-(lineWidth/2.0f),(x2-x1)+lineWidth+step,lineWidth+step);473return;474}475}476477predraw();478currentColor.bind();479TextureImpl.bindNone();480481LSR.start();482LSR.vertex(x1,y1);483LSR.vertex(x2,y2);484LSR.end();485486postdraw();487}488489/**490* Draw the outline of the given shape.491*492* @param shape493* The shape to draw.494* @param fill495* The fill type to apply496*/497public void draw(Shape shape, ShapeFill fill) {498predraw();499TextureImpl.bindNone();500501ShapeRenderer.draw(shape, fill);502503currentColor.bind();504postdraw();505}506507/**508* Draw the the given shape filled in.509*510* @param shape511* The shape to fill.512* @param fill513* The fill type to apply514*/515public void fill(Shape shape, ShapeFill fill) {516predraw();517TextureImpl.bindNone();518519ShapeRenderer.fill(shape, fill);520521currentColor.bind();522postdraw();523}524525/**526* Draw the outline of the given shape.527*528* @param shape529* The shape to draw.530*/531public void draw(Shape shape) {532predraw();533TextureImpl.bindNone();534currentColor.bind();535536ShapeRenderer.draw(shape);537538postdraw();539}540541/**542* Draw the the given shape filled in.543*544* @param shape545* The shape to fill.546*/547public void fill(Shape shape) {548predraw();549TextureImpl.bindNone();550currentColor.bind();551552ShapeRenderer.fill(shape);553554postdraw();555}556557/**558* Draw the the given shape filled in with a texture559*560* @param shape561* The shape to texture.562* @param image563* The image to tile across the shape564*/565public void texture(Shape shape, Image image) {566texture(shape, image, 0.01f, 0.01f, false);567}568569/**570* Draw the the given shape filled in with a texture571*572* @param shape573* The shape to texture.574* @param image575* The image to tile across the shape576* @param fill577* The shape fill to apply578*/579public void texture(Shape shape, Image image, ShapeFill fill) {580texture(shape, image, 0.01f, 0.01f, fill);581}582583/**584* Draw the the given shape filled in with a texture585*586* @param shape587* The shape to texture.588* @param image589* The image to tile across the shape590* @param fit591* True if we want to fit the image on to the shape592*/593public void texture(Shape shape, Image image, boolean fit) {594if (fit) {595texture(shape, image, 1, 1, true);596} else {597texture(shape, image, 0.01f, 0.01f, false);598}599}600601/**602* Draw the the given shape filled in with a texture603*604* @param shape605* The shape to texture.606* @param image607* The image to tile across the shape608* @param scaleX609* The scale to apply on the x axis for texturing610* @param scaleY611* The scale to apply on the y axis for texturing612*/613public void texture(Shape shape, Image image, float scaleX, float scaleY) {614texture(shape, image, scaleX, scaleY, false);615}616617/**618* Draw the the given shape filled in with a texture619*620* @param shape621* The shape to texture.622* @param image623* The image to tile across the shape624* @param scaleX625* The scale to apply on the x axis for texturing626* @param scaleY627* The scale to apply on the y axis for texturing628* @param fit629* True if we want to fit the image on to the shape630*/631public void texture(Shape shape, Image image, float scaleX, float scaleY,632boolean fit) {633predraw();634TextureImpl.bindNone();635currentColor.bind();636637if (fit) {638ShapeRenderer.textureFit(shape, image, scaleX, scaleY);639} else {640ShapeRenderer.texture(shape, image, scaleX, scaleY);641}642643postdraw();644}645646/**647* Draw the the given shape filled in with a texture648*649* @param shape650* The shape to texture.651* @param image652* The image to tile across the shape653* @param scaleX654* The scale to apply on the x axis for texturing655* @param scaleY656* The scale to apply on the y axis for texturing657* @param fill658* The shape fill to apply659*/660public void texture(Shape shape, Image image, float scaleX, float scaleY,661ShapeFill fill) {662predraw();663TextureImpl.bindNone();664currentColor.bind();665666ShapeRenderer.texture(shape, image, scaleX, scaleY, fill);667668postdraw();669}670671/**672* Draw a rectangle to the canvas in the current colour673*674* @param x1675* The x coordinate of the top left corner676* @param y1677* The y coordinate of the top left corner678* @param width679* The width of the rectangle to draw680* @param height681* The height of the rectangle to draw682*/683public void drawRect(float x1, float y1, float width, float height) {684float lineWidth = getLineWidth();685686drawLine(x1,y1,x1+width,y1);687drawLine(x1+width,y1,x1+width,y1+height);688drawLine(x1+width,y1+height,x1,y1+height);689drawLine(x1,y1+height,x1,y1);690}691692/**693* Clear the clipping being applied. This will allow graphics to be drawn694* anywhere on the screen695*/696public void clearClip() {697clip = null;698predraw();699GL.glDisable(SGL.GL_SCISSOR_TEST);700postdraw();701}702703/**704* Set clipping that controls which areas of the world will be drawn to.705* Note that world clip is different from standard screen clip in that it's706* defined in the space of the current world coordinate - i.e. it's affected707* by translate, rotate, scale etc.708*709* @param x710* The x coordinate of the top left corner of the allowed area711* @param y712* The y coordinate of the top left corner of the allowed area713* @param width714* The width of the allowed area715* @param height716* The height of the allowed area717*/718public void setWorldClip(float x, float y, float width, float height) {719predraw();720worldClipRecord = new Rectangle(x, y, width, height);721722GL.glEnable(SGL.GL_CLIP_PLANE0);723worldClip.put(1).put(0).put(0).put(-x).flip();724GL.glClipPlane(SGL.GL_CLIP_PLANE0, worldClip);725GL.glEnable(SGL.GL_CLIP_PLANE1);726worldClip.put(-1).put(0).put(0).put(x + width).flip();727GL.glClipPlane(SGL.GL_CLIP_PLANE1, worldClip);728729GL.glEnable(SGL.GL_CLIP_PLANE2);730worldClip.put(0).put(1).put(0).put(-y).flip();731GL.glClipPlane(SGL.GL_CLIP_PLANE2, worldClip);732GL.glEnable(SGL.GL_CLIP_PLANE3);733worldClip.put(0).put(-1).put(0).put(y + height).flip();734GL.glClipPlane(SGL.GL_CLIP_PLANE3, worldClip);735postdraw();736}737738/**739* Clear world clipping setup. This does not effect screen clipping740*/741public void clearWorldClip() {742predraw();743worldClipRecord = null;744GL.glDisable(SGL.GL_CLIP_PLANE0);745GL.glDisable(SGL.GL_CLIP_PLANE1);746GL.glDisable(SGL.GL_CLIP_PLANE2);747GL.glDisable(SGL.GL_CLIP_PLANE3);748postdraw();749}750751/**752* Set the world clip to be applied753*754* @see #setWorldClip(float, float, float, float)755* @param clip756* The area still visible757*/758public void setWorldClip(Rectangle clip) {759if (clip == null) {760clearWorldClip();761} else {762setWorldClip(clip.getX(), clip.getY(), clip.getWidth(), clip763.getHeight());764}765}766767/**768* Get the last set world clip or null of the world clip isn't set769*770* @return The last set world clip rectangle771*/772public Rectangle getWorldClip() {773return worldClipRecord;774}775776/**777* Set the clipping to apply to the drawing. Note that this clipping takes778* no note of the transforms that have been applied to the context and is779* always in absolute screen space coordinates.780*781* @param x782* The x coordinate of the top left corner of the allowed area783* @param y784* The y coordinate of the top left corner of the allowed area785* @param width786* The width of the allowed area787* @param height788* The height of the allowed area789*/790public void setClip(int x, int y, int width, int height) {791predraw();792793if (clip == null) {794GL.glEnable(SGL.GL_SCISSOR_TEST);795clip = new Rectangle(x, y, width, height);796} else {797clip.setBounds(x,y,width,height);798}799800GL.glScissor(x, screenHeight - y - height, width, height);801postdraw();802}803804/**805* Set the clipping to apply to the drawing. Note that this clipping takes806* no note of the transforms that have been applied to the context and is807* always in absolute screen space coordinates.808*809* @param rect810* The rectangle describing the clipped area in screen811* coordinates812*/813public void setClip(Rectangle rect) {814if (rect == null) {815clearClip();816return;817}818819setClip((int) rect.getX(), (int) rect.getY(), (int) rect.getWidth(),820(int) rect.getHeight());821}822823/**824* Return the currently applied clipping rectangle825*826* @return The current applied clipping rectangle or null if no clipping is827* applied828*/829public Rectangle getClip() {830return clip;831}832833/**834* Tile a rectangle with a pattern specifing the offset from the top corner835* that one tile should match836*837* @param x838* The x coordinate of the rectangle839* @param y840* The y coordinate of the rectangle841* @param width842* The width of the rectangle843* @param height844* The height of the rectangle845* @param pattern846* The image to tile across the rectangle847* @param offX848* The offset on the x axis from the top left corner849* @param offY850* The offset on the y axis from the top left corner851*/852public void fillRect(float x, float y, float width, float height,853Image pattern, float offX, float offY) {854int cols = ((int) Math.ceil(width / pattern.getWidth())) + 2;855int rows = ((int) Math.ceil(height / pattern.getHeight())) + 2;856857Rectangle preClip = getWorldClip();858setWorldClip(x, y, width, height);859860predraw();861// Draw all the quads we need862for (int c = 0; c < cols; c++) {863for (int r = 0; r < rows; r++) {864pattern.draw(c * pattern.getWidth() + x - offX, r865* pattern.getHeight() + y - offY);866}867}868postdraw();869870setWorldClip(preClip);871}872873/**874* Fill a rectangle on the canvas in the current color875*876* @param x1877* The x coordinate of the top left corner878* @param y1879* The y coordinate of the top left corner880* @param width881* The width of the rectangle to fill882* @param height883* The height of the rectangle to fill884*/885public void fillRect(float x1, float y1, float width, float height) {886predraw();887TextureImpl.bindNone();888currentColor.bind();889890GL.glBegin(SGL.GL_QUADS);891GL.glVertex2f(x1, y1);892GL.glVertex2f(x1 + width, y1);893GL.glVertex2f(x1 + width, y1 + height);894GL.glVertex2f(x1, y1 + height);895GL.glEnd();896postdraw();897}898899/**900* Draw an oval to the canvas901*902* @param x1903* The x coordinate of the top left corner of a box containing904* the oval905* @param y1906* The y coordinate of the top left corner of a box containing907* the oval908* @param width909* The width of the oval910* @param height911* The height of the oval912*/913public void drawOval(float x1, float y1, float width, float height) {914drawOval(x1, y1, width, height, DEFAULT_SEGMENTS);915}916917/**918* Draw an oval to the canvas919*920* @param x1921* The x coordinate of the top left corner of a box containing922* the oval923* @param y1924* The y coordinate of the top left corner of a box containing925* the oval926* @param width927* The width of the oval928* @param height929* The height of the oval930* @param segments931* The number of line segments to use when drawing the oval932*/933public void drawOval(float x1, float y1, float width, float height,934int segments) {935drawArc(x1, y1, width, height, segments, 0, 360);936}937938/**939* Draw an oval to the canvas940*941* @param x1942* The x coordinate of the top left corner of a box containing943* the arc944* @param y1945* The y coordinate of the top left corner of a box containing946* the arc947* @param width948* The width of the arc949* @param height950* The height of the arc951* @param start952* The angle the arc starts at953* @param end954* The angle the arc ends at955*/956public void drawArc(float x1, float y1, float width, float height,957float start, float end) {958drawArc(x1, y1, width, height, DEFAULT_SEGMENTS, start, end);959}960961/**962* Draw an oval to the canvas963*964* @param x1965* The x coordinate of the top left corner of a box containing966* the arc967* @param y1968* The y coordinate of the top left corner of a box containing969* the arc970* @param width971* The width of the arc972* @param height973* The height of the arc974* @param segments975* The number of line segments to use when drawing the arc976* @param start977* The angle the arc starts at978* @param end979* The angle the arc ends at980*/981public void drawArc(float x1, float y1, float width, float height,982int segments, float start, float end) {983predraw();984TextureImpl.bindNone();985currentColor.bind();986987while (end < start) {988end += 360;989}990991float cx = x1 + (width / 2.0f);992float cy = y1 + (height / 2.0f);993994LSR.start();995int step = 360 / segments;996997for (int a = (int) start; a < (int) (end + step); a += step) {998float ang = a;999if (ang > end) {1000ang = end;1001}1002float x = (float) (cx + (FastTrig.cos(Math.toRadians(ang)) * width / 2.0f));1003float y = (float) (cy + (FastTrig.sin(Math.toRadians(ang)) * height / 2.0f));10041005LSR.vertex(x,y);1006}1007LSR.end();1008postdraw();1009}10101011/**1012* Fill an oval to the canvas1013*1014* @param x11015* The x coordinate of the top left corner of a box containing1016* the oval1017* @param y11018* The y coordinate of the top left corner of a box containing1019* the oval1020* @param width1021* The width of the oval1022* @param height1023* The height of the oval1024*/1025public void fillOval(float x1, float y1, float width, float height) {1026fillOval(x1, y1, width, height, DEFAULT_SEGMENTS);1027}10281029/**1030* Fill an oval to the canvas1031*1032* @param x11033* The x coordinate of the top left corner of a box containing1034* the oval1035* @param y11036* The y coordinate of the top left corner of a box containing1037* the oval1038* @param width1039* The width of the oval1040* @param height1041* The height of the oval1042* @param segments1043* The number of line segments to use when filling the oval1044*/1045public void fillOval(float x1, float y1, float width, float height,1046int segments) {1047fillArc(x1, y1, width, height, segments, 0, 360);1048}10491050/**1051* Fill an arc to the canvas (a wedge)1052*1053* @param x11054* The x coordinate of the top left corner of a box containing1055* the arc1056* @param y11057* The y coordinate of the top left corner of a box containing1058* the arc1059* @param width1060* The width of the arc1061* @param height1062* The height of the arc1063* @param start1064* The angle the arc starts at1065* @param end1066* The angle the arc ends at1067*/1068public void fillArc(float x1, float y1, float width, float height,1069float start, float end) {1070fillArc(x1, y1, width, height, DEFAULT_SEGMENTS, start, end);1071}10721073/**1074* Fill an arc to the canvas (a wedge)1075*1076* @param x11077* The x coordinate of the top left corner of a box containing1078* the arc1079* @param y11080* The y coordinate of the top left corner of a box containing1081* the arc1082* @param width1083* The width of the arc1084* @param height1085* The height of the arc1086* @param segments1087* The number of line segments to use when filling the arc1088* @param start1089* The angle the arc starts at1090* @param end1091* The angle the arc ends at1092*/1093public void fillArc(float x1, float y1, float width, float height,1094int segments, float start, float end) {1095predraw();1096TextureImpl.bindNone();1097currentColor.bind();10981099while (end < start) {1100end += 360;1101}11021103float cx = x1 + (width / 2.0f);1104float cy = y1 + (height / 2.0f);11051106GL.glBegin(SGL.GL_TRIANGLE_FAN);1107int step = 360 / segments;11081109GL.glVertex2f(cx, cy);11101111for (int a = (int) start; a < (int) (end + step); a += step) {1112float ang = a;1113if (ang > end) {1114ang = end;1115}11161117float x = (float) (cx + (FastTrig.cos(Math.toRadians(ang)) * width / 2.0f));1118float y = (float) (cy + (FastTrig.sin(Math.toRadians(ang)) * height / 2.0f));11191120GL.glVertex2f(x, y);1121}1122GL.glEnd();11231124if (antialias) {1125GL.glBegin(SGL.GL_TRIANGLE_FAN);1126GL.glVertex2f(cx, cy);1127if (end != 360) {1128end -= 10;1129}11301131for (int a = (int) start; a < (int) (end + step); a += step) {1132float ang = a;1133if (ang > end) {1134ang = end;1135}11361137float x = (float) (cx + (FastTrig.cos(Math.toRadians(ang + 10))1138* width / 2.0f));1139float y = (float) (cy + (FastTrig.sin(Math.toRadians(ang + 10))1140* height / 2.0f));11411142GL.glVertex2f(x, y);1143}1144GL.glEnd();1145}11461147postdraw();1148}11491150/**1151* Draw a rounded rectangle1152*1153* @param x1154* The x coordinate of the top left corner of the rectangle1155* @param y1156* The y coordinate of the top left corner of the rectangle1157* @param width1158* The width of the rectangle1159* @param height1160* The height of the rectangle1161* @param cornerRadius1162* The radius of the rounded edges on the corners1163*/1164public void drawRoundRect(float x, float y, float width, float height,1165int cornerRadius) {1166drawRoundRect(x, y, width, height, cornerRadius, DEFAULT_SEGMENTS);1167}11681169/**1170* Draw a rounded rectangle1171*1172* @param x1173* The x coordinate of the top left corner of the rectangle1174* @param y1175* The y coordinate of the top left corner of the rectangle1176* @param width1177* The width of the rectangle1178* @param height1179* The height of the rectangle1180* @param cornerRadius1181* The radius of the rounded edges on the corners1182* @param segs1183* The number of segments to make the corners out of1184*/1185public void drawRoundRect(float x, float y, float width, float height,1186int cornerRadius, int segs) {1187if (cornerRadius < 0)1188throw new IllegalArgumentException("corner radius must be > 0");1189if (cornerRadius == 0) {1190drawRect(x, y, width, height);1191return;1192}11931194int mr = (int) Math.min(width, height) / 2;1195// make sure that w & h are larger than 2*cornerRadius1196if (cornerRadius > mr) {1197cornerRadius = mr;1198}11991200drawLine(x + cornerRadius, y, x + width - cornerRadius, y);1201drawLine(x, y + cornerRadius, x, y + height - cornerRadius);1202drawLine(x + width, y + cornerRadius, x + width, y + height1203- cornerRadius);1204drawLine(x + cornerRadius, y + height, x + width - cornerRadius, y1205+ height);12061207float d = cornerRadius * 2;1208// bottom right - 0, 901209drawArc(x + width - d, y + height - d, d, d, segs, 0, 90);1210// bottom left - 90, 1801211drawArc(x, y + height - d, d, d, segs, 90, 180);1212// top right - 270, 3601213drawArc(x + width - d, y, d, d, segs, 270, 360);1214// top left - 180, 2701215drawArc(x, y, d, d, segs, 180, 270);1216}12171218/**1219* Fill a rounded rectangle1220*1221* @param x1222* The x coordinate of the top left corner of the rectangle1223* @param y1224* The y coordinate of the top left corner of the rectangle1225* @param width1226* The width of the rectangle1227* @param height1228* The height of the rectangle1229* @param cornerRadius1230* The radius of the rounded edges on the corners1231*/1232public void fillRoundRect(float x, float y, float width, float height,1233int cornerRadius) {1234fillRoundRect(x, y, width, height, cornerRadius, DEFAULT_SEGMENTS);1235}12361237/**1238* Fill a rounded rectangle1239*1240* @param x1241* The x coordinate of the top left corner of the rectangle1242* @param y1243* The y coordinate of the top left corner of the rectangle1244* @param width1245* The width of the rectangle1246* @param height1247* The height of the rectangle1248* @param cornerRadius1249* The radius of the rounded edges on the corners1250* @param segs1251* The number of segments to make the corners out of1252*/1253public void fillRoundRect(float x, float y, float width, float height,1254int cornerRadius, int segs) {1255if (cornerRadius < 0)1256throw new IllegalArgumentException("corner radius must be > 0");1257if (cornerRadius == 0) {1258fillRect(x, y, width, height);1259return;1260}12611262int mr = (int) Math.min(width, height) / 2;1263// make sure that w & h are larger than 2*cornerRadius1264if (cornerRadius > mr) {1265cornerRadius = mr;1266}12671268float d = cornerRadius * 2;12691270fillRect(x + cornerRadius, y, width - d, cornerRadius);1271fillRect(x, y + cornerRadius, cornerRadius, height - d);1272fillRect(x + width - cornerRadius, y + cornerRadius, cornerRadius,1273height - d);1274fillRect(x + cornerRadius, y + height - cornerRadius, width - d,1275cornerRadius);1276fillRect(x + cornerRadius, y + cornerRadius, width - d, height - d);12771278// bottom right - 0, 901279fillArc(x + width - d, y + height - d, d, d, segs, 0, 90);1280// bottom left - 90, 1801281fillArc(x, y + height - d, d, d, segs, 90, 180);1282// top right - 270, 3601283fillArc(x + width - d, y, d, d, segs, 270, 360);1284// top left - 180, 2701285fillArc(x, y, d, d, segs, 180, 270);1286}12871288/**1289* Set the with of the line to be used when drawing line based primitives1290*1291* @param width1292* The width of the line to be used when drawing line based1293* primitives1294*/1295public void setLineWidth(float width) {1296predraw();1297this.lineWidth = width;1298LSR.setWidth(width);1299GL.glPointSize(width);1300postdraw();1301}13021303/**1304* Get the width of lines being drawn in this context1305*1306* @return The width of lines being draw in this context1307*/1308public float getLineWidth() {1309return lineWidth;1310}13111312/**1313* Reset the line width in use to the default for this graphics context1314*/1315public void resetLineWidth() {1316predraw();13171318Renderer.getLineStripRenderer().setWidth(1.0f);1319GL.glLineWidth(1.0f);1320GL.glPointSize(1.0f);13211322postdraw();1323}13241325/**1326* Indicate if we should antialias as we draw primitives1327*1328* @param anti1329* True if we should antialias1330*/1331public void setAntiAlias(boolean anti) {1332predraw();1333antialias = anti;1334LSR.setAntiAlias(anti);1335if (anti) {1336GL.glEnable(SGL.GL_POLYGON_SMOOTH);1337} else {1338GL.glDisable(SGL.GL_POLYGON_SMOOTH);1339}1340postdraw();1341}13421343/**1344* True if antialiasing has been turned on for this graphics context1345*1346* @return True if antialiasing has been turned on for this graphics context1347*/1348public boolean isAntiAlias() {1349return antialias;1350}13511352/**1353* Draw a string to the screen using the current font1354*1355* @param str1356* The string to draw1357* @param x1358* The x coordinate to draw the string at1359* @param y1360* The y coordinate to draw the string at1361*/1362public void drawString(String str, float x, float y) {1363predraw();1364font.drawString(x, y, str, currentColor);1365postdraw();1366}13671368/**1369* Draw an image to the screen1370*1371* @param image1372* The image to draw to the screen1373* @param x1374* The x location at which to draw the image1375* @param y1376* The y location at which to draw the image1377* @param col1378* The color to apply to the image as a filter1379*/1380public void drawImage(Image image, float x, float y, Color col) {1381predraw();1382image.draw(x, y, col);1383currentColor.bind();1384postdraw();1385}13861387/**1388* Draw an animation to this graphics context1389*1390* @param anim1391* The animation to be drawn1392* @param x1393* The x position to draw the animation at1394* @param y1395* The y position to draw the animation at1396*/1397public void drawAnimation(Animation anim, float x, float y) {1398drawAnimation(anim, x, y, Color.white);1399}14001401/**1402* Draw an animation to this graphics context1403*1404* @param anim1405* The animation to be drawn1406* @param x1407* The x position to draw the animation at1408* @param y1409* The y position to draw the animation at1410* @param col1411* The color to apply to the animation as a filter1412*/1413public void drawAnimation(Animation anim, float x, float y, Color col) {1414predraw();1415anim.draw(x, y, col);1416currentColor.bind();1417postdraw();1418}14191420/**1421* Draw an image to the screen1422*1423* @param image1424* The image to draw to the screen1425* @param x1426* The x location at which to draw the image1427* @param y1428* The y location at which to draw the image1429*/1430public void drawImage(Image image, float x, float y) {1431drawImage(image, x, y, Color.white);1432}14331434/**1435* Draw a section of an image at a particular location and scale on the1436* screen1437*1438* @param image1439* The image to draw a section of1440* @param x1441* The x position to draw the image1442* @param y1443* The y position to draw the image1444* @param x21445* The x position of the bottom right corner of the drawn image1446* @param y21447* The y position of the bottom right corner of the drawn image1448* @param srcx1449* The x position of the rectangle to draw from this image (i.e.1450* relative to the image)1451* @param srcy1452* The y position of the rectangle to draw from this image (i.e.1453* relative to the image)1454* @param srcx21455* The x position of the bottom right cornder of rectangle to1456* draw from this image (i.e. relative to the image)1457* @param srcy21458* The t position of the bottom right cornder of rectangle to1459* draw from this image (i.e. relative to the image)1460*/1461public void drawImage(Image image, float x, float y, float x2, float y2,1462float srcx, float srcy, float srcx2, float srcy2) {1463predraw();1464image.draw(x, y, x2, y2, srcx, srcy, srcx2, srcy2);1465currentColor.bind();1466postdraw();1467}14681469/**1470* Draw a section of an image at a particular location and scale on the1471* screen1472*1473* @param image1474* The image to draw a section of1475* @param x1476* The x position to draw the image1477* @param y1478* The y position to draw the image1479* @param srcx1480* The x position of the rectangle to draw from this image (i.e.1481* relative to the image)1482* @param srcy1483* The y position of the rectangle to draw from this image (i.e.1484* relative to the image)1485* @param srcx21486* The x position of the bottom right cornder of rectangle to1487* draw from this image (i.e. relative to the image)1488* @param srcy21489* The t position of the bottom right cornder of rectangle to1490* draw from this image (i.e. relative to the image)1491*/1492public void drawImage(Image image, float x, float y, float srcx,1493float srcy, float srcx2, float srcy2) {1494drawImage(image, x, y, x + image.getWidth(), y + image.getHeight(),1495srcx, srcy, srcx2, srcy2);1496}14971498/**1499* Copy an area of the rendered screen into an image. The width and height1500* of the area are assumed to match that of the image1501*1502* @param target1503* The target image1504* @param x1505* The x position to copy from1506* @param y1507* The y position to copy from1508*/1509public void copyArea(Image target, int x, int y) {1510int format = target.getTexture().hasAlpha() ? SGL.GL_RGBA : SGL.GL_RGB;1511target.bind();1512GL.glCopyTexImage2D(SGL.GL_TEXTURE_2D, 0, format, x, screenHeight1513- (y + target.getHeight()), target.getTexture()1514.getTextureWidth(), target.getTexture().getTextureHeight(), 0);1515target.ensureInverted();1516}15171518/**1519* Translate an unsigned int into a signed integer1520*1521* @param b1522* The byte to convert1523* @return The integer value represented by the byte1524*/1525private int translate(byte b) {1526if (b < 0) {1527return 256 + b;1528}15291530return b;1531}15321533/**1534* Get the colour of a single pixel in this graphics context1535*1536* @param x1537* The x coordinate of the pixel to read1538* @param y1539* The y coordinate of the pixel to read1540* @return The colour of the pixel at the specified location1541*/1542public Color getPixel(int x, int y) {1543predraw();1544GL.glReadPixels(x, screenHeight - y, 1, 1, SGL.GL_RGBA,1545SGL.GL_UNSIGNED_BYTE, readBuffer);1546postdraw();15471548return new Color(translate(readBuffer.get(0)), translate(readBuffer1549.get(1)), translate(readBuffer.get(2)), translate(readBuffer1550.get(3)));1551}15521553/**1554* Get an ara of pixels as RGBA values into a buffer1555*1556* @param x The x position in the context to grab from1557* @param y The y position in the context to grab from1558* @param width The width of the area to grab from1559* @param height The hiehgt of the area to grab from1560* @param target The target buffer to grab into1561*/1562public void getArea(int x, int y, int width, int height, ByteBuffer target)1563{1564if (target.capacity() < width * height * 4)1565{1566throw new IllegalArgumentException("Byte buffer provided to get area is not big enough");1567}15681569predraw();1570GL.glReadPixels(x, screenHeight - y - height, width, height, SGL.GL_RGBA,1571SGL.GL_UNSIGNED_BYTE, target);1572postdraw();1573}15741575/**1576* Draw a section of an image at a particular location and scale on the1577* screen1578*1579* @param image1580* The image to draw a section of1581* @param x1582* The x position to draw the image1583* @param y1584* The y position to draw the image1585* @param x21586* The x position of the bottom right corner of the drawn image1587* @param y21588* The y position of the bottom right corner of the drawn image1589* @param srcx1590* The x position of the rectangle to draw from this image (i.e.1591* relative to the image)1592* @param srcy1593* The y position of the rectangle to draw from this image (i.e.1594* relative to the image)1595* @param srcx21596* The x position of the bottom right cornder of rectangle to1597* draw from this image (i.e. relative to the image)1598* @param srcy21599* The t position of the bottom right cornder of rectangle to1600* draw from this image (i.e. relative to the image)1601* @param col1602* The color to apply to the image as a filter1603*/1604public void drawImage(Image image, float x, float y, float x2, float y2,1605float srcx, float srcy, float srcx2, float srcy2, Color col) {1606predraw();1607image.draw(x, y, x2, y2, srcx, srcy, srcx2, srcy2, col);1608currentColor.bind();1609postdraw();1610}16111612/**1613* Draw a section of an image at a particular location and scale on the1614* screen1615*1616* @param image1617* The image to draw a section of1618* @param x1619* The x position to draw the image1620* @param y1621* The y position to draw the image1622* @param srcx1623* The x position of the rectangle to draw from this image (i.e.1624* relative to the image)1625* @param srcy1626* The y position of the rectangle to draw from this image (i.e.1627* relative to the image)1628* @param srcx21629* The x position of the bottom right cornder of rectangle to1630* draw from this image (i.e. relative to the image)1631* @param srcy21632* The t position of the bottom right cornder of rectangle to1633* draw from this image (i.e. relative to the image)1634* @param col1635* The color to apply to the image as a filter1636*/1637public void drawImage(Image image, float x, float y, float srcx,1638float srcy, float srcx2, float srcy2, Color col) {1639drawImage(image, x, y, x + image.getWidth(), y + image.getHeight(),1640srcx, srcy, srcx2, srcy2, col);1641}16421643/**1644* Draw a line with a gradient between the two points.1645*1646* @param x11647* The starting x position to draw the line1648* @param y11649* The starting y position to draw the line1650* @param red11651* The starting position's shade of red1652* @param green11653* The starting position's shade of green1654* @param blue11655* The starting position's shade of blue1656* @param alpha11657* The starting position's alpha value1658* @param x21659* The ending x position to draw the line1660* @param y21661* The ending y position to draw the line1662* @param red21663* The ending position's shade of red1664* @param green21665* The ending position's shade of green1666* @param blue21667* The ending position's shade of blue1668* @param alpha21669* The ending position's alpha value1670*/1671public void drawGradientLine(float x1, float y1, float red1, float green1,1672float blue1, float alpha1, float x2, float y2, float red2,1673float green2, float blue2, float alpha2) {1674predraw();16751676TextureImpl.bindNone();16771678GL.glBegin(SGL.GL_LINES);16791680GL.glColor4f(red1, green1, blue1, alpha1);1681GL.glVertex2f(x1, y1);16821683GL.glColor4f(red2, green2, blue2, alpha2);1684GL.glVertex2f(x2, y2);16851686GL.glEnd();16871688postdraw();1689}16901691/**1692* Draw a line with a gradient between the two points.1693*1694* @param x11695* The starting x position to draw the line1696* @param y11697* The starting y position to draw the line1698* @param Color11699* The starting position's color1700* @param x21701* The ending x position to draw the line1702* @param y21703* The ending y position to draw the line1704* @param Color21705* The ending position's color1706*/1707public void drawGradientLine(float x1, float y1, Color Color1, float x2,1708float y2, Color Color2) {1709predraw();17101711TextureImpl.bindNone();17121713GL.glBegin(SGL.GL_LINES);17141715Color1.bind();1716GL.glVertex2f(x1, y1);17171718Color2.bind();1719GL.glVertex2f(x2, y2);17201721GL.glEnd();17221723postdraw();1724}17251726/**1727* Push the current state of the transform from this graphics contexts1728* onto the underlying graphics stack's transform stack. An associated1729* popTransform() must be performed to restore the state before the end1730* of the rendering loop.1731*/1732public void pushTransform() {1733predraw();17341735FloatBuffer buffer;1736if (stackIndex >= stack.size()) {1737buffer = BufferUtils.createFloatBuffer(18);1738stack.add(buffer);1739} else {1740buffer = (FloatBuffer) stack.get(stackIndex);1741}17421743GL.glGetFloat(GL11.GL_MODELVIEW_MATRIX, buffer);1744buffer.put(16, sx);1745buffer.put(17, sy);1746stackIndex++;17471748postdraw();1749}17501751/**1752* Pop a previously pushed transform from the stack to the current. This should1753* only be called if a transform has been previously pushed.1754*/1755public void popTransform() {1756if (stackIndex == 0) {1757throw new RuntimeException("Attempt to pop a transform that hasn't be pushed");1758}17591760predraw();17611762stackIndex--;1763FloatBuffer oldBuffer = (FloatBuffer) stack.get(stackIndex);1764GL.glLoadMatrix(oldBuffer);1765sx = oldBuffer.get(16);1766sy = oldBuffer.get(17);17671768postdraw();1769}17701771/**1772* Dispose this graphics context, this will release any underlying resourses. However1773* this will also invalidate it's use1774*/1775public void destroy() {17761777}1778}177917801781