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));
190 getTexture().resetResampledBitmapCache();
193 public Point3D getCharLocation(final int row, final int column) {
194 final Point3D coordinate = topLeft.clone();
196 coordinate.translateY((row * FONT_CHAR_HEIGHT)
197 + (FONT_CHAR_HEIGHT / 3.2));
199 coordinate.translateX((column * FONT_CHAR_WIDTH)
200 + (FONT_CHAR_WIDTH / 2));
205 public TextPointer getSize() {
209 public void locate(final int row, final int column) {
210 cursorLocation.row = row;
211 cursorLocation.column = column;
214 public void print(final String text) {
215 for (final char c : text.toCharArray())
219 public void putChar(final char character) {
220 putChar(cursorLocation, character);
222 cursorLocation.column++;
223 if (cursorLocation.column >= size.column) {
224 cursorLocation.column = 0;
225 cursorLocation.row++;
229 public void putChar(final int row, final int column, final char character) {
230 if ((row >= lines.length) || (row < 0))
233 final CanvasCharacter[] line = lines[row];
235 if ((column >= line.length) || (column < 0))
238 final CanvasCharacter canvasCharacter = line[column];
239 canvasCharacter.setValue(character);
240 canvasCharacter.setBackgroundColor(backgroundColor);
241 canvasCharacter.setForegroundColor(foregroundColor);
242 drawCharToTexture(row, column, character,
246 public void putChar(final TextPointer location, final char character) {
247 putChar(location.row, location.column, character);
250 public void setBackgroundColor(
251 final eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor) {
252 this.backgroundColor = backgroundColor;
255 public void setForegroundColor(
256 final eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor) {
257 this.foregroundColor = foregroundColor;
260 private void setRenderMode(final RenderMode mode) {
261 if (mode == renderMode)
266 hideGroup(GROUP_TEXTURE);
267 showGroup(GROUP_CHARACTERS);
270 hideGroup(GROUP_CHARACTERS);
271 showGroup(GROUP_TEXTURE);
278 public void setText(final String text) {
279 final BufferedReader reader = new BufferedReader(new StringReader(text));
286 line = reader.readLine();
287 } catch (IOException e) {
288 throw new RuntimeException(e);
295 for (final char c : line.toCharArray()) {
296 putChar(row, column, c);
303 public void setTextColor(final Color color) {
304 for (final CanvasCharacter[] line : lines)
305 for (final CanvasCharacter character : line)
306 character.setForegroundColor(color);