1 #include <stdarg.h>
2 #include "HImage.h"
3 #include "Local.h"
4 #include "Types.h"
5 #include "MemMan.h"
6 #include "Font.h"
7 #include "Debug.h"
8 #include "TranslationTable.h"
9 #include "VSurface.h"
10 #include "VObject.h"
11 #include "VObject_Blitters.h"
12 #include "UILayout.h"
13 #include "GameRes.h"
14 #include "Logger.h"
15 
16 typedef UINT8 GlyphIdx;
17 
18 
19 // Destination printing parameters
20 SGPFont             FontDefault      = 0;
21 static SGPVSurface* FontDestBuffer;
22 static SGPRect      FontDestRegion   = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
23 static UINT16       FontForeground16 = 0;
24 static UINT16       FontBackground16 = 0;
25 static UINT16       FontShadow16     = DEFAULT_SHADOW;
26 
27 // Temp, for saving printing parameters
28 static SGPFont      SaveFontDefault      = 0;
29 static SGPVSurface* SaveFontDestBuffer   = NULL;
30 static SGPRect      SaveFontDestRegion   = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
31 static UINT16       SaveFontForeground16 = 0;
32 static UINT16       SaveFontShadow16     = 0;
33 static UINT16       SaveFontBackground16 = 0;
34 
35 
36 /* Sets both the foreground and the background colors of the current font. The
37  * top byte of the parameter word is the background color, and the bottom byte
38  * is the foreground. */
SetFontColors(UINT16 usColors)39 void SetFontColors(UINT16 usColors)
40 {
41 	UINT8 ubForeground = usColors & 0xFF;
42 	UINT8 ubBackground = (usColors >> 8) & 0xFF;
43 
44 	SetFontForeground(ubForeground);
45 	SetFontBackground(ubBackground);
46 }
47 
48 
49 /* Sets the foreground color of the currently selected font. The parameter is
50  * the index into the 8-bit palette. In 16BPP mode, the RGB values from the
51  * palette are used to create the pixel color. Note that if you change fonts,
52  * the selected foreground/background colors will stay at what they are
53  * currently set to. */
SetFontForeground(UINT8 ubForeground)54 void SetFontForeground(UINT8 ubForeground)
55 {
56 	if (!FontDefault) return;
57 	const SGPPaletteEntry* const c = &FontDefault->Palette()[ubForeground];
58 	FontForeground16 = Get16BPPColor(FROMRGB(c->r, c->g, c->b));
59 }
60 
61 
SetFontShadow(UINT8 ubShadow)62 void SetFontShadow(UINT8 ubShadow)
63 {
64 	if (!FontDefault) return;
65 	const SGPPaletteEntry* const c = &FontDefault->Palette()[ubShadow];
66 	FontShadow16 = Get16BPPColor(FROMRGB(c->r, c->g, c->b));
67 
68 	if (ubShadow != 0 && FontShadow16 == 0) FontShadow16 = 1;
69 }
70 
71 
72 /* Sets the Background color of the currently selected font. The parameter is
73  * the index into the 8-bit palette. In 16BPP mode, the RGB values from the
74  * palette are used to create the pixel color. If the background value is zero,
75  * the background of the font will be transparent.  Note that if you change
76  * fonts, the selected foreground/background colors will stay at what they are
77  * currently set to. */
SetFontBackground(UINT8 ubBackground)78 void SetFontBackground(UINT8 ubBackground)
79 {
80 	if (!FontDefault) return;
81 	const SGPPaletteEntry* const c = &FontDefault->Palette()[ubBackground];
82 	FontBackground16 = Get16BPPColor(FROMRGB(c->r, c->g, c->b));
83 }
84 
85 
86 /* Loads a font from an ETRLE file */
LoadFontFile(const char * filename)87 SGPFont LoadFontFile(const char *filename)
88 {
89 	SGPFont const font = AddVideoObjectFromFile(filename);
90 	if (!FontDefault) FontDefault = font;
91 	return font;
92 }
93 
94 
95 /* Deletes the video object of a particular font. Frees up the memory and
96  * resources allocated for it. */
UnloadFont(SGPFont const font)97 void UnloadFont(SGPFont const font)
98 {
99 	Assert(font);
100 	DeleteVideoObject(font);
101 }
102 
103 
104 /* Returns the width of a given character in the font. */
GetWidth(HVOBJECT const hSrcVObject,GlyphIdx const ssIndex)105 static UINT32 GetWidth(HVOBJECT const hSrcVObject, GlyphIdx const ssIndex)
106 {
107 	// Get Offsets from Index into structure
108 	ETRLEObject const& pTrav = hSrcVObject->SubregionProperties(ssIndex);
109 	return pTrav.usWidth + pTrav.sOffsetX;
110 }
111 
112 
113 /* Returns the length of a string in pixels, depending on the font given. */
StringPixLength(const ST::utf32_buffer & codepoints,SGPFont font)114 INT16 StringPixLength(const ST::utf32_buffer& codepoints, SGPFont font)
115 {
116 	UINT32 w = 0;
117 	for (char32_t c : codepoints)
118 	{
119 		w += GetCharWidth(font, c);
120 	}
121 	return w;
122 }
123 
124 
125 /* Saves the current font printing settings into temporary locations. */
SaveFontSettings(void)126 void SaveFontSettings(void)
127 {
128 	SaveFontDefault      = FontDefault;
129 	SaveFontDestBuffer   = FontDestBuffer;
130 	SaveFontDestRegion   = FontDestRegion;
131 	SaveFontForeground16 = FontForeground16;
132 	SaveFontShadow16     = FontShadow16;
133 	SaveFontBackground16 = FontBackground16;
134 }
135 
136 
137 /* Restores the last saved font printing settings from the temporary lactions */
RestoreFontSettings(void)138 void RestoreFontSettings(void)
139 {
140 	FontDefault      = SaveFontDefault;
141 	FontDestBuffer   = SaveFontDestBuffer;
142 	FontDestRegion   = SaveFontDestRegion;
143 	FontForeground16 = SaveFontForeground16;
144 	FontShadow16     = SaveFontShadow16;
145 	FontBackground16 = SaveFontBackground16;
146 }
147 
148 
149 /* Returns the height of a given character in the font. */
GetHeight(HVOBJECT hSrcVObject,INT16 ssIndex)150 static UINT32 GetHeight(HVOBJECT hSrcVObject, INT16 ssIndex)
151 {
152 	// Get Offsets from Index into structure
153 	ETRLEObject const& pTrav = hSrcVObject->SubregionProperties(ssIndex);
154 	return pTrav.usHeight + pTrav.sOffsetY;
155 }
156 
157 
158 /* Returns the height of the first character in a font. */
GetFontHeight(SGPFont const font)159 UINT16 GetFontHeight(SGPFont const font)
160 {
161 	return GetHeight(font, 0);
162 }
163 
164 
IsPrintableChar(char32_t c)165 bool IsPrintableChar(char32_t c)
166 {
167 	if (TRANSLATION_TABLE_SIZE <= c) return false;
168 	return TranslationTable[c] != 0 || c == getZeroGlyphChar();
169 }
170 
171 
172 /* Given a unicode codepoint, this function returns the index of the glyph. If no glyph
173  * exists for the requested codepoint, the glyph index of '?' is returned. */
GetGlyphIndex(char32_t c)174 static GlyphIdx GetGlyphIndex(char32_t c)
175 {
176 	if (c < TRANSLATION_TABLE_SIZE)
177 	{
178 		GlyphIdx const idx = TranslationTable[c];
179 		if (idx != 0 || c == getZeroGlyphChar()) return idx;
180 	}
181 	SLOGE("Invalid character given U+%04X", c);
182 	return TranslationTable[L'?'];
183 }
184 
185 
GetCharWidth(HVOBJECT SGPFont,char32_t c)186 UINT32 GetCharWidth(HVOBJECT SGPFont, char32_t c)
187 {
188 	return GetWidth(SGPFont, GetGlyphIndex(c));
189 }
190 
191 
192 /* Sets the current font number. */
SetFont(SGPFont const font)193 void SetFont(SGPFont const font)
194 {
195 	Assert(font);
196 	FontDefault = font;
197 }
198 
199 
SetFontAttributes(SGPFont const font,UINT8 const foreground,UINT8 const shadow,UINT8 const background)200 void SetFontAttributes(SGPFont const font, UINT8 const foreground, UINT8 const shadow, UINT8 const background)
201 {
202 	SetFont(font);
203 	SetFontForeground(foreground);
204 	SetFontShadow(shadow);
205 	SetFontBackground(background);
206 }
207 
208 
SetFontDestBuffer(SGPVSurface * const dst,const INT32 x1,const INT32 y1,const INT32 x2,const INT32 y2)209 void SetFontDestBuffer(SGPVSurface* const dst, const INT32 x1, const INT32 y1, const INT32 x2, const INT32 y2)
210 {
211 	Assert(x2 > x1);
212 	Assert(y2 > y1);
213 
214 	FontDestBuffer         = dst;
215 	FontDestRegion.iLeft   = x1;
216 	FontDestRegion.iTop    = y1;
217 	FontDestRegion.iRight  = x2;
218 	FontDestRegion.iBottom = y2;
219 }
220 
221 
SetFontDestBuffer(SGPVSurface * const dst)222 void SetFontDestBuffer(SGPVSurface* const dst)
223 {
224 	SetFontDestBuffer(dst, 0, 0, dst->Width(), dst->Height());
225 }
226 
227 
228 /** Replace backbuffer if it is used by the font system. */
ReplaceFontBackBuffer(SGPVSurface * oldBackbuffer,SGPVSurface * newBackbuffer)229 void ReplaceFontBackBuffer(SGPVSurface* oldBackbuffer, SGPVSurface* newBackbuffer)
230 {
231 	if(FontDestBuffer == oldBackbuffer)
232 	{
233 		FontDestBuffer = newBackbuffer;
234 	}
235 
236 	if(SaveFontDestBuffer == oldBackbuffer)
237 	{
238 		SaveFontDestBuffer = newBackbuffer;
239 	}
240 }
241 
242 
FindFontRightCoordinates(INT16 sLeft,INT16 sTop,INT16 sWidth,INT16 sHeight,const ST::utf32_buffer & codepoints,SGPFont font,INT16 * psNewX,INT16 * psNewY)243 void FindFontRightCoordinates(INT16 sLeft, INT16 sTop, INT16 sWidth, INT16 sHeight, const ST::utf32_buffer& codepoints, SGPFont font, INT16* psNewX, INT16* psNewY)
244 {
245 	// Compute the coordinates to right justify the text
246 	INT16 xp = sWidth - StringPixLength(codepoints, font) + sLeft;
247 	INT16 yp = (sHeight - GetFontHeight(font)) / 2 + sTop;
248 
249 	*psNewX = xp;
250 	*psNewY = yp;
251 }
252 
253 
FindFontCenterCoordinates(INT16 sLeft,INT16 sTop,INT16 sWidth,INT16 sHeight,const ST::utf32_buffer & codepoints,SGPFont font,INT16 * psNewX,INT16 * psNewY)254 void FindFontCenterCoordinates(INT16 sLeft, INT16 sTop, INT16 sWidth, INT16 sHeight, const ST::utf32_buffer& codepoints, SGPFont font, INT16* psNewX, INT16* psNewY)
255 {
256 	// Compute the coordinates to center the text
257 	INT16 xp = (sWidth - StringPixLength(codepoints, font) + 1) / 2 + sLeft;
258 	INT16 yp = (sHeight - GetFontHeight(font)) / 2 + sTop;
259 
260 	*psNewX = xp;
261 	*psNewY = yp;
262 }
263 
264 
GPrint(INT32 x,INT32 y,const ST::utf32_buffer & codepoints)265 void GPrint(INT32 x, INT32 y, const ST::utf32_buffer& codepoints)
266 {
267 	SGPVSurface::Lock l(FontDestBuffer);
268 	UINT16* const buf   = l.Buffer<UINT16>();
269 	UINT32  const pitch = l.Pitch();
270 	SGPFont const font  = FontDefault;
271 	for (char32_t c : codepoints)
272 	{
273 		GlyphIdx const glyph = GetGlyphIndex(c);
274 		Blt8BPPDataTo16BPPBufferTransparentClip(buf, pitch, font, x, y, glyph, &FontDestRegion);
275 		x += GetWidth(font, glyph);
276 	}
277 }
278 
279 
MPrintChar(INT32 x,INT32 y,char32_t c)280 UINT32 MPrintChar(INT32 x, INT32 y, char32_t c)
281 {
282 	GlyphIdx const glyph = GetGlyphIndex(c);
283 	SGPFont  const font  = FontDefault;
284 	{ SGPVSurface::Lock l(FontDestBuffer);
285 		Blt8BPPDataTo16BPPBufferMonoShadowClip(l.Buffer<UINT16>(), l.Pitch(), font, x, y, glyph, &FontDestRegion, FontForeground16, FontBackground16, FontShadow16);
286 	}
287 	return GetWidth(font, glyph);
288 }
289 
290 
MPrintBuffer(UINT16 * pDestBuf,UINT32 uiDestPitchBYTES,INT32 x,INT32 y,const ST::utf32_buffer & codepoints)291 void MPrintBuffer(UINT16* pDestBuf, UINT32 uiDestPitchBYTES, INT32 x, INT32 y, const ST::utf32_buffer& codepoints)
292 {
293 	SGPFont const font = FontDefault;
294 	for (char32_t c : codepoints)
295 	{
296 		GlyphIdx const glyph = GetGlyphIndex(c);
297 		Blt8BPPDataTo16BPPBufferMonoShadowClip(pDestBuf, uiDestPitchBYTES, font, x, y, glyph, &FontDestRegion, FontForeground16, FontBackground16, FontShadow16);
298 		x += GetWidth(font, glyph);
299 	}
300 }
301 
302 
MPrint(INT32 x,INT32 y,const ST::utf32_buffer & codepoints)303 void MPrint(INT32 x, INT32 y, const ST::utf32_buffer& codepoints)
304 {
305 	SGPVSurface::Lock l(FontDestBuffer);
306 	MPrintBuffer(l.Buffer<UINT16>(), l.Pitch(), x, y, codepoints);
307 }
308 
309 
InitializeFontManager(void)310 void InitializeFontManager(void)
311 {
312 	FontDefault    = 0;
313 	SetFontDestBuffer(BACKBUFFER);
314 }
315