Fixed a build problem.
[gljewel.git] / text.c
blob83f9824bb339435bbf0069ca62ac1c3fd33dca87
1 /**
2 * @file text.c
3 * @brief The text display module for gljewel
5 * Copyright 2001, 2008 David Ashley <dashxdr@gmail.com>
6 * Copyright 2008 Stephen M. Webb <stephen.webb@bregmasoft.ca>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of Version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "text.h"
23 #if defined(_WIN32) && !defined(__CYGWIN__)
24 # define WIN32_LEAN_AND_MEAN 1
25 # include <windows.h>
26 #endif
27 #include <errno.h>
28 #include <GL/gl.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/stat.h>
34 typedef unsigned int uint32;
36 /* Maps ASCII characters to indexes into font texture. */
37 static int lmap[128];
38 #define UNDEFINED_CHAR 0xff
40 void init_font_map()
42 static char *fontcharacters="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.!:>^@() +";
43 char *p;
44 int i = 0;
46 memset(lmap, UNDEFINED_CHAR, sizeof(lmap));
47 for (p = fontcharacters; *p; ++p)
49 lmap[*p] = i++;
53 static GLint fontlist;
55 /**
56 * A loaded image.
58 struct pic {
59 unsigned char *image;
60 int w,h;
63 #define MAXCHARS 128
64 static struct letter {
65 unsigned char px,py,sx,sy;
66 float advance;
67 } letters[MAXCHARS];
70 static unsigned int textures[10];
71 #define T_WIDTH 256
72 #define T_HEIGHT T_WIDTH
75 void drawstring(int align, char *fmt, ...)
77 int t;
78 char temp[128],*p;
79 float advance;
80 va_list ap;
82 va_start(ap, fmt);
83 vsprintf(temp,fmt,ap);
84 va_end(ap);
86 glEnable(GL_BLEND);
87 glDisable(GL_DEPTH_TEST);
88 glPushMatrix();
89 glEnable(GL_TEXTURE_2D);
90 glBindTexture(GL_TEXTURE_2D,textures[0]);
92 glNormal3f( 0.0, 0.0, 1.0);
94 if(align)
96 advance=0.0;
97 p=temp;
98 while(*p)
100 if((t=lmap[(int)*p++])!=-1)
101 advance+=letters[t].advance;
103 if(align==1) advance/=2.0;
104 glTranslatef(-advance,0.0, 0.0);
106 p=temp;
107 while(*p)
109 if((t=lmap[(int)*p++])!=-1)
110 glCallList(fontlist+t);
112 glDisable(GL_TEXTURE_2D);
113 glPopMatrix();
114 glDisable(GL_BLEND);
115 glEnable(GL_DEPTH_TEST);
119 static FILE* ppmh;
120 static int ppmin;
121 static unsigned char ppmbuff[2048],*ppmp;
124 static int ppmci()
126 if(ppmin==0)
128 ppmin=fread(ppmbuff,sizeof(char),sizeof(ppmbuff),ppmh);
129 ppmp=ppmbuff;
131 if(ppmin<=0) return -1;
132 --ppmin;
133 return *ppmp++;
137 static void ppmline(unsigned char *put)
139 int c;
140 while((c=ppmci())>=0)
141 if(c==0x0a) break;
142 else *put++=c;
143 *put=0;
147 * A PPM file consists of a sequence of one or more PPM images. There are no data, delimiters, or padding before, after, or between images.
149 * Each PPM image consists of the following:
151 * 1. A "magic number" for identifying the file type. A ppm image's magic
152 * number is the two characters "P6".
153 * 2. Whitespace (blanks, TABs, CRs, LFs).
154 * 3. A width, formatted as ASCII characters in decimal.
155 * 4. Whitespace.
156 * 5. A height, again in ASCII decimal.
157 * 6. Whitespace.
158 * 7. The maximum color value (Maxval), again in ASCII decimal. Must be less
159 * than 65536 and more than zero.
160 * 8. A single whitespace character (usually a newline).
161 * 9. A raster of Height rows, in order from top to bottom. Each row consists
162 * of Width pixels, in order from left to right. Each pixel is a triplet of
163 * red, green, and blue samples, in that order. Each sample is represented
164 * in pure binary by either 1 or 2 bytes. If the Maxval is less than 256,
165 * it is 1 byte. Otherwise, it is 2 bytes. The most significant byte is first.
167 * A row of an image is horizontal. A column is vertical. The pixels in the
168 * image are square and contiguous.
169 * 10. In the raster, the sample values are "nonlinear." They are proportional
170 * to the intensity of the ITU-R Recommendation BT.709 red, green, and blue
171 * in the pixel, adjusted by the BT.709 gamma transfer function. (That
172 * transfer function specifies a gamma number of 2.2 and has a linear
173 * section for small intensities). A value of Maxval for all three samples
174 * represents CIE D65 white and the most intense color in the color universe
175 * of which the image is part (the color universe is all the colors in all
176 * images to which this image might be compared).
178 * ITU-R Recommendation BT.709 is a renaming of the former CCIR Recommendation
179 * 709. When CCIR was absorbed into its parent organization, the ITU, ca. 2000,
180 * the standard was renamed. This document once referred to the standard as CIE
181 * Rec. 709, but it isn't clear now that CIE ever sponsored such a standard.
183 * Note that another popular color space is the newer sRGB. A common variation
184 * on PPM is to subsitute this color space for the one specified.
185 * 11. Note that a common variation on the PPM format is to have the sample values
186 * be "linear," i.e. as specified above except without the gamma adjustment.
187 * pnmgamma takes such a PPM variant as input and produces a true PPM as output.
188 * 12. Strings starting with "#" may be comments, the same as with PBM.
190 static int readppm(char *name,struct pic *pic)
192 unsigned char line[8192];
193 int w,h;
194 int i,j;
195 int maxval;
196 unsigned char *put;
198 ppmin=0;
199 ppmh=fopen(name,"r");
200 if(!ppmh)
202 fprintf(stderr, "error %d reading \"%s\": %s\n",
203 errno, name, strerror(errno));
204 return 0;
207 /* get magic */
208 ppmline(line);
209 if(strcmp((char *)line,"P6")) {fclose(ppmh);return 0;}
211 /* get width and height */
212 ppmline(line);
213 if(sscanf((char *)line,"%d %d",&w,&h)!=2) {fclose(ppmh);return 0;}
215 /* get max colour value */
216 ppmline(line);
217 if (sscanf(line, "%d", &maxval) != 1) {fclose(ppmh); return 0; }
218 if (maxval > 255)
220 fprintf(stderr, "max colour value %d out of range in PPM file \"%s\"\n",
221 maxval, name);
224 pic->w=w;
225 pic->h=h;
226 pic->image=put=malloc(w*h*3);
227 if(!put) {fclose(ppmh);return 0;}
230 /* load raster */
231 for(j=0;j<h;++j)
233 for(i=0;i<w;++i)
235 *put++=ppmci(); /* red */
236 *put++=ppmci(); /* green */
237 *put++=ppmci(); /* blue */
240 return 1;
243 static int loadfont(struct pic *pic)
245 struct stat sbuf;
246 char *fontfile = "data/bigfont.ppm";
247 if (stat(fontfile, &sbuf))
249 fontfile = DATA_DIR "/bigfont.ppm";
250 if (stat(fontfile, &sbuf))
252 return 0;
255 return readppm(fontfile,pic);
258 void initfont(void)
260 int i,j,k;
261 struct pic pic;
262 unsigned char keyr,keyg,keyb,*p;
263 unsigned char gapr,gapg,gapb,r,g,b;
264 int x,y,xp,yp;
265 int cw;
266 struct letter *l;
267 uint32 *tpixels;
268 int fontheight;
270 init_font_map();
271 fontlist = glGenLists(MAXCHARS);
273 tpixels=malloc(T_WIDTH*T_HEIGHT*4);
274 memset(tpixels,0,T_WIDTH*T_HEIGHT*4);
276 if(!loadfont(&pic)) return;
278 /* pick out colorkey value from font image */
279 p=pic.image+3*(pic.w*pic.h-1);
280 keyr=*p++;
281 keyg=*p++;
282 keyb=*p++;
284 p=pic.image+3*pic.w;
285 gapr=*p++;
286 gapg=*p++;
287 gapb=*p++;
288 i=pic.w-1;
289 k=0;
290 j=0;
291 l=letters;
292 while(i--)
294 r=*p++;
295 g=*p++;
296 b=*p++;
297 if(r!=gapr || g!=gapg || b!=gapb) {++j;continue;}
298 l++ ->sx=j;
299 ++k;
300 j=0;
302 l=letters;
303 fontheight=pic.h-2;
304 xp=yp=0;
305 j=1;
306 for(i=0;i<k;++i)
308 cw=l->sx;
309 if(xp+cw>T_WIDTH)
311 xp=0;
312 yp+=fontheight;
314 l->px=xp;
315 l->py=yp;
316 l->sy=fontheight;
317 ++l;
318 for(y=0;y<fontheight;++y)
320 uint32 *t;
322 t=tpixels+(yp+y)*T_WIDTH+xp;
323 p=pic.image+3*(pic.w*(y+1)+j);
324 for(x=0;x<cw;++x)
326 r=*p++;
327 g=*p++;
328 b=*p++;
329 if(r==keyr && g==keyg && b==keyb)
330 *t++=0;
331 else
332 *t++=r | (g<<8) | (b<<16) | (255<<24);
335 xp+=cw;
336 j+=cw+1;
339 glGenTextures( 1, textures );
340 glBindTexture( GL_TEXTURE_2D, textures[0] );
342 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
343 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
344 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
345 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
346 glTexImage2D( GL_TEXTURE_2D, 0, 4, T_WIDTH, T_HEIGHT, 0, GL_RGBA,
347 GL_UNSIGNED_BYTE, tpixels );
349 l=letters;
350 for(i=0;i<k;++i)
352 const float sizex=2.0f*FONTSIZE*l->sx;
353 const float sizey=FONTSIZE*l->sy;
354 const float sx=l->px/(float)T_WIDTH;
355 const float sy=l->py/(float)T_HEIGHT;
356 const float ex=(l->px+l->sx-1)/(float)T_WIDTH;
357 const float ey=(l->py+l->sy-1)/(float)T_HEIGHT;
359 glNewList(fontlist+i, GL_COMPILE);
361 /* row = (x, y, u, v) */
362 GLfloat v[] = {
363 0.0f, -sizey, sx, ey,
364 sizex, -sizey, ex, ey,
365 0.0f, sizey, sx, sy,
366 sizex, sizey, ex, sy
369 const GLsizei row_width = (2*2);
370 const GLsizei stride = (row_width * sizeof(GLfloat));
371 const GLsizei vertex_count = 4;
373 glEnableClientState(GL_VERTEX_ARRAY);
374 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
375 glVertexPointer(2, GL_FLOAT, stride, v);
376 glTexCoordPointer(2, GL_FLOAT, stride, v + 2);
377 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count);
378 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
379 glDisableClientState(GL_VERTEX_ARRAY);
381 l->advance=FONTSIZE*2+sizex;
382 glTranslatef(l->advance, 0.0f, 0.0f);
383 glEndList();
385 ++l;