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-2017, 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.geometry.Transform;
14 import eu.svjatoslav.sixth.e3d.geometry.TransformPipe;
15 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
16 import eu.svjatoslav.sixth.e3d.gui.TextPointer;
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             throws IOException {
43         this(location, getTextDimensions(text), foregroundColor,
44                 backgroundColor);
45         setText(text);
46     }
47
48     public TextCanvas(final Transform location, final TextPointer dimensions,
49                       final Color foregroundColor, final Color backgroundColor) {
50         super(location);
51         getRelativityTracker().enableOrientationTracking();
52
53         size = dimensions;
54         final int columns = dimensions.column;
55         final int rows = dimensions.row;
56
57         this.backgroundColor = backgroundColor;
58         this.foregroundColor = foregroundColor;
59
60         // initialize underlying textured rectangle
61         initialize(columns * FONT_CHAR_WIDTH, rows * FONT_CHAR_HEIGHT, 0);
62
63         getTexture().primaryBitmap.fillColor(backgroundColor);
64         getTexture().resetResampledBitmapCache();
65
66         setGroupForUngrouped(GROUP_TEXTURE);
67
68         lines = new CanvasCharacter[rows][];
69         for (int row = 0; row < rows; row++) {
70             lines[row] = new CanvasCharacter[columns];
71
72             for (int column = 0; column < columns; column++) {
73                 final Point3D characterCoordinate = getCharLocation(row, column);
74
75                 final CanvasCharacter character = new CanvasCharacter(
76                         characterCoordinate, ' ', foregroundColor,
77                         backgroundColor);
78                 addShape(character);
79                 lines[row][column] = character;
80             }
81
82         }
83
84         setGroupForUngrouped(GROUP_CHARACTERS);
85
86         setRenderMode(RenderMode.TEXTURE);
87     }
88
89     public static TextPointer getTextDimensions(final String text)
90             throws IOException {
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 = reader.readLine();
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 background, final Color foreground) {
151         final Graphics2D graphics = getTexture().graphics;
152
153         getTexture().primaryBitmap.drawRectangle(column * FONT_CHAR_WIDTH, row
154                         * FONT_CHAR_HEIGHT, (column * FONT_CHAR_WIDTH)
155                         + FONT_CHAR_WIDTH, (row * FONT_CHAR_HEIGHT) + FONT_CHAR_HEIGHT,
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) - 0, (row * FONT_CHAR_HEIGHT) + 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)
170                 + ((FONT_CHAR_HEIGHT / 2) - 3));
171
172         coordinate.translateX((column * FONT_CHAR_WIDTH)
173                 + (FONT_CHAR_WIDTH / 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, backgroundColor,
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) throws IOException {
252         final BufferedReader reader = new BufferedReader(new StringReader(text));
253
254         int row = 0;
255
256         while (true) {
257             final String line = reader.readLine();
258
259             if (line == null)
260                 return;
261
262             int column = 0;
263             for (final char c : line.toCharArray()) {
264                 putChar(row, column, c);
265                 column++;
266             }
267             row++;
268         }
269     }
270
271     public void setTextColor(final Color color) {
272         for (final CanvasCharacter[] line : lines)
273             for (final CanvasCharacter character : line)
274                 character.setForegroundColor(color);
275     }
276
277     // @Override
278     // public void transform(final TransformPipe transformPipe,
279     // final RenderAggregator aggregator, final RenderingContext buffer) {
280     //
281     // super.transform(transformPipe, aggregator, buffer);
282     //
283     // }
284 }