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