source: git/trunk/src/fnt.cc @ 7bb8184

Last change on this file since 7bb8184 was 7bb8184, checked in by Olly Betts <olly@…>, 13 years ago

Retagging 1.2.0

git-svn-id: file:///home/survex-svn/survex/tags/1.2.0@3664 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 6.0 KB
Line 
1//
2//  fnt.cc
3//
4//  Draw text using texture mapped fonts.
5//
6//  Copyright (C) 2003,2004,2006,2010,2011 Olly Betts
7//
8//     Based on code from PLIB - http://plib.sourceforge.net
9//     Copyright (C) 1998,2002  Steve Baker
10//     Relicensed under the GNU GPL as permitted by the GNU LGPL
11//
12//  This program is free software; you can redistribute it and/or modify
13//  it under the terms of the GNU General Public License as published by
14//  the Free Software Foundation; either version 2 of the License, or
15//  (at your option) any later version.
16//
17//  This program is distributed in the hope that it will be useful,
18//  but WITHOUT ANY WARRANTY; without even the implied warranty of
19//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20//  GNU General Public License for more details.
21//
22//  You should have received a copy of the GNU General Public License
23//  along with this program; if not, write to the Free Software
24//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25//
26
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
31#include "fnt.h"
32
33#include <stdio.h>
34
35static bool isSwapped = false;
36
37inline unsigned char fnt_readByte(FILE *fd) {
38    return (unsigned char)GETC(fd);
39}
40
41inline unsigned short fnt_readShort(FILE *fd) {
42    unsigned short x;
43    if (isSwapped) {
44        x = GETC(fd) | (GETC(fd) << 8);
45    } else {
46        x = (GETC(fd) << 8) | GETC(fd);
47    }
48    return x;
49}
50
51inline unsigned int fnt_readInt(FILE *fd) {
52    unsigned int x;
53    if (isSwapped) {
54        x = GETC(fd) | (GETC(fd) << 8) | (GETC(fd) << 16) | (GETC(fd) << 24);
55    } else {
56        x = (GETC(fd) << 24) | (GETC(fd) << 16) | (GETC(fd) << 8) | GETC(fd);
57    }
58    return x;
59}
60
61#define FNT_BYTE_FORMAT         0
62#define FNT_BITMAP_FORMAT       1
63
64bool
65fntTexFont::load(const char *fname)
66{
67    FILE *fd;
68
69    if ((fd = fopen(fname, "rb")) == NULL) {
70        fprintf(stderr, "Failed to open '%s' for reading.\n", fname);
71        return false;
72    }
73
74    unsigned char magic[4];
75
76    if (fread(&magic, 4, 1, fd) != 1) {
77        fprintf(stderr, "'%s' an empty file!\n", fname);
78        return false;
79    }
80
81    if (memcmp(magic, "\xfftxf", 4) != 0) {
82        fprintf(stderr, "'%s' is not a 'txf' font file.\n", fname);
83        return false;
84    }
85
86    isSwapped = false;
87    int endianness = fnt_readInt(fd);
88
89    isSwapped = (endianness != 0x12345678);
90
91    int format      = fnt_readInt(fd);
92    int tex_width   = fnt_readInt(fd);
93    int tex_height  = fnt_readInt(fd);
94    fnt_size = fnt_readInt(fd);
95    fnt_size += fnt_size >> 2;
96    /* int unknown = */ fnt_readInt(fd);
97    int num_glyphs  = fnt_readInt(fd);
98    list_base = glGenLists(FNT_MAXCHAR - 32) - 32;
99
100    int i, j;
101
102    // Skip the glyph info first so we can set up the texture, then create
103    // display lists from it using the glyph info
104    int fpos = ftell(fd);
105    fseek(fd, num_glyphs * 12, SEEK_CUR);
106    // Load the image part of the file
107    int ntexels = tex_width * tex_height;
108
109    unsigned char *teximage = new unsigned char[ntexels];
110
111    switch (format) {
112        case FNT_BYTE_FORMAT: {
113            if ((int)fread(teximage, 1, ntexels, fd) != ntexels) {
114                delete [] teximage;
115                fprintf(stderr, "Premature EOF in '%s'.\n", fname);
116                return false;
117            }
118            break;
119        }
120
121        case FNT_BITMAP_FORMAT: {
122            int stride = (tex_width + 7) >> 3;
123
124            unsigned char *texbitmap = new unsigned char[stride * tex_height];
125
126            if ((int)fread(texbitmap, 1, stride * tex_height, fd)
127                    != stride * tex_height) {
128                delete [] texbitmap;
129                delete [] teximage;
130                fprintf(stderr, "Premature EOF in '%s'.\n", fname);
131                return false;
132            }
133
134            memset((void*)teximage, 0, ntexels);
135
136            for (i = 0; i < tex_height; ++i) {
137                for (j = 0; j < tex_width; ++j) {
138                    if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
139                        teximage[i * tex_width + j] = 0xff;
140                    }
141                }
142            }
143
144            delete [] texbitmap;
145            break;
146        }
147
148        default:
149            delete [] teximage;
150            fprintf(stderr, "Unrecognised format type in '%s'.\n", fname);
151            return false;
152    }
153    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
154
155    glGenTextures(1, & texture);
156    glBindTexture(GL_TEXTURE_2D, texture);
157
158    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
159
160    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
161    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
162    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0 /* Border */,
163                 GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid *)teximage);
164    delete [] teximage;
165
166    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
167    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
168
169    fseek(fd, fpos, SEEK_SET);
170
171    for (i = 0; i < FNT_MAXCHAR; ++i) widths[i] = -1;
172
173    // Load the glyph array
174
175    float W = 1.0f / (float)tex_width;
176    float H = 1.0f / (float)tex_height;
177    unsigned char max_w = 0;
178    for (i = 0; i < num_glyphs; ++i) {
179        unsigned short ch = fnt_readShort(fd);
180        unsigned char w = fnt_readByte(fd);
181        if (w > max_w) max_w = w;
182        unsigned char h = fnt_readByte(fd);
183        int vtx_left = (signed char)fnt_readByte(fd);
184        int vtx_bot = (signed char)fnt_readByte(fd);
185        signed char step = fnt_readByte(fd);
186        /* signed char unknown =*/ fnt_readByte(fd);
187        short x = fnt_readShort(fd);
188        short y = fnt_readShort(fd);
189
190        if (ch < 32 || ch >= FNT_MAXCHAR) continue;
191
192        float tex_left = x * W;
193        float tex_right = (x + w) * W;
194        float tex_bot = y * H;
195        float tex_top = (y + h) * H;
196        int vtx_right = vtx_left + w;
197        int vtx_top = vtx_bot + h;
198        glNewList(list_base + ch, GL_COMPILE);
199        if (w != 0 && h != 0) {
200            glBegin(GL_QUADS);
201            glTexCoord2f(tex_left, tex_bot);
202            glVertex2i(vtx_left, vtx_bot);
203            glTexCoord2f(tex_right, tex_bot);
204            glVertex2i(vtx_right, vtx_bot);
205            glTexCoord2f(tex_right, tex_top);
206            glVertex2i(vtx_right, vtx_top);
207            glTexCoord2f(tex_left, tex_top);
208            glVertex2i(vtx_left, vtx_top);
209            glEnd();
210        }
211        widths[ch] = step;
212        glTranslated(widths[ch], 0, 0);
213        glEndList();
214    }
215
216    if (widths[(int)' '] == -1) {
217        glNewList(list_base + ' ', GL_COMPILE);
218        widths[(int)' '] = widths[(int)'n'];
219        glTranslated(widths[(int)' '], 0, 0);
220        glEndList();
221    }
222
223    fclose(fd);
224    return true;
225}
Note: See TracBrowser for help on using the repository browser.