59fdb2bafd749c4d96e3f607c2b08e0aee3879ac
[sixth-3d.git] /
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.Point2D;
8 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
9 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
10 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
11
12 import java.awt.*;
13
14 import static eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon.drawPolygon;
15 import static eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas.FONT_CHAR_HEIGHT;
16 import static eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas.FONT_CHAR_WIDTH;
17 import static java.lang.String.valueOf;
18
19 /**
20  * Represents a single character on the text canvas.
21  */
22 public class CanvasCharacter extends AbstractCoordinateShape {
23
24     private static final int MAX_FONT_SIZE = 500;
25
26     /**
27      * Cached fonts.
28      */
29     private static final Font[] fonts = new Font[MAX_FONT_SIZE];
30
31     /**
32      * The character to be rendered.
33      */
34     private char value;
35
36     /**
37      * The foreground color of the character.
38      */
39     private eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor;
40
41     /**
42      * The background color of the character.
43      */
44     private eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor;
45
46     /**
47      * Creates a canvas character at the specified location with given colors.
48      *
49      * @param centerLocation  the center position in 3D space
50      * @param character       the character to render
51      * @param foregroundColor the foreground (text) color
52      * @param backgroundColor the background color
53      */
54     public CanvasCharacter(final Point3D centerLocation, final char character,
55                            final eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor,
56                            final eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor) {
57
58         // There are 5 coordinates: center, upper left, upper right, lower right, lower left
59         super(5);
60
61         value = character;
62         this.foregroundColor = foregroundColor;
63         this.backgroundColor = backgroundColor;
64
65
66         vertices[0].coordinate = centerLocation;
67
68         final double halfWidth = FONT_CHAR_WIDTH / 2d;
69         final double halfHeight = FONT_CHAR_HEIGHT / 2d;
70
71         // upper left
72         vertices[1].coordinate = centerLocation.clone().translateX(-halfWidth)
73                 .translateY(-halfHeight);
74
75         // upper right
76         vertices[2].coordinate = centerLocation.clone().translateX(halfWidth)
77                 .translateY(-halfHeight);
78
79         // lower right
80         vertices[3].coordinate = centerLocation.clone().translateX(halfWidth)
81                 .translateY(halfHeight);
82
83         // lower left
84         vertices[4].coordinate = centerLocation.clone().translateX(-halfWidth)
85                 .translateY(halfHeight);
86     }
87
88     /**
89      * Returns a font of the specified size.
90      * <p>
91      * If the font of the specified size is already cached, it will be
92      * returned. Otherwise, a new font will be created, cached and returned.
93      *
94      * @param size the size of the font
95      * @return the font
96      */
97     public static Font getFont(final int size) {
98         if (fonts[size] != null)
99             return fonts[size];
100
101         final Font font = new Font("Courier", Font.BOLD, size);
102         fonts[size] = font;
103         return font;
104     }
105
106     /**
107      * Returns the background color of the character.
108      *
109      * @return the background color
110      */
111     public eu.svjatoslav.sixth.e3d.renderer.raster.Color getBackgroundColor() {
112         return backgroundColor;
113     }
114
115     /**
116      * Sets the background color of the character.
117      *
118      * @param backgroundColor the new background color
119      */
120     public void setBackgroundColor(
121             final eu.svjatoslav.sixth.e3d.renderer.raster.Color backgroundColor) {
122         this.backgroundColor = backgroundColor;
123     }
124
125     /**
126      * Returns color of the foreground.
127      *
128      * @return the color
129      */
130     public eu.svjatoslav.sixth.e3d.renderer.raster.Color getForegroundColor() {
131         return foregroundColor;
132     }
133
134     /**
135      * Sets color of the foreground.
136      *
137      * @param foregroundColor the color
138      */
139     public void setForegroundColor(
140             final eu.svjatoslav.sixth.e3d.renderer.raster.Color foregroundColor) {
141         this.foregroundColor = foregroundColor;
142     }
143
144     /**
145      * Paints the character on the screen.
146      *
147      * @param renderingContext the rendering context
148      */
149     @Override
150     public void paint(final RenderingContext renderingContext) {
151
152         // Draw background rectangle first. It is composed of two triangles.
153         drawPolygon(renderingContext,
154                 vertices[1].onScreenCoordinate,
155                 vertices[2].onScreenCoordinate,
156                 vertices[3].onScreenCoordinate,
157                 mouseInteractionController,
158                 backgroundColor);
159
160         drawPolygon(renderingContext,
161                 vertices[1].onScreenCoordinate,
162                 vertices[3].onScreenCoordinate,
163                 vertices[4].onScreenCoordinate,
164                 mouseInteractionController,
165                 backgroundColor);
166
167         final int desiredFontSize = (int) ((renderingContext.width * 4.5) / onScreenZ);
168
169         // do not render too large characters
170         if (desiredFontSize >= MAX_FONT_SIZE)
171             return;
172
173         final Point2D onScreenLocation = vertices[0].onScreenCoordinate;
174
175         // screen borders check
176         if (onScreenLocation.x < 0)
177             return;
178         if (onScreenLocation.y < 0)
179             return;
180
181         if (onScreenLocation.x > renderingContext.width)
182             return;
183         if (onScreenLocation.y > renderingContext.height)
184             return;
185
186         // check render Y bounds
187         if (onScreenLocation.y + desiredFontSize < renderingContext.renderMinY)
188             return;
189         if (onScreenLocation.y - desiredFontSize >= renderingContext.renderMaxY)
190             return;
191
192         // draw the character
193         final int fontSize = desiredFontSize;
194         final int drawX = (int) onScreenLocation.x - (int) (fontSize / 3.2);
195         final int drawY = (int) onScreenLocation.y + (int) (fontSize / 2.5);
196
197         renderingContext.executeWithGraphics(g -> {
198             g.setFont(getFont(fontSize));
199             g.setColor(foregroundColor.toAwtColor());
200             g.drawString(valueOf(value), drawX, drawY);
201         });
202
203     }
204
205     /**
206      * Sets the character value to render.
207      *
208      * @param value the new character value
209      */
210     public void setValue(final char value) {
211         this.value = value;
212     }
213
214 }