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