mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 22:28:10 +00:00
b5ce8d9320
svn-id: r38783
359 lines
9.3 KiB
C++
359 lines
9.3 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
|
|
#include "sci/gfx/gfx_system.h"
|
|
#include "sci/gfx/gfx_resource.h"
|
|
#include "sci/gfx/gfx_tools.h"
|
|
|
|
namespace Sci {
|
|
|
|
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, 0, 0, 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;
|
|
}
|
|
|
|
} // End of namespace Sci
|