use of processing.opengl.PGraphicsOpenGL.IndexCache in project processing by processing.
the class PShapeOpenGL method updatePolyIndexCache.
// Updates the index cache for the range that corresponds to this shape.
protected void updatePolyIndexCache() {
IndexCache cache = tessGeo.polyIndexCache;
if (family == GROUP) {
// Updates the index cache to include the elements corresponding to
// a group shape, using the cache entries of the child shapes. The
// index cache has a pyramidal structure where the base is formed
// by the entries corresponding to the leaf (geometry) shapes, and
// each subsequent level is determined by the higher-level group shapes
// The index pyramid is flattened into arrays in order to use simple
// data structures, so each shape needs to store the positions in the
// cache that corresponds to itself.
// The index ranges of the child shapes that share the vertex offset
// are unified into a single range in the parent level.
firstPolyIndexCache = lastPolyIndexCache = -1;
int gindex = -1;
for (int i = 0; i < childCount; i++) {
PShapeOpenGL child = (PShapeOpenGL) children[i];
int first = child.firstPolyIndexCache;
int count = -1 < first ? child.lastPolyIndexCache - first + 1 : -1;
for (int n = first; n < first + count; n++) {
if (gindex == -1) {
gindex = cache.addNew(n);
firstPolyIndexCache = gindex;
} else {
if (cache.vertexOffset[gindex] == cache.vertexOffset[n]) {
// When the vertex offsets are the same, this means that the
// current index range in the group shape can be extended to
// include the index range in the current child shape.
// This is a result of how the indices are updated for the
// leaf shapes.
cache.incCounts(gindex, cache.indexCount[n], cache.vertexCount[n]);
} else {
gindex = cache.addNew(n);
}
}
}
// Updating the first and last poly vertices for this group shape.
if (-1 < child.firstPolyVertex) {
if (firstPolyVertex == -1) {
firstPolyVertex = Integer.MAX_VALUE;
}
firstPolyVertex = PApplet.min(firstPolyVertex, child.firstPolyVertex);
}
if (-1 < child.lastPolyVertex) {
lastPolyVertex = PApplet.max(lastPolyVertex, child.lastPolyVertex);
}
}
lastPolyIndexCache = gindex;
} else {
// The index cache is updated in order to reflect the fact that all
// the vertices will be stored in a single VBO in the root shape.
// This update works as follows (the methodology is the same for
// poly, line and point): the VertexAbs variable in the root shape
// stores the index of the last vertex up to this shape (plus one)
// without taking into consideration the MAX_VERTEX_INDEX limit, so
// it effectively runs over the entire range.
// VertexRel, on the other hand, is reset every time the limit is
// exceeded, therefore creating the start of a new index group in the
// root shape. When this happens, the indices in the child shape need
// to be restarted as well to reflect the new index offset.
firstPolyVertex = lastPolyVertex = cache.vertexOffset[firstPolyIndexCache];
for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) {
int ioffset = cache.indexOffset[n];
int icount = cache.indexCount[n];
int vcount = cache.vertexCount[n];
if (// Too many vertices already signal the start of a new cache...
PGL.MAX_VERTEX_INDEX1 <= root.polyVertexRel + vcount || (is2D() && startStrokedTex(n))) {
// ... or, in 2D, the beginning of line or points.
root.polyVertexRel = 0;
root.polyVertexOffset = root.polyVertexAbs;
cache.indexOffset[n] = root.polyIndexOffset;
} else {
tessGeo.incPolyIndices(ioffset, ioffset + icount - 1, root.polyVertexRel);
}
cache.vertexOffset[n] = root.polyVertexOffset;
if (is2D()) {
setFirstStrokeVertex(n, lastPolyVertex);
}
root.polyIndexOffset += icount;
root.polyVertexAbs += vcount;
root.polyVertexRel += vcount;
lastPolyVertex += vcount;
}
lastPolyVertex--;
if (is2D()) {
setLastStrokeVertex(lastPolyVertex);
}
}
}
use of processing.opengl.PGraphicsOpenGL.IndexCache in project processing by processing.
the class PShapeOpenGL method renderPolys.
protected void renderPolys(PGraphicsOpenGL g, PImage textureImage) {
boolean customShader = g.polyShader != null;
boolean needNormals = customShader ? g.polyShader.accessNormals() : false;
boolean needTexCoords = customShader ? g.polyShader.accessTexCoords() : false;
Texture tex = textureImage != null ? g.getTexture(textureImage) : null;
boolean renderingFill = false, renderingStroke = false;
PShader shader = null;
IndexCache cache = tessGeo.polyIndexCache;
for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) {
if (is3D() || (tex != null && (firstLineIndexCache == -1 || n < firstLineIndexCache) && (firstPointIndexCache == -1 || n < firstPointIndexCache))) {
// Rendering fill triangles, which can be lit and textured.
if (!renderingFill) {
shader = g.getPolyShader(g.lights, tex != null);
shader.bind();
renderingFill = true;
}
} else {
// Rendering line or point triangles, which are never lit nor textured.
if (!renderingStroke) {
if (tex != null) {
tex.unbind();
tex = null;
}
if (shader != null && shader.bound()) {
shader.unbind();
}
// If the renderer is 2D, then g.lights should always be false,
// so no need to worry about that.
shader = g.getPolyShader(g.lights, false);
shader.bind();
renderingFill = false;
renderingStroke = true;
}
}
int ioffset = cache.indexOffset[n];
int icount = cache.indexCount[n];
int voffset = cache.vertexOffset[n];
shader.setVertexAttribute(root.bufPolyVertex.glId, 4, PGL.FLOAT, 0, 4 * voffset * PGL.SIZEOF_FLOAT);
shader.setColorAttribute(root.bufPolyColor.glId, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE);
if (g.lights) {
shader.setNormalAttribute(root.bufPolyNormal.glId, 3, PGL.FLOAT, 0, 3 * voffset * PGL.SIZEOF_FLOAT);
shader.setAmbientAttribute(root.bufPolyAmbient.glId, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE);
shader.setSpecularAttribute(root.bufPolySpecular.glId, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE);
shader.setEmissiveAttribute(root.bufPolyEmissive.glId, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE);
shader.setShininessAttribute(root.bufPolyShininess.glId, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT);
}
if (g.lights || needNormals) {
shader.setNormalAttribute(root.bufPolyNormal.glId, 3, PGL.FLOAT, 0, 3 * voffset * PGL.SIZEOF_FLOAT);
}
if (tex != null || needTexCoords) {
shader.setTexcoordAttribute(root.bufPolyTexcoord.glId, 2, PGL.FLOAT, 0, 2 * voffset * PGL.SIZEOF_FLOAT);
shader.setTexture(tex);
}
for (VertexAttribute attrib : polyAttribs.values()) {
if (!attrib.active(shader))
continue;
attrib.bind(pgl);
shader.setAttributeVBO(attrib.glLoc, attrib.buf.glId, attrib.tessSize, attrib.type, attrib.isColor(), 0, attrib.sizeInBytes(voffset));
}
shader.draw(root.bufPolyIndex.glId, icount, ioffset);
}
for (VertexAttribute attrib : polyAttribs.values()) {
if (attrib.active(shader))
attrib.unbind(pgl);
}
if (shader != null && shader.bound()) {
shader.unbind();
}
}
use of processing.opengl.PGraphicsOpenGL.IndexCache in project processing by processing.
the class PShapeOpenGL method updateLineIndexCache.
protected void updateLineIndexCache() {
IndexCache cache = tessGeo.lineIndexCache;
if (family == GROUP) {
firstLineIndexCache = lastLineIndexCache = -1;
int gindex = -1;
for (int i = 0; i < childCount; i++) {
PShapeOpenGL child = (PShapeOpenGL) children[i];
int first = child.firstLineIndexCache;
int count = -1 < first ? child.lastLineIndexCache - first + 1 : -1;
for (int n = first; n < first + count; n++) {
if (gindex == -1) {
gindex = cache.addNew(n);
firstLineIndexCache = gindex;
} else {
if (cache.vertexOffset[gindex] == cache.vertexOffset[n]) {
cache.incCounts(gindex, cache.indexCount[n], cache.vertexCount[n]);
} else {
gindex = cache.addNew(n);
}
}
}
// Updating the first and last line vertices for this group shape.
if (-1 < child.firstLineVertex) {
if (firstLineVertex == -1)
firstLineVertex = Integer.MAX_VALUE;
firstLineVertex = PApplet.min(firstLineVertex, child.firstLineVertex);
}
if (-1 < child.lastLineVertex) {
lastLineVertex = PApplet.max(lastLineVertex, child.lastLineVertex);
}
}
lastLineIndexCache = gindex;
} else {
firstLineVertex = lastLineVertex = cache.vertexOffset[firstLineIndexCache];
for (int n = firstLineIndexCache; n <= lastLineIndexCache; n++) {
int ioffset = cache.indexOffset[n];
int icount = cache.indexCount[n];
int vcount = cache.vertexCount[n];
if (PGL.MAX_VERTEX_INDEX1 <= root.lineVertexRel + vcount) {
root.lineVertexRel = 0;
root.lineVertexOffset = root.lineVertexAbs;
cache.indexOffset[n] = root.lineIndexOffset;
} else {
tessGeo.incLineIndices(ioffset, ioffset + icount - 1, root.lineVertexRel);
}
cache.vertexOffset[n] = root.lineVertexOffset;
root.lineIndexOffset += icount;
root.lineVertexAbs += vcount;
root.lineVertexRel += vcount;
lastLineVertex += vcount;
}
lastLineVertex--;
}
}
use of processing.opengl.PGraphicsOpenGL.IndexCache in project processing by processing.
the class PShapeOpenGL method getTessellation.
///////////////////////////////////////////////////////////
//
// Tessellated geometry getter.
@Override
public PShape getTessellation() {
updateTessellation();
float[] vertices = tessGeo.polyVertices;
float[] normals = tessGeo.polyNormals;
int[] color = tessGeo.polyColors;
float[] uv = tessGeo.polyTexCoords;
short[] indices = tessGeo.polyIndices;
PShape tess;
// if (is3D()) {
// //tess = PGraphics3D.createShapeImpl(pg, PShape.GEOMETRY);
// tess = pg.createShapeFamily(PShape.GEOMETRY);
// } else if (is2D()) {
// //tess = PGraphics2D.createShapeImpl(pg, PShape.GEOMETRY);
// tess = pg.createShapeFamily(PShape.GEOMETRY);
// } else {
// PGraphics.showWarning("This shape is not either 2D or 3D!");
// return null;
// }
tess = pg.createShapeFamily(PShape.GEOMETRY);
// if this is a 3D shape, make the new shape 3D as well
tess.set3D(is3D);
tess.beginShape(TRIANGLES);
tess.noStroke();
IndexCache cache = tessGeo.polyIndexCache;
for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) {
int ioffset = cache.indexOffset[n];
int icount = cache.indexCount[n];
int voffset = cache.vertexOffset[n];
for (int tr = ioffset / 3; tr < (ioffset + icount) / 3; tr++) {
int i0 = voffset + indices[3 * tr + 0];
int i1 = voffset + indices[3 * tr + 1];
int i2 = voffset + indices[3 * tr + 2];
if (is3D()) {
float x0 = vertices[4 * i0 + 0];
float y0 = vertices[4 * i0 + 1];
float z0 = vertices[4 * i0 + 2];
float x1 = vertices[4 * i1 + 0];
float y1 = vertices[4 * i1 + 1];
float z1 = vertices[4 * i1 + 2];
float x2 = vertices[4 * i2 + 0];
float y2 = vertices[4 * i2 + 1];
float z2 = vertices[4 * i2 + 2];
float nx0 = normals[3 * i0 + 0];
float ny0 = normals[3 * i0 + 1];
float nz0 = normals[3 * i0 + 2];
float nx1 = normals[3 * i1 + 0];
float ny1 = normals[3 * i1 + 1];
float nz1 = normals[3 * i1 + 2];
float nx2 = normals[3 * i2 + 0];
float ny2 = normals[3 * i2 + 1];
float nz2 = normals[3 * i2 + 2];
int argb0 = PGL.nativeToJavaARGB(color[i0]);
int argb1 = PGL.nativeToJavaARGB(color[i1]);
int argb2 = PGL.nativeToJavaARGB(color[i2]);
tess.fill(argb0);
tess.normal(nx0, ny0, nz0);
tess.vertex(x0, y0, z0, uv[2 * i0 + 0], uv[2 * i0 + 1]);
tess.fill(argb1);
tess.normal(nx1, ny1, nz1);
tess.vertex(x1, y1, z1, uv[2 * i1 + 0], uv[2 * i1 + 1]);
tess.fill(argb2);
tess.normal(nx2, ny2, nz2);
tess.vertex(x2, y2, z2, uv[2 * i2 + 0], uv[2 * i2 + 1]);
} else if (is2D()) {
float x0 = vertices[4 * i0 + 0], y0 = vertices[4 * i0 + 1];
float x1 = vertices[4 * i1 + 0], y1 = vertices[4 * i1 + 1];
float x2 = vertices[4 * i2 + 0], y2 = vertices[4 * i2 + 1];
int argb0 = PGL.nativeToJavaARGB(color[i0]);
int argb1 = PGL.nativeToJavaARGB(color[i1]);
int argb2 = PGL.nativeToJavaARGB(color[i2]);
tess.fill(argb0);
tess.vertex(x0, y0, uv[2 * i0 + 0], uv[2 * i0 + 1]);
tess.fill(argb1);
tess.vertex(x1, y1, uv[2 * i1 + 0], uv[2 * i1 + 1]);
tess.fill(argb2);
tess.vertex(x2, y2, uv[2 * i2 + 0], uv[2 * i2 + 1]);
}
}
}
tess.endShape();
return tess;
}
use of processing.opengl.PGraphicsOpenGL.IndexCache in project processing by processing.
the class PShapeOpenGL method renderLines.
protected void renderLines(PGraphicsOpenGL g) {
PShader shader = g.getLineShader();
shader.bind();
IndexCache cache = tessGeo.lineIndexCache;
for (int n = firstLineIndexCache; n <= lastLineIndexCache; n++) {
int ioffset = cache.indexOffset[n];
int icount = cache.indexCount[n];
int voffset = cache.vertexOffset[n];
shader.setVertexAttribute(root.bufLineVertex.glId, 4, PGL.FLOAT, 0, 4 * voffset * PGL.SIZEOF_FLOAT);
shader.setColorAttribute(root.bufLineColor.glId, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE);
shader.setLineAttribute(root.bufLineAttrib.glId, 4, PGL.FLOAT, 0, 4 * voffset * PGL.SIZEOF_FLOAT);
shader.draw(root.bufLineIndex.glId, icount, ioffset);
}
shader.unbind();
}
Aggregations