Updated to work with freeglut 2.4.0
[crack-attack.git] / src / String.cxx
blobd9acac1a95ef25399c7d16e5a19b919dc057bcda
1 /*
2 * String.cxx
3 * Daniel Nelson - 11/10/0
5 * Copyright (C) 2000 Daniel Nelson
6 * Copyright (C) 2004 Andrew Sayman
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * Daniel Nelson - aluminumangel.org
23 * 174 W. 18th Ave.
24 * Columbus, OH 43210
26 * Holds string display utilities.
29 #include <cctype>
30 #include <cstring>
31 #include <GL/glut.h>
33 #include "glext.h"
35 using namespace std;
37 #include "TextureLoader.h"
38 #include "Game.h"
39 #include "Displayer.h"
40 #include "String.h"
42 const char *String::letter_texture_files[DC_FONT_NUMBER][DC_LETTER_NUMBER]
43 = { { GC_DATA_DIRECTORY("font0_0.tga"),
44 GC_DATA_DIRECTORY("font0_1.tga"),
45 GC_DATA_DIRECTORY("font0_2.tga"),
46 GC_DATA_DIRECTORY("font0_3.tga"),
47 GC_DATA_DIRECTORY("font0_4.tga"),
48 GC_DATA_DIRECTORY("font0_5.tga"),
49 GC_DATA_DIRECTORY("font0_6.tga"),
50 GC_DATA_DIRECTORY("font0_7.tga"),
51 GC_DATA_DIRECTORY("font0_8.tga"),
52 GC_DATA_DIRECTORY("font0_9.tga"),
53 GC_DATA_DIRECTORY("font0_ca.tga"),
54 GC_DATA_DIRECTORY("font0_cb.tga"),
55 GC_DATA_DIRECTORY("font0_cc.tga"),
56 GC_DATA_DIRECTORY("font0_cd.tga"),
57 GC_DATA_DIRECTORY("font0_ce.tga"),
58 GC_DATA_DIRECTORY("font0_cf.tga"),
59 GC_DATA_DIRECTORY("font0_cg.tga"),
60 GC_DATA_DIRECTORY("font0_ch.tga"),
61 GC_DATA_DIRECTORY("font0_ci.tga"),
62 GC_DATA_DIRECTORY("font0_cj.tga"),
63 GC_DATA_DIRECTORY("font0_ck.tga"),
64 GC_DATA_DIRECTORY("font0_cl.tga"),
65 GC_DATA_DIRECTORY("font0_cm.tga"),
66 GC_DATA_DIRECTORY("font0_cn.tga"),
67 GC_DATA_DIRECTORY("font0_co.tga"),
68 GC_DATA_DIRECTORY("font0_cp.tga"),
69 GC_DATA_DIRECTORY("font0_cq.tga"),
70 GC_DATA_DIRECTORY("font0_cr.tga"),
71 GC_DATA_DIRECTORY("font0_cs.tga"),
72 GC_DATA_DIRECTORY("font0_ct.tga"),
73 GC_DATA_DIRECTORY("font0_cu.tga"),
74 GC_DATA_DIRECTORY("font0_cv.tga"),
75 GC_DATA_DIRECTORY("font0_cw.tga"),
76 GC_DATA_DIRECTORY("font0_cx.tga"),
77 GC_DATA_DIRECTORY("font0_cy.tga"),
78 GC_DATA_DIRECTORY("font0_cz.tga"),
79 GC_DATA_DIRECTORY("font0_a.tga"),
80 GC_DATA_DIRECTORY("font0_b.tga"),
81 GC_DATA_DIRECTORY("font0_c.tga"),
82 GC_DATA_DIRECTORY("font0_d.tga"),
83 GC_DATA_DIRECTORY("font0_e.tga"),
84 GC_DATA_DIRECTORY("font0_f.tga"),
85 GC_DATA_DIRECTORY("font0_g.tga"),
86 GC_DATA_DIRECTORY("font0_h.tga"),
87 GC_DATA_DIRECTORY("font0_i.tga"),
88 GC_DATA_DIRECTORY("font0_j.tga"),
89 GC_DATA_DIRECTORY("font0_k.tga"),
90 GC_DATA_DIRECTORY("font0_l.tga"),
91 GC_DATA_DIRECTORY("font0_m.tga"),
92 GC_DATA_DIRECTORY("font0_n.tga"),
93 GC_DATA_DIRECTORY("font0_o.tga"),
94 GC_DATA_DIRECTORY("font0_p.tga"),
95 GC_DATA_DIRECTORY("font0_q.tga"),
96 GC_DATA_DIRECTORY("font0_r.tga"),
97 GC_DATA_DIRECTORY("font0_s.tga"),
98 GC_DATA_DIRECTORY("font0_t.tga"),
99 GC_DATA_DIRECTORY("font0_u.tga"),
100 GC_DATA_DIRECTORY("font0_v.tga"),
101 GC_DATA_DIRECTORY("font0_w.tga"),
102 GC_DATA_DIRECTORY("font0_x.tga"),
103 GC_DATA_DIRECTORY("font0_y.tga"),
104 GC_DATA_DIRECTORY("font0_z.tga"),
105 GC_DATA_DIRECTORY("font0_mn.tga"),
106 GC_DATA_DIRECTORY("font0_cln.tga"),
107 GC_DATA_DIRECTORY("font0_pe.tga"),
108 GC_DATA_DIRECTORY("font0_cma.tga"),
109 GC_DATA_DIRECTORY("font0_ep.tga"),
110 GC_DATA_DIRECTORY("font0_at.tga"),
111 GC_DATA_DIRECTORY("font0_td.tga"),
112 GC_DATA_DIRECTORY("font0_pd.tga"),
113 GC_DATA_DIRECTORY("font0_ds.tga"),
114 GC_DATA_DIRECTORY("font0_ps.tga"),
115 GC_DATA_DIRECTORY("font0_and.tga"),
116 GC_DATA_DIRECTORY("font0_pl.tga"),
117 GC_DATA_DIRECTORY("font0_pr.tga"),
118 GC_DATA_DIRECTORY("font0_sl.tga"),
119 GC_DATA_DIRECTORY("font0_lt.tga"),
120 GC_DATA_DIRECTORY("font0_gt.tga"),
121 GC_DATA_DIRECTORY("font0_qm.tga"),
122 GC_DATA_DIRECTORY("font0_eq.tga"),
123 GC_DATA_DIRECTORY("font0_pu.tga"),
124 GC_DATA_DIRECTORY("font0_br.tga"),
125 GC_DATA_DIRECTORY("font0_za.tga"),
126 GC_DATA_DIRECTORY("font0_zb.tga"),
127 GC_DATA_DIRECTORY("font0_zc.tga"),
128 GC_DATA_DIRECTORY("font0_zd.tga") } };
130 const char String::letter_mapping[DC_LETTER_NUMBER]
131 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
133 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
134 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
135 'U', 'V', 'W', 'X', 'Y', 'Z',
137 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
138 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
139 'u', 'v', 'w', 'x', 'y', 'z',
141 '-', ':', '.', ',', '!', '@', '~', '#', '$', '%',
142 '&', '(', ')', '/', '<', '>', '?', '=', '+', '|',
143 ';', '[', '*', ']' };
145 const int String::letter_widths[DC_FONT_NUMBER][DC_LETTER_NUMBER]
146 = { { 20, 12, 17, 14, 16, 15, 16, 19, 17, 16,
148 28, 20, 17, 20, 18, 20, 20, 19, 11, 17,
149 19, 17, 30, 20, 20, 21, 22, 22, 16, 21,
150 20, 20, 30, 25, 22, 19,
152 19, 14, 13, 14, 13, 14, 15, 14, 8, 12,
153 14, 12, 22, 15, 14, 14, 16, 16, 12, 15,
154 14, 15, 22, 18, 17, 13,
156 20, 12, 11, 10, 11, 21, 23, 23, 18, 19,
157 20, 12, 13, 18, 16, 16, 17, 20, 23, 16,
158 22, 22, 16, 22 } };
161 const float String::colors[DC_FONT_COLOR_NUMBER][3]
162 = { { 0.2f, 0.2f, 1.0f },
163 { 1.0f, 0.1f, 0.1f },
164 { 0.1f, 1.0f, 0.1f },
165 { 0.8f, 0.8f, 0.1f },
166 { 0.9f, 0.0f, 0.9f },
167 { 0.1f, 0.8f, 0.8f },
168 { 0.9f, 0.3f, 0.1f },
169 { 1.0f, 0.5f, 0.5f },
170 { 0.4f, 0.0f, 1.0f },
171 { 0.1f, 0.1f, 0.1f } };
173 GLubyte *String::letter_textures[DC_FONT_NUMBER][DC_LETTER_NUMBER];
175 int String::mapCharToCode ( char c )
177 int code = -1;
178 for (int n = DC_LETTER_NUMBER; n--; )
179 if (c == letter_mapping[n]) {
180 code = n;
181 break;
183 return code;
186 int String::stringWidth ( const char *string, int max_width )
188 * Determines the pixel width of a string.
191 int length = 0;
193 int font = 0;
194 for (unsigned int n = 0; n < strlen(string) && length < max_width; n++) {
196 if (string[n] == '~') {
197 switch (string[++n]) {
198 case '<':
199 if (length >= DC_BACK_SPACE_WIDTH) length -= DC_BACK_SPACE_WIDTH;
200 break;
201 case '>':
202 length += DC_BACK_SPACE_WIDTH;
203 break;
204 default:
205 int c = string[n] - 'a';
206 if (c >= 0 && c < DC_FONT_NUMBER)
207 font = c;
208 break;
211 if (string[n] != '~') continue;
213 } else if (string[n] == ' ') {
214 length += DC_SPACE_WIDTH;
215 continue;
218 int code = mapCharToCode(string[n]);
219 if (code != -1) {
220 if (length + letter_widths[font][code] > max_width) break;
221 length += letter_widths[font][code];
225 return length;
228 void String::readyLetterTextures ( )
230 for (int n = DC_FONT_NUMBER; n--; )
231 for (int m = DC_LETTER_NUMBER; m--; )
232 letter_textures[n][m]
233 = TextureLoader::loadAlphaTGA(letter_texture_files[n][m],
234 DC_LETTER_TEX_LENGTH, DC_LETTER_TEX_LENGTH);
237 void String::freeLetterTextures ( )
239 for (int n = DC_FONT_NUMBER; n--; )
240 for (int m = DC_LETTER_NUMBER; m--; )
241 if (letter_textures[n][m] != null) {
242 delete [] letter_textures[n][m];
243 letter_textures[n][m] = null;
248 void String::fillStringTexture ( const char *string, GLubyte *texture,
249 int width, bool use_alpha, int texture_width )
251 * Fills the memory space pointed to by texture with a string texture. The
252 * texture height must equal DC_LETTER_TEX_LENGTH. readyLetterTextures() must
253 * be called first, and freeLetterTextures() must be called after this
254 * function's final use.
257 if (texture_width == 0)
258 texture_width = width;
260 // initialize texture
261 if (!use_alpha)
262 for (int t = DC_LETTER_TEX_LENGTH; t--; )
263 for (int s = width; s--; ) {
264 texture[(t * texture_width + s) * 4 + 0] = 0;
265 texture[(t * texture_width + s) * 4 + 1] = 0;
266 texture[(t * texture_width + s) * 4 + 2] = 0;
267 texture[(t * texture_width + s) * 4 + 3] = 255;
270 int cursor = 0;
271 int font = 0;
272 int base_color = DC_DEFAULT_FONT_COLOR;
273 for (unsigned int n = 0; n < strlen(string) && cursor < width; n++) {
275 // special cases
276 if (string[n] == '~') {
277 switch (string[++n]) {
278 case '<':
279 if (cursor > DC_BACK_SPACE_WIDTH)
280 cursor -= DC_BACK_SPACE_WIDTH;
281 else
282 cursor = 0;
283 break;
284 case '>':
285 cursor += DC_BACK_SPACE_WIDTH;
286 break;
287 default:
288 // color change
289 if (isdigit(string[n])) {
290 int c = string[n] - '0';
291 if (c < DC_FONT_COLOR_NUMBER)
292 base_color = c;
294 // font change
295 } else {
296 int c = string[n] - 'a';
297 if (c >= 0 && c < DC_FONT_NUMBER)
298 font = c;
300 break;
303 if (string[n] != '~') continue;
305 } else if (string[n] == ' ') {
306 cursor += DC_SPACE_WIDTH;
307 continue;
310 int code = mapCharToCode(string[n]);
311 if (code == -1) continue;
313 if (cursor + letter_widths[font][code] > width) break;
315 // copy letter
316 if (!use_alpha)
317 for (int t = DC_LETTER_TEX_LENGTH; t--; )
318 for (int s = DC_LETTER_TEX_LENGTH; s--; ) {
319 if (cursor + s >= width) continue;
321 float alpha = letter_textures[font][code][t * DC_LETTER_TEX_LENGTH
322 + s] * (1.0f / 255.0f);
323 for (int c = 3; c--; ) {
324 float color = colors[base_color][c] + (1.0f - colors[base_color][c])
325 * (DC_LETTER_TEX_LENGTH - t + (s >= letter_widths[font][code]
326 ? DC_LETTER_TEX_LENGTH : s + (DC_LETTER_TEX_LENGTH
327 - letter_widths[font][code])))
328 * (0.5f / (float) DC_LETTER_TEX_LENGTH);
329 float result = (255.0f * color * alpha)
330 + texture[(t * texture_width + cursor + s) * 4 + c];
331 if (result >= 255.0f)
332 texture[(t * texture_width + cursor + s) * 4 + c] = (GLubyte) 255;
333 else
334 texture[(t * texture_width + cursor + s) * 4 + c]
335 = (GLubyte) result;
339 else
340 for (int t = DC_LETTER_TEX_LENGTH; t--; )
341 for (int s = DC_LETTER_TEX_LENGTH; s--; ) {
342 if (cursor + s >= width)
343 continue;
344 if (letter_textures[font][code][t * DC_LETTER_TEX_LENGTH + s] == 0)
345 continue;
347 int old_alpha = texture[(t * texture_width + cursor + s) * 4 + 3];
348 int new_alpha = letter_textures[font][code][t * DC_LETTER_TEX_LENGTH
349 + s];
350 if (new_alpha + old_alpha >= 255)
351 texture[(t * texture_width + cursor + s) * 4 + 3] = 255;
352 else
353 texture[(t * texture_width + cursor + s) * 4 + 3]
354 = (GLubyte) (new_alpha + old_alpha);
356 for (int c = 3; c--; ) {
357 float color = colors[base_color][c] + (1.0f - colors[base_color][c])
358 * (DC_LETTER_TEX_LENGTH - t + (s >= letter_widths[font][code]
359 ? DC_LETTER_TEX_LENGTH : s + (DC_LETTER_TEX_LENGTH
360 - letter_widths[font][code])))
361 * (0.5f / (float) DC_LETTER_TEX_LENGTH);
362 float result = (255.0f * color) + (old_alpha * (1.0f / 255.0f))
363 * texture[(t * texture_width + cursor + s) * 4 + c];
364 if (result >= 255.0f)
365 texture[(t * texture_width + cursor + s) * 4 + c] = 255;
366 else
367 texture[(t * texture_width + cursor + s) * 4 + c]
368 = (GLubyte) result;
372 cursor += letter_widths[font][code];