1 // OpenGL Font Renderer.
2 // The font must be small enough to fit one texture (not a problem with *real*
6 #define WIN32_LEAN_AND_MEAN
10 #define max(a,b) ((a) > (b) ? (a) : (b))
18 #include <string.h> /* fix memmove warning */
20 static int initOk = 0;
22 static jfrfont_t *fonts; // The list of fonts.
23 static int current; // Index of the current font.
27 // Returns zero if no errors.
30 if(initOk) return -1; // No reinitializations...
33 fonts = 0; // No fonts!
39 // Destroys the font with the index.
40 static void FR_DestroyFontIdx(int idx)
42 jfrfont_t *font = fonts + idx;
44 glDeleteTextures(1, &font->texture);
45 memmove(fonts+idx, fonts+idx+1, sizeof(jfrfont_t)*(numFonts-idx-1));
47 fonts = realloc(fonts, sizeof(jfrfont_t)*numFonts);
48 if(current == idx) current = -1;
54 while(numFonts) FR_DestroyFontIdx(0);
60 int FR_GetFontIdx(int id)
63 for(i=0; i<numFonts; i++)
64 if(fonts[i].id == id) return i;
68 jfrfont_t *FR_GetFont(int id)
70 int idx = FR_GetFontIdx(id);
71 if(idx == -1) return 0;
76 static int FR_GetMaxId()
79 for(i=0; i<numFonts; i++)
80 if(fonts[i].id > grid) grid = fonts[i].id;
84 static int findPow2(int num)
87 for(cumul=1; num > cumul; cumul *= 2);
93 // Prepare a GDI font. Select it as the current font.
94 int FR_PrepareGDIFont(HFONT hfont)
97 int i, x, y, maxh, bmpWidth=256, bmpHeight=0, imgWidth, imgHeight;
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;
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++)
117 jfrchar_t *fc = font->chars + i;
119 char ch[2] = { i, 0 };
120 GetTextExtentPoint32(hdc, ch, 1, &size);
123 maxh = max(maxh, fc->h);
132 bmpHeight = y + maxh;
133 hbmp = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
134 SelectObject(hdc, hbmp);
135 SetBkMode(hdc, OPAQUE);
137 SetTextColor(hdc, 0xffffff);
138 // Print all the characters.
139 for(i=0, x=0, y=0, maxh=0; i<256; i++)
141 jfrchar_t *fc = font->chars + i;
142 char ch[2] = { i, 0 };
143 if(x+fc->w >= bmpWidth)
149 if(i) TextOut(hdc, x, y, ch, 1);
152 maxh = max(maxh, fc->h);
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;
166 //if(test3dfx) saveTGA24_rgba8888("jhxfont.tga", bmpWidth, bmpHeight, (unsigned char*)image);
168 font->texWidth = imgWidth;
169 font->texHeight = imgHeight;
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);
179 // We no longer need these.
186 int FR_PrepareGDIFont(void* hfont)
192 // Change the current font.
193 void FR_SetFont(int id)
195 int idx = FR_GetFontIdx(id);
196 if(idx == -1) return; // No such font.
200 int FR_TextWidth(char *text)
202 int i, width = 0, len = strlen(text);
205 if(current == -1) return 0;
207 // Just add them together.
208 for(cf=fonts+current, i=0; i<len; i++)
209 width += cf->chars[(int)text[i]].w;
214 int FR_TextHeight(char *text)
216 int i, height = 0, len;
219 if(current == -1 || !text) return 0;
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);
228 // (x,y) is the upper left corner. Returns the length.
229 int FR_TextOut(int x, int y, char *text)
238 if(current == -1) return 0; // No selected font.
239 cf = fonts + current;
241 /*glMatrixMode(GL_TEXTURE);
244 glScaled(1.0/cf->texWidth, 1.0/cf->texHeight, 1);*/
247 glBindTexture(GL_TEXTURE_2D, cf->texture);
253 jfrchar_t *ch = cf->chars + text[i];
254 float texw = (float)cf->texWidth, texh = (float)cf->texHeight;
257 glTexCoord2f(ch->x/texw, ch->y/texh);
260 glTexCoord2f((ch->x+ch->w)/texw, ch->y/texh);
261 glVertex2i(x+ch->w, y);
263 glTexCoord2f((ch->x+ch->w)/texw, (ch->y+ch->h)/texh);
264 glVertex2i(x+ch->w, y+ch->h);
266 glTexCoord2f(ch->x/texw, (ch->y+ch->h)/texh);
267 glVertex2i(x, y+ch->h);
279 glVertex2f(640, 160);
281 glVertex2f(320, 160);
291 if(current == -1) return 0;
292 return fonts[current].id;