From f78e17413b6888726a2cef3d36e2865299c01c1b Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 5 Dec 2011 05:33:40 +0000 Subject: [PATCH] Integrating text rendering with the new immediate mode --- .../src/processing/opengl/PFontTexture.java | 26 ++ .../processing/opengl/PGraphicsOpenGL.java | 119 +++--- .../src/processing/opengl/PShape3D.java | 351 +++++++++++++++++- 3 files changed, 416 insertions(+), 80 deletions(-) diff --git a/java/libraries/opengl/src/processing/opengl/PFontTexture.java b/java/libraries/opengl/src/processing/opengl/PFontTexture.java index eb2158e15..755f9da1b 100644 --- a/java/libraries/opengl/src/processing/opengl/PFontTexture.java +++ b/java/libraries/opengl/src/processing/opengl/PFontTexture.java @@ -27,6 +27,7 @@ import java.util.HashMap; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PFont; +import processing.core.PImage; /** * All the infrastructure needed for optimized font rendering @@ -56,6 +57,7 @@ class PFontTexture implements PConstants { protected int offsetY; protected int lineHeight; protected PTexture[] textures = null; + protected PImage[] images = null; protected int currentTex; protected int lastTex; protected TextureInfo[] glyphTexinfos; @@ -143,6 +145,10 @@ class PFontTexture implements PConstants { if (textures == null) { textures = new PTexture[1]; textures[0] = tex; + images = new PImage[1]; + images[0] = new PImage(tex.width, tex.height, ARGB); + images[0].setCache(ogl, tex); + currentTex = 0; } else if (resize) { // Replacing old smaller texture with larger one. @@ -151,6 +157,10 @@ class PFontTexture implements PConstants { PTexture tex0 = textures[currentTex]; tex.put(tex0); textures[currentTex] = tex; + + images[currentTex].setCache(ogl, tex); + images[currentTex].width = tex.width; + images[currentTex].height = tex.height; } else { // Adding new texture to the list. PTexture[] temp = textures; @@ -158,6 +168,13 @@ class PFontTexture implements PConstants { PApplet.arrayCopy(temp, textures, temp.length); textures[temp.length] = tex; currentTex = textures.length - 1; + + PImage[] temp2 = images; + images = new PImage[textures.length + 1]; + PApplet.arrayCopy(temp2, images, temp2.length); + + images[temp.length] = new PImage(tex.width, tex.height, ARGB); + images[temp.length].setCache(ogl, tex); } lastTex = currentTex; @@ -181,6 +198,15 @@ class PFontTexture implements PConstants { } + public PImage getTexture(int idx) { + if (0 <= idx && idx < images.length) { + currentTex = idx; + return images[currentTex]; + } + return null; + + } + // Add all the current glyphs to opengl texture. public void addAllGlyphsToTexture() { // loop over current glyphs. diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index c669d948a..a4be49686 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -2786,13 +2786,14 @@ public class PGraphicsOpenGL extends PGraphics { */ protected void textLineImpl(char buffer[], int start, int stop, float x, float y) { // Init opengl state for text rendering... - gl.glEnable(GL.GL_TEXTURE_2D); +// gl.glEnable(GL.GL_TEXTURE_2D); +// +// if (screenBlendMode != BLEND) { +// gl.glEnable(GL.GL_BLEND); +// if (blendEqSupported) gl.glBlendEquation(GL.GL_FUNC_ADD); +// gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); +// } - if (screenBlendMode != BLEND) { - gl.glEnable(GL.GL_BLEND); - if (blendEqSupported) gl.glBlendEquation(GL.GL_FUNC_ADD); - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - } textTex = (PFontTexture)textFont.getCache(ogl); if (textTex == null) { @@ -2801,43 +2802,43 @@ public class PGraphicsOpenGL extends PGraphics { } textTex.setFirstTexture(); - // Setting the current fill color as the font color. - setFillColor(); - - if (textMode == MODEL) { - if (textVertexBuffer == null) { - allocateTextModel(); - } - - // Setting Z axis as the normal to the text geometry - setDefNormals(0, 0, 1); - - if (!textBlockMode) { - // Resetting vertex count when we are not defining a - // block of text. - textVertexCount = 0; - } - } +// // Setting the current fill color as the font color. +// setFillColor(); +// +// if (textMode == MODEL) { +// if (textVertexBuffer == null) { +// allocateTextModel(); +// } +// +// // Setting Z axis as the normal to the text geometry +// setDefNormals(0, 0, 1); +// +// if (!textBlockMode) { +// // Resetting vertex count when we are not defining a +// // block of text. +// textVertexCount = 0; +// } +// } super.textLineImpl(buffer, start, stop, x, y); - if (textMode == MODEL && 0 < textVertexCount) { - if (!textBlockMode) { - // Pushing text geometry to the GPU. - renderTextModel(); - } else { - // We don't push any geometry here because we will - // do it when endText is called. For now we just - // save the current texture. - textBlockTex = textTex.currentTex; - } - } - - // Restoring current blend mode. - blendMode(screenBlendMode); - - gl.glBindTexture(GL.GL_TEXTURE_2D, 0); - gl.glDisable(GL.GL_TEXTURE_2D); +// if (textMode == MODEL && 0 < textVertexCount) { +// if (!textBlockMode) { +// // Pushing text geometry to the GPU. +// renderTextModel(); +// } else { +// // We don't push any geometry here because we will +// // do it when endText is called. For now we just +// // save the current texture. +// textBlockTex = textTex.currentTex; +// } +// } +// +// // Restoring current blend mode. +// blendMode(screenBlendMode); +// +// gl.glBindTexture(GL.GL_TEXTURE_2D, 0); +// gl.glDisable(GL.GL_TEXTURE_2D); } protected void textCharImpl(char ch, float x, float y) { @@ -2867,25 +2868,24 @@ public class PGraphicsOpenGL extends PGraphics { } } - protected void textCharModelImpl(PFontTexture.TextureInfo info, float x1, float y1, - float x2, float y2) { - if ((textTex.currentTex != info.texIndex) || - (textBlockMode && textBlockTex != info.texIndex)) { - if (0 < textVertexCount) { - // Current texture changes (the font is so large that needs more than one texture). - // So rendering all we got until now, and reseting vertex counter. - renderTextModel(); - textVertexCount = 0; - } - textTex.setTexture(info.texIndex); - } - - // Division by three needed because each int element in the buffer is used - // to store three coordinates. - if (textVertexBuffer.capacity() / 3 < textVertexCount + 6) { - expandTextBuffers(); - } + protected void textCharModelImpl(PFontTexture.TextureInfo info, float x0, float y0, + float x1, float y1) { + PImage tex = textTex.getTexture(info.texIndex); + int mode0 = textureMode; + noStroke(); + textureMode(NORMAL); + beginShape(QUADS); + texture(tex); + normal(0, 0, 1); + vertex(x0, y0, info.u0, info.v0); + vertex(x1, y0, info.u1, info.v0); + vertex(x1, y1, info.u1, info.v1); + vertex(x0, y1, info.u0, info.v1); + endShape(); + textureMode(mode0); + +/* int n = textVertexCount; textVertexArray[3 * n + 0] = x1; textVertexArray[3 * n + 1] = y1; @@ -2928,8 +2928,7 @@ public class PGraphicsOpenGL extends PGraphics { textTexCoordArray[2 * n + 0] = info.u1; textTexCoordArray[2 * n + 1] = info.v1; n++; - - textVertexCount = n; +*/ } protected void textCharScreenImpl(PFontTexture.TextureInfo info, int xx, int yy, diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index ab229d2f9..7bc73f091 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -32,6 +32,7 @@ import processing.core.PGraphics; import processing.core.PImage; import processing.core.PMatrix3D; import processing.core.PShape; +import processing.core.PStyle; import processing.opengl.PGraphicsOpenGL.InGeometry; import processing.opengl.PGraphicsOpenGL.TessGeometry; import processing.opengl.PGraphicsOpenGL.Tessellator; @@ -41,6 +42,9 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.HashSet; +// TODO: check shape in 2D mode (and handling in renderFill), and group shape mixing 2D and 2D child shapes. + + /** * This class holds a 3D model composed of vertices, normals, colors (per vertex) and * texture coordinates (also per vertex). All this data is stored in Vertex Buffer Objects @@ -156,6 +160,22 @@ public class PShape3D extends PShape { protected float curveVertices[][]; protected int curveVertexCount; + // ........................................................ + + // Fill color + + /** true if fill() is enabled, (read-only) */ + public boolean fill; + + /** fill that was last set (read-only) */ + public int fillColor = 0xffFFFFFF; + + protected boolean fillAlpha; + protected float fillR, fillG, fillB, fillA; + protected int fillRi, fillGi, fillBi, fillAi; + + + public PShape3D(PApplet parent, int family) { ogl = (PGraphicsOpenGL)parent.g; @@ -305,28 +325,9 @@ public class PShape3D extends PShape { currentNormal[2] = nz; } - public void noFill() { - fill(0, 0, 0, 0); - } - - public void fill(float r, float g, float b, float a) { - currentColor[0] = r; - currentColor[1] = g; - currentColor[2] = b; - currentColor[3] = a; - } + - public void stroke(float r, float g, float b, float a) { - currentStroke[0] = r; - currentStroke[1] = g; - currentStroke[2] = b; - currentStroke[3] = a; - } - - public void noStroke() { - stroke(0, 0, 0, 0); - } public void strokeWeight(float w) { currentStroke[4] = w; @@ -344,6 +345,316 @@ public class PShape3D extends PShape { // ? } + + ////////////////////////////////////////////////////////////// + + // FILL COLOR + +/* + public void noFill() { + fill = false; + } + + public void fill(int rgb) { + colorCalc(rgb); + fillFromCalc(); + } + + public void fill(int rgb, float alpha) { + colorCalc(rgb, alpha); + fillFromCalc(); + } + + public void fill(float gray) { + colorCalc(gray); + fillFromCalc(); + } + + public void fill(float gray, float alpha) { + colorCalc(gray, alpha); + fillFromCalc(); + } + + public void fill(float x, float y, float z) { + colorCalc(x, y, z); + fillFromCalc(); + } + + public void fill(float x, float y, float z, float a) { + colorCalc(x, y, z, a); + fillFromCalc(); + } + + protected void fillFromCalc() { + fill = true; + fillR = calcR; + fillG = calcG; + fillB = calcB; + fillA = calcA; + fillRi = calcRi; + fillGi = calcGi; + fillBi = calcBi; + fillAi = calcAi; + fillColor = calcColor; + fillAlpha = calcAlpha; + } + */ + + public void noFill() { + fill(0, 0, 0, 0); + } + + public void fill(float r, float g, float b, float a) { + currentColor[0] = r; + currentColor[1] = g; + currentColor[2] = b; + currentColor[3] = a; + } + + + ////////////////////////////////////////////////////////////// + + // STROKE CAP/JOIN/WEIGHT + +/* + public void strokeWeight(float weight) { + strokeWeight = weight; + } + + public void strokeJoin(int join) { + strokeJoin = join; + } + + + public void strokeCap(int cap) { + strokeCap = cap; + } + + */ + + ////////////////////////////////////////////////////////////// + + // STROKE COLOR + + + public void stroke(float r, float g, float b, float a) { + currentStroke[0] = r; + currentStroke[1] = g; + currentStroke[2] = b; + currentStroke[3] = a; + } + + public void noStroke() { + stroke(0, 0, 0, 0); + } + +/* + public void noStroke() { + stroke = false; + } + + public void stroke(int rgb) { + colorCalc(rgb); + strokeFromCalc(); + } + + public void stroke(int rgb, float alpha) { + colorCalc(rgb, alpha); + strokeFromCalc(); + } + + public void stroke(float gray) { + colorCalc(gray); + strokeFromCalc(); + } + + public void stroke(float gray, float alpha) { + colorCalc(gray, alpha); + strokeFromCalc(); + } + + public void stroke(float x, float y, float z) { + colorCalc(x, y, z); + strokeFromCalc(); + } + + public void stroke(float x, float y, float z, float alpha) { + colorCalc(x, y, z, alpha); + strokeFromCalc(); + } + + protected void strokeFromCalc() { + stroke = true; + strokeR = calcR; + strokeG = calcG; + strokeB = calcB; + strokeA = calcA; + strokeRi = calcRi; + strokeGi = calcGi; + strokeBi = calcBi; + strokeAi = calcAi; + strokeColor = calcColor; + strokeAlpha = calcAlpha; + } + +*/ + + /* + public void imageMode(int mode) { + if ((mode == CORNER) || (mode == CORNERS) || (mode == CENTER)) { + imageMode = mode; + } else { + String msg = + "imageMode() only works with CORNER, CORNERS, or CENTER"; + throw new RuntimeException(msg); + } + } + */ + + + ////////////////////////////////////////////////////////////// + + // STYLE + +/* + public void pushStyle() { + if (styleStackDepth == styleStack.length) { + styleStack = (PStyle[]) PApplet.expand(styleStack); + } + if (styleStack[styleStackDepth] == null) { + styleStack[styleStackDepth] = new PStyle(); + } + PStyle s = styleStack[styleStackDepth++]; + getStyle(s); + } + + + public void popStyle() { + if (styleStackDepth == 0) { + throw new RuntimeException("Too many popStyle() without enough pushStyle()"); + } + styleStackDepth--; + style(styleStack[styleStackDepth]); + } + + + public void style(PStyle s) { + // if (s.smooth) { + // smooth(); + // } else { + // noSmooth(); + // } + + imageMode(s.imageMode); + rectMode(s.rectMode); + ellipseMode(s.ellipseMode); + shapeMode(s.shapeMode); + + if (s.tint) { + tint(s.tintColor); + } else { + noTint(); + } + if (s.fill) { + fill(s.fillColor); + } else { + noFill(); + } + if (s.stroke) { + stroke(s.strokeColor); + } else { + noStroke(); + } + strokeWeight(s.strokeWeight); + strokeCap(s.strokeCap); + strokeJoin(s.strokeJoin); + + // Set the colorMode() for the material properties. + // TODO this is really inefficient, need to just have a material() method, + // but this has the least impact to the API. + colorMode(RGB, 1); + ambient(s.ambientR, s.ambientG, s.ambientB); + emissive(s.emissiveR, s.emissiveG, s.emissiveB); + specular(s.specularR, s.specularG, s.specularB); + shininess(s.shininess); + + // material(s.ambientR, s.ambientG, s.ambientB, + // s.emissiveR, s.emissiveG, s.emissiveB, + // s.specularR, s.specularG, s.specularB, + // s.shininess); + + // Set this after the material properties. + colorMode(s.colorMode, + s.colorModeX, s.colorModeY, s.colorModeZ, s.colorModeA); + + // This is a bit asymmetric, since there's no way to do "noFont()", + // and a null textFont will produce an error (since usually that means that + // the font couldn't load properly). So in some cases, the font won't be + // 'cleared' to null, even though that's technically correct. + if (s.textFont != null) { + textFont(s.textFont, s.textSize); + textLeading(s.textLeading); + } + // These don't require a font to be set. + textAlign(s.textAlign, s.textAlignY); + textMode(s.textMode); + } + + + public PStyle getStyle() { // ignore + return getStyle(null); + } + + + public PStyle getStyle(PStyle s) { // ignore + if (s == null) { + s = new PStyle(); + } + + s.imageMode = imageMode; + s.rectMode = rectMode; + s.ellipseMode = ellipseMode; + s.shapeMode = shapeMode; + + s.colorMode = colorMode; + s.colorModeX = colorModeX; + s.colorModeY = colorModeY; + s.colorModeZ = colorModeZ; + s.colorModeA = colorModeA; + + s.tint = tint; + s.tintColor = tintColor; + s.fill = fill; + s.fillColor = fillColor; + s.stroke = stroke; + s.strokeColor = strokeColor; + s.strokeWeight = strokeWeight; + s.strokeCap = strokeCap; + s.strokeJoin = strokeJoin; + + s.ambientR = ambientR; + s.ambientG = ambientG; + s.ambientB = ambientB; + s.specularR = specularR; + s.specularG = specularG; + s.specularB = specularB; + s.emissiveR = emissiveR; + s.emissiveG = emissiveG; + s.emissiveB = emissiveB; + s.shininess = shininess; + + s.textFont = textFont; + s.textAlign = textAlign; + s.textAlignY = textAlignY; + s.textMode = textMode; + s.textSize = textSize; + s.textLeading = textLeading; + + return s; + } +*/ + + /////////////////////////////////////////////////////////// //