JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
* Makefile: add DESTDIR and use GNU install dir names.
[vor.git] / font.c
1 //  Copyright (C) 2006 Jason Woofenden
2 //
3 //  This file is part of VoR.
4 //
5 //  VoR is free software; you can redistribute it and/or modify it
6 //  under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 2, or (at your option)
8 //  any later version.
9 //
10 //  VoR is distributed in the hope that it will be useful, but
11 //  WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with VoR; see the file COPYING.  If not, write to the
17 //  Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 //  MA 02111-1307, USA.
19
20 #include <stdlib.h>
21 #include <SDL.h>
22 #include <SDL_image.h>
23
24 #include "font.h"
25
26 font *cur_font;
27 extern SDL_Surface *surf_screen;
28
29 int font_height() {
30         return cur_font->bounds[0].h;
31 }
32
33 void font_set(font *to) {
34         cur_font = to;
35 }
36
37 // return true if column of pixels (pix points to the top one) is all black
38 int line_clear(unsigned char* pix, int height, int width) {
39         int i;
40         for(i = 0; i < height; ++i) {
41                 if(pix[0] != 0) {
42                         return 0;
43                 }
44                 pix += width;
45         }
46         
47         return 1;
48 }
49
50
51 // return the number of consecutive colums of pixels are still clear (or still not clear)
52 int find_change(unsigned char* pix, int height, int width) {
53         int i;
54         int state = line_clear(pix, height, width);
55         pix += 3;
56
57         for(i = 1; /*forever*/; pix += 3, ++i) {
58                 if(line_clear(pix, height, width) != state) {
59                         return i;
60                 }
61         }
62 }
63
64 void font_free(font* garbage) {
65         SDL_FreeSurface(garbage->pixels);
66         free(garbage);
67 }
68
69 font* font_load(const char *filename) {
70         font* new_font;
71         int i;
72         unsigned char* pix;
73         int x = 0;
74         int width;
75
76         new_font = (font*) malloc(sizeof(font));
77         if(!new_font) {
78                 fprintf(stderr, "couldn't allocate memory for font.\n");
79                 exit(1);
80         }
81         new_font->pixels = (SDL_Surface*)IMG_Load(filename);
82         if(!new_font->pixels) {
83                 fprintf(stderr, "couldn't load font file '%s'.\n", filename);
84                 exit(1);
85         }
86
87         //SDL_SetColorKey(new_font->pixels, SDL_SRCCOLORKEY, 0);
88
89         pix = new_font->pixels->pixels;
90
91         // set all font rects to be the full height
92         for(i = 0; i < 94; ++i) {
93                 new_font->bounds[i].y = 0;
94                 new_font->bounds[i].h = new_font->pixels->h;
95         }
96
97         // find the characters
98         new_font->bounds[0].x = 0; // the first character starts at the begining
99         for(i = 0; i < 93; ) {
100                 // find the end of the character
101                 width = find_change(pix, new_font->pixels->h, new_font->pixels->pitch);
102                 x += width;
103                 pix += width * new_font->pixels->format->BytesPerPixel;
104                 new_font->bounds[i].w = width;
105
106                 ++i;
107
108                 width = find_change(pix, new_font->pixels->h, new_font->pixels->pitch);
109                 x += width;
110                 pix += width * new_font->pixels->format->BytesPerPixel;
111                 new_font->bounds[i].x = x;
112         }
113         new_font->bounds[93].w = new_font->pixels->w - new_font->bounds[93].x; // the last character ends at the end
114
115         // There is a common problem where with some fonts there is a column of all
116         // black pixels between the parts of the double-quote, and this code thinks
117         // that it is two seperate characters. This code currently assumes that
118         // there is no such column. To change it so it assumes that the
119         // double-quote character looks like 2, change the loop above to start at
120         // zero, and uncomment the following indented stuff.
121
122                         //      // The above has 3 problems:
123                         //
124                         //      // 1) space is missing from the begining
125                         //      // 2) ! is first instead of seccond
126                         //      // 3) " is taking 2nd and 3rd position
127                         //
128                         //      // merge pieces of double-quote
129                         //      width = font_rects[2].x - font_rects[1].x;
130                         //      font_rects[2].w += width;
131                         //      font_rects[2].x = font_rects[1].x;
132                         //
133                         //      // move !
134                         //      font_rects[1].x = font_rects[0].x;
135                         //      font_rects[1].w = font_rects[0].w;
136
137
138         // the width of the space is set to half the space between the first two characters
139         width = new_font->bounds[1].x - (new_font->bounds[0].x + new_font->bounds[0].w);
140         new_font->space_width = width / 2;
141         new_font->letter_spacing = new_font->space_width / 4 ;
142         if(new_font->space_width < 2) {
143                 new_font->space_width = 2;
144         }
145         if(new_font->letter_spacing < 1) {
146                 new_font->letter_spacing = 1;
147         }
148
149         font_set(new_font);
150         return new_font;
151 }
152
153 void font_write(int x, int y, const char* message) {
154         SDL_Rect dest = {x, y, 0, font_height()};
155         char c;
156
157         if(message[0] == 0) {
158                 return;
159         }
160
161         for(c = *message++; c; c = *message++) {
162                 if(c > 31 && c < 127) {
163                         if(c == 32) {
164                                 dest.x += cur_font->space_width;
165                         } else {
166                                 c -= 33;
167                                 dest.w = cur_font->bounds[(int)c].w;
168                                 SDL_BlitSurface(cur_font->pixels, &(cur_font->bounds[(int)c]), surf_screen, &dest);
169                                 dest.x += dest.w;
170                         }
171                         dest.x += cur_font->letter_spacing;
172                 } else {
173                         fprintf(stderr, "tried to print unknown char: %d (0x%x)\n", c, c);
174                 }
175         }
176 }
177
178 // return the width in pixels of the string
179 int font_width(const char* message) {
180         int width = 0;
181         char c;
182
183         if(message[0] == 0) {
184                 return 0;
185         }
186
187         for(c = *message++; c; c = *message++) {
188                 if(c > 31 && c < 127) {
189                         if(c == 32) {
190                                 width += cur_font->space_width;
191                         } else {
192                                 c -= 33;
193                                 width += cur_font->bounds[(int)c].w;
194                         }
195                         width += cur_font->letter_spacing;
196                 } else {
197                         fprintf(stderr, "tried to print unknown char: %d (0x%x)\n", c, c);
198                 }
199         }
200
201         // don't count spacing after the last char
202         if(width) {
203                 width -= cur_font->letter_spacing;
204         }
205
206         return width;
207 }