]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/ttf2conchars/ttf2conchars.c
remove the debug code that now causes portals to crash
[divverent/nexuiz.git] / misc / ttf2conchars / ttf2conchars.c
1 #include <stdio.h>
2 #include <err.h>
3 #include <math.h>
4 #include "SDL/SDL.h" 
5 #include "SDL/SDL_ttf.h" 
6 #include "SDL/SDL_image.h" 
7
8 void Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
9 {
10     int y;
11     unsigned char *buffer, *out;
12     const unsigned char *in, *end;
13         FILE *f;
14
15     buffer = (unsigned char *)malloc(width*height*4 + 18);
16
17     memset (buffer, 0, 18);
18     buffer[2] = 2;      // uncompressed type
19     buffer[12] = (width >> 0) & 0xFF;
20     buffer[13] = (width >> 8) & 0xFF;
21     buffer[14] = (height >> 0) & 0xFF;
22     buffer[15] = (height >> 8) & 0xFF;
23
24     for (y = 3;y < width*height*4;y += 4)
25         if (data[y] < 255)
26             break;
27
28     if (y < width*height*4)
29     {   
30         // save the alpha channel
31         buffer[16] = 32;    // pixel size
32         buffer[17] = 8; // 8 bits of alpha
33
34         // flip upside down
35         out = buffer + 18;
36         for (y = height - 1;y >= 0;y--)
37         {   
38             memcpy(out, data + y * width * 4, width * 4);
39             out += width*4;
40         }
41     }
42     else
43     {   
44         // save only the color channels
45         buffer[16] = 24;    // pixel size
46         buffer[17] = 0; // 8 bits of alpha
47
48         // truncate bgra to bgr and flip upside down
49         out = buffer + 18;
50         for (y = height - 1;y >= 0;y--)
51         {
52             in = data + y * width * 4;
53             end = in + width * 4;
54             for (;in < end;in += 4)
55             {
56                 *out++ = in[0];
57                 *out++ = in[1];
58                 *out++ = in[2];
59             }
60         }
61     }
62
63         f = fopen(filename, "wb");
64         if(!f)
65                 err(1, "WriteTGA");
66         if(fwrite(buffer, out - buffer, 1, f) != 1)
67                 err(1, "WriteTGA");
68         if(fclose(f))
69                 err(1, "WriteTGA");
70
71     free(buffer);
72 }
73
74 /*
75  * Return the pixel value at (x, y)
76  * NOTE: The surface must be locked before calling this!
77  */
78 Uint32 getpixel(SDL_Surface *surface, int x, int y)
79 {
80     int bpp = surface->format->BytesPerPixel;
81     /* Here p is the address to the pixel we want to retrieve */
82     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
83
84     switch(bpp) {
85     case 1:
86         return *p;
87
88     case 2:
89         return *(Uint16 *)p;
90
91     case 3:
92         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
93             return p[0] << 16 | p[1] << 8 | p[2];
94         else
95             return p[0] | p[1] << 8 | p[2] << 16;
96
97     case 4:
98         return *(Uint32 *)p;
99
100     default:
101         return 0;       /* shouldn't happen, but avoids warnings */
102     }
103 }
104
105 /*
106  * Set the pixel at (x, y) to the given value
107  * NOTE: The surface must be locked before calling this!
108  */
109 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
110 {
111     int bpp = surface->format->BytesPerPixel;
112     /* Here p is the address to the pixel we want to set */
113     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
114
115     switch(bpp) {
116     case 1:
117         *p = pixel;
118         break;
119
120     case 2:
121         *(Uint16 *)p = pixel;
122         break;
123
124     case 3:
125         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
126             p[0] = (pixel >> 16) & 0xff;
127             p[1] = (pixel >> 8) & 0xff;
128             p[2] = pixel & 0xff;
129         } else {
130             p[0] = pixel & 0xff;
131             p[1] = (pixel >> 8) & 0xff;
132             p[2] = (pixel >> 16) & 0xff;
133         }
134         break;
135
136     case 4:
137         *(Uint32 *)p = pixel;
138         break;
139     }
140 }
141
142 #define MIN(a,b) (((a)<(b))?(a):(b))
143 #define MAX(a,b) (((a)>(b))?(a):(b))
144 #define BOUND(a,b,c) MAX(a,MIN(b,c))
145 #define BLURFUNC(d,A,B) A-B*(d)
146 #define BLURFUNCIMAX(A,B) ceil(sqrt((A)/(B)))
147
148 Uint32 getpixelfilter(SDL_Surface *src, SDL_PixelFormat *fmt, int x, int y, double A, double B, double C)
149 {
150         double r, g, b, a, f;
151         Uint8 pr, pg, pb, pa;
152         int i, j;
153         int imax = BLURFUNCIMAX(A,B);
154
155         // 1. calculate blackened blurred image
156         a = 0;
157         for(i=-imax; i<=imax; ++i)
158                 if(y+i >= 0 && y+i < src->h)
159                         for(j=-imax; j<=imax; ++j)
160                                 if(x+j >= 0 && x+j < src->w)
161                                 {
162                                         SDL_GetRGBA(getpixel(src, x+j, y+i), src->format, &pr, &pg, &pb, &pa);
163                                         f = BLURFUNC(i*i+j*j, A, B);
164                                         f = MAX(0, f);
165
166                                         if(C == 0)
167                                                 a = MAX(a, pa * f);
168                                         else
169                                                 a = a + pa * f;
170                                 }
171         a = MIN(a, 255);
172
173         if(C == 0)
174         {
175                 // 2. overlap it with the actual image again
176                 if(y >= 0 && y < src->h && x >= 0 && x < src->w)
177                 {
178                         SDL_GetRGBA(getpixel(src, x, y), src->format, &pr, &pg, &pb, &pa);
179
180                         f = a + pa - (a * pa) / 255L;
181
182                         r = pr * pa / f;
183                         g = pg * pa / f;
184                         b = pb * pa / f;
185
186                         a = f;
187                 }
188                 else
189                 {
190                         r = 0;
191                         g = 0;
192                         b = 0;
193                         a = a;
194                 }
195         }
196         else if(C > 0)
197                 r = g = b = MAX(0, 255 - C * (255 - a));
198         else if(C < 0)
199                 r = g = b = MAX(0, 255 + C * a);
200
201         return SDL_MapRGBA(fmt, r, g, b, a);
202 }
203
204 void blitfilter(SDL_Surface *src, SDL_Surface *dest, int x0, int y0, double A, double B, double C)
205 {
206         // note: x0, y0 is the origin of the UNFILTERED image; it is "transparently" expanded by a BLURFUNCIMAX.
207         int x, y, d;
208
209         d = BLURFUNCIMAX(A,B);
210         SDL_LockSurface(src);
211         SDL_LockSurface(dest);
212         for(y = -d; y < d + src->h; ++y)
213                 for(x = -d; x < d + src->w; ++x)
214                         putpixel(dest, x + x0, y + y0, getpixelfilter(src, dest->format, x, y, A, B, C));
215         SDL_UnlockSurface(dest);
216         SDL_UnlockSurface(src);
217 }
218
219 int mapFont(int d, char *c_)
220 {
221         unsigned char *c = (unsigned char *) c_;
222         if(!d)
223                 return ((*c >= 0x20 && *c <= 0x7E) || (*c >= 0xA0 && *c <= 0xFE)) ? 0 : -1;
224         if(*c >= 0x20 && *c <= 0x7E)
225                 return 0;
226         if(*c >= 0xA0 && *c <= 0xAF)
227         {
228                 *c &= 0x7F;
229                 return 1;
230         }
231         if(*c >= 0xB0 && *c <= 0xB9)
232         {
233                 *c &= 0x7F;
234                 return 2;
235         }
236         if(*c >= 0xBA && *c <= 0xDF)
237         {
238                 *c &= 0x7F;
239                 return 1; // cool
240         }
241         if(*c >= 0xE0 && *c <= 0xFE)
242         {
243                 *c &= 0x5F;
244                 return 2; // lcd
245         }
246         return -1;
247 }
248
249 /**
250  * @brief Blit a surface onto another and stretch it.
251  * With a 4.2 gcc you can use -fopenmp :)
252  * You might want to add some linear fading for scaling up?
253  *
254  * @param dst Destination surface
255  * @param src Source surface, if NULL, the destination surface is used
256  * @param drec The target area
257  * @param srec The source area, if NULL, then you suck :P
258  */
259 void StretchBlit(SDL_Surface *dst, SDL_Surface *src, SDL_Rect *drec, SDL_Rect *srec)
260 {
261         if(!src)
262                 src = dst;
263
264         unsigned int freeSource = 0;
265         if(src == dst) {
266                 // To avoid copying copied pixels, that would suck :)
267                 src = SDL_ConvertSurface(dst, dst->format, dst->flags);
268                 freeSource = 1;
269         }
270
271         if(!drec)
272                 drec = &dst->clip_rect;
273         if(!srec)
274                 srec = &src->clip_rect;
275
276         SDL_LockSurface(dst);
277         SDL_LockSurface(src);
278
279         double scaleX = (double)srec->w / (double)drec->w;
280         double scaleY = (double)srec->h / (double)drec->h;
281         
282         int x, y;
283
284         for(y = drec->y; y < (drec->y + drec->h); ++y)
285         {
286                 if(y >= dst->h)
287                         break;
288                 int dy = y - drec->y;
289                 for(x = drec->x; x < (drec->x + drec->w); ++x)
290                 {
291                         if(x >= dst->w)
292                                 break;
293                         // dx, dy relative to the drec start
294                         int dx = x - drec->x;
295
296                         double dfromX, dfromY, dtoX, dtoY;
297                         int fromX, fromY, toX, toY;
298                         // Get the pixel range which represents the current pixel
299                         // When scaling down this should be a rectangle :)
300                         // Otherwise it's just 1 pixel anyway, from==to then
301                         dfromX = dx * scaleX;
302                         dfromY = dy * scaleY;
303                         dtoX = (dx+1) * scaleX;
304                         dtoY = (dy+1) * scaleY;
305                         // The first and last one usually aren't 100% within this space
306                         fromX = (int)dfromX; dfromX = 1.0 - (dfromX - fromX); // invert the from percentage
307                         fromY = (int)dfromY; dfromY = 1.0 - (dfromY - fromY);
308                         toX = (int)dtoX; dtoX -= toX; // this one is ok
309                         toY = (int)dtoY; dtoY -= toY;
310                                                 
311                         /* Short explanation:
312                          * FROM is where to START, so when it's 5.7, then 30% of the 5th pixel is to be used
313                          * TO is where it ENDS, so if it's 8.4, then 40% of the 9th pixel is to be used!
314                          */
315                                                 
316                         // Now get all the pixels and merge them together...
317                         int i, j;
318                         unsigned int r, g, b, a, ar, ag, ab;
319                         unsigned int count = 0;
320                         r = g = b = a = ar = ag = ab = 0;
321                         /*if(drec->w > 1024)
322                           printf("%i %i - %f %f\n", fromX, toX, dfromX, dtoX);*/
323
324                         // when going from one to the next there's usually one
325                         // situation where the left pixel has a value of 0.1something and
326                         // the right one of 0
327                         // so adjust the values here
328                         // otherwise we get lines in the image with the original color
329                         // of the left pixel
330                         if(toX - fromX == 1 && drec->w > srec->w) {
331                                 dfromX = 1.0 - dtoX;
332                                 ++fromX;
333                         }
334                         if(fromX == toX) {
335                                 dfromX -= 0.5;
336                                 if(dfromX > 0.0) {
337                                         --fromX;
338                                         dtoX = 1.0-dfromX;
339                                 } else {
340                                         ++toX;
341                                         dtoX = -dfromX;
342                                         dfromX = 1.0-dtoX;
343                                 }
344                         }
345                         if(toY - fromY == 1 && drec->h > srec->h) {
346                                 dfromY = 1.0 - dtoY;
347                                 ++fromY;
348                         }
349                         if(fromY == toY) {
350                                 dfromY -= 0.5;
351                                 if(dfromY > 0.0) {
352                                         --fromY;
353                                         dtoY = 1.0-dfromY;
354                                 } else {
355                                         ++toY;
356                                         dtoY = -dfromY;
357                                         dfromY = 1.0-dtoY;
358                                 }
359                         }
360                         for(j = fromY; j <= toY; ++j)
361                         {
362                                 if(j < 0)
363                                         continue;
364                                 if((j+srec->y) >= src->h)
365                                         break;
366                                 for(i = fromX; i <= toX; ++i)
367                                 {
368                                         Uint8 pr, pg, pb, pa;
369                                         Uint16 par, pag, pab;
370                                         double inc = 1;
371                                         if(x < 0)
372                                                 continue;
373                                         if((i+srec->x) >= src->w)
374                                                 break;
375
376                                         SDL_GetRGBA(getpixel(src, i + srec->x, j + srec->y), src->format, &pr, &pg, &pb, &pa);
377                                         par = pa * (unsigned int)pr;
378                                         pag = pa * (unsigned int)pg;
379                                         pab = pa * (unsigned int)pb;
380
381                                         if(i == fromX)
382                                                 inc *= dfromX;
383                                         if(j == fromY)
384                                                 inc *= dfromY;
385                                         if(i == (toX))
386                                                 inc *= dtoX;
387                                         if(j == (toY))
388                                                 inc *= dtoY;
389
390                                         int iinc = inc * 256;
391
392                                         r += (pr * iinc);
393                                         g += (pg * iinc);
394                                         b += (pb * iinc);
395                                         ar += (par * iinc);
396                                         ag += (pag * iinc);
397                                         ab += (pab * iinc);
398                                         a += (pa * iinc);
399                                         //++count;
400                                         count += iinc;
401                                 }
402                         }
403                         //printf("COLOR VALUE: %i, %i, %i, %i \t COUNT: %f\n", r, g, b, a, count);
404                         if(a)
405                         {
406                                 r = ar / a;
407                                 g = ag / a;
408                                 b = ab / a;
409                                 a /= count;
410                         }
411                         else
412                         {
413                                 r /= count;
414                                 g /= count;
415                                 b /= count;
416                                 a /= count;
417                         }
418
419                         putpixel(dst, x, y, SDL_MapRGBA(dst->format, (Uint8)r, (Uint8)g, (Uint8)b, (Uint8)a));
420                 }
421         }
422         
423         SDL_UnlockSurface(dst);
424         SDL_UnlockSurface(src);
425
426         if(freeSource)
427                 SDL_FreeSurface(src);
428 }
429
430 void StretchDown(SDL_Surface *srfc, int x, int y, int w, int h, int wtarget)
431 {
432         // @"#$ SDL has no StretchBlit
433         // this one is slow, but at least I know how it works
434         int r, c;
435         unsigned int stretchedline[8 * wtarget]; // ra ga ba r g b a n
436         SDL_LockSurface(srfc);
437
438         for(r = y; r < y + h; ++r)
439         {
440                 // each input pixel is wtarget pixels "worth"
441                 //memset(stretchedline, sizeof(stretchedline), 0);
442                 memset(stretchedline, 0, sizeof(stretchedline));
443                 for(c = 0; c < w * wtarget; ++c)
444                 {
445                         Uint8 pr, pg, pb, pa;
446                         unsigned int *p = &stretchedline[8 * (c / w)];
447                         SDL_GetRGBA(getpixel(srfc, x + c / wtarget, r), srfc->format, &pr, &pg, &pb, &pa);
448                         p[0] += (unsigned int) pr * (unsigned int) pa;
449                         p[1] += (unsigned int) pg * (unsigned int) pa;
450                         p[2] += (unsigned int) pb * (unsigned int) pa;
451                         p[3] += (unsigned int) pr;
452                         p[4] += (unsigned int) pg;
453                         p[5] += (unsigned int) pb;
454                         p[6] += (unsigned int) pa;
455                         p[7] += 1;
456                 }
457                 for(c = 0; c < wtarget; ++c)
458                 {
459                         unsigned int *p = &stretchedline[8 * c];
460                         if(p[6])
461                                 putpixel(srfc, x + c, r, SDL_MapRGBA(srfc->format, p[0] / p[6], p[1] / p[6], p[2] / p[6], p[6] / p[7]));
462                         else
463                                 putpixel(srfc, x + c, r, SDL_MapRGBA(srfc->format, p[3] / p[7], p[4] / p[7], p[5] / p[7], p[6] / p[7]));
464                 }
465                 for(c = wtarget; c < w; ++c)
466                         putpixel(srfc, x + c, r, SDL_MapRGBA(srfc->format, 0, 0, 0, 0));
467         }
468
469         SDL_UnlockSurface(srfc);
470 }
471
472 int GetBoundingBox(SDL_Surface *surf, const SDL_Rect *inbox, SDL_Rect *outbox)
473 {
474         int bx = -1, by = -1; // start
475         //int bw = 0, bh = 0;
476         int ex = -1, ey = -1; // end
477         int cx, cy;
478         for(cx = inbox->x; cx < inbox->x + inbox->w; ++cx)
479         {
480                 for(cy = inbox->y; cy < inbox->y + inbox->h; ++cy)
481                 {
482                         Uint8 pr, pg, pb, pa;
483                         SDL_GetRGBA(getpixel(surf, cx, cy), surf->format, &pr, &pg, &pb, &pa);
484                         // include colors, or only care about pa?
485                         if(!pa)
486                                 continue;
487
488                         if(bx < 0) {
489                                 bx = ex = cx;
490                                 by = ey = cy;
491                                 continue;
492                         }
493                         
494                         if(cx < bx) // a pixel more on the left
495                                 bx = cx;
496                         /*if(cy < by) // a pixel more above... wait... this cannot happen actually
497                           by = cy;*/
498                         if(cx > ex) // a pixel on the right
499                                 ex = cx;
500                         if(cy > ey) // a pixel on the bottom :)
501                                 ey = cy;
502                 }
503         }
504
505         if(ex < 0)
506                 return 0;
507
508         outbox->x = bx;
509         outbox->y = by;
510         outbox->w = (ex - bx + 1);
511         outbox->h = (ey - by + 1);
512         return 1;
513 }
514
515 int main(int argc, char **argv)
516 {
517         SDL_Rect in, out;
518         SDL_Surface *conchars, *conchars0;
519         SDL_Surface *glyph;
520         TTF_Font *fonts[3];
521         SDL_Color white = {255, 255, 255, 255};
522         Uint32 transparent;
523         int maxAscent, maxDescent, maxWidth;
524         int i;
525         int currentSize;
526         int isfixed;
527
528         if(argc != 12)
529                 errx(1, "Usage: %s infile.tga topref bottomref cellheight outfile.tga font.ttf fontCOOL.ttf fontLCD.ttf blurA blurB blurColors\n", argv[0]);
530
531         const char *infilename = argv[1];
532         int referenceTop = atoi(argv[2]);
533         int referenceBottom = atoi(argv[3]);
534         int cell = atoi(argv[4]);
535         const char *outfilename = argv[5];
536         const char *font0 = argv[6];
537         const char *font1 = argv[7];
538         const char *font2 = argv[8];
539         double A = atof(argv[9]);
540         double B = atof(argv[10]);
541         double C = atof(argv[11]);
542         int differentFonts;
543
544         char widthfilename[512];
545         snprintf(widthfilename, sizeof(widthfilename), "%.*s.width", (int)strlen(outfilename) - 4, outfilename);
546
547         int border=BLURFUNCIMAX(A, B);
548
549         fprintf(stderr, "Using %d border pixels\n", border);
550
551         if(SDL_Init(0) < 0)
552                 errx(1, "SDL_Init failed");
553
554         if(TTF_Init() < 0)
555                 errx(1, "TTF_Init failed: %s", TTF_GetError());
556
557         conchars0 = IMG_Load(infilename);
558         if(!conchars0)
559                 errx(1, "IMG_Load failed: %s", IMG_GetError());
560
561         if(conchars0->w != conchars0->h)
562                 errx(1, "conchars aren't square");
563         if(conchars0->w % 16)
564                 errx(1, "conchars have bad width");
565         
566         conchars = SDL_CreateRGBSurface(SDL_SWSURFACE, cell * 16, cell * 16, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
567         in.x = in.y = out.x = out.y = 0;
568         in.w = in.h = conchars0->w;
569         out.w = out.h = cell * 16;
570         StretchBlit(conchars, conchars0, &out, &in);
571         SDL_FreeSurface(conchars0);
572
573         for(currentSize = cell * 2; currentSize; --currentSize)
574         {
575                 fonts[0] = TTF_OpenFont(font0, currentSize);
576                 if(!fonts[0])
577                         errx(1, "TTF_OpenFont %s failed: %s", font0, TTF_GetError());
578
579                 if(strcmp(font0, font1) || strcmp(font0, font2))
580                 {
581                         if(*font1)
582                         {
583                                 fonts[1] = TTF_OpenFont(font1, currentSize);
584                                 if(!fonts[1])
585                                         warnx("TTF_OpenFont %s failed: %s", font1, TTF_GetError());
586                         }
587                         else
588                                 fonts[1] = NULL;
589
590                         if(*font2)
591                         {
592                                 fonts[2] = TTF_OpenFont(font2, currentSize);
593                                 if(!fonts[2])
594                                         warnx("TTF_OpenFont %s failed: %s", font2, TTF_GetError());
595                         }
596                         else
597                                 fonts[2] = NULL;
598
599                         differentFonts = 1;
600                 }
601                 else
602                 {
603                         fonts[1] = fonts[2] = fonts[0];
604                         differentFonts = 0;
605                 }
606
607                 //maxAscent = MAX(MAX(TTF_FontAscent(fonts[0]), fonts[1] ? TTF_FontAscent(fonts[1]) : 0), fonts[2] ? TTF_FontAscent(fonts[2]) : 0);
608                 //maxDescent = -MIN(MIN(TTF_FontDescent(fonts[0]), fonts[1] ? TTF_FontDescent(fonts[1]) : 0), fonts[2] ? TTF_FontDescent(fonts[2]) : 0);
609                 maxAscent = 0;
610                 maxDescent = 0;
611                 maxWidth = 0;
612                 for(i = 0; i < 256; ++i)
613                 {
614                         char str[2]; str[0] = i; str[1] = 0;
615                         int fntid = mapFont(differentFonts, &str[0]);
616                         if(fntid < 0)
617                                 continue;
618                         if(!fonts[fntid])
619                                 continue;
620                         glyph = TTF_RenderText_Blended(fonts[fntid], str, white);
621                         if(!glyph)
622                                 errx(1, "TTF_RenderText_Blended %d failed: %s", i, TTF_GetError());
623                         if(fntid == 0)
624                                 maxWidth = MAX(maxWidth, glyph->w);
625
626                         in.x = 0;
627                         in.y = 0;
628                         in.w = glyph->w;
629                         in.h = glyph->h;
630                         if(GetBoundingBox(glyph, &in, &out))
631                         {
632                                 int baseline = TTF_FontAscent(fonts[fntid]);
633                                 int asc = baseline - out.y;
634                                 int desc = (out.y + out.h - 1) - baseline;
635                                 if(asc > maxAscent)
636                                         maxAscent = asc;
637                                 if(desc > maxDescent)
638                                         maxDescent = desc;
639                         }
640
641                         SDL_FreeSurface(glyph);
642                 }
643
644                 if(border + maxAscent + 1 + maxDescent + border <= cell)
645                         if(border + maxWidth + border <= cell)
646                                 break; // YEAH
647
648                 if(differentFonts)
649                 {
650                         TTF_CloseFont(fonts[2]);
651                         TTF_CloseFont(fonts[1]);
652                 }
653                 TTF_CloseFont(fonts[0]);
654         }
655         if(!currentSize)
656                 errx(1, "Sorry, no suitable size found.");
657         fprintf(stderr, "Using font size %d (%d + 1 + %d)\n", currentSize, maxAscent, maxDescent);
658
659         isfixed = TTF_FontFaceIsFixedWidth(fonts[0]);
660         if(getenv("FORCE_FIXED"))
661                 isfixed = 1;
662
663         // TODO convert conchars to BGRA (so the TGA writer can reliably use it)
664
665         transparent = SDL_MapRGBA(conchars->format, 255, 0, 255, 0);
666
667         FILE *widthfile = fopen(widthfilename, "w");
668         if(!widthfile)
669                 err(1, "fopen widthfile");
670         fprintf(widthfile, "extraspacing %f ", 0.0);
671
672         for(i = 0; i < 256; ++i)
673         {
674                 int w, h;
675                 int fntid;
676                 SDL_Rect dest;
677                 char str[2]; str[0] = i; str[1] = 0;
678
679                 if(!(i % 16))
680                         fprintf(widthfile, "\n");
681
682                 fntid = mapFont(differentFonts, &str[0]);
683                 if(fntid < 0 || !fonts[fntid])
684                 {
685                         SDL_Rect src, src2;
686                         src.x = cell * (i % 16);
687                         src.y = cell * (i / 16);
688                         src.w = cell;
689                         src.h = cell;
690                         src2.x = 0;
691                         src2.y = 0;
692                         src2.w = cell;
693                         src2.h = cell;
694                         glyph = SDL_CreateRGBSurface(SDL_SWSURFACE, cell, cell, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
695                         SDL_FillRect(glyph, &src2, transparent);
696
697                         // map:
698                         //   referenceTop    -> (cell - (maxAscent + 1 + maxDescent)) / 2
699                         //   referenceBottom -> (cell - (maxAscent + 1 + maxDescent)) / 2 + maxAscent
700
701                         int destTop = (cell - (maxAscent + 1 + maxDescent)) / 2;
702                         int destBottom = (cell - (maxAscent + 1 + maxDescent)) / 2 + maxAscent;
703
704                         // map is:
705                         //   x' = x / cell * h + y
706                         // solve:
707                         //   destTop = referenceTop / cell * h + y
708                         //   destBottom = referenceBottom / cell * h + y
709
710                         dest.x = 0;
711                         dest.y = (destBottom * referenceTop - destTop * referenceBottom) / (double) (referenceTop - referenceBottom);
712                         dest.h = cell * (destBottom - destTop) / (double) (referenceBottom - referenceTop);
713                         dest.w = dest.h;
714
715                         /*
716                         if(dest.y < 0)
717                                 dest.y = 0;
718                         if(dest.w > glyph->w)
719                                 dest.w = glyph->w;
720                         if(dest.y + dest.h > glyph->h)
721                                 dest.h = glyph->h - dest.y;
722                         */
723
724                         if(isfixed)
725                                 dest.w = border + maxWidth + border;
726                         StretchBlit(glyph, conchars, &dest, &src);
727                         //SDL_FillRect(conchars, &src, transparent);
728                         //SDL_BlitSurface(glyph, &src2, conchars, &src);
729                         StretchBlit(conchars, glyph, &src, &src2);
730                         SDL_FreeSurface(glyph);
731                         fprintf(widthfile, "%f ", dest.w / (double) cell);
732                         continue;
733                 }
734
735                 fprintf(stderr, "glyph %d...\n", i);
736
737                 glyph = TTF_RenderText_Blended(fonts[fntid], str, white);
738                 if(!glyph)
739                         errx(1, "TTF_RenderText_Blended %d failed: %s", i, TTF_GetError());
740
741                 w = border + glyph->w + border;
742                 h = border + glyph->h + border;
743                 if(w > cell)
744                         warnx("sorry, this font contains a character that is too wide... output will be borked");
745
746                 dest.x = cell * (i % 16);
747                 dest.y = cell * (i / 16);
748                 dest.w = cell;
749                 dest.h = cell;
750                 SDL_FillRect(conchars, &dest, transparent);
751
752                 dest.x += border + (isfixed ? ((border + maxWidth + border - w) / 2) : 0);
753                 dest.y += (cell - (maxAscent + 1 + maxDescent)) / 2 + (maxAscent - TTF_FontAscent(fonts[fntid]));
754                 blitfilter(glyph, conchars, dest.x, dest.y, A, B, C);
755
756                 SDL_FreeSurface(glyph);
757
758                 if(isfixed && w > border + maxWidth + border)
759                 {
760                         StretchDown(conchars, cell * (i % 16), cell * (i / 16), w, cell, border + maxWidth + border);
761                         fprintf(widthfile, "%f ", (border + maxWidth + border) / (double) cell);
762                 }
763                 else
764                         fprintf(widthfile, "%f ", (isfixed ? border + maxWidth + border : w) / (double) cell);
765         }
766
767         fprintf(widthfile, "\n");
768         fclose(widthfile);
769
770         fprintf(stderr, "Writing...\n");
771
772         Image_WriteTGABGRA(outfilename, conchars->w, conchars->h, conchars->pixels);
773
774         SDL_FreeSurface(conchars);
775
776         SDL_Quit();
777
778         return 0;
779 }