BFont.c 6.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/***********************************************************/
/*                                                         */
/*   BFONT.c v. 1.0.3 - Billi Font Library by Diego Billi  */
/*   Heavily modified for FreedroidRPG needs over years    */
/*                                                         */
/***********************************************************/

#define _bfont_c

#include "system.h"
#include "defs.h"
#include "struct.h"
#include "proto.h"
#include "global.h"

16
extern int gl_max_texture_size;	//defined in open_gl.c
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

/**
 * Initialize a font.
 */
static void find_character_positions(BFont_Info *font, SDL_Rect char_rect[MAX_CHARS_IN_FONT])
{
	unsigned int x = 0, i = 0, y = 0, max_h = 1;
	SDL_Rect *rect;
	SDL_Surface *font_surf = font->font_image.surface;
	
	i = FIRST_FONT_CHAR;
	int sentry_horiz = SDL_MapRGB(font_surf->format, 255, 0, 255);
	int sentry_vert = SDL_MapRGB(font_surf->format, 0, 255, 0);

	if (SDL_MUSTLOCK(font_surf))
		SDL_LockSurface(font_surf);

	while (1) {
		if (i == MAX_CHARS_IN_FONT)
			break;

		// Read this line of characters
		while (x < font_surf->w - 1 && i < MAX_CHARS_IN_FONT) {
40
			if (sdl_get_pixel(font_surf, x, y) != sentry_horiz) {
41 42 43 44 45 46 47 48
				// Found a character
				rect = &char_rect[i];
				rect->x = x;
				rect->y = y;

				// Compute character width
				int x2 = x;
				while (x2 < font_surf->w) {
49
					if (sdl_get_pixel(font_surf, x2, y) == sentry_horiz)
50 51 52 53 54 55 56 57 58 59 60
						break;
					x2++;
				}
				rect->w = x2 - x;

				if (x2 == font_surf->w)
					break;

				// Compute character height
				int y2 = y;
				while (y2 < font_surf->h) {
61 62
					if (sdl_get_pixel(font_surf, x, y2) == sentry_horiz ||
							sdl_get_pixel(font_surf, x, y2) == sentry_vert)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
						break;
					y2++;
				}
				rect->h = y2 - y;

				// Update maximal h
				if (max_h < y2 - y)
					max_h = y2 - y;

				// Move on to the next character
				i++;
				x = x2;
			} else {
				// On a sentry? Move right.
				x++;
			}
		}

		// Find the next line of characters
		y += max_h + 1;
		max_h = 1;
		x = 0;

		if (y >= font_surf->h)
			break;	

	}

	if (SDL_MUSTLOCK(font_surf))
		SDL_UnlockSurface(font_surf);

	// Set "space" character width
	char_rect[' '].w = char_rect['!'].w;
	char_rect[' '].h = char_rect['!'].h;
	
	// We assume a constant font height
	font->h = char_rect['!'].h;
	font->number_of_chars = i;
}


/**	
 * Prepare font for rendering: create struct image for each character in the font.
 */
static void prepare_font(BFont_Info *font, SDL_Rect char_rect[MAX_CHARS_IN_FONT])
{
	int i;

111
#ifdef HAVE_LIBGL
112
	if (use_open_gl) {
113 114 115 116 117 118 119 120
		if (font->font_image.w > gl_max_texture_size || font->font_image.h > gl_max_texture_size) {
			error_message(__FUNCTION__,
			              "Your system only supports %dx%d textures. "
			              "A font image is %dx%d and therefore cannot be used as an OpenGL texture.",
			              NO_REPORT, gl_max_texture_size, gl_max_texture_size, font->font_image.w, font->font_image.h);
		} else {
			make_texture_out_of_surface(&font->font_image);
		}
121
	}
122
#endif
123 124 125 126 127 128 129 130 131 132 133

	// Create each char_image
	for (i = FIRST_FONT_CHAR; i < font->number_of_chars; i++) {
		struct image *img = &font->char_image[i];

		create_subimage(&font->font_image, img, &char_rect[i]);
	}
	
	// Space is a special case	
	create_subimage(&font->font_image, &font->char_image[' '], &char_rect[' ']);
	
134
	// Delete the now unneeded global bitmap
135 136 137 138 139 140
	free_image_surface(&font->font_image);
}

/**
 * Load the font and stores it in the BFont_Info structure 
 */
141
int load_bfont(const char *filepath, struct font *font)
142
{
143
	BFont_Info *bfont = MyMalloc(sizeof(BFont_Info));
144

145 146
	// Load the font_image->surface
	load_image_surface(&bfont->font_image, filepath, NO_MOD);
147 148 149 150

	// Find character coordinates in the image
	SDL_Rect char_rect[MAX_CHARS_IN_FONT];
	memset(char_rect, 0, sizeof(char_rect));
151
	find_character_positions(bfont, char_rect);
152 153

	// Prepare the data structures according to the rendering mode
154 155 156 157 158 159 160
	prepare_font(bfont, char_rect);

	// References the bfont data into the struct font
	font->bfont = bfont;
	font->height = bfont->h;

	return TRUE;
161 162
}

163
void free_bfont( struct font *font)
164
{
165
	int i;
166

167 168
	if (!font->bfont)
		return;
169

170 171 172 173
	for (i = FIRST_FONT_CHAR; i < font->bfont->number_of_chars; i++) {
		delete_image(&font->bfont->char_image[i]);
	}
	delete_image(&font->bfont->char_image[' ']);
174

175
	delete_image(&font->bfont->font_image);
176

177 178
	free(font->bfont);
	font->bfont = NULL;
179 180 181
}

/**
182
 * Return the width of specified character
183
 */
184
int font_char_width(struct font *font, unsigned char c)
185
{
186 187 188
	if (c < ' ' || c > font->bfont->number_of_chars - 1)
		c = '.';
	return font->bfont->char_image[c].w;
189 190 191 192 193
}

/**
 * Puts a single char on the surface with the specified font 
 */
194
int put_char(struct font *font, int x, int y, unsigned char c)
195
{
196 197 198 199 200 201 202 203
	SDL_Rect dest = {
		.w = font->bfont->char_image[' '].w,
		.h = font->bfont->h,
		.x = x,
		.y = y
	};

	if (c < ' ' || c > font->bfont->number_of_chars - 1)
204 205 206
		c = '.';

	if ((c != ' ') && (c != '\n')) {
207 208 209 210
		struct image *img = &font->bfont->char_image[c];
		SDL_Rect clipping_rect;
		SDL_GetClipRect(Screen, &clipping_rect);
		if ((dest.x >= clipping_rect.x) && (dest.x < clipping_rect.x + clipping_rect.w)) {
211 212 213 214
			display_image_on_screen(img, dest.x, dest.y, IMAGE_NO_TRANSFO);
		}
	}

215
	return font->bfont->char_image[c].w;
216 217 218
}

/**
219 220
 * Write a string on a surface using specified font, taking letter-spacing
 * into account.
221
 */
222
void put_string(struct font *font, int x, int y, const char *text)
223
{
224
	char *ptr = (char *)text;
225

226 227 228
	set_current_font(font);

#ifdef HAVE_LIBGL
229 230
	if (use_open_gl) {
		SDL_Rect clip_rect;
231
		SDL_GetClipRect(Screen, &clip_rect);
232 233
		set_gl_clip_rect(&clip_rect);
	}
234
#endif
235 236 237

	start_image_batch();

238 239 240 241 242 243 244 245
	int letter_spacing = get_letter_spacing(get_current_font());

	while (*ptr != '\0') {
		// handle_switch_font_char() can change the current font, so we need
		// to call get_current_font() at each step
		if (handle_switch_font_char(&ptr)) {
			letter_spacing = get_letter_spacing(get_current_font());
			continue;
246
		}
247 248
		x += put_char(get_current_font(), x, y, *ptr) + letter_spacing;
		ptr++;
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	}

	end_image_batch();

#ifdef HAVE_LIBGL
	if (use_open_gl) {
		unset_gl_clip_rect();
	}
#endif
}

/**
 * Calculate the width of a string using a certain font, taking letter-spacing
 * into account.
 */
264
int text_width(struct font *font, const char *text)
265
{
266 267
	char *ptr = (char *)text;
	int width = 0;
268
	int letter_spacing = get_letter_spacing(font);
269 270 271

	while (*ptr != '\0') {
		if (handle_switch_font_char(&ptr)) {
272
			letter_spacing = get_letter_spacing(font);
273 274 275 276
			continue;
		}
		width += font_char_width(font, *ptr) + letter_spacing;
		ptr++;
277 278 279 280 281 282 283 284
	}
	return width;
}

/**
 *
 *
 */
285
int limit_text_width(struct font *font, const char *text, int limit)
286
{
287 288
	char *ptr = (char *)text;
	int width = 0;
289
	int letter_spacing = get_letter_spacing(font);
290 291 292

	while (*ptr != '\0') {
		if (handle_switch_font_char(&ptr)) {
293 294 295
			letter_spacing = get_letter_spacing(font);
			continue;
		}
296 297
		width += font_char_width(font, *ptr) + letter_spacing;
		ptr++;
298
		if (width >= limit)
299
			return (ptr - text);
300 301 302 303 304
	}
	return -1;
}

#undef _bfont_c