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