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