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