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))
17 #include <string.h> /* fix memmove warning */
19 static int initOk = 0;
21 static jfrfont_t *fonts; // The list of fonts.
22 static int current; // Index of the current font.
26 // Returns zero if no errors.
29 if(initOk) return -1; // No reinitializations...
32 fonts = 0; // No fonts!
38 // Destroys the font with the index.
39 static void FR_DestroyFontIdx(int idx)
41 jfrfont_t *font = fonts + idx;
43 glDeleteTextures(1, &font->texture);
44 memmove(fonts+idx, fonts+idx+1, sizeof(jfrfont_t)*(numFonts-idx-1));
46 fonts = realloc(fonts, sizeof(jfrfont_t)*numFonts);
47 if(current == idx) current = -1;
53 while(numFonts) FR_DestroyFontIdx(0);
59 int FR_GetFontIdx(int id)
62 for(i=0; i<numFonts; i++)
63 if(fonts[i].id == id) return i;
67 jfrfont_t *FR_GetFont(int id)
69 int idx = FR_GetFontIdx(id);
70 if(idx == -1) return 0;
75 static int FR_GetMaxId()
78 for(i=0; i<numFonts; i++)
79 if(fonts[i].id > grid) grid = fonts[i].id;
83 static int findPow2(int num)
86 for(cumul=1; num > cumul; cumul *= 2);
92 // Prepare a GDI font. Select it as the current font.
93 int FR_PrepareGDIFont(HFONT hfont)
96 int i, x, y, maxh, bmpWidth=256, bmpHeight=0, imgWidth, imgHeight;
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;
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++)
116 jfrchar_t *fc = font->chars + i;
118 char ch[2] = { i, 0 };
119 GetTextExtentPoint32(hdc, ch, 1, &size);
122 maxh = max(maxh, fc->h);
131 bmpHeight = y + maxh;
132 hbmp = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
133 SelectObject(hdc, hbmp);
134 SetBkMode(hdc, OPAQUE);
136 SetTextColor(hdc, 0xffffff);
137 // Print all the characters.
138 for(i=0, x=0, y=0, maxh=0; i<256; i++)
140 jfrchar_t *fc = font->chars + i;
141 char ch[2] = { i, 0 };
142 if(x+fc->w >= bmpWidth)
148 if(i) TextOut(hdc, x, y, ch, 1);
151 maxh = max(maxh, fc->h);
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;
165 //if(test3dfx) saveTGA24_rgba8888("jhxfont.tga", bmpWidth, bmpHeight, (unsigned char*)image);
167 font->texWidth = imgWidth;
168 font->texHeight = imgHeight;
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);
178 // We no longer need these.
185 int FR_PrepareGDIFont(void* hfont)
191 // Change the current font.
192 void FR_SetFont(int id)
194 int idx = FR_GetFontIdx(id);
195 if(idx == -1) return; // No such font.
199 int FR_TextWidth(char *text)
201 int i, width = 0, len = strlen(text);
204 if(current == -1) return 0;
206 // Just add them together.
207 for(cf=fonts+current, i=0; i<len; i++)
208 width += cf->chars[(int)text[i]].w;
213 int FR_TextHeight(char *text)
215 int i, height = 0, len;
218 if(current == -1 || !text) return 0;
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);
227 // (x,y) is the upper left corner. Returns the length.
228 int FR_TextOut(int x, int y, char *text)
237 if(current == -1) return 0; // No selected font.
238 cf = fonts + current;
240 /*glMatrixMode(GL_TEXTURE);
243 glScaled(1.0/cf->texWidth, 1.0/cf->texHeight, 1);*/
246 glBindTexture(GL_TEXTURE_2D, cf->texture);
252 jfrchar_t *ch = cf->chars + text[i];
253 float texw = (float)cf->texWidth, texh = (float)cf->texHeight;
256 glTexCoord2f(ch->x/texw, ch->y/texh);
259 glTexCoord2f((ch->x+ch->w)/texw, ch->y/texh);
260 glVertex2i(x+ch->w, y);
262 glTexCoord2f((ch->x+ch->w)/texw, (ch->y+ch->h)/texh);
263 glVertex2i(x+ch->w, y+ch->h);
265 glTexCoord2f(ch->x/texw, (ch->y+ch->h)/texh);
266 glVertex2i(x, y+ch->h);
278 glVertex2f(640, 160);
280 glVertex2f(320, 160);
290 if(current == -1) return 0;
291 return fonts[current].id;