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