aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/font.c
diff options
context:
space:
mode:
authorJordi Vilalta Prat2009-02-15 06:10:59 +0000
committerJordi Vilalta Prat2009-02-15 06:10:59 +0000
commitfa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch)
treece87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/gfx/font.c
parent7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff)
downloadscummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz
scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2
scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/gfx/font.c')
-rw-r--r--engines/sci/gfx/font.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/engines/sci/gfx/font.c b/engines/sci/gfx/font.c
new file mode 100644
index 0000000000..c5de8715b8
--- /dev/null
+++ b/engines/sci/gfx/font.c
@@ -0,0 +1,385 @@
+/***************************************************************************
+ font.c Copyright (C) 2000 Christoph Reichenbach
+
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+
+ Please contact the maintainer for bug reports or inquiries.
+
+ Current Maintainer:
+
+ Christoph Reichenbach (CR) <jameson@linuxgames.com>
+
+***************************************************************************/
+
+
+#include <gfx_system.h>
+#include <gfx_resource.h>
+#include <gfx_tools.h>
+
+int font_counter = 0;
+
+void
+gfxr_free_font(gfx_bitmap_font_t *font)
+{
+ if (font->widths)
+ free(font->widths);
+
+ if (font->data)
+ free(font->data);
+
+ --font_counter;
+
+ free(font);
+}
+
+
+
+void
+scale_char(byte *dest, byte *src, int width, int height, int newwidth, int xfact, int yfact)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ int yc;
+ byte *bdest = dest;
+ byte *bsrc = src;
+
+ for (x = 0; x < width; x++) {
+ int xbitc;
+ int bits = 0;
+ int value = 0;
+
+ for (xbitc = 128; xbitc; xbitc >>= 1) {
+ int xc;
+
+ for (xc = 0; xc < xfact; xc++) {
+ if (*bsrc & xbitc)
+ value |= 1;
+ value <<= 1;
+
+ if (++bits == 8) {
+ *bdest++ = value;
+ bits = value = 0;
+ }
+ }
+ }
+ bsrc++;
+ }
+
+ src += width;
+ for (yc = 1; yc < yfact; yc++) {
+ memcpy(dest + newwidth, dest, newwidth);
+ dest += newwidth;
+ }
+ dest += newwidth;
+ }
+}
+
+gfx_bitmap_font_t *
+gfxr_scale_font_unfiltered(gfx_bitmap_font_t *orig_font, gfx_mode_t *mode)
+{
+ gfx_bitmap_font_t *font = (gfx_bitmap_font_t*)sci_malloc(sizeof(gfx_bitmap_font_t));
+ int height = orig_font->height * mode->yfact;
+ int width = 0;
+ int byte_width;
+ int i;
+
+ font->chars_nr = orig_font->chars_nr;
+ for (i = 0; i < font->chars_nr; i++)
+ if (orig_font->widths[i] > width)
+ width = orig_font->widths[i];
+
+ width *= mode->xfact;
+ byte_width = (width + 7) >> 3;
+ if (byte_width == 3)
+ byte_width = 4;
+ if (byte_width > 4)
+ byte_width = (byte_width + 3) & ~3;
+
+ font->row_size = byte_width;
+ font->height = height;
+ font->line_height = orig_font->line_height * mode->yfact;
+
+ font->widths = (int*)sci_malloc(sizeof(int) * orig_font->chars_nr);
+ font->char_size = byte_width * height;
+ font->data = (byte*)sci_malloc(font->chars_nr * font->char_size);
+
+ for (i = 0; i < font->chars_nr; i++) {
+ font->widths[i] = orig_font->widths[i] * mode->xfact;
+ scale_char(font->data + font->char_size * i,
+ orig_font->data + orig_font->char_size * i,
+ orig_font->row_size, orig_font->height,
+ font->row_size,
+ mode->xfact, mode->yfact);
+ }
+ return font;
+}
+
+
+gfx_bitmap_font_t *
+gfxr_scale_font(gfx_bitmap_font_t *orig_font, gfx_mode_t *mode, gfxr_font_scale_filter_t filter)
+{
+ GFXWARN("This function hasn't been tested yet!\n");
+
+ switch (filter) {
+
+ case GFXR_FONT_SCALE_FILTER_NONE:
+ return gfxr_scale_font_unfiltered(orig_font, mode);
+
+ default:
+ GFXERROR("Invalid font filter mode %d!\n", filter);
+ return NULL;
+ }
+}
+
+
+
+
+text_fragment_t *
+gfxr_font_calculate_size(gfx_bitmap_font_t *font, int max_width, const char *text,
+ int *width, int *height,
+ int *lines, int *line_height_p, int *last_offset_p,
+ int flags)
+{
+ int est_char_width = font->widths[(font->chars_nr > 'M')? 'M' : font->chars_nr - 1];
+ /* 'M' is typically among the widest chars */
+ int fragments_nr;
+ text_fragment_t *fragments;
+ int lineheight = font->line_height;
+ int maxheight = lineheight;
+ int last_breakpoint = 0;
+ int last_break_width = 0;
+ int max_allowed_width = max_width;
+ int maxwidth = 0, localmaxwidth = 0;
+ int current_fragment = 1;
+ const char *breakpoint_ptr = NULL;
+ unsigned char foo;
+
+ if (line_height_p)
+ *line_height_p = lineheight;
+
+ if (max_width>1) fragments_nr = 3 + (strlen(text) * est_char_width)*3 / (max_width << 1); else fragments_nr = 1;
+
+ fragments = (text_fragment_t*)sci_calloc(sizeof(text_fragment_t), fragments_nr);
+
+
+ fragments[0].offset = text;
+
+ while ((foo = *text++)) {
+
+ if (foo >= font->chars_nr) {
+ GFXWARN("Invalid char 0x%02x (max. 0x%02x) encountered in text string '%s', font %04x\n",
+ foo, font->chars_nr, text, font->ID);
+ if (font->chars_nr > ' ')
+ foo = ' ';
+ else {
+ free(fragments);
+ return NULL;
+ }
+ }
+
+ if (((foo == '\n') || (foo == 0x0d))
+ && !(flags & GFXR_FONT_FLAG_NO_NEWLINES)) {
+
+ fragments[current_fragment-1].length = text - 1 - fragments[current_fragment-1].offset;
+
+ if (*text)
+ maxheight += lineheight;
+
+ if (foo == 0x0d && *text == '\n')
+ text++; /* Interpret DOS-style CR LF as single NL */
+
+ fragments[current_fragment++].offset = text;
+
+ if (localmaxwidth > maxwidth)
+ maxwidth = localmaxwidth;
+
+ if (current_fragment == fragments_nr)
+ fragments = (text_fragment_t*)sci_realloc(fragments, sizeof(text_fragment_t) * (fragments_nr <<= 1));
+
+ localmaxwidth = 0;
+
+ } else { /* foo != '\n' */
+ localmaxwidth += font->widths[foo];
+
+ if (localmaxwidth > max_allowed_width) {
+ int blank_break = 1; /* break is at a blank char, i.e. not within a word */
+
+ maxheight += lineheight;
+
+ if (last_breakpoint == 0) { /* Text block too long and without whitespace? */
+ last_breakpoint = localmaxwidth - font->widths[foo];
+ last_break_width = 0;
+ --text;
+ blank_break = 0; /* non-blank break */
+ } else {
+ text = breakpoint_ptr + 1;
+ assert(breakpoint_ptr);
+ }
+
+ if (last_breakpoint == 0) {
+ GFXWARN("Warning: maxsize %d too small for '%s'\n",
+ max_allowed_width, text);
+ }
+
+ if (last_breakpoint > maxwidth)
+ maxwidth = last_breakpoint;
+
+ fragments[current_fragment-1].length = text - blank_break - fragments[current_fragment-1].offset;
+ fragments[current_fragment++].offset = text;
+
+ if (current_fragment == fragments_nr)
+ fragments = (text_fragment_t*)sci_realloc(fragments, sizeof(text_fragment_t *) * (fragments_nr <<= 1));
+
+ localmaxwidth = localmaxwidth - last_breakpoint;
+ if (!(flags & GFXR_FONT_FLAG_COUNT_WHITESPACE))
+ localmaxwidth -= last_break_width;
+ last_breakpoint = localmaxwidth = 0;
+
+ } else if (*text == ' ') {
+ last_breakpoint = localmaxwidth;
+ last_break_width = font->widths[foo];
+ breakpoint_ptr = text;
+ }
+
+ }
+ }
+
+ if (localmaxwidth > maxwidth)
+ *width = localmaxwidth;
+ else
+ *width = maxwidth;
+
+ if (last_offset_p)
+ *last_offset_p = localmaxwidth;
+
+ if (height)
+ *height = maxheight;
+ if (lines)
+ *lines = current_fragment;
+
+ fragments[current_fragment-1].length = text - fragments[current_fragment-1].offset - 1;
+
+ return fragments;
+}
+
+
+static inline void
+render_char(byte *dest, byte *src, int width, int line_width, int lines, int bytes_per_src_line, int fg0, int fg1, int bg)
+{
+ int x, y;
+
+ for (y = 0; y < lines; y++) {
+ int dat = 0;
+ byte *vdest = dest;
+ byte *vsrc = src;
+ int xc = 0;
+
+ for (x = 0; x < width; x++) {
+ if (!xc) {
+ dat = *vsrc++;
+ xc = 8;
+ }
+ xc--;
+
+ if (dat & 0x80)
+ *vdest++ = ((xc ^ y) & 1)? fg0 : fg1; /* dither */
+ else
+ *vdest++ = bg;
+
+ dat <<= 1;
+ }
+ src += bytes_per_src_line;
+ dest += line_width;
+ }
+}
+
+gfx_pixmap_t *
+gfxr_draw_font(gfx_bitmap_font_t *font, const char *stext, int characters,
+ gfx_pixmap_color_t *fg0, gfx_pixmap_color_t *fg1, gfx_pixmap_color_t *bg)
+{
+ unsigned char *text = (unsigned char *) stext;
+ int height = font->height;
+ int width = 0;
+ gfx_pixmap_t *pxm;
+ int fore_0, fore_1, back;
+ int i;
+ int hack = 0;
+ gfx_pixmap_color_t dummy = {0};
+ byte *offset;
+
+ for (i = 0; i < characters; i++) {
+ int ch = (int) text[i];
+
+ if (ch >= font->chars_nr) {
+ GFXERROR("Invalid character 0x%02x encountered!\n", text[i]);
+ return NULL;
+ }
+
+ width += font->widths[ch];
+ }
+
+ pxm = gfx_pixmap_alloc_index_data(gfx_new_pixmap(width, height, GFX_RESID_NONE, 0, 0));
+
+ pxm->colors_nr = !!fg0 + !!fg1 + !!bg;
+ if (pxm->colors_nr == 0)
+ {
+ GFXWARN("Pixmap would have zero colors, resetting!\n");
+ pxm->colors_nr = 3;
+ hack = 1;
+ fg0 = fg1 = bg = &dummy;
+ }
+ pxm->colors = (gfx_pixmap_color_t*)sci_malloc(sizeof(gfx_pixmap_color_t) * pxm->colors_nr);
+#ifdef SATISFY_PURIFY
+ memset(pxm->colors, 0, sizeof(gfx_pixmap_color_t) * pxm->colors_nr);
+#endif
+ pxm->flags |= GFX_PIXMAP_FLAG_PALETTE_ALLOCATED | GFX_PIXMAP_FLAG_DONT_UNALLOCATE_PALETTE;
+
+ i = 0;
+
+ if (fg0 || hack) {
+ memcpy(pxm->colors + i, fg0, sizeof(gfx_pixmap_color_t));
+ fore_0 = i++;
+ } else fore_0 = pxm->color_key;
+
+ if (fg1 || hack) {
+ memcpy(pxm->colors + i, fg1, sizeof(gfx_pixmap_color_t));
+ fore_1 = i++;
+ } else fore_1 = pxm->color_key;
+
+ if (bg || hack) {
+ memcpy(pxm->colors + i, bg, sizeof(gfx_pixmap_color_t));
+ back = i++;
+ } else back = pxm->color_key;
+
+ offset = pxm->index_data;
+
+ memset(pxm->index_data, back, pxm->index_xl * pxm->index_yl);
+ for (i = 0; i < characters; i++) {
+ unsigned char ch = text[i];
+ width = font->widths[ch];
+
+ render_char(offset, font->data + (ch * font->char_size), width,
+ pxm->index_xl, pxm->index_yl, font->row_size,
+ fore_0, fore_1, back);
+
+ offset += width;
+ }
+
+ return pxm;
+}
+