1
// rendertext.cpp: font rendering
8
static hashtable<const char *, font> fonts;
9
static font *fontdef = NULL;
13
void newfont(char *name, char *tex, char *defaultw, char *defaulth, char *offsetx, char *offsety, char *offsetw, char *offseth)
15
font *f = fonts.access(name);
18
name = newstring(name);
23
f->tex = textureload(tex);
25
f->defaultw = ATOI(defaultw);
26
f->defaulth = ATOI(defaulth);
27
f->offsetx = ATOI(offsetx);
28
f->offsety = ATOI(offsety);
29
f->offsetw = ATOI(offsetw);
30
f->offseth = ATOI(offseth);
35
void fontchar(int x, int y, int w, int h)
39
font::charinfo &c = fontdef->chars.add();
42
c.w = w ? w : fontdef->defaultw;
43
c.h = h ? h : fontdef->defaulth;
46
COMMANDN(font, newfont, ARG_8STR);
47
COMMANDN(fontchar, fontchar, ARG_4INT);
49
bool setfont(const char *name)
51
font *f = fonts.access(name);
57
int text_width(const char *str)
60
text_bounds(str, width, height);
64
void draw_textf(const char *fstr, int left, int top, ...)
66
s_sprintfdlv(str, top, fstr);
67
draw_text(str, left, top);
70
static int draw_char(int c, int x, int y)
72
font::charinfo &info = curfont->chars[c-33];
73
float tc_left = (info.x + curfont->offsetx) / float(curfont->tex->xs);
74
float tc_top = (info.y + curfont->offsety) / float(curfont->tex->ys);
75
float tc_right = (info.x + info.w + curfont->offsetw) / float(curfont->tex->xs);
76
float tc_bottom = (info.y + info.h + curfont->offseth) / float(curfont->tex->ys);
78
glTexCoord2f(tc_left, tc_top ); glVertex2f(x, y);
79
glTexCoord2f(tc_right, tc_top ); glVertex2f(x + info.w, y);
80
glTexCoord2f(tc_right, tc_bottom); glVertex2f(x + info.w, y + info.h);
81
glTexCoord2f(tc_left, tc_bottom); glVertex2f(x, y + info.h);
87
//stack[sp] is current color index
88
static void text_color(char c, char *stack, int size, int &sp, bvec color, int a)
90
if(c=='s') // save color
93
if(sp<size-1) stack[++sp] = c;
97
if(c=='r') c = stack[(sp > 0) ? --sp : sp]; // restore color
101
case '0': color = bvec(64, 255, 128); break; // green: player talk
102
case '1': color = bvec(96, 160, 255); break; // blue: team chat
103
case '2': color = bvec(255, 192, 64); break; // yellow: gameplay action messages, only actions done by players
104
case '3': color = bvec(255, 64, 64); break; // red: important errors and notes
105
case '4': color = bvec(128, 128, 128); break; // gray
106
case '5': color = bvec(255, 255, 255); break; // white
107
case '6': color = bvec(96, 48, 0); break; // dark brown
108
case '7': color = bvec(128, 48, 48); break; // dark red: dead admin
109
// white (provided color): everything else
111
glColor4ub(color.x, color.y, color.z, a);
115
static vector<int> *columns = NULL;
117
void text_startcolumns()
119
if(!columns) columns = new vector<int>;
122
void text_endcolumns()
127
#define TABALIGN(x) ((((x)+PIXELTAB)/PIXELTAB)*PIXELTAB)
129
#define TEXTGETCOLUMN \
130
if(columns && col<columns->length()) \
132
colx += (*columns)[col++]; \
135
else x = TABALIGN(x);
137
#define TEXTSETCOLUMN \
140
while(col>=columns->length()) columns->add(0); \
141
int w = TABALIGN(x) - colx; \
142
w = max(w, (*columns)[col]); \
143
(*columns)[col] = w; \
148
else x = TABALIGN(x);
151
#define TEXTSKELETON \
152
int y = 0, x = 0, col = 0, colx = 0;\
154
for(i = 0; str[i]; i++)\
158
if(c=='\t') { TEXTTAB(i); TEXTWHITE(i) }\
159
else if(c==' ') { x += curfont->defaultw; TEXTWHITE(i) }\
160
else if(c=='\n') { TEXTLINE(i) x = 0; y += FONTH; }\
161
else if(c=='\f') { if(str[i+1]) { i++; TEXTCOLOR(i) }}\
162
else if(curfont->chars.inrange(c-33))\
167
int w = curfont->chars[c-33].w;\
168
for(; str[i+1]; i++)\
171
if(c=='\f') { if(str[i+2]) i++; continue; }\
173
if(!curfont->chars.inrange(c-33)) break;\
174
int cw = curfont->chars[c-33].w + 1;\
175
if(w + cw >= maxwidth) break;\
178
if(x + w >= maxwidth && j!=0) { TEXTLINE(j-1) x = 0; y += FONTH; }\
186
//all the chars are guaranteed to be either drawable or color commands
187
#define TEXTWORDSKELETON \
192
if(c=='\f') { if(str[j+1]) { j++; TEXTCOLOR(j) }}\
193
else { TEXTCHAR(j) }\
196
int text_visible(const char *str, int hitx, int hity, int maxwidth)
198
#define TEXTINDEX(idx)
199
#define TEXTTAB(idx) TEXTGETCOLUMN
200
#define TEXTWHITE(idx) if(y+FONTH > hity && x >= hitx) return idx;
201
#define TEXTLINE(idx) if(y+FONTH > hity) return idx;
202
#define TEXTCOLOR(idx)
203
#define TEXTCHAR(idx) x += curfont->chars[c-33].w+1; TEXTWHITE(idx)
204
#define TEXTWORD TEXTWORDSKELETON
216
//inverse of text_visible
217
void text_pos(const char *str, int cursor, int &cx, int &cy, int maxwidth)
219
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; break; }
220
#define TEXTTAB(idx) TEXTGETCOLUMN
221
#define TEXTWHITE(idx)
222
#define TEXTLINE(idx)
223
#define TEXTCOLOR(idx)
224
#define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
225
#define TEXTWORD TEXTWORDSKELETON if(i >= cursor) break;
229
if(cx == INT_MIN) { cx = x; cy = y; }
239
void text_bounds(const char *str, int &width, int &height, int maxwidth)
241
#define TEXTINDEX(idx)
242
#define TEXTTAB(idx) TEXTSETCOLUMN
243
#define TEXTWHITE(idx)
244
#define TEXTLINE(idx) if(x > width) width = x;
245
#define TEXTCOLOR(idx)
246
#define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
247
#define TEXTWORD x += w + 1;
261
void draw_text(const char *str, int left, int top, int r, int g, int b, int a, int cursor, int maxwidth)
263
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; cc = str[idx]; }
264
#define TEXTTAB(idx) TEXTGETCOLUMN
265
#define TEXTWHITE(idx)
266
#define TEXTLINE(idx)
267
#define TEXTCOLOR(idx) text_color(str[idx], colorstack, sizeof(colorstack), colorpos, color, a);
268
#define TEXTCHAR(idx) x += draw_char(c, left+x, top+y)+1;
269
#define TEXTWORD TEXTWORDSKELETON
272
int colorpos = 0, cx = INT_MIN, cy = 0, cc = ' ';
273
colorstack[0] = 'c'; //indicate user color
274
glBlendFunc(GL_SRC_ALPHA, curfont->tex->bpp==32 ? GL_ONE_MINUS_SRC_ALPHA : GL_ONE);
275
glBindTexture(GL_TEXTURE_2D, curfont->tex->id);
277
glColor4ub(color.x, color.y, color.z, a);
282
if(cx == INT_MIN) { cx = x; cy = y; }
283
if(maxwidth != -1 && cx >= maxwidth) { cx = 0; cy += FONTH; }
284
int cw = curfont->chars.inrange(cc-33) ? curfont->chars[cc-33].w + 1 : curfont->defaultw;
285
rendercursor(left+cx, top+cy, cw);
298
enumerate(fonts, font, f,
299
if(!reloadtexture(*f.tex)) fatal("failed to reload font texture");