diff --git a/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java b/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java index c4ac9b26f0..e6d9f86e6a 100644 --- a/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java +++ b/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java @@ -1,229 +1,239 @@ -/* - * Copyright (c) 2009-2021 jMonkeyEngine - * 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 'jMonkeyEngine' nor the names of its 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 OWNER 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 com.jme3.font; - -import com.jme3.material.Material; -import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.jme3.scene.VertexBuffer; -import com.jme3.scene.VertexBuffer.Type; -import com.jme3.texture.Texture2D; -import com.jme3.util.BufferUtils; -import com.jme3.util.clone.Cloner; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.ShortBuffer; -import java.util.LinkedList; - -/** - * One page per BitmapText Font Texture. - * @author Lim, YongHoon - */ -class BitmapTextPage extends Geometry { - - private final float[] pos; - private final float[] tc; - private final short[] idx; - private final byte[] color; - private final int page; - private final Texture2D texture; - private final LinkedList pageQuads = new LinkedList<>(); - - BitmapTextPage(BitmapFont font, boolean arrayBased, int page) { - super("BitmapFont", new Mesh()); - setRequiresUpdates(false); - setBatchHint(BatchHint.Never); - if (font == null) { - throw new IllegalArgumentException("font cannot be null."); - } - - this.page = page; - - Material mat = font.getPage(page); - if (mat == null) { - throw new IllegalStateException("The font's texture was not found!"); - } - - setMaterial(mat); - this.texture = (Texture2D) mat.getTextureParam("ColorMap").getTextureValue(); - - // initialize buffers - Mesh m = getMesh(); - m.setBuffer(Type.Position, 3, new float[0]); - m.setBuffer(Type.TexCoord, 2, new float[0]); - m.setBuffer(Type.Color, 4, new byte[0]); - m.setBuffer(Type.Index, 3, new short[0]); - - // scale colors from 0 - 255 range into 0 - 1 - m.getBuffer(Type.Color).setNormalized(true); - - arrayBased = true; - - /* - * TODO: Since this is forced to true, should we just lose the conditional? - * - Skye (sbook) - */ - if (arrayBased) { - pos = new float[4 * 3]; // 4 vertices * 3 floats - tc = new float[4 * 2]; // 4 vertices * 2 floats - idx = new short[2 * 3]; // 2 triangles * 3 indices - color = new byte[4 * 4]; // 4 vertices * 4 bytes - } else { - pos = null; - tc = null; - idx = null; - color = null; - } - } - - BitmapTextPage(BitmapFont font, boolean arrayBased) { - this(font, arrayBased, 0); - } - - BitmapTextPage(BitmapFont font) { - this(font, false, 0); - } - - Texture2D getTexture() { - return texture; - } - - @Override - public BitmapTextPage clone() { - BitmapTextPage clone = (BitmapTextPage) super.clone(); - //clone.mesh = mesh.deepClone(); - return clone; - } - - /** - * Called internally by com.jme3.util.clone.Cloner. Do not call directly. - */ - @Override - public void cloneFields(Cloner cloner, Object original) { - - Mesh originalMesh = this.mesh; - - super.cloneFields(cloner, original); - - // BitmapTextPage always requires a new mesh or different - // BitmapText instances will clobber one another. - // But if we were already deep cloning meshes then we don't - // want to do it again... so we'll check first. - if (this.mesh == originalMesh) { - this.mesh = mesh.deepClone(); - } - } - - // Here is where one might add JmeCloneable related stuff except - // the old clone() method doesn't actually bother to clone anything. - // The arrays and the pageQuads are shared across all BitmapTextPage - // clones, and it doesn't seem to bother anything. That means the - // fields could probably just as well be static... but this code is - // all very fragile. I'm not tipping that particular boat today. -pspeed - - void assemble(Letters quads) { - pageQuads.clear(); - quads.rewind(); - - while (quads.nextCharacter()) { - if (quads.isPrintable()) { - if (quads.getCharacterSetPage() == page) { - pageQuads.add(quads.getQuad()); - } - } - } - - Mesh m = getMesh(); - int vertCount = pageQuads.size() * 4; - int triCount = pageQuads.size() * 2; - - VertexBuffer pb = m.getBuffer(Type.Position); - VertexBuffer tb = m.getBuffer(Type.TexCoord); - VertexBuffer ib = m.getBuffer(Type.Index); - VertexBuffer cb = m.getBuffer(Type.Color); - - FloatBuffer fpb = (FloatBuffer) pb.getData(); - FloatBuffer ftb = (FloatBuffer) tb.getData(); - ShortBuffer sib = (ShortBuffer) ib.getData(); - ByteBuffer bcb = (ByteBuffer) cb.getData(); - - // increase capacity of buffers as needed - fpb.rewind(); - fpb = BufferUtils.ensureLargeEnough(fpb, vertCount * 3); - fpb.limit(vertCount * 3); - pb.updateData(fpb); - - ftb.rewind(); - ftb = BufferUtils.ensureLargeEnough(ftb, vertCount * 2); - ftb.limit(vertCount * 2); - tb.updateData(ftb); - - bcb.rewind(); - bcb = BufferUtils.ensureLargeEnough(bcb, vertCount * 4); - bcb.limit(vertCount * 4); - cb.updateData(bcb); - - sib.rewind(); - sib = BufferUtils.ensureLargeEnough(sib, triCount * 3); - sib.limit(triCount * 3); - ib.updateData(sib); - - m.updateCounts(); - - // go for each quad and append it to the buffers - if (pos != null) { - for (int i = 0; i < pageQuads.size(); i++) { - LetterQuad fq = pageQuads.get(i); - fq.storeToArrays(pos, tc, idx, color, i); - fpb.put(pos); - ftb.put(tc); - sib.put(idx); - bcb.put(color); - } - } else { - for (int i = 0; i < pageQuads.size(); i++) { - LetterQuad fq = pageQuads.get(i); - fq.appendPositions(fpb); - fq.appendTexCoords(ftb); - fq.appendIndices(sib, i); - fq.appendColors(bcb); - } - } - - fpb.rewind(); - ftb.rewind(); - sib.rewind(); - bcb.rewind(); - - updateModelBound(); - } -} +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * 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 'jMonkeyEngine' nor the names of its 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 OWNER 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 com.jme3.font; + +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.texture.Texture2D; +import com.jme3.util.BufferUtils; +import com.jme3.util.clone.Cloner; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +import java.util.LinkedList; + +/** + * One page per BitmapText Font Texture. + * @author Lim, YongHoon + */ +class BitmapTextPage extends Geometry { + + private final float[] pos; + private final float[] tc; + private final short[] idx; + private final byte[] color; + private final int page; + private final Texture2D texture; + private final LinkedList pageQuads = new LinkedList<>(); + + /** + * Creates the page at the given index for the specified font. + * + * @param font the font to use (not null) + * @param page the index of the font page to display + */ + BitmapTextPage(BitmapFont font, int page) { + super("BitmapFont", new Mesh()); + setRequiresUpdates(false); + setBatchHint(BatchHint.Never); + if (font == null) { + throw new IllegalArgumentException("font cannot be null."); + } + + this.page = page; + + Material mat = font.getPage(page); + if (mat == null) { + throw new IllegalStateException("The font's texture was not found!"); + } + + setMaterial(mat); + this.texture = (Texture2D) mat.getTextureParam("ColorMap").getTextureValue(); + + // initialize buffers + Mesh m = getMesh(); + m.setBuffer(Type.Position, 3, new float[0]); + m.setBuffer(Type.TexCoord, 2, new float[0]); + m.setBuffer(Type.Color, 4, new byte[0]); + m.setBuffer(Type.Index, 3, new short[0]); + + // scale colors from 0 - 255 range into 0 - 1 + m.getBuffer(Type.Color).setNormalized(true); + + // The buffers are always array-based: one quad is stored in these + // arrays and reused for every quad of this page. + pos = new float[4 * 3]; // 4 vertices * 3 floats + tc = new float[4 * 2]; // 4 vertices * 2 floats + idx = new short[2 * 3]; // 2 triangles * 3 indices + color = new byte[4 * 4]; // 4 vertices * 4 bytes + } + + /** + * @deprecated The arrayBased parameter is ignored; array-based buffers are + * always used. Use {@link #BitmapTextPage(BitmapFont, int)} instead. + * + * @param font the font to use (not null) + * @param arrayBased ignored + * @param page the index of the font page to display + */ + @Deprecated + BitmapTextPage(BitmapFont font, boolean arrayBased, int page) { + this(font, page); + } + + /** + * @deprecated The arrayBased parameter is ignored; array-based buffers are + * always used. Use {@link #BitmapTextPage(BitmapFont, int)} instead. + * + * @param font the font to use (not null) + * @param arrayBased ignored + */ + @Deprecated + BitmapTextPage(BitmapFont font, boolean arrayBased) { + this(font, 0); + } + + BitmapTextPage(BitmapFont font) { + this(font, 0); + } + + Texture2D getTexture() { + return texture; + } + + @Override + public BitmapTextPage clone() { + BitmapTextPage clone = (BitmapTextPage) super.clone(); + //clone.mesh = mesh.deepClone(); + return clone; + } + + /** + * Called internally by com.jme3.util.clone.Cloner. Do not call directly. + */ + @Override + public void cloneFields(Cloner cloner, Object original) { + + Mesh originalMesh = this.mesh; + + super.cloneFields(cloner, original); + + // BitmapTextPage always requires a new mesh or different + // BitmapText instances will clobber one another. + // But if we were already deep cloning meshes then we don't + // want to do it again... so we'll check first. + if (this.mesh == originalMesh) { + this.mesh = mesh.deepClone(); + } + } + + // Here is where one might add JmeCloneable related stuff except + // the old clone() method doesn't actually bother to clone anything. + // The arrays and the pageQuads are shared across all BitmapTextPage + // clones, and it doesn't seem to bother anything. That means the + // fields could probably just as well be static... but this code is + // all very fragile. I'm not tipping that particular boat today. -pspeed + + void assemble(Letters quads) { + pageQuads.clear(); + quads.rewind(); + + while (quads.nextCharacter()) { + if (quads.isPrintable()) { + if (quads.getCharacterSetPage() == page) { + pageQuads.add(quads.getQuad()); + } + } + } + + Mesh m = getMesh(); + int vertCount = pageQuads.size() * 4; + int triCount = pageQuads.size() * 2; + + VertexBuffer pb = m.getBuffer(Type.Position); + VertexBuffer tb = m.getBuffer(Type.TexCoord); + VertexBuffer ib = m.getBuffer(Type.Index); + VertexBuffer cb = m.getBuffer(Type.Color); + + FloatBuffer fpb = (FloatBuffer) pb.getData(); + FloatBuffer ftb = (FloatBuffer) tb.getData(); + ShortBuffer sib = (ShortBuffer) ib.getData(); + ByteBuffer bcb = (ByteBuffer) cb.getData(); + + // increase capacity of buffers as needed + fpb.rewind(); + fpb = BufferUtils.ensureLargeEnough(fpb, vertCount * 3); + fpb.limit(vertCount * 3); + pb.updateData(fpb); + + ftb.rewind(); + ftb = BufferUtils.ensureLargeEnough(ftb, vertCount * 2); + ftb.limit(vertCount * 2); + tb.updateData(ftb); + + bcb.rewind(); + bcb = BufferUtils.ensureLargeEnough(bcb, vertCount * 4); + bcb.limit(vertCount * 4); + cb.updateData(bcb); + + sib.rewind(); + sib = BufferUtils.ensureLargeEnough(sib, triCount * 3); + sib.limit(triCount * 3); + ib.updateData(sib); + + m.updateCounts(); + + // go for each quad and append it to the buffers. + // pageQuads is a LinkedList, so iterate it with a for-each loop: + // indexed access (get(i)) walks the list from the head every time, + // which makes this loop quadratic in the number of quads. + int i = 0; + for (LetterQuad fq : pageQuads) { + fq.storeToArrays(pos, tc, idx, color, i); + fpb.put(pos); + ftb.put(tc); + sib.put(idx); + bcb.put(color); + i++; + } + + fpb.rewind(); + ftb.rewind(); + sib.rewind(); + bcb.rewind(); + + updateModelBound(); + } +}