Formatting update
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / raster / shapes / composite / textcanvas / TextCanvas.java
1 /*
2  * Sixth 3D engine. Author: Svjatoslav Agejenko. 
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas;
6
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.TransformPipe;
12 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
13 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.TexturedRectangle;
14
15 import java.awt.*;
16 import java.io.BufferedReader;
17 import java.io.IOException;
18 import java.io.StringReader;
19
20 import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.BLACK;
21 import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.WHITE;
22
23 public class TextCanvas extends TexturedRectangle {
24
25     public static final int FONT_CHAR_WIDTH_PIXELS = 8;
26     public static final int FONT_CHAR_HEIGHT_PIXELS = 16;
27     public static final Font FONT = CanvasCharacter.getFont(15);
28     private static final String GROUP_TEXTURE = "texture";
29     private static final String GROUP_CHARACTERS = "characters";
30     private final TextPointer size;
31     private final TextPointer cursorLocation = new TextPointer();
32     CanvasCharacter lines[][];
33     private RenderMode renderMode = null;
34     private Color backgroundColor = BLACK;
35     private Color foregroundColor = WHITE;
36
37     public TextCanvas(final Transform location, final String text,
38                       final Color foregroundColor, final Color backgroundColor) {
39         this(location, getTextDimensions(text), foregroundColor,
40                 backgroundColor);
41         setText(text);
42     }
43
44     public TextCanvas(final Transform location, final TextPointer dimensions,
45                       final Color foregroundColor, final Color backgroundColor) {
46         super(location);
47         getRelativityTracker().enableOrientationTracking();
48
49         size = dimensions;
50         final int columns = dimensions.column;
51         final int rows = dimensions.row;
52
53         this.backgroundColor = backgroundColor;
54         this.foregroundColor = foregroundColor;
55
56         // initialize underlying textured rectangle
57         initialize(columns * FONT_CHAR_WIDTH_PIXELS, rows * FONT_CHAR_HEIGHT_PIXELS, 0);
58
59         getTexture().primaryBitmap.fillColor(backgroundColor);
60         getTexture().resetResampledBitmapCache();
61
62         setGroupForUngrouped(GROUP_TEXTURE);
63
64         lines = new CanvasCharacter[rows][];
65         for (int row = 0; row < rows; row++) {
66             lines[row] = new CanvasCharacter[columns];
67
68             for (int column = 0; column < columns; column++) {
69                 final Point3D characterCoordinate = getCharLocation(row, column);
70
71                 final CanvasCharacter character = new CanvasCharacter(
72                         characterCoordinate, ' ', foregroundColor,
73                         backgroundColor);
74                 addShape(character);
75                 lines[row][column] = character;
76             }
77
78         }
79
80         setGroupForUngrouped(GROUP_CHARACTERS);
81
82         setRenderMode(RenderMode.TEXTURE);
83     }
84
85     public static TextPointer getTextDimensions(final String text) {
86
87         final BufferedReader reader = new BufferedReader(new StringReader(text));
88
89         int rows = 0;
90         int columns = 0;
91
92         while (true) {
93             final String line;
94             try {
95                 line = reader.readLine();
96             } catch (IOException e) {
97                 throw new RuntimeException(e);
98             }
99
100             if (line == null)
101                 return new TextPointer(rows, columns);
102
103             rows++;
104             columns = Math.max(columns, line.length());
105         }
106     }
107
108     @Override
109     public void beforeTransformHook(final TransformPipe transformPipe,
110                                     final RenderingContext context) {
111
112         final double textRelativeSize = context.width
113                 / getRelativityTracker().getDistanceToUser();
114
115         if (textRelativeSize < 2d) {
116             if (renderMode == RenderMode.CHARACTERS)
117                 setRenderMode(RenderMode.TEXTURE);
118             return;
119         }
120
121         final double piHalf = Math.PI / 2;
122
123         final double deviation = Math.abs(getRelativityTracker().getAngleXZ()
124                 + piHalf)
125                 + Math.abs(getRelativityTracker().getAngleYZ() + piHalf);
126
127         final double maxDeviation = 0.5;
128
129         if (deviation > maxDeviation) {
130             if (renderMode == RenderMode.CHARACTERS)
131                 setRenderMode(RenderMode.TEXTURE);
132         } else if (renderMode == RenderMode.TEXTURE)
133             setRenderMode(RenderMode.CHARACTERS);
134     }
135
136     public void cls() {
137         for (final CanvasCharacter[] line : lines)
138             for (final CanvasCharacter character : line) {
139                 character.setValue(' ');
140                 character.setBackgroundColor(backgroundColor);
141                 character.setForegroundColor(foregroundColor);
142             }
143
144         // set background color
145         getTexture().primaryBitmap.fillColor(backgroundColor);
146         getTexture().resetResampledBitmapCache();
147     }
148
149     private void drawCharToTexture(final int row, final int column,
150                                    final char character, final Color foreground) {
151         final Graphics2D graphics = getTexture().graphics;
152
153         getTexture().primaryBitmap.drawRectangle(column * FONT_CHAR_WIDTH_PIXELS, row
154                         * FONT_CHAR_HEIGHT_PIXELS, (column * FONT_CHAR_WIDTH_PIXELS)
155                         + FONT_CHAR_WIDTH_PIXELS, (row * FONT_CHAR_HEIGHT_PIXELS) + FONT_CHAR_HEIGHT_PIXELS,
156                 backgroundColor);
157
158         graphics.setFont(FONT);
159         graphics.setColor(foreground.toAwtColor());
160         graphics.drawChars(new char[]{character,}, 0, 1,
161                 (column * FONT_CHAR_WIDTH_PIXELS) - 0, (row * FONT_CHAR_HEIGHT_PIXELS) + 13);
162
163         getTexture().resetResampledBitmapCache();
164     }
165
166     public Point3D getCharLocation(final int row, final int column) {
167         final Point3D coordinate = topLeft.clone();
168
169         coordinate.translateY((row * FONT_CHAR_HEIGHT_PIXELS)
170                 + ((FONT_CHAR_HEIGHT_PIXELS / 2) - 3));
171
172         coordinate.translateX((column * FONT_CHAR_WIDTH_PIXELS)
173                 + (FONT_CHAR_WIDTH_PIXELS / 2));
174
175         return coordinate;
176     }
177
178     public TextPointer getSize() {
179         return size;
180     }
181
182     public void locate(final int row, final int column) {
183         cursorLocation.row = row;
184         cursorLocation.column = column;
185     }
186
187     public void print(final String text) {
188         for (final char c : text.toCharArray())
189             putChar(c);
190     }
191
192     public void putChar(final char character) {
193         putChar(cursorLocation, character);
194
195         cursorLocation.column++;
196         if (cursorLocation.column >= size.column) {
197             cursorLocation.column = 0;
198             cursorLocation.row++;
199         }
200     }
201
202     public void putChar(final int row, final int column, final char character) {
203         if ((row >= lines.length) || (row < 0))
204             return;
205
206         final CanvasCharacter[] line = lines[row];
207
208         if ((column >= line.length) || (column < 0))
209             return;
210
211         final CanvasCharacter canvasCharacter = line[column];
212         canvasCharacter.setValue(character);
213         canvasCharacter.setBackgroundColor(backgroundColor);
214         canvasCharacter.setForegroundColor(foregroundColor);
215         drawCharToTexture(row, column, character,
216                 foregroundColor);
217     }
218
219     public void putChar(final TextPointer location, final char character) {
220         putChar(location.row, location.column, character);
221     }
222
223     public void setBackgroundColor(
224             final eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor) {
225         this.backgroundColor = backgroundColor;
226     }
227
228     public void setForegroundColor(
229             final eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor) {
230         this.foregroundColor = foregroundColor;
231     }
232
233     private void setRenderMode(final RenderMode mode) {
234         if (mode == renderMode)
235             return;
236
237         switch (mode) {
238             case CHARACTERS:
239                 hideGroup(GROUP_TEXTURE);
240                 showGroup(GROUP_CHARACTERS);
241                 break;
242             case TEXTURE:
243                 hideGroup(GROUP_CHARACTERS);
244                 showGroup(GROUP_TEXTURE);
245                 break;
246         }
247
248         renderMode = mode;
249     }
250
251     public void setText(final String text) {
252         final BufferedReader reader = new BufferedReader(new StringReader(text));
253
254         int row = 0;
255
256         while (true) {
257             final String line;
258             try {
259                 line = reader.readLine();
260             } catch (IOException e) {
261                 throw new RuntimeException(e);
262             }
263
264             if (line == null)
265                 return;
266
267             int column = 0;
268             for (final char c : line.toCharArray()) {
269                 putChar(row, column, c);
270                 column++;
271             }
272             row++;
273         }
274     }
275
276     public void setTextColor(final Color color) {
277         for (final CanvasCharacter[] line : lines)
278             for (final CanvasCharacter character : line)
279                 character.setForegroundColor(color);
280     }
281
282     // @Override
283     // public void transform(final TransformPipe transformPipe,
284     // final RenderAggregator aggregator, final RenderingContext buffer) {
285     //
286     // super.transform(transformPipe, aggregator, buffer);
287     //
288     // }
289 }