2 * Sixth 3D engine. Author: Svjatoslav Agejenko.
3 * This project is released under Creative Commons Zero (CC0) license.
5 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas;
7 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
8 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
9 import eu.svjatoslav.sixth.e3d.gui.TextPointer;
10 import eu.svjatoslav.sixth.e3d.math.Transform;
11 import eu.svjatoslav.sixth.e3d.math.TransformsStack;
12 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
13 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.TexturedRectangle;
16 import java.io.BufferedReader;
17 import java.io.IOException;
18 import java.io.StringReader;
20 import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.BLACK;
21 import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.WHITE;
22 import static java.lang.Math.PI;
23 import static java.lang.Math.abs;
25 public class TextCanvas extends TexturedRectangle {
28 * Font character width in world coordinates.
30 public static final int FONT_CHAR_WIDTH = 8;
33 * Font character height in world coordinates.
35 public static final int FONT_CHAR_HEIGHT = 16;
38 * Font character width in texture pixels.
40 public static final int FONT_CHAR_WIDTH_TEXTURE_PIXELS = 16;
43 * Font character height in texture pixels.
45 public static final int FONT_CHAR_HEIGHT_TEXTURE_PIXELS = 32;
48 public static final Font FONT = CanvasCharacter.getFont((int) (FONT_CHAR_HEIGHT_TEXTURE_PIXELS / 1.066));
49 private static final String GROUP_TEXTURE = "texture";
50 private static final String GROUP_CHARACTERS = "characters";
51 private final TextPointer size;
52 private final TextPointer cursorLocation = new TextPointer();
53 CanvasCharacter[][] lines;
54 private RenderMode renderMode = null;
55 private Color backgroundColor = BLACK;
56 private Color foregroundColor = WHITE;
58 public TextCanvas(final Transform location, final String text,
59 final Color foregroundColor, final Color backgroundColor) {
60 this(location, getTextDimensions(text), foregroundColor,
65 public TextCanvas(final Transform location, final TextPointer dimensions,
66 final Color foregroundColor, final Color backgroundColor) {
68 getRelativityTracker().enableOrientationTracking();
71 final int columns = dimensions.column;
72 final int rows = dimensions.row;
74 this.backgroundColor = backgroundColor;
75 this.foregroundColor = foregroundColor;
77 // initialize underlying textured rectangle
79 columns * FONT_CHAR_WIDTH,
80 rows * FONT_CHAR_HEIGHT,
81 columns * FONT_CHAR_WIDTH_TEXTURE_PIXELS,
82 rows * FONT_CHAR_HEIGHT_TEXTURE_PIXELS,
85 getTexture().primaryBitmap.fillColor(backgroundColor);
86 getTexture().resetResampledBitmapCache();
88 setGroupForUngrouped(GROUP_TEXTURE);
90 lines = new CanvasCharacter[rows][];
91 for (int row = 0; row < rows; row++) {
92 lines[row] = new CanvasCharacter[columns];
94 for (int column = 0; column < columns; column++) {
95 final Point3D characterCoordinate = getCharLocation(row, column);
97 final CanvasCharacter character = new CanvasCharacter(
98 characterCoordinate, ' ', foregroundColor,
101 lines[row][column] = character;
106 setGroupForUngrouped(GROUP_CHARACTERS);
108 setRenderMode(RenderMode.TEXTURE);
111 public static TextPointer getTextDimensions(final String text) {
113 final BufferedReader reader = new BufferedReader(new StringReader(text));
121 line = reader.readLine();
122 } catch (IOException e) {
123 throw new RuntimeException(e);
127 return new TextPointer(rows, columns);
130 columns = Math.max(columns, line.length());
135 public void beforeTransformHook(final TransformsStack transformPipe,
136 final RenderingContext context) {
137 ensureOptimalRenderMode(context);
140 private void ensureOptimalRenderMode(RenderingContext context) {
142 // if the text is too far away, use texture
143 final double textRelativeSize = context.width / getRelativityTracker().getDistanceToUser();
144 if (textRelativeSize < 2d) {
145 setRenderMode(RenderMode.TEXTURE);
149 // if user is looking at the text from the side, use texture
150 final double piHalf = PI / 2;
151 final double deviation = abs(getRelativityTracker().getAngleXZ()
153 + abs(getRelativityTracker().getAngleYZ() + piHalf);
155 final double maxDeviation = 0.5;
156 setRenderMode(deviation > maxDeviation ? RenderMode.TEXTURE : RenderMode.CHARACTERS);
159 public void clear() {
160 for (final CanvasCharacter[] line : lines)
161 for (final CanvasCharacter character : line) {
162 character.setValue(' ');
163 character.setBackgroundColor(backgroundColor);
164 character.setForegroundColor(foregroundColor);
167 // set background color
168 getTexture().primaryBitmap.fillColor(backgroundColor);
169 getTexture().resetResampledBitmapCache();
172 private void drawCharToTexture(final int row, final int column,
173 final char character, final Color foreground) {
174 final Graphics2D graphics = getTexture().graphics;
176 getTexture().primaryBitmap.drawRectangle(
177 column * FONT_CHAR_WIDTH_TEXTURE_PIXELS,
178 row * FONT_CHAR_HEIGHT_TEXTURE_PIXELS,
179 (column * FONT_CHAR_WIDTH_TEXTURE_PIXELS) + FONT_CHAR_WIDTH_TEXTURE_PIXELS,
180 (row * FONT_CHAR_HEIGHT_TEXTURE_PIXELS) + FONT_CHAR_HEIGHT_TEXTURE_PIXELS,
183 graphics.setFont(FONT);
184 graphics.setColor(foreground.toAwtColor());
186 new char[]{character,}, 0, 1,
187 (column * FONT_CHAR_WIDTH_TEXTURE_PIXELS),
188 (row * FONT_CHAR_HEIGHT_TEXTURE_PIXELS) + (int) (FONT_CHAR_HEIGHT_TEXTURE_PIXELS / 1.23f));
189 getTexture().resetResampledBitmapCache();
192 public Point3D getCharLocation(final int row, final int column) {
193 final Point3D coordinate = topLeft.clone();
195 coordinate.translateY((row * FONT_CHAR_HEIGHT)
196 + (FONT_CHAR_HEIGHT / 3.2));
198 coordinate.translateX((column * FONT_CHAR_WIDTH)
199 + (FONT_CHAR_WIDTH / 2));
204 public TextPointer getSize() {
208 public void locate(final int row, final int column) {
209 cursorLocation.row = row;
210 cursorLocation.column = column;
213 public void print(final String text) {
214 for (final char c : text.toCharArray())
218 public void putChar(final char character) {
219 putChar(cursorLocation, character);
221 cursorLocation.column++;
222 if (cursorLocation.column >= size.column) {
223 cursorLocation.column = 0;
224 cursorLocation.row++;
228 public void putChar(final int row, final int column, final char character) {
229 if ((row >= lines.length) || (row < 0))
232 final CanvasCharacter[] line = lines[row];
234 if ((column >= line.length) || (column < 0))
237 final CanvasCharacter canvasCharacter = line[column];
238 canvasCharacter.setValue(character);
239 canvasCharacter.setBackgroundColor(backgroundColor);
240 canvasCharacter.setForegroundColor(foregroundColor);
241 drawCharToTexture(row, column, character,
245 public void putChar(final TextPointer location, final char character) {
246 putChar(location.row, location.column, character);
249 public void setBackgroundColor(
250 final eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor) {
251 this.backgroundColor = backgroundColor;
254 public void setForegroundColor(
255 final eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor) {
256 this.foregroundColor = foregroundColor;
259 private void setRenderMode(final RenderMode mode) {
260 if (mode == renderMode)
265 hideGroup(GROUP_TEXTURE);
266 showGroup(GROUP_CHARACTERS);
269 hideGroup(GROUP_CHARACTERS);
270 showGroup(GROUP_TEXTURE);
277 public void setText(final String text) {
278 final BufferedReader reader = new BufferedReader(new StringReader(text));
285 line = reader.readLine();
286 } catch (IOException e) {
287 throw new RuntimeException(e);
294 for (final char c : line.toCharArray()) {
295 putChar(row, column, c);
302 public void setTextColor(final Color color) {
303 for (final CanvasCharacter[] line : lines)
304 for (final CanvasCharacter character : line)
305 character.setForegroundColor(color);