Each module now includes its own header first. Removed sstream.h and the definition...
[crack-attack.git] / src / String.cxx
blob26e696c89076df3ccd7590c6e47c070fe3fa46c1
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 "String.h"
31 #include <cctype>
32 #include <cstring>
33 #include <GL/glut.h>
35 #include "glext.h"
37 #include "TextureLoader.h"
38 #include "Game.h"
39 #include "Displayer.h"
41 const char *String::letter_texture_files[DC_FONT_NUMBER][DC_LETTER_NUMBER]
42 = { { GC_DATA_DIRECTORY("font0_0.tga"),
43 GC_DATA_DIRECTORY("font0_1.tga"),
44 GC_DATA_DIRECTORY("font0_2.tga"),
45 GC_DATA_DIRECTORY("font0_3.tga"),
46 GC_DATA_DIRECTORY("font0_4.tga"),
47 GC_DATA_DIRECTORY("font0_5.tga"),
48 GC_DATA_DIRECTORY("font0_6.tga"),
49 GC_DATA_DIRECTORY("font0_7.tga"),
50 GC_DATA_DIRECTORY("font0_8.tga"),
51 GC_DATA_DIRECTORY("font0_9.tga"),
52 GC_DATA_DIRECTORY("font0_ca.tga"),
53 GC_DATA_DIRECTORY("font0_cb.tga"),
54 GC_DATA_DIRECTORY("font0_cc.tga"),
55 GC_DATA_DIRECTORY("font0_cd.tga"),
56 GC_DATA_DIRECTORY("font0_ce.tga"),
57 GC_DATA_DIRECTORY("font0_cf.tga"),
58 GC_DATA_DIRECTORY("font0_cg.tga"),
59 GC_DATA_DIRECTORY("font0_ch.tga"),
60 GC_DATA_DIRECTORY("font0_ci.tga"),
61 GC_DATA_DIRECTORY("font0_cj.tga"),
62 GC_DATA_DIRECTORY("font0_ck.tga"),
63 GC_DATA_DIRECTORY("font0_cl.tga"),
64 GC_DATA_DIRECTORY("font0_cm.tga"),
65 GC_DATA_DIRECTORY("font0_cn.tga"),
66 GC_DATA_DIRECTORY("font0_co.tga"),
67 GC_DATA_DIRECTORY("font0_cp.tga"),
68 GC_DATA_DIRECTORY("font0_cq.tga"),
69 GC_DATA_DIRECTORY("font0_cr.tga"),
70 GC_DATA_DIRECTORY("font0_cs.tga"),
71 GC_DATA_DIRECTORY("font0_ct.tga"),
72 GC_DATA_DIRECTORY("font0_cu.tga"),
73 GC_DATA_DIRECTORY("font0_cv.tga"),
74 GC_DATA_DIRECTORY("font0_cw.tga"),
75 GC_DATA_DIRECTORY("font0_cx.tga"),
76 GC_DATA_DIRECTORY("font0_cy.tga"),
77 GC_DATA_DIRECTORY("font0_cz.tga"),
78 GC_DATA_DIRECTORY("font0_a.tga"),
79 GC_DATA_DIRECTORY("font0_b.tga"),
80 GC_DATA_DIRECTORY("font0_c.tga"),
81 GC_DATA_DIRECTORY("font0_d.tga"),
82 GC_DATA_DIRECTORY("font0_e.tga"),
83 GC_DATA_DIRECTORY("font0_f.tga"),
84 GC_DATA_DIRECTORY("font0_g.tga"),
85 GC_DATA_DIRECTORY("font0_h.tga"),
86 GC_DATA_DIRECTORY("font0_i.tga"),
87 GC_DATA_DIRECTORY("font0_j.tga"),
88 GC_DATA_DIRECTORY("font0_k.tga"),
89 GC_DATA_DIRECTORY("font0_l.tga"),
90 GC_DATA_DIRECTORY("font0_m.tga"),
91 GC_DATA_DIRECTORY("font0_n.tga"),
92 GC_DATA_DIRECTORY("font0_o.tga"),
93 GC_DATA_DIRECTORY("font0_p.tga"),
94 GC_DATA_DIRECTORY("font0_q.tga"),
95 GC_DATA_DIRECTORY("font0_r.tga"),
96 GC_DATA_DIRECTORY("font0_s.tga"),
97 GC_DATA_DIRECTORY("font0_t.tga"),
98 GC_DATA_DIRECTORY("font0_u.tga"),
99 GC_DATA_DIRECTORY("font0_v.tga"),
100 GC_DATA_DIRECTORY("font0_w.tga"),
101 GC_DATA_DIRECTORY("font0_x.tga"),
102 GC_DATA_DIRECTORY("font0_y.tga"),
103 GC_DATA_DIRECTORY("font0_z.tga"),
104 GC_DATA_DIRECTORY("font0_mn.tga"),
105 GC_DATA_DIRECTORY("font0_cln.tga"),
106 GC_DATA_DIRECTORY("font0_pe.tga"),
107 GC_DATA_DIRECTORY("font0_cma.tga"),
108 GC_DATA_DIRECTORY("font0_ep.tga"),
109 GC_DATA_DIRECTORY("font0_at.tga"),
110 GC_DATA_DIRECTORY("font0_td.tga"),
111 GC_DATA_DIRECTORY("font0_pd.tga"),
112 GC_DATA_DIRECTORY("font0_ds.tga"),
113 GC_DATA_DIRECTORY("font0_ps.tga"),
114 GC_DATA_DIRECTORY("font0_and.tga"),
115 GC_DATA_DIRECTORY("font0_pl.tga"),
116 GC_DATA_DIRECTORY("font0_pr.tga"),
117 GC_DATA_DIRECTORY("font0_sl.tga"),
118 GC_DATA_DIRECTORY("font0_lt.tga"),
119 GC_DATA_DIRECTORY("font0_gt.tga"),
120 GC_DATA_DIRECTORY("font0_qm.tga"),
121 GC_DATA_DIRECTORY("font0_eq.tga"),
122 GC_DATA_DIRECTORY("font0_pu.tga"),
123 GC_DATA_DIRECTORY("font0_br.tga"),
124 GC_DATA_DIRECTORY("font0_za.tga"),
125 GC_DATA_DIRECTORY("font0_zb.tga"),
126 GC_DATA_DIRECTORY("font0_zc.tga"),
127 GC_DATA_DIRECTORY("font0_zd.tga") } };
129 const char String::letter_mapping[DC_LETTER_NUMBER]
130 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
132 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
133 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
134 'U', 'V', 'W', 'X', 'Y', 'Z',
136 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
137 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
138 'u', 'v', 'w', 'x', 'y', 'z',
140 '-', ':', '.', ',', '!', '@', '~', '#', '$', '%',
141 '&', '(', ')', '/', '<', '>', '?', '=', '+', '|',
142 ';', '[', '*', ']' };
144 const int String::letter_widths[DC_FONT_NUMBER][DC_LETTER_NUMBER]
145 = { { 20, 12, 17, 14, 16, 15, 16, 19, 17, 16,
147 28, 20, 17, 20, 18, 20, 20, 19, 11, 17,
148 19, 17, 30, 20, 20, 21, 22, 22, 16, 21,
149 20, 20, 30, 25, 22, 19,
151 19, 14, 13, 14, 13, 14, 15, 14, 8, 12,
152 14, 12, 22, 15, 14, 14, 16, 16, 12, 15,
153 14, 15, 22, 18, 17, 13,
155 20, 12, 11, 10, 11, 21, 23, 23, 18, 19,
156 20, 12, 13, 18, 16, 16, 17, 20, 23, 16,
157 22, 22, 16, 22 } };
160 const float String::colors[DC_FONT_COLOR_NUMBER][3]
161 = { { 0.2f, 0.2f, 1.0f },
162 { 1.0f, 0.1f, 0.1f },
163 { 0.1f, 1.0f, 0.1f },
164 { 0.8f, 0.8f, 0.1f },
165 { 0.9f, 0.0f, 0.9f },
166 { 0.1f, 0.8f, 0.8f },
167 { 0.9f, 0.3f, 0.1f },
168 { 1.0f, 0.5f, 0.5f },
169 { 0.4f, 0.0f, 1.0f },
170 { 0.1f, 0.1f, 0.1f } };
172 GLubyte *String::letter_textures[DC_FONT_NUMBER][DC_LETTER_NUMBER];
174 int String::mapCharToCode ( char c )
176 int code = -1;
177 for (int n = DC_LETTER_NUMBER; n--; )
178 if (c == letter_mapping[n]) {
179 code = n;
180 break;
182 return code;
185 int String::stringWidth ( const char *string, int max_width )
187 * Determines the pixel width of a string.
190 int length = 0;
192 int font = 0;
193 for (unsigned int n = 0; n < strlen(string) && length < max_width; n++) {
195 if (string[n] == '~') {
196 switch (string[++n]) {
197 case '<':
198 if (length >= DC_BACK_SPACE_WIDTH) length -= DC_BACK_SPACE_WIDTH;
199 break;
200 case '>':
201 length += DC_BACK_SPACE_WIDTH;
202 break;
203 default:
204 int c = string[n] - 'a';
205 if (c >= 0 && c < DC_FONT_NUMBER)
206 font = c;
207 break;
210 if (string[n] != '~') continue;
212 } else if (string[n] == ' ') {
213 length += DC_SPACE_WIDTH;
214 continue;
217 int code = mapCharToCode(string[n]);
218 if (code != -1) {
219 if (length + letter_widths[font][code] > max_width) break;
220 length += letter_widths[font][code];
224 return length;
227 void String::readyLetterTextures ( )
229 for (int n = DC_FONT_NUMBER; n--; )
230 for (int m = DC_LETTER_NUMBER; m--; )
231 letter_textures[n][m]
232 = TextureLoader::loadAlphaTGA(letter_texture_files[n][m],
233 DC_LETTER_TEX_LENGTH, DC_LETTER_TEX_LENGTH);
236 void String::freeLetterTextures ( )
238 for (int n = DC_FONT_NUMBER; n--; )
239 for (int m = DC_LETTER_NUMBER; m--; )
240 if (letter_textures[n][m] != null) {
241 delete [] letter_textures[n][m];
242 letter_textures[n][m] = null;
247 void String::fillStringTexture ( const char *string, GLubyte *texture,
248 int width, bool use_alpha, int texture_width )
250 * Fills the memory space pointed to by texture with a string texture. The
251 * texture height must equal DC_LETTER_TEX_LENGTH. readyLetterTextures() must
252 * be called first, and freeLetterTextures() must be called after this
253 * function's final use.
256 if (texture_width == 0)
257 texture_width = width;
259 // initialize texture
260 if (!use_alpha)
261 for (int t = DC_LETTER_TEX_LENGTH; t--; )
262 for (int s = width; s--; ) {
263 texture[(t * texture_width + s) * 4 + 0] = 0;
264 texture[(t * texture_width + s) * 4 + 1] = 0;
265 texture[(t * texture_width + s) * 4 + 2] = 0;
266 texture[(t * texture_width + s) * 4 + 3] = 255;
269 int cursor = 0;
270 int font = 0;
271 int base_color = DC_DEFAULT_FONT_COLOR;
272 for (unsigned int n = 0; n < strlen(string) && cursor < width; n++) {
274 // special cases
275 if (string[n] == '~') {
276 switch (string[++n]) {
277 case '<':
278 if (cursor > DC_BACK_SPACE_WIDTH)
279 cursor -= DC_BACK_SPACE_WIDTH;
280 else
281 cursor = 0;
282 break;
283 case '>':
284 cursor += DC_BACK_SPACE_WIDTH;
285 break;
286 default:
287 // color change
288 if (isdigit(string[n])) {
289 int c = string[n] - '0';
290 if (c < DC_FONT_COLOR_NUMBER)
291 base_color = c;
293 // font change
294 } else {
295 int c = string[n] - 'a';
296 if (c >= 0 && c < DC_FONT_NUMBER)
297 font = c;
299 break;
302 if (string[n] != '~') continue;
304 } else if (string[n] == ' ') {
305 cursor += DC_SPACE_WIDTH;
306 continue;
309 int code = mapCharToCode(string[n]);
310 if (code == -1) continue;
312 if (cursor + letter_widths[font][code] > width) break;
314 // copy letter
315 if (!use_alpha)
316 for (int t = DC_LETTER_TEX_LENGTH; t--; )
317 for (int s = DC_LETTER_TEX_LENGTH; s--; ) {
318 if (cursor + s >= width) continue;
320 float alpha = letter_textures[font][code][t * DC_LETTER_TEX_LENGTH
321 + s] * (1.0f / 255.0f);
322 for (int c = 3; c--; ) {
323 float color = colors[base_color][c] + (1.0f - colors[base_color][c])
324 * (DC_LETTER_TEX_LENGTH - t + (s >= letter_widths[font][code]
325 ? DC_LETTER_TEX_LENGTH : s + (DC_LETTER_TEX_LENGTH
326 - letter_widths[font][code])))
327 * (0.5f / (float) DC_LETTER_TEX_LENGTH);
328 float result = (255.0f * color * alpha)
329 + texture[(t * texture_width + cursor + s) * 4 + c];
330 if (result >= 255.0f)
331 texture[(t * texture_width + cursor + s) * 4 + c] = (GLubyte) 255;
332 else
333 texture[(t * texture_width + cursor + s) * 4 + c]
334 = (GLubyte) result;
338 else
339 for (int t = DC_LETTER_TEX_LENGTH; t--; )
340 for (int s = DC_LETTER_TEX_LENGTH; s--; ) {
341 if (cursor + s >= width)
342 continue;
343 if (letter_textures[font][code][t * DC_LETTER_TEX_LENGTH + s] == 0)
344 continue;
346 int old_alpha = texture[(t * texture_width + cursor + s) * 4 + 3];
347 int new_alpha = letter_textures[font][code][t * DC_LETTER_TEX_LENGTH
348 + s];
349 if (new_alpha + old_alpha >= 255)
350 texture[(t * texture_width + cursor + s) * 4 + 3] = 255;
351 else
352 texture[(t * texture_width + cursor + s) * 4 + 3]
353 = (GLubyte) (new_alpha + old_alpha);
355 for (int c = 3; c--; ) {
356 float color = colors[base_color][c] + (1.0f - colors[base_color][c])
357 * (DC_LETTER_TEX_LENGTH - t + (s >= letter_widths[font][code]
358 ? DC_LETTER_TEX_LENGTH : s + (DC_LETTER_TEX_LENGTH
359 - letter_widths[font][code])))
360 * (0.5f / (float) DC_LETTER_TEX_LENGTH);
361 float result = (255.0f * color) + (old_alpha * (1.0f / 255.0f))
362 * texture[(t * texture_width + cursor + s) * 4 + c];
363 if (result >= 255.0f)
364 texture[(t * texture_width + cursor + s) * 4 + c] = 255;
365 else
366 texture[(t * texture_width + cursor + s) * 4 + c]
367 = (GLubyte) result;
371 cursor += letter_widths[font][code];