mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Integrating text rendering with the new immediate mode
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user