Permalink
Browse files

updating tests, adding framebuffers

  • Loading branch information...
mattdesl committed Dec 15, 2012
1 parent 2a352fd commit 3feb67b662c0e42c77bd88bf370ca3fa225f62d1
@@ -63,7 +63,7 @@
public final static Color ORANGE = new Color(255, 200, 0, 255);
/** The fixed colour dark magenta */
public final static Color MAGENTA = new Color(255, 0, 255, 255);
-
+
/** The red component [0.0 - 1.0]. */
public float r;
/** The green component [0.0 - 1.0]. */
@@ -0,0 +1,188 @@
+/**
+ * Copyright (c) 2012, Matt DesLauriers All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of the Matt DesLauriers nor the names
+ * of his contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package mdesl.graphics;
+
+import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT;
+import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT;
+import static org.lwjgl.opengl.EXTFramebufferObject.glCheckFramebufferStatusEXT;
+import static org.lwjgl.opengl.EXTFramebufferObject.glDeleteFramebuffersEXT;
+import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT;
+import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT;
+import static org.lwjgl.opengl.GL11.glViewport;
+import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
+import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
+import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_COMPLETE;
+import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.GLContext;
+
+/**
+ * A very thin wrapper around OpenGL Frame Buffer Objects, intended for
+ * 2D purposes. This uses GL_FRAMEBUFFER_EXT for GL 2.1 compatibility.
+ *
+ * @author davedes
+ */
+public class Framebuffer implements ITexture {
+
+ public static boolean isSupported() {
+ return GLContext.getCapabilities().GL_EXT_framebuffer_object;
+ }
+
+ /** The ID of the FBO in use */
+ protected int id;
+ protected Texture texture;
+ protected boolean ownsTexture;
+
+ Framebuffer(Texture texture, boolean ownsTexture) throws LWJGLException {
+ this.texture = texture;
+ this.ownsTexture = ownsTexture;
+ if (!isSupported()) {
+ throw new LWJGLException("FBO extension not supported in hardware");
+ }
+ texture.bind();
+ id = glGenFramebuffersEXT();
+ glBindFramebufferEXT(GL_FRAMEBUFFER, id);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texture.getTarget(), texture.getID(), 0);
+ int result = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+ if (result!=GL_FRAMEBUFFER_COMPLETE) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(id);
+ throw new LWJGLException("exception "+result+" when checking FBO status");
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ }
+
+ /**
+ * Advanced constructor which creates a frame buffer from a texture; the framebuffer
+ * does not "own" the texture and thus calling dispose() on this framebuffer will not
+ * destroy the texture.
+ *
+ * @param texture the texture to use
+ * @throws LWJGLException if the framebuffer was not initialized correctly
+ */
+ public Framebuffer(Texture texture) throws LWJGLException {
+ this(texture, false);
+ }
+
+ /**
+ *
+ * @param width
+ * @param height
+ * @param filter
+ * @param wrap
+ * @throws LWJGLException
+ */
+ public Framebuffer(int width, int height, int filter, int wrap) throws LWJGLException {
+ this(new Texture(width, height, filter, wrap), true);
+ }
+
+ public Framebuffer(int width, int height, int filter) throws LWJGLException {
+ this(width, height, filter, Texture.DEFAULT_WRAP);
+ }
+
+ public Framebuffer(int width, int height) throws LWJGLException {
+ this(width, height, Texture.DEFAULT_FILTER, Texture.DEFAULT_WRAP);
+ }
+
+ public int getID() {
+ return id;
+ }
+
+ public int getWidth() {
+ return texture.getWidth();
+ }
+
+ public int getHeight() {
+ return texture.getHeight();
+ }
+
+ public Texture getTexture() {
+ return texture;
+ }
+
+ /**
+ * Binds the FBO and sets glViewport to the texture region width/height.
+ */
+ public void begin() {
+ if (id == 0)
+ throw new IllegalStateException("can't use FBO as it has been destroyed..");
+ glViewport(0, 0, getWidth(), getHeight());
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
+ //glReadBuffer(GL_COLOR_ATTACHMENT0);
+ }
+
+ /**
+ * Unbinds the FBO and resets glViewport to the display size.
+ */
+ public void end() {
+ if (id==0)
+ return;
+ glViewport(0, 0, Display.getWidth(), Display.getHeight());
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+
+ /**
+ * Disposes this FBO without destroying the texture.
+ */
+ public void dispose() {
+ if (id==0)
+ return;
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDeleteFramebuffersEXT(id);
+ if (ownsTexture)
+ texture.dispose();
+ id = 0;
+ //glReadBuffer(GL_BACK);
+ }
+
+ @Override
+ public float getU() {
+ return 0;
+ }
+
+ @Override
+ public float getV() {
+ return 1f;
+ }
+
+ @Override
+ public float getU2() {
+ return 1f;
+ }
+
+ @Override
+ public float getV2() {
+ return 0;
+ }
+}
@@ -40,8 +40,8 @@
public interface ITexture {
public Texture getTexture();
- public float getWidth();
- public float getHeight();
+ public int getWidth();
+ public int getHeight();
public float getU();
public float getV();
public float getU2();
@@ -31,7 +31,6 @@
package mdesl.graphics;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
-import static org.lwjgl.opengl.GL20.glUniform1i;
import java.nio.FloatBuffer;
import java.util.Arrays;
@@ -46,7 +45,6 @@
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Matrix4f;
-import org.lwjgl.util.vector.Vector2f;
/** @author Matt (mdesl) DesLauriers
* @author matheusdev */
@@ -94,16 +92,16 @@
private Color color = new Color();
private boolean drawing = false;
- static ShaderProgram getDefaultShader() throws LWJGLException {
- return defaultShader == null ? new ShaderProgram(DEFAULT_VERT_SHADER, DEFAULT_FRAG_SHADER,
- ATTRIBUTES) : defaultShader;
+ public static ShaderProgram getDefaultShader() throws LWJGLException {
+ return defaultShader == null ? (defaultShader = new ShaderProgram(DEFAULT_VERT_SHADER, DEFAULT_FRAG_SHADER,
+ ATTRIBUTES)) : defaultShader;
}
public SpriteBatch(ShaderProgram program) {
this(program, 1000);
}
- public SpriteBatch(ShaderProgram program, int size) {
+ public SpriteBatch(ShaderProgram program, int size) {
this.program = program;
// later we can do some abstraction to replace this with VBOs...
@@ -118,6 +116,11 @@ public SpriteBatch(ShaderProgram program, int size) {
resize(Display.getWidth(), Display.getHeight());
}
+ /**
+ * Creates a sprite batch with a default shader, shared across all sprite batches.
+ * @param size
+ * @throws LWJGLException
+ */
public SpriteBatch(int size) throws LWJGLException {
this(getDefaultShader(), size);
}
@@ -141,7 +144,7 @@ public Matrix4f getProjectionMatrix() {
* @param width
* @param height */
public void resize(int width, int height) {
- projMatrix = MathUtil.toOrtho2D(projMatrix, 0, 0, Display.getWidth(), Display.getHeight());
+ projMatrix = MathUtil.toOrtho2D(projMatrix, 0, 0, width, height);
updateUniforms();
}
@@ -205,6 +208,8 @@ public void updateUniforms(ShaderProgram program) {
* @param updateUniforms whether to call updateUniforms after changing the
* programs */
public void setShader(ShaderProgram program, boolean updateUniforms) {
+ if (program==null)
+ throw new NullPointerException("shader cannot be null; use getDefaultShader instead");
if (drawing) {
flush();
this.program.use();
@@ -222,6 +227,10 @@ public void setShader(ShaderProgram program) {
setShader(program, true);
}
+ public ShaderProgram getShader() {
+ return program;
+ }
+
public void begin() {
if (drawing)
throw new IllegalStateException("must not be drawing before calling begin()");
@@ -261,6 +270,16 @@ public void drawRegion(Texture tex, float srcX, float srcY, float srcWidth, floa
float v2 = (srcY + srcHeight) / tex.getHeight();
draw(tex, dstX, dstY, dstWidth, dstHeight, u, v, u2, v2);
}
+
+ public void drawRegion(TextureRegion region, float srcX, float srcY, float srcWidth, float srcHeight, float dstX, float dstY) {
+ drawRegion(region, srcX, srcY, srcWidth, srcHeight, dstX, dstY, srcWidth, srcHeight);
+ }
+
+ public void drawRegion(TextureRegion region, float srcX, float srcY, float srcWidth, float srcHeight,
+ float dstX, float dstY, float dstWidth, float dstHeight) {
+ drawRegion(region.getTexture(), region.getRegionX() + srcX, region.getRegionY() + srcY,
+ srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight);
+ }
public void draw(ITexture tex, float x, float y) {
draw(tex, x, y, tex.getWidth(), tex.getHeight());
@@ -270,23 +289,84 @@ public void draw(ITexture tex, float x, float y, float width, float height) {
draw(tex, x, y, width, height, tex.getU(), tex.getV(), tex.getU2(), tex.getV2());
}
- public void draw(ITexture tex, float x, float y, float width, float height, float u, float v,
+
+ public void draw(ITexture tex, float x, float y, float originX, float originY, float rotationRadians) {
+ draw(tex, x, y, tex.getWidth(), tex.getHeight(), originX, originY, rotationRadians);
+ }
+
+ public void draw(ITexture tex, float x, float y, float width, float height,
+ float originX, float originY, float rotationRadians) {
+ draw(tex, x, y, width, height, originX, originY, rotationRadians, tex.getU(), tex.getV(), tex.getU2(), tex.getV2());
+ }
+
+ public void draw(ITexture tex, float x, float y, float width, float height,
+ float originX, float originY, float rotationRadians,
+ float u, float v,
float u2, float v2) {
checkFlush(tex);
final float r = color.r;
final float g = color.g;
final float b = color.b;
final float a = color.a;
+
+ float x1,y1, x2,y2, x3,y3, x4,y4;
+
+ if (rotationRadians != 0) {
+ float scaleX = 1f;//width/tex.getWidth();
+ float scaleY = 1f;//height/tex.getHeight();
+
+ float cx = originX*scaleX;
+ float cy = originY*scaleY;
+
+ float p1x = -cx;
+ float p1y = -cy;
+ float p2x = width - cx;
+ float p2y = -cy;
+ float p3x = width - cx;
+ float p3y = height - cy;
+ float p4x = -cx;
+ float p4y = height - cy;
+
+ final float cos = (float) Math.cos(rotationRadians);
+ final float sin = (float) Math.sin(rotationRadians);
+
+ x1 = x + (cos * p1x - sin * p1y) + cx; // TOP LEFT
+ y1 = y + (sin * p1x + cos * p1y) + cy;
+ x2 = x + (cos * p2x - sin * p2y) + cx; // TOP RIGHT
+ y2 = y + (sin * p2x + cos * p2y) + cy;
+ x3 = x + (cos * p3x - sin * p3y) + cx; // BOTTOM RIGHT
+ y3 = y + (sin * p3x + cos * p3y) + cy;
+ x4 = x + (cos * p4x - sin * p4y) + cx; // BOTTOM LEFT
+ y4 = y + (sin * p4x + cos * p4y) + cy;
+ } else {
+ x1 = x;
+ y1 = y;
+
+ x2 = x+width;
+ y2 = y;
+
+ x3 = x+width;
+ y3 = y+height;
+
+ x4 = x;
+ y4 = y+height;
+ }
+
// top left, top right, bottom left
- vertex(x, y, r, g, b, a, u, v);
- vertex(x + width, y, r, g, b, a, u2, v);
- vertex(x, y + height, r, g, b, a, u, v2);
+ vertex(x1, y1, r, g, b, a, u, v);
+ vertex(x2, y2, r, g, b, a, u2, v);
+ vertex(x4, y4, r, g, b, a, u, v2);
// top right, bottom right, bottom left
- vertex(x + width, y, r, g, b, a, u2, v);
- vertex(x + width, y + height, r, g, b, a, u2, v2);
- vertex(x, y + height, r, g, b, a, u, v2);
+ vertex(x2, y2, r, g, b, a, u2, v);
+ vertex(x3, y3, r, g, b, a, u2, v2);
+ vertex(x4, y4, r, g, b, a, u, v2);
+ }
+
+ public void draw(ITexture tex, float x, float y, float width, float height, float u, float v,
+ float u2, float v2) {
+ draw(tex, x, y, width, height, x, y, 0f, u, v, u2, v2);
}
/** Renders a texture using custom vertex attributes; e.g. for different
Oops, something went wrong.

0 comments on commit 3feb67b

Please sign in to comment.