]> icculus.org git repositories - theoddone33/hheretic.git/blob - opengl/ogl_font.c
More 64bit fixes
[theoddone33/hheretic.git] / opengl / ogl_font.c
1 // OpenGL Font Renderer.
2 // The font must be small enough to fit one texture (not a problem with *real*
3 // graphics cars!).
4
5 #ifdef __WIN32__
6 #define WIN32_LEAN_AND_MEAN
7 #include <windows.h>
8 #include "tga.h"
9 #else
10 #define max(a,b) ((a) > (b) ? (a) : (b))
11 #endif
12
13 #include <GL/gl.h>
14 #include <stdlib.h>
15 #include "ogl_font.h"
16 #include <stdio.h>
17 #include <string.h> /* fix memmove warning */
18
19 static int              initOk = 0;
20 static int              numFonts;
21 static jfrfont_t *fonts;                // The list of fonts.
22 static int              current;                // Index of the current font.
23
24 extern int test3dfx;
25
26 // Returns zero if no errors.
27 int FR_Init()
28 {
29         if(initOk) return -1; // No reinitializations...
30         
31         numFonts = 0;
32         fonts = 0;                      // No fonts!
33         current = -1;
34         initOk = 1;
35         return 0;
36 }
37
38 // Destroys the font with the index.
39 static void FR_DestroyFontIdx(int idx)
40 {
41         jfrfont_t *font = fonts + idx;
42         
43         glDeleteTextures(1, &font->texture); 
44         memmove(fonts+idx, fonts+idx+1, sizeof(jfrfont_t)*(numFonts-idx-1));
45         numFonts--;
46         fonts = realloc(fonts, sizeof(jfrfont_t)*numFonts);
47         if(current == idx) current = -1;
48 }
49
50 void FR_Shutdown()
51 {
52         // Destroy all fonts.
53         while(numFonts) FR_DestroyFontIdx(0);
54         fonts = 0;
55         current = -1;
56         initOk = 0;
57 }
58
59 int FR_GetFontIdx(int id)
60 {
61         int i;
62         for(i=0; i<numFonts; i++)
63                 if(fonts[i].id == id) return i;
64         return -1;
65 }
66
67 jfrfont_t *FR_GetFont(int id)
68 {
69         int idx = FR_GetFontIdx(id);
70         if(idx == -1) return 0;
71         return fonts + idx;
72 }
73
74 /*
75 static int FR_GetMaxId()
76 {
77         int     i, grid=0;
78         for(i=0; i<numFonts; i++)
79                 if(fonts[i].id > grid) grid = fonts[i].id;
80         return grid;
81 }
82
83 static int findPow2(int num)
84 {
85         int cumul;
86         for(cumul=1; num > cumul; cumul *= 2);
87         return cumul;
88 }
89 */
90
91 #ifdef __WIN32__
92 // Prepare a GDI font. Select it as the current font.
93 int FR_PrepareGDIFont(HFONT hfont)
94 {
95         jfrfont_t       *font;
96         int                     i, x, y, maxh, bmpWidth=256, bmpHeight=0, imgWidth, imgHeight;
97         HDC                     hdc;
98         HBITMAP         hbmp;
99         unsigned int *image;
100
101         // Create a new font.
102         fonts = realloc(fonts, sizeof(jfrfont_t) * ++numFonts);
103         font = fonts + numFonts-1;
104         memset(font, 0, sizeof(jfrfont_t));
105         font->id = FR_GetMaxId() + 1;
106         current = numFonts - 1; 
107                 
108         // Now we'll create the actual data.
109         hdc = CreateCompatibleDC(NULL);
110         SetMapMode(hdc, MM_TEXT);
111         SelectObject(hdc, hfont);
112         // Let's first find out the sizes of all the characters.
113         // Then we can decide how large a texture we need.
114         for(i=0, x=0, y=0, maxh=0; i<256; i++)
115         {
116                 jfrchar_t *fc = font->chars + i;
117                 SIZE size;
118                 char ch[2] = { i, 0 };
119                 GetTextExtentPoint32(hdc, ch, 1, &size);
120                 fc->w = size.cx;
121                 fc->h = size.cy;
122                 maxh = max(maxh, fc->h);
123                 x += fc->w;
124                 if(x >= bmpWidth)       
125                 {
126                         x = 0;
127                         y += maxh;
128                         maxh = 0;
129                 }
130         }
131         bmpHeight = y + maxh;
132         hbmp = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
133         SelectObject(hdc, hbmp);
134         SetBkMode(hdc, OPAQUE);
135         SetBkColor(hdc, 0);
136         SetTextColor(hdc, 0xffffff);
137         // Print all the characters.
138         for(i=0, x=0, y=0, maxh=0; i<256; i++)
139         {
140                 jfrchar_t *fc = font->chars + i;
141                 char ch[2] = { i, 0 };
142                 if(x+fc->w >= bmpWidth)
143                 {
144                         x = 0;
145                         y += maxh;
146                         maxh = 0;
147                 }
148                 if(i) TextOut(hdc, x, y, ch, 1);
149                 fc->x = x;
150                 fc->y = y;
151                 maxh = max(maxh, fc->h);
152                 x += fc->w;
153         }
154         // Now we can make a version that OpenGL can read.      
155         imgWidth = findPow2(bmpWidth);
156         imgHeight = findPow2(bmpHeight);
157 //      printf( "font: %d x %d\n", imgWidth, imgHeight);
158         image = malloc(4*imgWidth*imgHeight);
159         memset(image, 0, 4*imgWidth*imgHeight);
160         for(y=0; y<bmpHeight; y++)
161                 for(x=0; x<bmpWidth; x++)
162                         if(GetPixel(hdc, x, y))
163                                 image[x + y*imgWidth] = 0xffffffff;
164
165         //if(test3dfx) saveTGA24_rgba8888("jhxfont.tga", bmpWidth, bmpHeight, (unsigned char*)image);
166
167         font->texWidth = imgWidth;
168         font->texHeight = imgHeight;
169
170         // Create the OpenGL texture.
171         glGenTextures(1, &font->texture);
172         glBindTexture(GL_TEXTURE_2D, font->texture);
173         glTexImage2D(GL_TEXTURE_2D, 0, 4, imgWidth, imgHeight, 0, GL_RGBA, 
174                 GL_UNSIGNED_BYTE, image);
175         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
176         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
177         
178         // We no longer need these.
179         free(image);
180         DeleteObject(hbmp);
181         DeleteDC(hdc);
182         return 0;
183 }
184 #else
185 int FR_PrepareGDIFont(void* hfont)
186 {
187         return 0;
188 }
189 #endif
190
191 // Change the current font.
192 void FR_SetFont(int id)
193 {
194         int idx = FR_GetFontIdx(id);    
195         if(idx == -1) return;   // No such font.
196         current = idx;
197 }
198
199 int FR_TextWidth(char *text)
200 {
201         int i, width = 0, len = strlen(text);
202         jfrfont_t *cf;
203
204         if(current == -1) return 0;
205         
206         // Just add them together.
207         for(cf=fonts+current, i=0; i<len; i++)
208                 width += cf->chars[(int)text[i]].w;
209         
210         return width;
211 }
212
213 int FR_TextHeight(char *text)
214 {
215         int i, height = 0, len;
216         jfrfont_t *cf;
217
218         if(current == -1 || !text) return 0;
219
220         // Find the greatest height.
221         for(len=strlen(text), cf=fonts+current, i=0; i<len; i++)
222                 height = max(height, cf->chars[(int)text[i]].h);
223
224         return height;
225 }
226
227 // (x,y) is the upper left corner. Returns the length.
228 int FR_TextOut(int x, int y, char *text)
229 {
230         int i, width=0, len;
231         jfrfont_t *cf;
232
233         if(!text) return 0;
234         len = strlen(text);
235
236         // Check the font.
237         if(current == -1) return 0;     // No selected font.
238         cf = fonts + current;
239
240         /*glMatrixMode(GL_TEXTURE);
241         glPushMatrix();
242         glLoadIdentity();
243         glScaled(1.0/cf->texWidth, 1.0/cf->texHeight, 1);*/
244
245         // Set the texture.
246         glBindTexture(GL_TEXTURE_2D, cf->texture);
247
248         // Print it.
249         glBegin(GL_QUADS);
250         for(i=0; i<len; i++)
251         {
252                 jfrchar_t *ch = cf->chars + text[i];
253                 float texw = (float)cf->texWidth, texh = (float)cf->texHeight;
254
255                 // Upper left.
256                 glTexCoord2f(ch->x/texw, ch->y/texh);
257                 glVertex2i(x, y);
258                 // Upper right.
259                 glTexCoord2f((ch->x+ch->w)/texw, ch->y/texh);
260                 glVertex2i(x+ch->w, y);
261                 // Lower right.
262                 glTexCoord2f((ch->x+ch->w)/texw, (ch->y+ch->h)/texh);
263                 glVertex2i(x+ch->w, y+ch->h);
264                 // Lower left.
265                 glTexCoord2f(ch->x/texw, (ch->y+ch->h)/texh);
266                 glVertex2i(x, y+ch->h);
267                 // Move on.
268                 width += ch->w;
269                 x += ch->w;
270         }
271         if(test3dfx)
272         {
273                 glTexCoord2f(0, 0);
274                 glVertex2f(320, 0);
275                 glTexCoord2f(1, 0);
276                 glVertex2f(640, 0);
277                 glTexCoord2f(1, 1);
278                 glVertex2f(640, 160);
279                 glTexCoord2f(0, 1);
280                 glVertex2f(320, 160);
281         }
282         glEnd();
283
284         //glPopMatrix();
285         return width;
286 }
287
288 int FR_GetCurrent()
289 {
290         if(current == -1) return 0;
291         return fonts[current].id;
292 }