4 static hashtable
<const char *, font
> fonts
;
5 static font
*fontdef
= NULL
;
9 void newfont(char *name
, char *tex
, int *defaultw
, int *defaulth
, int *offsetx
, int *offsety
, int *offsetw
, int *offseth
)
11 font
*f
= fonts
.access(name
);
14 name
= newstring(name
);
19 f
->tex
= textureload(tex
);
21 f
->defaultw
= *defaultw
;
22 f
->defaulth
= *defaulth
;
23 f
->offsetx
= *offsetx
;
24 f
->offsety
= *offsety
;
25 f
->offsetw
= *offsetw
;
26 f
->offseth
= *offseth
;
31 void fontchar(int *x
, int *y
, int *w
, int *h
)
35 font::charinfo
&c
= fontdef
->chars
.add();
38 c
.w
= *w
? *w
: fontdef
->defaultw
;
39 c
.h
= *h
? *h
: fontdef
->defaulth
;
42 COMMANDN(font
, newfont
, "ssiiiiii");
43 COMMAND(fontchar
, "iiii");
45 bool setfont(const char *name
)
47 font
*f
= fonts
.access(name
);
53 void gettextres(int &w
, int &h
)
55 if(w
< MINRESW
|| h
< MINRESH
)
57 if(MINRESW
> w
*MINRESH
/h
)
70 #define PIXELTAB (4*curfont->defaultw)
72 int text_width(const char *str
) { //@TODO deprecate in favour of text_bounds(..)
74 text_bounds(str
, width
, height
);
78 void draw_textf(const char *fstr
, int left
, int top
, ...)
80 s_sprintfdlv(str
, top
, fstr
);
81 draw_text(str
, left
, top
);
84 static int draw_char(int c
, int x
, int y
)
86 font::charinfo
&info
= curfont
->chars
[c
-33];
87 float tc_left
= (info
.x
+ curfont
->offsetx
) / float(curfont
->tex
->xs
);
88 float tc_top
= (info
.y
+ curfont
->offsety
) / float(curfont
->tex
->ys
);
89 float tc_right
= (info
.x
+ info
.w
+ curfont
->offsetw
) / float(curfont
->tex
->xs
);
90 float tc_bottom
= (info
.y
+ info
.h
+ curfont
->offseth
) / float(curfont
->tex
->ys
);
92 glTexCoord2f(tc_left
, tc_top
); glVertex2f(x
, y
);
93 glTexCoord2f(tc_right
, tc_top
); glVertex2f(x
+ info
.w
, y
);
94 glTexCoord2f(tc_right
, tc_bottom
); glVertex2f(x
+ info
.w
, y
+ info
.h
);
95 glTexCoord2f(tc_left
, tc_bottom
); glVertex2f(x
, y
+ info
.h
);
101 //stack[sp] is current color index
102 static void text_color(char c
, char *stack
, int size
, int &sp
, bvec color
, int a
)
104 if(c
=='s') // save color
107 if(sp
<size
-1) stack
[sp
++] = c
;
111 if(c
=='r') c
= stack
[(sp
> 0) ? --sp
: sp
]; // restore color
115 case '0': color
= bvec( 64, 255, 128); break; // green: player talk
116 case '1': color
= bvec( 96, 160, 255); break; // blue: "echo" command
117 case '2': color
= bvec(255, 192, 64); break; // yellow: gameplay messages
118 case '3': color
= bvec(255, 64, 64); break; // red: important errors
119 case '4': color
= bvec(128, 128, 128); break; // gray
120 case '5': color
= bvec(192, 64, 192); break; // magenta
121 case '6': color
= bvec(255, 128, 0); break; // orange
122 // white (provided color): everything else
124 glColor4ub(color
.x
, color
.y
, color
.z
, a
);
128 #define TEXTSKELETON \
131 for(i = 0; str[i]; i++)\
135 if(c=='\t') { x = ((x+PIXELTAB)/PIXELTAB)*PIXELTAB; TEXTWHITE(i) }\
136 else if(c==' ') { x += curfont->defaultw; TEXTWHITE(i) }\
137 else if(c=='\n') { TEXTLINE(i) x = 0; y += FONTH; }\
138 else if(c=='\f') { if(str[i+1]) { i++; TEXTCOLOR(i) }}\
139 else if(curfont->chars.inrange(c-33))\
144 int w = curfont->chars[c-33].w;\
145 for(; str[i+1]; i++)\
148 if(c=='\f') { if(str[i+2]) i++; continue; }\
150 if(!curfont->chars.inrange(c-33)) break;\
151 int cw = curfont->chars[c-33].w + 1;\
152 if(w + cw >= maxwidth) break;\
155 if(x + w >= maxwidth && j!=0) { TEXTLINE(j-1) x = 0; y += FONTH; }\
163 //all the chars are guaranteed to be either drawable or color commands
164 #define TEXTWORDSKELETON \
169 if(c=='\f') { if(str[j+1]) { j++; TEXTCOLOR(j) }}\
170 else { TEXTCHAR(j) }\
173 int text_visible(const char *str
, int hitx
, int hity
, int maxwidth
)
175 #define TEXTINDEX(idx)
176 #define TEXTWHITE(idx) if(y+FONTH > hity && x >= hitx) return idx;
177 #define TEXTLINE(idx) if(y+FONTH > hity) return idx;
178 #define TEXTCOLOR(idx)
179 #define TEXTCHAR(idx) x += curfont->chars[c-33].w+1; TEXTWHITE(idx)
180 #define TEXTWORD TEXTWORDSKELETON
191 //inverse of text_visible
192 void text_pos(const char *str
, int cursor
, int &cx
, int &cy
, int maxwidth
)
194 #define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; break; }
195 #define TEXTWHITE(idx)
196 #define TEXTLINE(idx)
197 #define TEXTCOLOR(idx)
198 #define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
199 #define TEXTWORD TEXTWORDSKELETON if(i >= cursor) break;
203 if(cx
== INT_MIN
) { cx
= x
; cy
= y
; }
212 void text_bounds(const char *str
, int &width
, int &height
, int maxwidth
)
214 #define TEXTINDEX(idx)
215 #define TEXTWHITE(idx)
216 #define TEXTLINE(idx) if(x > width) width = x;
217 #define TEXTCOLOR(idx)
218 #define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
219 #define TEXTWORD x += w + 1;
232 void draw_text(const char *str
, int left
, int top
, int r
, int g
, int b
, int a
, int cursor
, int maxwidth
)
234 #define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; }
235 #define TEXTWHITE(idx)
236 #define TEXTLINE(idx)
237 #define TEXTCOLOR(idx) text_color(str[idx], colorstack, sizeof(colorstack), colorpos, color, a);
238 #define TEXTCHAR(idx) x += draw_char(c, left+x, top+y)+1;
239 #define TEXTWORD TEXTWORDSKELETON
242 int colorpos
= 0, cx
= INT_MIN
, cy
= 0;
243 colorstack
[0] = 'c'; //indicate user color
244 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
245 glBindTexture(GL_TEXTURE_2D
, curfont
->tex
->id
);
247 glColor4ub(color
.x
, color
.y
, color
.z
, a
);
249 if(cursor
>= 0 && (totalmillis
/250)&1)
251 glColor4ub(r
, g
, b
, a
);
252 if(cx
== INT_MIN
) { cx
= x
; cy
= y
; }
253 if(maxwidth
!= -1 && cx
>= maxwidth
) { cx
= 0; cy
+= FONTH
; }
254 draw_char('_', left
+cx
, top
+cy
);
267 enumerate(fonts
, font
, f
,
268 if(!reloadtexture(*f
.tex
)) fatal("failed to reload font texture");