/** * Create an image based on a file at the specified location * * @param ref The location of the image file to load * @param flipped True if the image should be flipped on the y-axis on load * @param f The filtering method to use when scaling this image * @param transparent The color to treat as transparent * @throws SlickException Indicates a failure to load the image */ public Image(String ref, boolean flipped, int f, Color transparent) throws SlickException { this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; this.transparent = transparent; this.flipped = flipped; try { this.ref = ref; int[] trans = null; if (transparent != null) { trans = new int[3]; trans[0] = (int) (transparent.r * 255); trans[1] = (int) (transparent.g * 255); trans[2] = (int) (transparent.b * 255); } texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans); } catch (IOException e) { Log.error(e); throw new SlickException("Failed to load image from: "+ref, e); } }
/** * Load the image * * @param in The input stream to read the image from * @param ref The name that should be assigned to the image * @param flipped True if the image should be flipped on the y-axis on load * @param f The filter to use when scaling this image * @param transparent The color to treat as transparent * @throws SlickException Indicates a failure to load the image */ private void load(InputStream in, String ref, boolean flipped, int f, Color transparent) throws SlickException { this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; try { this.ref = ref; int[] trans = null; if (transparent != null) { trans = new int[3]; trans[0] = (int) (transparent.r * 255); trans[1] = (int) (transparent.g * 255); trans[2] = (int) (transparent.b * 255); } texture = InternalTextureLoader.get().getTexture(in, ref, flipped, filter, trans); } catch (IOException e) { Log.error(e); throw new SlickException("Failed to load image from: "+ref, e); } }
/** * Reload a given texture blob * * @param texture The texture being reloaded * @param srcPixelFormat The source pixel format * @param componentCount The component count * @param minFilter The minification filter * @param magFilter The magnification filter * @param textureBuffer The pixel data * @return The ID of the newly created texture */ public int reload(TextureImpl texture, int srcPixelFormat, int componentCount, int minFilter, int magFilter, ByteBuffer textureBuffer) { int target = SGL.GL_TEXTURE_2D; int textureID = createTextureID(); GL.glBindTexture(target, textureID); GL.glTexParameteri(target, SGL.GL_TEXTURE_MIN_FILTER, minFilter); GL.glTexParameteri(target, SGL.GL_TEXTURE_MAG_FILTER, magFilter); // produce a texture from the byte buffer GL.glTexImage2D(target, 0, dstPixelFormat, texture.getTextureWidth(), texture.getTextureHeight(), 0, srcPixelFormat, SGL.GL_UNSIGNED_BYTE, textureBuffer); return textureID; }
/** * Set clipping that controls which areas of the world will be drawn to. * Note that world clip is different from standard screen clip in that it's * defined in the space of the current world coordinate - i.e. it's affected * by translate, rotate, scale etc. * * @param x * The x coordinate of the top left corner of the allowed area * @param y * The y coordinate of the top left corner of the allowed area * @param width * The width of the allowed area * @param height * The height of the allowed area */ public void setWorldClip(float x, float y, float width, float height) { predraw(); worldClipRecord = new Rectangle(x, y, width, height); GL.glEnable(SGL.GL_CLIP_PLANE0); worldClip.put(1).put(0).put(0).put(-x).flip(); GL.glClipPlane(SGL.GL_CLIP_PLANE0, worldClip); GL.glEnable(SGL.GL_CLIP_PLANE1); worldClip.put(-1).put(0).put(0).put(x + width).flip(); GL.glClipPlane(SGL.GL_CLIP_PLANE1, worldClip); GL.glEnable(SGL.GL_CLIP_PLANE2); worldClip.put(0).put(1).put(0).put(-y).flip(); GL.glClipPlane(SGL.GL_CLIP_PLANE2, worldClip); GL.glEnable(SGL.GL_CLIP_PLANE3); worldClip.put(0).put(-1).put(0).put(y + height).flip(); GL.glClipPlane(SGL.GL_CLIP_PLANE3, worldClip); postdraw(); }
/** * Draw the the given shape filled in. Only the vertices are set. * The colour has to be set independently of this method. * * @param shape The shape to fill. * @param callback The callback that will be invoked for each shape point */ private static final void fill(Shape shape, PointCallback callback) { Triangulator tris = shape.getTriangles(); GL.glBegin(SGL.GL_TRIANGLES); for (int i=0;i<tris.getTriangleCount();i++) { for (int p=0;p<3;p++) { float[] pt = tris.getTrianglePoint(i, p); float[] np = callback.preRenderPoint(shape, pt[0],pt[1]); if (np == null) { GL.glVertex2f(pt[0],pt[1]); } else { GL.glVertex2f(np[0],np[1]); } } } GL.glEnd(); }
/** * Loads a single glyph to the backing texture, if it fits. * * @param glyph The glyph to be rendered * @param width The expected width of the glyph * @param height The expected height of the glyph * @throws SlickException if the glyph could not be rendered. */ private void renderGlyph(Glyph glyph, int width, int height) throws SlickException { // Draw the glyph to the scratch image using Java2D. scratchGraphics.setComposite(AlphaComposite.Clear); scratchGraphics.fillRect(0, 0, MAX_GLYPH_SIZE, MAX_GLYPH_SIZE); scratchGraphics.setComposite(AlphaComposite.SrcOver); scratchGraphics.setColor(java.awt.Color.white); for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext();) ((Effect)iter.next()).draw(scratchImage, scratchGraphics, unicodeFont, glyph); glyph.setShape(null); // The shape will never be needed again. WritableRaster raster = scratchImage.getRaster(); int[] row = new int[width]; for (int y = 0; y < height; y++) { raster.getDataElements(0, y, width, 1, row); scratchIntBuffer.put(row); } GL.glTexSubImage2D(SGL.GL_TEXTURE_2D, 0, pageX, pageY, width, height, SGL.GL_BGRA, SGL.GL_UNSIGNED_BYTE, scratchByteBuffer); scratchIntBuffer.clear(); glyph.setImage(pageImage.getSubImage(pageX, pageY, width, height)); }
/** * Build the display list */ private void build() { if (list == -1) { list = GL.glGenLists(1); SlickCallable.enterSafeBlock(); GL.glNewList(list, SGL.GL_COMPILE); runnable.run(); GL.glEndList(); SlickCallable.leaveSafeBlock(); } else { throw new RuntimeException("Attempt to build the display list more than once in CachedRender"); } }
/** * Clamp the loaded texture to it's edges */ public void clampTexture() { if (GL.canTextureMirrorClamp()) { GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT); GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT); } else { GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_CLAMP); GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_CLAMP); } }
/** * @see Font#drawString(float, float, String, Color, int, int) */ public void drawString(float x, float y, String text, Color col, int startIndex, int endIndex) { fontImage.bind(); col.bind(); GL.glTranslatef(x, y, 0); if (displayListCaching && startIndex == 0 && endIndex == text.length() - 1) { DisplayList displayList = (DisplayList)displayLists.get(text); if (displayList != null) { GL.glCallList(displayList.id); } else { // Compile a new display list. displayList = new DisplayList(); displayList.text = text; int displayListCount = displayLists.size(); if (displayListCount < DISPLAY_LIST_CACHE_SIZE) { displayList.id = baseDisplayListID + displayListCount; } else { displayList.id = eldestDisplayListID; displayLists.remove(eldestDisplayList.text); } displayLists.put(text, displayList); GL.glNewList(displayList.id, SGL.GL_COMPILE_AND_EXECUTE); render(text, startIndex, endIndex); GL.glEndList(); } } else { render(text, startIndex, endIndex); } GL.glTranslatef(-x, -y, 0); }
/** * Render based on immediate rendering * * @param text The text to be rendered * @param start The index of the first character in the string to render * @param end The index of the last character in the string to render */ private void render(String text, int start, int end) { GL.glBegin(SGL.GL_QUADS); int x = 0, y = 0; CharDef lastCharDef = null; char[] data = text.toCharArray(); for (int i = 0; i < data.length; i++) { int id = data[i]; if (id == '\n') { x = 0; y += getLineHeight(); continue; } if (id >= chars.length) { continue; } CharDef charDef = chars[id]; if (charDef == null) { continue; } if (lastCharDef != null) x += lastCharDef.getKerning(id); lastCharDef = charDef; if ((i >= start) && (i <= end)) { charDef.draw(x, y); } x += charDef.xadvance; } GL.glEnd(); }
/** * Create an empty image * * @param width The width of the image * @param height The height of the image * @param f The filter to apply to scaling the new image * @throws SlickException Indicates a failure to create the underlying resource */ public Image(int width, int height, int f) throws SlickException { ref = super.toString(); this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; try { texture = InternalTextureLoader.get().createTexture(width, height, this.filter); } catch (IOException e) { Log.error(e); throw new SlickException("Failed to create empty image "+width+"x"+height); } init(); }
/** * Create an image from a image data source. Note that this method uses * * @param data The pixelData to use to create the image * @param f The filter to use when scaling this image */ public Image(ImageData data, int f) { try { this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; texture = InternalTextureLoader.get().getTexture(data, this.filter); ref = texture.toString(); } catch (IOException e) { Log.error(e); } }
/** * Fill a rectangle on the canvas in the current color * * @param x1 * The x coordinate of the top left corner * @param y1 * The y coordinate of the top left corner * @param width * The width of the rectangle to fill * @param height * The height of the rectangle to fill */ public void fillRect(float x1, float y1, float width, float height) { predraw(); TextureImpl.bindNone(); currentColor.bind(); GL.glBegin(SGL.GL_QUADS); GL.glVertex2f(x1, y1); GL.glVertex2f(x1 + width, y1); GL.glVertex2f(x1 + width, y1 + height); GL.glVertex2f(x1, y1 + height); GL.glEnd(); postdraw(); }
/** * Draw a section of this image at a particular location and scale on the screen * * @param x The x position to draw the image * @param y The y position to draw the image * @param x2 The x position of the bottom right corner of the drawn image * @param y2 The y position of the bottom right corner of the drawn image * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) * @param filter The colour filter to apply when drawing */ public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) { init(); if (alpha != 1) { if (filter == null) { filter = Color.white; } filter = new Color(filter); filter.a *= alpha; } filter.bind(); texture.bind(); GL.glTranslatef(x, y, 0); if (angle != 0) { GL.glTranslatef(centerX, centerY, 0.0f); GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); GL.glTranslatef(-centerX, -centerY, 0.0f); } GL.glBegin(SGL.GL_QUADS); drawEmbedded(0,0,x2-x,y2-y,srcx,srcy,srcx2,srcy2); GL.glEnd(); if (angle != 0) { GL.glTranslatef(centerX, centerY, 0.0f); GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); GL.glTranslatef(-centerX, -centerY, 0.0f); } GL.glTranslatef(-x, -y, 0); // GL.glBegin(SGL.GL_QUADS); // drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2); // GL.glEnd(); }
/** * Start using this sheet. This method can be used for optimal rendering of a collection * of sprites from a single sprite sheet. First, startUse(). Then render each sprite by * calling renderInUse(). Finally, endUse(). Between start and end there can be no rendering * of other sprites since the rendering is locked for this sprite sheet. */ public void startUse() { if (inUse != null) { throw new RuntimeException("Attempt to start use of a sprite sheet before ending use with another - see endUse()"); } inUse = this; init(); Color.white.bind(); texture.bind(); GL.glBegin(SGL.GL_QUADS); }
/** * Get the current graphics context background color * * @return The background color of this graphics context */ public Color getBackground() { predraw(); FloatBuffer buffer = BufferUtils.createFloatBuffer(16); GL.glGetFloat(SGL.GL_COLOR_CLEAR_VALUE, buffer); postdraw(); return new Color(buffer); }
/** * @see org.newdawn.slick.opengl.Texture#bind() */ public void bind() { if (lastBind != this) { lastBind = this; GL.glEnable(SGL.GL_TEXTURE_2D); GL.glBindTexture(target, textureID); } }
/** * @see org.newdawn.slick.opengl.Texture#getTextureData() */ public byte[] getTextureData() { ByteBuffer buffer = BufferUtils.createByteBuffer((hasAlpha() ? 4 : 3) * texWidth * texHeight); bind(); GL.glGetTexImage(SGL.GL_TEXTURE_2D, 0, hasAlpha() ? SGL.GL_RGBA : SGL.GL_RGB, SGL.GL_UNSIGNED_BYTE, buffer); byte[] data = new byte[buffer.limit()]; buffer.get(data); buffer.clear(); return data; }
/** * Render this particle */ public void render() { if ((engine.usePoints() && (usePoints == INHERIT_POINTS)) || (usePoints == USE_POINTS)) { TextureImpl.bindNone(); GL.glEnable(SGL.GL_POINT_SMOOTH); GL.glPointSize(size / 2); color.bind(); GL.glBegin(SGL.GL_POINTS); GL.glVertex2f(x, y); GL.glEnd(); } else if (oriented || scaleY != 1.0f) { GL.glPushMatrix(); GL.glTranslatef(x, y, 0f); if (oriented) { float angle = (float) (Math.atan2(y, x) * 180 / Math.PI); GL.glRotatef(angle, 0f, 0f, 1.0f); } // scale GL.glScalef(1.0f, scaleY, 1.0f); image.draw((int) (-(size / 2)), (int) (-(size / 2)), (int) size, (int) size, color); GL.glPopMatrix(); } else { color.bind(); image.drawEmbedded((int) (x - (size / 2)), (int) (y - (size / 2)), (int) size, (int) size); } }
/** * Start defining the screen mask. After calling this use graphics functions to * mask out the area */ public static void defineMask() { GL.glDepthMask(true); GL.glClearDepth(1); GL.glClear(SGL.GL_DEPTH_BUFFER_BIT); GL.glDepthFunc(SGL.GL_ALWAYS); GL.glEnable(SGL.GL_DEPTH_TEST); GL.glDepthMask(true); GL.glColorMask(false, false, false, false); }
/** * Clear the clipping being applied. This will allow graphics to be drawn * anywhere on the screen */ public void clearClip() { clip = null; predraw(); GL.glDisable(SGL.GL_SCISSOR_TEST); postdraw(); }
/** * Clear world clipping setup. This does not effect screen clipping */ public void clearWorldClip() { predraw(); worldClipRecord = null; GL.glDisable(SGL.GL_CLIP_PLANE0); GL.glDisable(SGL.GL_CLIP_PLANE1); GL.glDisable(SGL.GL_CLIP_PLANE2); GL.glDisable(SGL.GL_CLIP_PLANE3); postdraw(); }
/** * Indicate if we should antialias as we draw primitives * * @param anti * True if we should antialias */ public void setAntiAlias(boolean anti) { predraw(); antialias = anti; LSR.setAntiAlias(anti); if (anti) { GL.glEnable(SGL.GL_POLYGON_SMOOTH); } else { GL.glDisable(SGL.GL_POLYGON_SMOOTH); } postdraw(); }
/** * Get an ara of pixels as RGBA values into a buffer * * @param x The x position in the context to grab from * @param y The y position in the context to grab from * @param width The width of the area to grab from * @param height The hiehgt of the area to grab from * @param target The target buffer to grab into */ public void getArea(int x, int y, int width, int height, ByteBuffer target) { if (target.capacity() < width * height * 4) { throw new IllegalArgumentException("Byte buffer provided to get area is not big enough"); } predraw(); GL.glReadPixels(x, screenHeight - y - height, width, height, SGL.GL_RGBA, SGL.GL_UNSIGNED_BYTE, target); postdraw(); }
/** * @see Font#drawString(float, float, String, org.newdawn.slick.Color, int, int) */ public void drawString(float x, float y, String whatchars, org.newdawn.slick.Color color, int startIndex, int endIndex) { color.bind(); fontTexture.bind(); IntObject intObject = null; int charCurrent; GL.glBegin(SGL.GL_QUADS); int totalwidth = 0; for (int i = 0; i < whatchars.length(); i++) { charCurrent = whatchars.charAt(i); if (charCurrent < 256) { intObject = charArray[charCurrent]; } else { intObject = (IntObject)customChars.get( new Character( (char) charCurrent ) ); } if( intObject != null ) { if ((i >= startIndex) || (i <= endIndex)) { drawQuad((x + totalwidth), y, (x + totalwidth + intObject.width), (y + intObject.height), intObject.storedX, intObject.storedY, intObject.storedX + intObject.width, intObject.storedY + intObject.height); } totalwidth += intObject.width; } } GL.glEnd(); }
/** * Render the diagram to the given graphics context * * @param g The graphics context to which we should render the diagram */ public void render(Graphics g) { // last list generation if (list == -1) { list = GL.glGenLists(1); GL.glNewList(list, SGL.GL_COMPILE); render(g, diagram); GL.glEndList(); } GL.glCallList(list); TextureImpl.bindNone(); }