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