2.50:
[blender.git] / source / blender / blenkernel / intern / bmfont.c
1 /**
2  * bmfont.c
3  *
4  * 04-10-2000 frank
5  *
6  * $Id$
7  *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  *
24  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25  * All rights reserved.
26  *
27  * The Original Code is: all of this file.
28  *
29  * Contributor(s): none yet.
30  *
31  * ***** END GPL LICENSE BLOCK *****
32  *
33  */
34
35 /**
36  * Two external functions:
37  *
38  * void detectBitmapFont(ImBuf *ibuf)
39  *   detects if an image buffer contains a bitmap font. It makes the
40  *   specific bitmap data which is stored in the bitmap invisible to blender.
41  *
42  * void matrixGlyph(ImBuf * ibuf, unsigned short unicode, *float x 7)
43  *   returns all the information about the character (unicode) in the floats
44  *
45  * Room for improvement:
46  *   add kerning data in the bitmap
47  *   all calculations in matrixGlyph() are static and could be done during
48  *     initialization
49  */
50
51 #include <stdio.h>
52
53 #include "MEM_guardedalloc.h"
54 #include "BLI_blenlib.h"
55 #include "BKE_global.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "BKE_bmfont.h"
59 #include "BKE_bmfont_types.h"
60
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 void printfGlyph(bmGlyph * glyph)
66 {
67         printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode);
68         printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy);
69         printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey);
70         printf(" ofsx:  %3d ofsy:  %3d\n", glyph->ofsx, glyph->ofsy);
71         printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved);
72 }
73
74 #define MAX2(x,y)          ( (x)>(y) ? (x) : (y) )
75 #define MAX3(x,y,z)                MAX2( MAX2((x),(y)) , (z) )  
76
77 void calcAlpha(ImBuf * ibuf)
78 {
79         int i;
80         char * rect;
81         
82         if (ibuf) {
83                 rect = (char *) ibuf->rect;
84                 for (i = ibuf->x * ibuf->y ; i > 0 ; i--) {
85                         rect[3] = MAX3(rect[0], rect[1], rect[2]);
86                         rect += 4;
87                 }
88         }
89 }
90
91 void readBitmapFontVersion0(ImBuf * ibuf, unsigned char * rect, int step)
92 {
93         int glyphcount, bytes, i, index, linelength, ysize;
94         unsigned char * buffer;
95         bmFont * bmfont;
96         
97         linelength = ibuf->x * step;
98         
99         glyphcount = (rect[6 * step] << 8) | rect[7 * step];
100         bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont);
101         
102         ysize = (bytes + (ibuf->x - 1)) / ibuf->x;
103         
104         if (ysize < ibuf->y) {
105                 // we're first going to copy all data into a liniar buffer.
106                 // step can be 4 or 1 bytes, and the data is not sequential because
107                 // the bitmap was flipped vertically.
108                 
109                 buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer");
110                 
111                 index = 0;      
112                 for (i = 0; i < bytes; i++) {
113                         buffer[i] = rect[index];
114                         index += step;
115                         if (index >= linelength) {
116                                 // we've read one line, no skip to the line *before* that
117                                 rect -= linelength;
118                                 index -= linelength;
119                         }
120                 }
121                 
122                 // we're now going to endian convert the data
123                 
124                 bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont");
125                 index = 0;
126                 
127                 // first read the header
128                 bmfont->magic[0]    = buffer[index++];
129                 bmfont->magic[1]    = buffer[index++];
130                 bmfont->magic[2]    = buffer[index++];
131                 bmfont->magic[3]    = buffer[index++];
132                 bmfont->version     = (buffer[index] << 8) | buffer[index + 1]; index += 2;
133                 bmfont->glyphcount  = (buffer[index] << 8) | buffer[index + 1]; index += 2;
134                 bmfont->xsize       = (buffer[index] << 8) | buffer[index + 1]; index += 2;
135                 bmfont->ysize       = (buffer[index] << 8) | buffer[index + 1]; index += 2;
136                 
137                 for (i = 0; i < bmfont->glyphcount; i++) {
138                         bmfont->glyphs[i].unicode  = (buffer[index] << 8) | buffer[index + 1]; index += 2;
139                         bmfont->glyphs[i].locx     = (buffer[index] << 8) | buffer[index + 1]; index += 2;
140                         bmfont->glyphs[i].locy     = (buffer[index] << 8) | buffer[index + 1]; index += 2;
141                         bmfont->glyphs[i].ofsx     = buffer[index++];
142                         bmfont->glyphs[i].ofsy     = buffer[index++];
143                         bmfont->glyphs[i].sizex    = buffer[index++];
144                         bmfont->glyphs[i].sizey    = buffer[index++];
145                         bmfont->glyphs[i].advance  = buffer[index++];
146                         bmfont->glyphs[i].reserved = buffer[index++];
147                         if (G.f & G_DEBUG) {
148                                 printfGlyph(&bmfont->glyphs[i]);
149                         }
150                 }
151                 
152                 MEM_freeN(buffer);
153                 
154                 if (G.f & G_DEBUG) {
155                         printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize);
156                         printf("glyphcount = %d\n", glyphcount);
157                         printf("bytes = %d\n", bytes);
158                 }
159
160                 // we've read the data from the image. Now we're going
161                 // to crop the image vertically so only the bitmap data
162                 // remains visible
163                 
164                 ibuf->y -= ysize;
165                 ibuf->userdata = bmfont;
166                 ibuf->userflags |= IB_BITMAPFONT;
167
168                 if (ibuf->depth < 32) {
169                         // we're going to fake alpha here:
170                         calcAlpha(ibuf);
171                 }
172         } else {
173                 printf("readBitmapFontVersion0: corrupted bitmapfont\n");
174         }
175 }
176
177 void detectBitmapFont(ImBuf *ibuf)
178 {
179         unsigned char * rect;
180         unsigned short version;
181         int i;
182         
183         if (ibuf != NULL) {
184                 // bitmap must have an x size that is a power of two
185                 if (is_power_of_two(ibuf->x)) {
186                         rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1)));
187                         // printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]);
188                         if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') {
189                                 // printf("found 8bit font !\n");
190                                 // round y size down
191                                 // do the 8 bit font stuff. (not yet)
192                         } else {
193                                 // we try all 4 possible combinations
194                                 for (i = 0; i < 4; i++) {
195                                         if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') {
196                                                 // printf("found 24bit font !\n");
197                                                 // We're going to parse the file:
198                                                 
199                                                 version = (rect[16] << 8) | rect[20];
200                                                 
201                                                 if (version == 0) {
202                                                         readBitmapFontVersion0(ibuf, rect, 4);
203                                                 } else {
204                                                         printf("detectBitmapFont :Unsupported version %d\n", version);
205                                                 }
206                                                 
207                                                 // on succes ibuf->userdata points to the bitmapfont
208                                                 if (ibuf->userdata) {
209                                                         break;
210                                                 }
211                                         }
212                                         rect++;
213                                 }
214                         }
215                 }
216         }
217 }
218
219 int locateGlyph(bmFont *bmfont, unsigned short unicode)
220 {
221         int min, max, current = 0;
222         
223         if (bmfont) {
224                 min = 0;
225                 max = bmfont->glyphcount;
226                 while (1) {
227                         // look halfway for glyph
228                         current = (min + max) >> 1;
229
230                         if (bmfont->glyphs[current].unicode == unicode) {
231                                 break;
232                         } else if (bmfont->glyphs[current].unicode < unicode) {
233                                 // have to move up
234                                 min = current;
235                         } else {
236                                 // have to move down
237                                 max = current;
238                         }
239                         
240                         if (max - min <= 1) {
241                                 // unable to locate glyph
242                                 current = 0;
243                                 break;
244                         }
245                 }
246         }
247         
248         return(current);
249 }
250
251 void matrixGlyph(ImBuf * ibuf, unsigned short unicode,
252                 float *centerx, float *centery,
253                 float *sizex,   float *sizey,
254                 float *transx,  float *transy,
255                 float *movex,   float *movey,
256                 float *advance)
257 {
258         int index;
259         bmFont *bmfont;
260         
261         *centerx = *centery = 0.0;
262         *sizex = *sizey = 1.0;
263         *transx = *transy = 0.0;
264         *movex = *movey = 0.0;
265         *advance = 1.0;
266                 
267         if (ibuf) {
268                 bmfont = ibuf->userdata;
269                 if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) {
270                         index = locateGlyph(bmfont, unicode);
271                         if (index) {
272                                                                 
273                                 *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex);
274                                 *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey);
275
276                                 *transx = bmfont->glyphs[index].locx / (float) ibuf->x;
277                                 *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y;
278
279                                 *centerx = bmfont->glyphs[0].locx / (float) ibuf->x;
280                                 *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y;
281
282                                 // 2.0 units is the default size of an object
283                                 
284                                 *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey;
285                                 *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex;
286                                 
287                                 *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance;
288
289                                 // printfGlyph(&bmfont->glyphs[index]);
290                                 // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f \n", unicode, index, *sizex, *sizey, *transx, *transy, *advance);
291                         }
292                 }
293         }
294 }