1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32package com.jme3.font;
33
34import com.jme3.material.Material;
35import com.jme3.scene.Geometry;
36import com.jme3.scene.Mesh;
37import com.jme3.scene.VertexBuffer;
38import com.jme3.scene.VertexBuffer.Type;
39import com.jme3.texture.Texture2D;
40import com.jme3.util.BufferUtils;
41import java.nio.ByteBuffer;
42import java.nio.FloatBuffer;
43import java.nio.ShortBuffer;
44import java.util.LinkedList;
45
46/**
47 * One page per BitmapText Font Texture.
48 * @author Lim, YongHoon
49 */
50class BitmapTextPage extends Geometry {
51
52    private final float[] pos;
53    private final float[] tc;
54    private final short[] idx;
55    private final byte[] color;
56    private final int page;
57    private final Texture2D texture;
58    private final LinkedList<LetterQuad> pageQuads = new LinkedList<LetterQuad>();
59
60    BitmapTextPage(BitmapFont font, boolean arrayBased, int page) {
61        super("BitmapFont", new Mesh());
62
63        if (font == null) {
64            throw new NullPointerException("'font' cannot be null.");
65        }
66
67        this.page = page;
68
69        Material mat = font.getPage(page);
70        if (mat == null) {
71            throw new IllegalStateException("The font's texture was not found!");
72        }
73
74        setMaterial(mat);
75        this.texture = (Texture2D) mat.getTextureParam("ColorMap").getTextureValue();
76
77        // initialize buffers
78        Mesh m = getMesh();
79        m.setBuffer(Type.Position, 3, new float[0]);
80        m.setBuffer(Type.TexCoord, 2, new float[0]);
81        m.setBuffer(Type.Color, 4, new byte[0]);
82        m.setBuffer(Type.Index, 3, new short[0]);
83
84        // scale colors from 0 - 255 range into 0 - 1
85        m.getBuffer(Type.Color).setNormalized(true);
86
87        arrayBased = true;
88
89        if (arrayBased) {
90            pos = new float[4 * 3];  // 4 verticies * 3 floats
91            tc = new float[4 * 2];  // 4 verticies * 2 floats
92            idx = new short[2 * 3];  // 2 triangles * 3 indices
93            color = new byte[4 * 4];   // 4 verticies * 4 bytes
94        } else {
95            pos = null;
96            tc = null;
97            idx = null;
98            color = null;
99        }
100    }
101
102    BitmapTextPage(BitmapFont font, boolean arrayBased) {
103        this(font, arrayBased, 0);
104    }
105
106    BitmapTextPage(BitmapFont font) {
107        this(font, false, 0);
108    }
109
110    Texture2D getTexture() {
111        return texture;
112    }
113
114    @Override
115    public BitmapTextPage clone() {
116        BitmapTextPage clone = (BitmapTextPage) super.clone();
117        clone.mesh = mesh.deepClone();
118        return clone;
119    }
120
121    void assemble(Letters quads) {
122        pageQuads.clear();
123        quads.rewind();
124
125        while (quads.nextCharacter()) {
126            if (quads.isPrintable()) {
127                if (quads.getCharacterSetPage() == page) {
128                    pageQuads.add(quads.getQuad());
129                }
130            }
131        }
132
133        Mesh m = getMesh();
134        int vertCount = pageQuads.size() * 4;
135        int triCount = pageQuads.size() * 2;
136
137        VertexBuffer pb = m.getBuffer(Type.Position);
138        VertexBuffer tb = m.getBuffer(Type.TexCoord);
139        VertexBuffer ib = m.getBuffer(Type.Index);
140        VertexBuffer cb = m.getBuffer(Type.Color);
141
142        FloatBuffer fpb = (FloatBuffer) pb.getData();
143        FloatBuffer ftb = (FloatBuffer) tb.getData();
144        ShortBuffer sib = (ShortBuffer) ib.getData();
145        ByteBuffer bcb = (ByteBuffer) cb.getData();
146
147        // increase capacity of buffers as needed
148        fpb.rewind();
149        fpb = BufferUtils.ensureLargeEnough(fpb, vertCount * 3);
150        fpb.limit(vertCount * 3);
151        pb.updateData(fpb);
152
153        ftb.rewind();
154        ftb = BufferUtils.ensureLargeEnough(ftb, vertCount * 2);
155        ftb.limit(vertCount * 2);
156        tb.updateData(ftb);
157
158        bcb.rewind();
159        bcb = BufferUtils.ensureLargeEnough(bcb, vertCount * 4);
160        bcb.limit(vertCount * 4);
161        cb.updateData(bcb);
162
163        sib.rewind();
164        sib = BufferUtils.ensureLargeEnough(sib, triCount * 3);
165        sib.limit(triCount * 3);
166        ib.updateData(sib);
167
168        m.updateCounts();
169
170        // go for each quad and append it to the buffers
171        if (pos != null) {
172            for (int i = 0; i < pageQuads.size(); i++) {
173                LetterQuad fq = pageQuads.get(i);
174                fq.storeToArrays(pos, tc, idx, color, i);
175                fpb.put(pos);
176                ftb.put(tc);
177                sib.put(idx);
178                bcb.put(color);
179            }
180        } else {
181            for (int i = 0; i < pageQuads.size(); i++) {
182                LetterQuad fq = pageQuads.get(i);
183                fq.appendPositions(fpb);
184                fq.appendTexCoords(ftb);
185                fq.appendIndices(sib, i);
186                fq.appendColors(bcb);
187            }
188        }
189
190        fpb.rewind();
191        ftb.rewind();
192        sib.rewind();
193        bcb.rewind();
194
195        updateModelBound();
196    }
197}
198