Adding texture caching in immediate mode

This commit is contained in:
codeanticode
2011-12-19 14:17:57 +00:00
parent 19c6476887
commit da9273b9c6
2 changed files with 180 additions and 37 deletions
+5 -2
View File
@@ -570,8 +570,11 @@ public interface PConstants {
static final int ENABLE_ACCURATE_2D = 7;
static final int DISABLE_ACCURATE_2D = -7;
static final int HINT_COUNT = 8;
static final int DISABLE_TEXTURE_CACHE = 8;
static final int ENABLE_TEXTURE_CACHE = -8;
static final int HINT_COUNT = 9;
// Rendering pipeline modes
@@ -456,6 +456,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected InGeometry in;
protected TessGeometry tess;
protected TexturingState texState;
protected float[] currentVertex = { 0, 0, 0 };
protected float[] currentColor = { 0, 0, 0, 0 };
@@ -476,9 +477,10 @@ public class PGraphicsOpenGL extends PGraphics {
public static final int DEFAULT_IN_VERTICES = 512;
public static final int DEFAULT_IN_EDGES = 1024;
public static final int DEFAULT_IN_TEXTURES = 64;
public static final int DEFAULT_TESS_VERTICES = 64;
public static final int DEFAULT_TESS_INDICES = 1024;
protected Tessellator tessellator;
static protected PShader lineShader;
@@ -520,6 +522,7 @@ public class PGraphicsOpenGL extends PGraphics {
in = newInGeometry();
tess = newTessGeometry(IMMEDIATE);
texState = newTexturingState();
glFillVertexBufferID = 0;
glFillColorBufferID = 0;
@@ -1460,8 +1463,11 @@ public class PGraphicsOpenGL extends PGraphics {
ogl.disableLights();
}
// TODO: rename in/tess to inGeo/tessGeo.
// And inGeo/tessGeo in Tessellator class to in/tess.
in.reset();
tess.reset();
texState.reset();
// Each frame starts with textures disabled.
super.noTexture();
@@ -2006,6 +2012,8 @@ public class PGraphicsOpenGL extends PGraphics {
public void endShape(int mode) {
/*
// Disabled for now. This should be controlled by an additional hint...
if (textureImage0 != null && textureImage == null && flushMode == FLUSH_WHEN_FULL) {
// The previous shape had a texture and this one doesn't. So we need to flush
// the textured geometry.
@@ -2013,6 +2021,7 @@ public class PGraphicsOpenGL extends PGraphics {
flush();
textureImage = null;
}
*/
tessellate(mode);
@@ -2028,25 +2037,29 @@ public class PGraphicsOpenGL extends PGraphics {
public void texture(PImage image) {
/*
if (image != textureImage0 && flushMode == FLUSH_WHEN_FULL) {
// Changing the texture image, so we need to flush the
// tessellated geometry accumulated until now, so that
// textures are not mixed.
textureImage = textureImage0;
flush();
}
}
*/
super.texture(image);
}
public void noTexture() {
/*
if (null != textureImage0 && flushMode == FLUSH_WHEN_FULL) {
// Changing the texture image, so we need to flush the
// tessellated geometry accumulated until now, so that
// textures are not mixed.
textureImage = textureImage0;
flush();
}
}
*/
super.noTexture();
}
@@ -2228,6 +2241,8 @@ public class PGraphicsOpenGL extends PGraphics {
} else {
tessellator.set3D();
}
int first = tess.fillIndexCount;
if (shape == POINTS) {
tessellator.tessellatePoints();
@@ -2251,7 +2266,16 @@ public class PGraphicsOpenGL extends PGraphics {
} else if (shape == POLYGON) {
if (stroke && defaultEdges) in.addPolygonEdges(mode == CLOSE);
tessellator.tessellatePolygon(false, mode == CLOSE);
}
}
int last = tess.lastFillIndex;
if (textureImage0 != textureImage || texState.count == 0) {
texState.addTexture(textureImage, first, last);
//PApplet.println("Adding texture image " + textureImage + " " + first + " - " + last);
} else {
texState.setLastIndex(last);
//PApplet.println("updating last " + texState.firstVertex[texState.count] + " - " + last);
}
}
public void flush() {
@@ -2296,7 +2320,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
tess.reset();
tess.reset();
texState.reset();
}
@@ -2436,48 +2461,82 @@ public class PGraphicsOpenGL extends PGraphics {
fillVBOsCreated = true;
}
int size = tess.fillVertexCount;
gl2f.glEnableClientState(GL2.GL_NORMAL_ARRAY);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillNormalBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 3 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillNormals, 0, 3 * size), vboMode);
gl2f.glNormalPointer(GL.GL_FLOAT, 0, 0);
gl2f.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl2f.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl2f.glEnableClientState(GL2.GL_NORMAL_ARRAY);
int size = tess.fillVertexCount;
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillVertexBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 3 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillVertices, 0, 3 * size), vboMode);
gl2f.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillColorBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 4 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillColors, 0, 4 * size), vboMode);
gl2f.glColorPointer(4, GL.GL_FLOAT, 0, 0);
gl2f.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillVertexBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 3 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillVertices, 0, 3 * size), vboMode);
gl2f.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillNormalBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 3 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillNormals, 0, 3 * size), vboMode);
gl2f.glNormalPointer(GL.GL_FLOAT, 0, 0);
PTexture tex = null;
if (textureImage != null) {
tex = ogl.getTexture(textureImage);
if (tex != null) {
gl2f.glEnable(tex.glTarget);
gl2f.glActiveTexture(GL.GL_TEXTURE0);
gl2f.glBindTexture(tex.glTarget, tex.glID);
}
if (texState.hasTexture) {
gl2f.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, glFillTexCoordBufferID);
gl2f.glBufferData(GL.GL_ARRAY_BUFFER, 2 * size * PGraphicsOpenGL.SIZEOF_FLOAT, FloatBuffer.wrap(tess.fillTexcoords, 0, 2 * size), vboMode);
gl2f.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);
}
}
//size = tess.fillIndexCount;
gl2f.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID);
//PApplet.println("Rendering " + texState.count + " tex groups");
for (int i = 0; i < texState.count; i++) {
PImage img = texState.textures[i];
PTexture tex;
if (img != null) {
tex = ogl.getTexture(img);
if (tex != null) {
gl2f.glEnable(tex.glTarget);
gl2f.glActiveTexture(GL.GL_TEXTURE0);
gl2f.glBindTexture(tex.glTarget, tex.glID);
}
// TODO: disable last texture target if current texture is null.
}
int offset = texState.firstIndex[i];
size = texState.lastIndex[i] - texState.firstIndex[i] + 1;
//PApplet.println("rendering " + i + ": " + offset + " " + size);
gl2f.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, size * PGraphicsOpenGL.SIZEOF_INT, IntBuffer.wrap(tess.fillIndices, offset, size), vboMode);
gl2f.glDrawElements(GL.GL_TRIANGLES, size, GL.GL_UNSIGNED_INT, 0);
}
size = tess.fillIndexCount;
gl2f.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID);
gl2f.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, size * PGraphicsOpenGL.SIZEOF_INT, IntBuffer.wrap(tess.fillIndices, 0, size), vboMode);
gl2f.glDrawElements(GL.GL_TRIANGLES, size, GL.GL_UNSIGNED_INT, 0);
if (tex != null) {
gl2f.glActiveTexture(GL.GL_TEXTURE0);
gl2f.glBindTexture(tex.glTarget, 0);
gl2f.glDisable(tex.glTarget);
if (texState.hasTexture) {
PTexture tex0 = null;
for (int i = 0; i < texState.count; i++) {
PImage img = texState.textures[i];
if (img != null) {
PTexture tex = ogl.getTexture(img);
if (tex0 != tex) {
gl2f.glDisable(tex.glTarget);
tex0 = tex;
}
}
}
if (tex0 != null) {
gl2f.glActiveTexture(GL.GL_TEXTURE0);
gl2f.glBindTexture(tex0.glTarget, 0);
}
gl2f.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
}
}
// } else {
// size = tess.fillIndexCount;
// gl2f.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID);
// gl2f.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, size * PGraphicsOpenGL.SIZEOF_INT, IntBuffer.wrap(tess.fillIndices, 0, size), vboMode);
// gl2f.glDrawElements(GL.GL_TRIANGLES, size, GL.GL_UNSIGNED_INT, 0);
//
// }
gl2f.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
gl2f.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
@@ -6798,6 +6857,87 @@ public class PGraphicsOpenGL extends PGraphics {
return new TessGeometry(mode);
}
protected TexturingState newTexturingState() {
return new TexturingState();
}
public class TexturingState {
int count;
PImage[] textures;
int[] firstIndex;
int[] lastIndex;
boolean hasTexture;
public TexturingState() {
allocate();
}
public void allocate() {
textures = new PImage[DEFAULT_IN_TEXTURES];
firstIndex = new int[DEFAULT_IN_TEXTURES];
lastIndex = new int[DEFAULT_IN_TEXTURES];
count = 0;
hasTexture = false;
}
public void reset() {
java.util.Arrays.fill(textures, 0, count, null);
count = 0;
hasTexture = false;
}
public void dispose() {
textures = null;
firstIndex = null;
lastIndex = null;
}
public void addTexture(PImage img, int first, int last) {
textureCheck();
textures[count] = img;
firstIndex[count] = first;
lastIndex[count] = last;
// At least one non-null texture since last reset.
hasTexture |= img != null;
count++;
}
public void setLastIndex(int last) {
lastIndex[count - 1] = last;
}
public void textureCheck() {
if (count == textures.length) {
int newSize = count << 1;
expandTextures(newSize);
expandFirstIndex(newSize);
expandLastIndex(newSize);
}
}
public void expandTextures(int n) {
PImage[] temp = new PImage[n];
PApplet.arrayCopy(textures, 0, temp, 0, count);
textures = temp;
}
public void expandFirstIndex(int n) {
int[] temp = new int[n];
PApplet.arrayCopy(firstIndex, 0, temp, 0, count);
firstIndex = temp;
}
public void expandLastIndex(int n) {
int[] temp = new int[n];
PApplet.arrayCopy(lastIndex, 0, temp, 0, count);
lastIndex = temp;
}
}
public class InGeometry {
public int vertexCount;
public int edgeCount;