source: git/src/fnt.cc @ eaaa55b

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since eaaa55b was eaaa55b, checked in by Olly Betts <olly@…>, 14 years ago

Make the map array static const

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@3361 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 6.4 KB
Line 
1//
2//  fnt.cc
3//
4//  Draw text using texture mapped fonts.
5//
6//  Copyright (C) 2003,2004,2006 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25//
26
27#include "fnt.h"
28
29#include <stdio.h>
30
31static bool isSwapped = false;
32
33inline unsigned char fnt_readByte(FILE *fd) {
34    return (unsigned char)getc(fd);
35}
36
37inline unsigned short fnt_readShort(FILE *fd) {
38    unsigned short x;
39    if (isSwapped) {
40        x = getc(fd) | (getc(fd) << 8);
41    } else {
42        x = (getc(fd) << 8) | getc(fd);
43    }
44    return x;
45}
46
47inline unsigned int fnt_readInt(FILE *fd) {
48    unsigned int x;
49    if (isSwapped) {
50        x = getc(fd) | (getc(fd) << 8) | (getc(fd) << 16) | (getc(fd) << 24);
51    } else {
52        x = (getc(fd) << 24) | (getc(fd) << 16) | (getc(fd) << 8) | getc(fd);
53    }
54    return x;
55}
56
57#define FNT_BYTE_FORMAT         0
58#define FNT_BITMAP_FORMAT       1
59
60bool
61fntTexFont::load(const char *fname)
62{
63    FILE *fd;
64
65    if ((fd = fopen(fname, "rb")) == NULL) {
66        fprintf(stderr, "Failed to open '%s' for reading.\n", fname);
67        return false;
68    }
69
70    unsigned char magic[4];
71
72    if (fread(&magic, 4, 1, fd) != 1) {
73        fprintf(stderr, "'%s' an empty file!\n", fname);
74        return false;
75    }
76
77    if (memcmp(magic, "\xfftxf", 4) != 0) {
78        fprintf(stderr, "'%s' is not a 'txf' font file.\n", fname);
79        return false;
80    }
81
82    isSwapped = false;
83    int endianness = fnt_readInt(fd);
84
85    isSwapped = (endianness != 0x12345678);
86
87    int format      = fnt_readInt(fd);
88    int tex_width   = fnt_readInt(fd);
89    int tex_height  = fnt_readInt(fd);
90    /* int max_height = */ fnt_readInt(fd);
91    /* int unknown = */ fnt_readInt(fd);
92    int num_glyphs  = fnt_readInt(fd);
93    list_base = glGenLists(256 - 32) - 32;
94
95    int i, j;
96
97    // Skip the glyph info first so we can set up the texture, then create
98    // display lists from it using the glyph info
99    int fpos = ftell(fd);
100    fseek(fd, num_glyphs * 12, SEEK_CUR);
101    // Load the image part of the file
102    int ntexels = tex_width * tex_height;
103
104    unsigned char *teximage = new unsigned char[ntexels];
105
106    switch (format) {
107        case FNT_BYTE_FORMAT: {
108            if ((int)fread(teximage, 1, ntexels, fd) != ntexels) {
109                delete [] teximage;
110                fprintf(stderr, "Premature EOF in '%s'.\n", fname);
111                return false;
112            }
113            break;
114        }
115
116        case FNT_BITMAP_FORMAT: {
117            int stride = (tex_width + 7) >> 3;
118
119            unsigned char *texbitmap = new unsigned char[stride * tex_height];
120
121            if ((int)fread(texbitmap, 1, stride * tex_height, fd)
122                    != stride * tex_height) {
123                delete [] texbitmap;
124                delete [] teximage;
125                fprintf(stderr, "Premature EOF in '%s'.\n", fname);
126                return false;
127            }
128
129            memset((void*)teximage, 0, ntexels);
130
131            for (i = 0; i < tex_height; ++i) {
132                for (j = 0; j < tex_width; ++j) {
133                    if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
134                        teximage[(i * tex_width + j)] = 1;
135                    }
136                }
137            }
138
139            delete [] texbitmap;
140            break;
141        }
142
143        default:
144            delete [] teximage;
145            fprintf(stderr, "Unrecognised format type in '%s'.\n", fname);
146            return false;
147    }
148    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
149
150    glGenTextures(1, & texture);
151    glBindTexture(GL_TEXTURE_2D, texture);
152
153    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
154
155    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
156    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
157    static const GLuint map[2] = { 0, 0xffffffff };
158    glPixelMapuiv(GL_PIXEL_MAP_I_TO_A, 2, map);
159    glPixelMapuiv(GL_PIXEL_MAP_I_TO_R, 2, map);
160    glPixelMapuiv(GL_PIXEL_MAP_I_TO_G, 2, map);
161    glPixelMapuiv(GL_PIXEL_MAP_I_TO_B, 2, map);
162    glTexImage2D(GL_TEXTURE_2D, 0, 4, tex_width, tex_height, 0 /* Border */,
163                 GL_COLOR_INDEX, 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    int u = 0, d = 0;
179    for (i = 0; i < num_glyphs; ++i) {
180        unsigned short ch = fnt_readShort(fd);
181        unsigned char w = fnt_readByte(fd);
182        if (w > max_w) max_w = w;
183        unsigned char h = fnt_readByte(fd);
184        int vtx_left = (signed char)fnt_readByte(fd);
185        // We can't handle lbearing and rbearing correctly so ignore them.
186        vtx_left = 0;
187        int vtx_bot = (signed char)fnt_readByte(fd);
188        /* signed char step =*/ fnt_readByte(fd);
189        /* signed char unknown =*/ fnt_readByte(fd);
190        short x = fnt_readShort(fd);
191        short y = fnt_readShort(fd);
192
193        if (ch < 32 || ch >= FNT_MAXCHAR) continue;
194
195        float tex_left = x * W;
196        float tex_right = (x + w) * W;
197        float tex_bot = y * H;
198        float tex_top = (y + h) * H;
199        int vtx_right = vtx_left + w;
200        int vtx_top = vtx_bot + h;
201        glNewList(list_base + ch, GL_COMPILE);
202        if (w != 0 && h != 0) {
203            glBegin(GL_QUADS);
204            glTexCoord2f(tex_left, tex_bot);
205            glVertex2i(vtx_left, vtx_bot);
206            glTexCoord2f(tex_right, tex_bot);
207            glVertex2i(vtx_right, vtx_bot);
208            glTexCoord2f(tex_right, tex_top);
209            glVertex2i(vtx_right, vtx_top);
210            glTexCoord2f(tex_left, tex_top);
211            glVertex2i(vtx_left, vtx_top);
212            glEnd();
213            widths[ch] = w + 1;
214        } else {
215            widths[ch] = fnt_size / 2;
216        }
217        glTranslated(widths[ch], 0, 0);
218        glEndList();
219        if (vtx_bot < d) d = vtx_bot;
220        if (vtx_top > u) u = vtx_top;
221    }
222    fnt_size = u - d;
223
224    if (widths[(int)' '] == -1) {
225        glNewList(list_base + ' ', GL_COMPILE);
226        widths[(int)' '] = widths[(int)'n'];
227        glTranslated(widths[(int)' '], 0, 0);
228        glEndList();
229    }
230
231    fclose(fd);
232    return true;
233}
Note: See TracBrowser for help on using the repository browser.