1 /*
2 * XPilotNG/SDL, an SDL/OpenGL XPilot client.
3 *
4 * Copyright (C) 2003-2004 Erik Andersson <deity_at_home.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 glfont: An example of using the SDL_ttf library with OpenGL.
23 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
24
25 This library is free software; you can redistribute it and/or
26 modify it under the terms of the GNU Library General Public
27 License as published by the Free Software Foundation; either
28 version 2 of the License, or (at your option) any later version.
29
30 This library is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 Library General Public License for more details.
34
35 You should have received a copy of the GNU Library General Public
36 License along with this library; if not, write to the Free
37 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38
39 The SDL_GL_* functions in this file are available in the public domain.
40
41 Sam Lantinga
42 slouken@libsdl.org
43 */
44
45 /* $Id: text.c,v 1.36 2005/09/08 11:09:05 maximan Exp $ */
46 /* modified for xpilot by Erik Andersson deity_at_home.se */
47
48 #ifdef _WINDOWS
49 # include <windows.h>
50 # define vsnprintf _vsnprintf
51 # ifndef GL_BGR
52 # define GL_BGR 0x80E0 /* OpenGL 1.2, for which I did not have headers */
53 # endif
54 #endif
55
56 #include "xpclient_sdl.h"
57
58 #include "text.h"
59
60 #define BUFSIZE 1024
61
62 float modelview_matrix[16];
63 int renderstyle;
64 enum rendertype rendertype;
65
66 void pushScreenCoordinateMatrix(void);
67 void pop_projection_matrix(void);
68 int next_p2 ( int a );
69 void print(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, int length, const char *text, bool onHUD);
70 int FTinit(font_data *font, const char * fontname, int ptsize);
71
next_p2(int a)72 int next_p2 ( int a )
73 {
74 int rval=1;
75 while(rval<a) rval<<=1;
76 return rval;
77 }
78
SDL_GL_LoadTexture(SDL_Surface * surface,texcoord_t * texcoord)79 GLuint SDL_GL_LoadTexture(SDL_Surface *surface, texcoord_t *texcoord)
80 {
81 GLuint texture;
82 int w, h;
83 SDL_Surface *image;
84 SDL_Rect area;
85 Uint32 saved_flags;
86 Uint8 saved_alpha;
87
88 /* Use the surface width and height expanded to powers of 2 */
89 w = next_p2(surface->w);
90 h = next_p2(surface->h);
91 texcoord->MinX = 0.0f; /* Min X */
92 texcoord->MinY = 0.0f; /* Min Y */
93 texcoord->MaxX = (GLfloat)surface->w / w; /* Max X */
94 texcoord->MaxY = (GLfloat)surface->h / h; /* Max Y */
95
96 image = SDL_CreateRGBSurface(
97 SDL_SWSURFACE,
98 w, h,
99 32,
100 RMASK,
101 GMASK,
102 BMASK,
103 AMASK
104 );
105 if ( image == NULL ) {
106 return 0;
107 }
108
109 /* Save the alpha blending attributes */
110 saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
111 saved_alpha = surface->format->alpha;
112 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
113 SDL_SetAlpha(surface, 0, 0);
114 }
115
116 /* Copy the surface into the GL texture image */
117 area.x = 0;
118 area.y = 0;
119 area.w = surface->w;
120 area.h = surface->h;
121 SDL_BlitSurface(surface, &area, image, &area);
122
123 /* Restore the alpha blending attributes */
124 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
125 SDL_SetAlpha(surface, saved_flags, saved_alpha);
126 }
127
128 /* Create an OpenGL texture for the image */
129 glGenTextures(1, &texture);
130 glBindTexture(GL_TEXTURE_2D, texture);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
133 glTexImage2D(GL_TEXTURE_2D,
134 0,
135 GL_RGBA,
136 w, h,
137 0,
138 GL_RGBA,
139 GL_UNSIGNED_BYTE,
140 image->pixels);
141 SDL_FreeSurface(image); /* No longer needed */
142
143 return texture;
144 }
145
FTinit(font_data * font,const char * fontname,int ptsize)146 int FTinit(font_data *font, const char * fontname, int ptsize)
147 {
148 int i;
149 SDL_Color white = { 0xFF, 0xFF, 0xFF, 0x00 };
150 SDL_Color black = { 0x00, 0x00, 0x00, 0 };
151 SDL_Color *forecol;
152 SDL_Color *backcol;
153 GLenum gl_error;
154 texcoord_t texcoords;
155 int minx = 0,miny = 0,maxx = 0,maxy = 0;
156
157 /* We might support changing theese later */
158 /* Look for special rendering types */
159 renderstyle = TTF_STYLE_NORMAL;
160 rendertype = RENDER_LATIN1;
161 /* Default is black and white */
162 forecol = &white;
163 backcol = &black;
164
165 /* Initialize the TTF library */
166 /*if ( TTF_Init() < 0 ) {
167 fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError());
168 return(2);
169 }*/
170 font->ttffont = TTF_OpenFont(fontname, ptsize);
171 if ( font->ttffont == NULL ) {
172 fprintf(stderr, "Couldn't load %d pt font from %s: %s\n", ptsize, fontname, SDL_GetError());
173 return(2);
174 }
175 TTF_SetFontStyle(font->ttffont, renderstyle);
176 font->list_base=glGenLists(next_p2(NUMCHARS));
177 /* Get the recommended spacing between lines of text for this font */
178 font->linespacing = TTF_FontLineSkip(font->ttffont);
179 font->h = ptsize;
180
181 for( i = 0; i < NUMCHARS; i++ ) {
182 SDL_Surface *glyph = NULL;
183 GLuint height = 0; /* kps - added default value */
184
185 forecol = &white;
186
187 glyph = TTF_RenderGlyph_Blended( font->ttffont, i, *forecol );
188 if(glyph) {
189 glGetError();
190 font->textures[i] = SDL_GL_LoadTexture(glyph, &texcoords);
191 if ( (gl_error = glGetError()) != GL_NO_ERROR )
192 printf("Warning: Couldn't create texture: 0x%x\n", gl_error);
193
194 font->W[i] = glyph->w;
195 height = glyph->h;
196 TTF_GlyphMetrics( font->ttffont, i, &minx,&maxx,&miny,&maxy,NULL);
197 }
198 SDL_FreeSurface(glyph);
199
200 glNewList(font->list_base+i,GL_COMPILE);
201
202 glBindTexture(GL_TEXTURE_2D, font->textures[i]);
203 glTranslatef(1,0,0);
204 glPushMatrix();
205 glBegin(GL_TRIANGLE_STRIP);
206 glTexCoord2f(texcoords.MinX, texcoords.MaxY);
207 glVertex2i(0 , miny);
208 glTexCoord2f(texcoords.MaxX, texcoords.MaxY);
209 glVertex2i(font->W[i] , miny);
210 glTexCoord2f(texcoords.MinX, texcoords.MinY);
211 glVertex2i(0 ,miny+height );
212 glTexCoord2f(texcoords.MaxX, texcoords.MinY);
213 glVertex2i(font->W[i] , miny+height);
214 glEnd();
215 glPopMatrix();
216 glTranslatef((font->W[i]>3)?font->W[i]:(font->W[i] = 3) + 1,0,0);
217 /*one would think this should be += 2... I guess they overlap or the edge
218 * isn't painted
219 */
220 font->W[i] += 1;
221
222 glEndList();
223 }
224
225 /*TTF_CloseFont(font->ttffont);*/
226 /*TTF_Quit();*/
227 return 0;
228 }
229
fontinit(font_data * ft_font,const char * fname,unsigned int size)230 int fontinit(font_data *ft_font, const char * fname, unsigned int size)
231 {
232 return FTinit(ft_font,fname,size);
233 }
234
fontclean(font_data * ft_font)235 void fontclean(font_data *ft_font)
236 {
237 if (ft_font == NULL) return;
238 glDeleteLists(ft_font->list_base,next_p2(NUMCHARS));
239 if (ft_font->textures != NULL) {
240 glDeleteTextures(NUMCHARS,ft_font->textures);
241 }
242 }
243
244 /* A fairly straight forward function that pushes
245 * a projection matrix that will make object world
246 * coordinates identical to window coordinates.
247 */
pushScreenCoordinateMatrix(void)248 void pushScreenCoordinateMatrix(void)
249 {
250 GLint viewport[4];
251 glPushAttrib(GL_TRANSFORM_BIT);
252 glGetIntegerv(GL_VIEWPORT, viewport);
253 glMatrixMode(GL_PROJECTION);
254 glPushMatrix();
255 glLoadIdentity();
256 gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
257 glPopAttrib();
258 }
259
260 /* Pops the projection matrix without changing the current
261 * MatrixMode.
262 */
pop_projection_matrix(void)263 void pop_projection_matrix(void)
264 {
265 glPushAttrib(GL_TRANSFORM_BIT);
266 glMatrixMode(GL_PROJECTION);
267 glPopMatrix();
268 glPopAttrib();
269 }
270
271
nprintsize(font_data * ft_font,int length,const char * fmt,...)272 fontbounds nprintsize(font_data *ft_font, int length, const char *fmt, ...)
273 {
274 int i=0,j,textlength;
275 float len;
276 fontbounds returnval;
277 int start,end,toklen;
278 char text[BUFSIZE]; /* Holds Our String */
279 va_list ap;
280
281 returnval.width=0.0;
282 returnval.height=0.0;
283
284 if (ft_font == NULL) return returnval;
285
286 if (fmt == NULL) /* If There's No Text */
287 *text=0; /* Do Nothing */
288 else {
289 va_start(ap, fmt); /* Parses The String For Variables */
290 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
291 va_end(ap); /* Results Are Stored In Text */
292 }
293 if (!(textlength = MIN((int)strlen(text),length))) {
294 return returnval;
295 }
296
297 start = 0;
298 for (;;) {
299
300 for (end=start;end<textlength;++end)
301 if (text[end] == '\n') {
302 break;
303 }
304
305 toklen = end - start;
306
307 len = 0.0;
308 for (j=start;j<=end-1;++j)
309 len = len + ft_font->W[(GLubyte)text[j]];
310
311 if (len > returnval.width)
312 returnval.width = len;
313
314 ++i;
315
316 if (end >= textlength - 1) break;
317
318 start = end + 1;
319 }
320 /* i should be atleast 1 if we get here...*/
321 returnval.height = ft_font->h + (i-1)*ft_font->linespacing;
322
323 return returnval;
324 }
325
printsize(font_data * ft_font,const char * fmt,...)326 fontbounds printsize(font_data *ft_font, const char *fmt, ...)
327 {
328 fontbounds returnval;
329 char text[BUFSIZE]; /* Holds Our String */
330 va_list ap; /* Pointer To List Of Arguments */
331
332 returnval.width=0.0;
333 returnval.height=0.0;
334
335 if (ft_font == NULL) return returnval;
336
337
338 if (fmt == NULL) /* If There's No Text */
339 *text=0; /* Do Nothing */
340 else {
341 va_start(ap, fmt); /* Parses The String For Variables */
342 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
343 va_end(ap); /* Results Are Stored In Text */
344 }
345 return nprintsize(ft_font, BUFSIZE, "%s", text);
346 }
347
render_text(font_data * ft_font,const char * text,string_tex_t * string_tex)348 bool render_text(font_data *ft_font, const char *text, string_tex_t *string_tex)
349 {
350 SDL_Color white = { 0xFF, 0xFF, 0xFF, 0x00 };
351 SDL_Color *forecol;
352 SDL_Surface *string_glyph = NULL;
353 SDL_Surface *glyph = NULL;
354 SDL_Rect src, dest;
355 GLenum gl_error;
356
357 if (!(ft_font)) return false;
358 if (!(ft_font->ttffont)) return false;
359 if (!(string_tex)) return false;
360 #if 0
361 if (!strlen(text)) return false; /* something is printing an empty string each frame */
362 #else
363 /* kps - fix for empty author field in cannon dodgers */
364 if (!strlen(text))
365 text = " ";
366 #endif
367
368 forecol = &white;
369
370 string_tex->font_height = ft_font->h;
371
372 string_glyph = TTF_RenderText_Blended( ft_font->ttffont, text, *forecol );
373
374 string_tex->tex_list = Arraylist_alloc(sizeof(tex_t));
375
376 string_tex->width = 0;
377 string_tex->height = string_glyph->h;
378
379 if (string_glyph) {
380 int i, num = 1 + string_glyph->w / 254;
381 string_tex->text = (char *)malloc(sizeof(char)*(strlen(text)+1));
382 sprintf(string_tex->text,"%s",text);
383 for( i=0 ; i<num ; ++i ) {
384 tex_t tex;
385
386 tex.texture = 0;
387 tex.texcoords.MinX = 0.0;
388 tex.texcoords.MaxX = 0.0;
389 tex.texcoords.MinY = 0.0;
390 tex.texcoords.MaxY = 0.0;
391 tex.width = 0;
392
393 src.x = i*254;
394 dest.x = 0;
395 src.y = dest.y = 0;
396 if (i==num-1)
397 dest.w = src.w = string_glyph->w - i*254;
398 else
399 dest.w = src.w = 254;
400 src.h = dest.h = string_glyph->h;
401
402 glyph = SDL_CreateRGBSurface(0,dest.w,dest.h,32,0,0,0,0);
403 SDL_SetColorKey(glyph, SDL_SRCCOLORKEY, 0x00000000);
404 SDL_BlitSurface(string_glyph,&src,glyph,&dest);
405
406 glGetError();
407 tex.texture = SDL_GL_LoadTexture(glyph,&(tex.texcoords));
408 if ( (gl_error = glGetError()) != GL_NO_ERROR )
409 printf("Warning: Couldn't create texture: 0x%x\n", gl_error);
410
411 tex.width = dest.w;
412 string_tex->width += dest.w;
413
414 SDL_FreeSurface(glyph);
415
416 Arraylist_add(string_tex->tex_list,&tex);
417 }
418 SDL_FreeSurface(string_glyph);
419 } else {
420 printf("TTF_RenderText_Blended failed for [%s]\n",text);
421 return false;
422 }
423 return true;
424 }
425
draw_text(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,const char * text,bool savetex,string_tex_t * string_tex,bool onHUD)426 bool draw_text(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, const char *text, bool savetex, string_tex_t *string_tex, bool onHUD)
427 {
428 return draw_text_fraq(ft_font, color, XALIGN, YALIGN, x, y, text, 0.0f, 1.0f, 0.0f, 1.0f, savetex, string_tex, onHUD);
429 }
430
draw_text_fraq(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,const char * text,float xstart,float xstop,float ystart,float ystop,bool savetex,string_tex_t * string_tex,bool onHUD)431 bool draw_text_fraq(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, const char *text
432 , float xstart
433 , float xstop
434 , float ystart
435 , float ystop
436 , bool savetex, string_tex_t *string_tex, bool onHUD)
437 {
438 bool remove_tex = false;
439 if (!(ft_font)) return false;
440 if (!(ft_font->ttffont)) return false;
441
442 if (!string_tex) {
443 remove_tex = true;
444 string_tex = XMALLOC(string_tex_t, 1);
445 }
446
447 if (render_text(ft_font,text,string_tex)) {
448 disp_text_fraq(string_tex, color, XALIGN, YALIGN, x, y, xstart, xstop, ystart, ystop, onHUD);
449 }
450
451 if (!savetex || remove_tex)
452 free_string_texture(string_tex);
453
454 return true;
455 }
456
disp_text(string_tex_t * string_tex,int color,int XALIGN,int YALIGN,int x,int y,bool onHUD)457 void disp_text(string_tex_t *string_tex, int color, int XALIGN, int YALIGN, int x, int y, bool onHUD)
458 {
459 disp_text_fraq(string_tex, color, XALIGN, YALIGN, x, y, 0.0f, 1.0f, 0.0f, 1.0f, onHUD);
460 }
461
disp_text_fraq(string_tex_t * string_tex,int color,int XALIGN,int YALIGN,int x,int y,float xstart,float xstop,float ystart,float ystop,bool onHUD)462 void disp_text_fraq(string_tex_t *string_tex, int color, int XALIGN, int YALIGN, int x, int y
463 , float xstart
464 , float xstop
465 , float ystart
466 , float ystop
467 , bool onHUD)
468 {
469 int i,num,xpos;
470
471 if (!(string_tex)) return;
472 set_alphacolor(color);
473
474 x -= (int)(string_tex->width/2.0f*XALIGN);
475 y += (int)(string_tex->height/2.0f*YALIGN - string_tex->height);
476
477 if (onHUD) pushScreenCoordinateMatrix();
478
479 xpos=x;
480 num = Arraylist_get_num_elements(string_tex->tex_list);
481 for (i=0;i<num;++i) {
482 tex_t tex = *((tex_t *)Arraylist_get(string_tex->tex_list,i));
483
484 glBindTexture(GL_TEXTURE_2D, tex.texture);
485
486 glEnable(GL_TEXTURE_2D);
487 glEnable(GL_BLEND);
488 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
489
490 glBegin(GL_TRIANGLE_STRIP);
491 glTexCoord2f( xstart*tex.texcoords.MaxX , ystop*tex.texcoords.MaxY );
492 glVertex2f( xpos + xstart*tex.width , y + ystart*string_tex->height );
493
494 glTexCoord2f( xstop*tex.texcoords.MaxX , ystop*tex.texcoords.MaxY );
495 glVertex2f( xpos + xstop*tex.width , y + ystart*string_tex->height );
496
497 glTexCoord2f( xstart*tex.texcoords.MaxX , ystart*tex.texcoords.MaxY );
498 glVertex2f( xpos + xstart*tex.width , y + ystop*string_tex->height );
499
500 glTexCoord2f( xstop*tex.texcoords.MaxX , ystart*tex.texcoords.MaxY );
501 glVertex2f( xpos + xstop*tex.width , y + ystop*string_tex->height );
502 glEnd();
503
504 glDisable(GL_TEXTURE_2D);
505
506 xpos += tex.width;
507 }
508
509 if (onHUD) pop_projection_matrix();
510 }
511
free_string_texture(string_tex_t * string_tex)512 void free_string_texture(string_tex_t *string_tex)
513 {
514 if (string_tex) {
515 if (string_tex->tex_list) {
516 int i,num = Arraylist_get_num_elements(string_tex->tex_list);
517 for (i=0;i<num;++i) {
518 tex_t tex;
519 tex = *((tex_t *)Arraylist_get(string_tex->tex_list,i));
520 glDeleteTextures(1,&(tex.texture));
521 }
522 Arraylist_free(string_tex->tex_list);
523 string_tex->tex_list = NULL;
524 }
525 XFREE(string_tex->text);
526 }
527 }
528
print(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,int length,const char * text,bool onHUD)529 void print(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, int length, const char *text, bool onHUD)
530 {
531 int i=0,j,textlength;
532 fontbounds returnval,dummy;
533 float xoff = 0.0,yoff = 0.0;
534 int start,end,toklen;
535 int X,Y;
536 GLuint font;
537
538 returnval.width = 0.0;
539 returnval.height = 0.0;
540
541 if (!(textlength = MIN(strlen(text),length))) return;
542
543 font=ft_font->list_base;
544
545 returnval = nprintsize(ft_font,length,"%s",text);
546
547 yoff = (returnval.height/2.0f)*((float)YALIGN) - ft_font->h;
548
549 glListBase(font);
550
551 if (onHUD) pushScreenCoordinateMatrix();
552
553 glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
554 glMatrixMode(GL_MODELVIEW);
555 glDisable(GL_LIGHTING);
556 glEnable(GL_TEXTURE_2D);
557 glDisable(GL_DEPTH_TEST);
558 glEnable(GL_BLEND);
559 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
560
561 glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);
562
563 /* This is where the text display actually happens.
564 * For each line of text we reset the modelview matrix
565 * so that the line's text will start in the correct position.
566 * Notice that we need to reset the matrix, rather than just translating
567 * down by h. This is because when each character is
568 * draw it modifies the current matrix so that the next character
569 * will be drawn immediatly after it.
570 */
571 /* make sure not to use mytok until we are done!!! */
572 start = 0;
573 for (;;) {
574
575 for (end=start;end<textlength;++end)
576 if (text[end] == '\n') {
577 break;
578 }
579
580 toklen = end - start;
581
582 dummy.width = 0.0;
583 for (j=start;j<=end-1;++j)
584 dummy.width = dummy.width + ft_font->W[(GLubyte)text[j]];
585
586 xoff = - (dummy.width/2.0f)*((float)XALIGN);
587
588 glPushMatrix();
589 glLoadIdentity();
590
591 X = (int)(x + xoff);
592 Y = (int)(y - ft_font->linespacing*i + yoff);
593
594 if (color) set_alphacolor(color);
595 if (onHUD) glTranslatef(X, Y, 0);
596 else glTranslatef(X * clData.scale,Y * clData.scale, 0);
597 glMultMatrixf(modelview_matrix);
598
599 glCallLists(toklen, GL_UNSIGNED_BYTE, (GLubyte *) &text[start]);
600
601 glPopMatrix();
602
603 ++i;
604
605 if (end >= textlength - 1) break;
606
607 start = end + 1;
608 }
609 glPopAttrib();
610
611 if (onHUD) pop_projection_matrix();
612
613 }
614
mapnprint(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,int length,const char * fmt,...)615 void mapnprint(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, int length, const char *fmt,...)
616 {
617 int textlength;
618
619 char text[BUFSIZE]; /* Holds Our String */
620 va_list ap; /* Pointer To List Of Arguments */
621
622 if (fmt == NULL) /* If There's No Text */
623 *text=0; /* Do Nothing */
624 else {
625 va_start(ap, fmt); /* Parses The String For Variables */
626 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
627 va_end(ap); /* Results Are Stored In Text */
628 }
629 if (!(textlength = MIN((int)strlen(text),length))) {
630 return;
631 }
632
633 if (ft_font == NULL) return;
634
635 print(ft_font, color, XALIGN, YALIGN, x, y, length, text, false);
636 }
637
HUDnprint(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,int length,const char * fmt,...)638 void HUDnprint(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, int length, const char *fmt, ...)
639 {
640 int textlength;
641
642 char text[BUFSIZE]; /* Holds Our String */
643 va_list ap; /* Pointer To List Of Arguments */
644
645 if (fmt == NULL) /* If There's No Text */
646 *text=0; /* Do Nothing */
647 else {
648 va_start(ap, fmt); /* Parses The String For Variables */
649 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
650 va_end(ap); /* Results Are Stored In Text */
651 }
652 if (!(textlength = MIN((int)strlen(text),length))) {
653 return;
654 }
655
656 if (ft_font == NULL) return;
657
658 print( ft_font, color, XALIGN, YALIGN, x, y, length, text, true);
659 }
660
mapprint(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,const char * fmt,...)661 void mapprint(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, const char *fmt,...)
662 {
663 unsigned int textlength;
664
665 char text[BUFSIZE]; /* Holds Our String */
666 va_list ap; /* Pointer To List Of Arguments */
667
668 if (fmt == NULL) /* If There's No Text */
669 *text=0; /* Do Nothing */
670 else {
671 va_start(ap, fmt); /* Parses The String For Variables */
672 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
673 va_end(ap); /* Results Are Stored In Text */
674 }
675 if (!(textlength = strlen(text))) {
676 return;
677 }
678
679 if (ft_font == NULL) return;
680
681 print(ft_font, color, XALIGN, YALIGN, x, y, BUFSIZE, text, false);
682 }
683
HUDprint(font_data * ft_font,int color,int XALIGN,int YALIGN,int x,int y,const char * fmt,...)684 void HUDprint(font_data *ft_font, int color, int XALIGN, int YALIGN, int x, int y, const char *fmt, ...)
685 {
686 unsigned int textlength;
687
688 char text[BUFSIZE]; /* Holds Our String */
689 va_list ap; /* Pointer To List Of Arguments */
690
691 if (fmt == NULL) /* If There's No Text */
692 *text=0; /* Do Nothing */
693 else {
694 va_start(ap, fmt); /* Parses The String For Variables */
695 vsnprintf(text, BUFSIZE, fmt, ap); /* And Converts Symbols To Actual Numbers */
696 va_end(ap); /* Results Are Stored In Text */
697 }
698 if (!(textlength = strlen(text))) {
699 return;
700 }
701
702 if (ft_font == NULL) return;
703
704 print( ft_font, color, XALIGN, YALIGN, x, y, BUFSIZE, text, true);
705 }
706