mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 06:39:17 +00:00
76024785fe
svn-id: r38412
687 lines
20 KiB
C++
687 lines
20 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$
|
|
*
|
|
*/
|
|
|
|
/* Resource manager core part */
|
|
|
|
|
|
#include "sci/include/gfx_resource.h"
|
|
#include "sci/include/gfx_tools.h"
|
|
#include "sci/include/gfx_driver.h"
|
|
#include "sci/include/gfx_resmgr.h"
|
|
#include "sci/include/gfx_state_internal.h"
|
|
|
|
#undef TIME_PICDRAWING
|
|
|
|
/* Invalid hash mode: Used to invalidate modified pics */
|
|
#define MODE_INVALID -1
|
|
|
|
struct param_struct {
|
|
int args[4];
|
|
gfx_driver_t *driver;
|
|
};
|
|
|
|
|
|
gfx_resstate_t *
|
|
gfxr_new_resource_manager(int version, gfx_options_t *options,
|
|
gfx_driver_t *driver, void *misc_payload) {
|
|
gfx_resstate_t *state = (gfx_resstate_t*)sci_malloc(sizeof(gfx_resstate_t));
|
|
int ii;
|
|
|
|
state->version = version;
|
|
state->options = options;
|
|
state->driver = driver;
|
|
state->misc_payload = misc_payload;
|
|
|
|
state->tag_lock_counter = state->lock_counter = 0;
|
|
for (ii = 0; ii < GFX_RESOURCE_TYPES_NR; ii++) {
|
|
gfx_resource_type_t i = (gfx_resource_type_t) ii;
|
|
sbtree_t *tree;
|
|
int entries_nr;
|
|
int *resources = gfxr_interpreter_get_resources(state, i, version,
|
|
&entries_nr, misc_payload);
|
|
|
|
if (!resources)
|
|
state->resource_trees[i] = NULL;
|
|
else {
|
|
tree = sbtree_new(entries_nr, resources);
|
|
if (!tree) {
|
|
GFXWARN("Failed to allocate tree for %d entries of resource type %d!\n", entries_nr, i);
|
|
}
|
|
state->resource_trees[i] = tree;
|
|
free(resources);
|
|
}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
#define FREEALL(freecmd, type) \
|
|
if (resource->scaled_data.type) \
|
|
freecmd(driver, resource->scaled_data.type); \
|
|
resource->scaled_data.type = NULL; \
|
|
if (resource->unscaled_data.type) \
|
|
freecmd(driver, resource->unscaled_data.type); \
|
|
resource->unscaled_data.type = NULL;
|
|
|
|
#define FREEALL_SIMPLE(freecmd, type) \
|
|
if (resource->scaled_data.type) \
|
|
freecmd(resource->scaled_data.type); \
|
|
resource->scaled_data.type = NULL; \
|
|
if (resource->unscaled_data.type) \
|
|
freecmd(resource->unscaled_data.type); \
|
|
resource->unscaled_data.type = NULL;
|
|
|
|
|
|
void
|
|
gfxr_free_resource(gfx_driver_t *driver, gfx_resource_t *resource, int type) {
|
|
if (!resource)
|
|
return;
|
|
|
|
switch (type) {
|
|
|
|
case GFX_RESOURCE_TYPE_VIEW:
|
|
FREEALL(gfxr_free_view, view);
|
|
break;
|
|
|
|
case GFX_RESOURCE_TYPE_PIC:
|
|
FREEALL(gfxr_free_pic, pic);
|
|
break;
|
|
|
|
case GFX_RESOURCE_TYPE_FONT:
|
|
FREEALL_SIMPLE(gfxr_free_font, font);
|
|
break;
|
|
|
|
case GFX_RESOURCE_TYPE_CURSOR:
|
|
FREEALL(gfx_free_pixmap, pointer);
|
|
break;
|
|
|
|
default:
|
|
GFXWARN("Attempt to free invalid resource type %d\n", type);
|
|
}
|
|
|
|
free(resource);
|
|
}
|
|
|
|
#undef FREECMD
|
|
|
|
|
|
void *
|
|
gfxr_sbtree_free_func(sbtree_t *tree, const int key, const void *value, void *args) {
|
|
struct param_struct *params = (struct param_struct *) args;
|
|
int type = params->args[0];
|
|
gfx_driver_t *driver = params->driver;
|
|
|
|
if (value)
|
|
gfxr_free_resource(driver, (gfx_resource_t *) value, type);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define SBTREE_FREE_TAGGED_ARG_TYPE 0
|
|
#define SBTREE_FREE_TAGGED_ARG_TAGVALUE 1
|
|
#define SBTREE_FREE_TAGGED_ARG_ACTION 2
|
|
|
|
#define ARG_ACTION_RESET 0
|
|
#define ARG_ACTION_DECREMENT 1
|
|
|
|
void *
|
|
gfxr_sbtree_free_tagged_func(sbtree_t *tree, const int key, const void *value, void *args) {
|
|
struct param_struct *params = (struct param_struct *) args;
|
|
int type = params->args[SBTREE_FREE_TAGGED_ARG_TYPE];
|
|
int tag_value = params->args[SBTREE_FREE_TAGGED_ARG_TAGVALUE];
|
|
int action = params->args[SBTREE_FREE_TAGGED_ARG_ACTION];
|
|
gfx_driver_t *driver = params->driver;
|
|
gfx_resource_t *resource = (gfx_resource_t *) value;
|
|
if (resource) {
|
|
if (resource->lock_sequence_nr < tag_value) {
|
|
gfxr_free_resource(driver, (gfx_resource_t *) value, type);
|
|
return NULL;
|
|
} else {
|
|
if (action == ARG_ACTION_RESET)
|
|
resource->lock_sequence_nr = 0;
|
|
else
|
|
(resource->lock_sequence_nr)--;
|
|
return (void *) value;
|
|
}
|
|
} else return NULL;
|
|
}
|
|
|
|
|
|
void
|
|
gfxr_free_all_resources(gfx_driver_t *driver, gfx_resstate_t *state) {
|
|
struct param_struct params;
|
|
int i;
|
|
sbtree_t *tree = NULL;
|
|
|
|
for (i = 0; i < GFX_RESOURCE_TYPES_NR; i++)
|
|
if ((tree = state->resource_trees[i])) {
|
|
params.args[0] = i;
|
|
params.driver = driver;
|
|
sbtree_foreach(tree, (void *) ¶ms, gfxr_sbtree_free_func);
|
|
}
|
|
}
|
|
|
|
void
|
|
gfxr_free_resource_manager(gfx_driver_t *driver, gfx_resstate_t *state) {
|
|
struct param_struct params;
|
|
int i;
|
|
sbtree_t *tree = NULL;
|
|
|
|
for (i = 0; i < GFX_RESOURCE_TYPES_NR; i++)
|
|
if ((tree = state->resource_trees[i])) {
|
|
params.args[0] = i;
|
|
params.driver = driver;
|
|
sbtree_foreach(tree, (void *) ¶ms, gfxr_sbtree_free_func);
|
|
sbtree_free(tree);
|
|
}
|
|
|
|
free(state);
|
|
}
|
|
|
|
|
|
void
|
|
gfxr_tag_resources(gfx_resstate_t *state) {
|
|
(state->tag_lock_counter)++;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
gfxr_free_tagged_resources(gfx_driver_t *driver, gfx_resstate_t *state) {
|
|
/* Current heuristics: free tagged views and old pics */
|
|
struct param_struct params;
|
|
|
|
if (state->resource_trees[GFX_RESOURCE_TYPE_VIEW]) {
|
|
params.args[SBTREE_FREE_TAGGED_ARG_TYPE] = GFX_RESOURCE_TYPE_VIEW;
|
|
params.args[SBTREE_FREE_TAGGED_ARG_TAGVALUE] = state->tag_lock_counter;
|
|
params.args[SBTREE_FREE_TAGGED_ARG_ACTION] = ARG_ACTION_RESET;
|
|
params.driver = driver;
|
|
sbtree_foreach(state->resource_trees[GFX_RESOURCE_TYPE_VIEW], (void *) ¶ms, gfxr_sbtree_free_tagged_func);
|
|
}
|
|
|
|
if (state->resource_trees[GFX_RESOURCE_TYPE_PIC]) {
|
|
params.args[SBTREE_FREE_TAGGED_ARG_TYPE] = GFX_RESOURCE_TYPE_PIC;
|
|
params.args[SBTREE_FREE_TAGGED_ARG_TAGVALUE] = 0;
|
|
params.args[SBTREE_FREE_TAGGED_ARG_ACTION] = ARG_ACTION_DECREMENT;
|
|
params.driver = driver;
|
|
sbtree_foreach(state->resource_trees[GFX_RESOURCE_TYPE_PIC], (void *) ¶ms, gfxr_sbtree_free_tagged_func);
|
|
}
|
|
|
|
state->tag_lock_counter = 0;
|
|
}
|
|
|
|
|
|
#define XLATE_AS_APPROPRIATE(key, entry) \
|
|
if (maps & key) { \
|
|
if (res->unscaled_data.pic \
|
|
&& (force || !res->unscaled_data.pic->entry->data)) { \
|
|
if (key == GFX_MASK_VISUAL) \
|
|
gfx_get_res_config(options, res->unscaled_data.pic->entry); \
|
|
gfx_xlate_pixmap(res->unscaled_data.pic->entry, mode, filter); \
|
|
} if (scaled && res->scaled_data.pic \
|
|
&& (force || !res->scaled_data.pic->entry->data)) { \
|
|
if (key == GFX_MASK_VISUAL) \
|
|
gfx_get_res_config(options, res->scaled_data.pic->entry); \
|
|
gfx_xlate_pixmap(res->scaled_data.pic->entry, mode, filter); \
|
|
} \
|
|
}
|
|
|
|
static gfxr_pic_t *
|
|
gfxr_pic_xlate_common(gfx_resource_t *res, int maps, int scaled,
|
|
int force, gfx_mode_t *mode, gfx_xlate_filter_t filter, int endianize,
|
|
gfx_options_t *options) {
|
|
XLATE_AS_APPROPRIATE(GFX_MASK_VISUAL, visual_map);
|
|
XLATE_AS_APPROPRIATE(GFX_MASK_PRIORITY, priority_map);
|
|
XLATE_AS_APPROPRIATE(GFX_MASK_CONTROL, control_map);
|
|
|
|
if (endianize && (maps & GFX_MASK_VISUAL) && res->scaled_data.pic->visual_map)
|
|
gfxr_endianness_adjust(res->scaled_data.pic->visual_map, mode);
|
|
|
|
|
|
return scaled ? res->scaled_data.pic : res->unscaled_data.pic;
|
|
}
|
|
#undef XLATE_AS_APPROPRIATE
|
|
|
|
|
|
gfxr_pic_t *
|
|
gfxr_get_pic(gfx_resstate_t *state, int nr, int maps, int flags, int default_palette, int scaled) {
|
|
gfxr_pic_t *npic = NULL;
|
|
gfx_resource_type_t restype = GFX_RESOURCE_TYPE_PIC;
|
|
sbtree_t *tree = state->resource_trees[restype];
|
|
gfx_resource_t *res = NULL;
|
|
int hash = gfxr_interpreter_options_hash(restype, state->version,
|
|
state->options, state->misc_payload, 0);
|
|
int must_post_process_pic = 0;
|
|
int need_unscaled =
|
|
(state->driver->mode->xfact != 1 || state->driver->mode->yfact != 1);
|
|
|
|
if (!tree)
|
|
return NULL;
|
|
|
|
hash |= (flags << 20) | ((default_palette & 0x7) << 28);
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, nr);
|
|
|
|
if (!res || res->mode != hash) {
|
|
gfxr_pic_t *pic;
|
|
gfxr_pic_t *unscaled_pic = NULL;
|
|
|
|
if (state->options->pic0_unscaled) {
|
|
need_unscaled = 0;
|
|
pic = gfxr_interpreter_init_pic(state->version,
|
|
&mode_1x1_color_index,
|
|
GFXR_RES_ID(restype, nr),
|
|
state->misc_payload);
|
|
} else pic = gfxr_interpreter_init_pic(state->version,
|
|
state->driver->mode,
|
|
GFXR_RES_ID(restype, nr),
|
|
state->misc_payload);
|
|
|
|
if (!pic) {
|
|
GFXERROR("Failed to allocate scaled pic!\n");
|
|
return NULL;
|
|
}
|
|
|
|
gfxr_interpreter_clear_pic(state->version, pic, state->misc_payload);
|
|
|
|
if (need_unscaled) {
|
|
unscaled_pic = gfxr_interpreter_init_pic(state->version,
|
|
&mode_1x1_color_index,
|
|
GFXR_RES_ID(restype, nr),
|
|
state->misc_payload);
|
|
if (!unscaled_pic) {
|
|
GFXERROR("Failed to allocate unscaled pic!\n");
|
|
return NULL;
|
|
}
|
|
gfxr_interpreter_clear_pic(state->version, unscaled_pic,
|
|
state->misc_payload);
|
|
}
|
|
#ifdef TIME_PICDRAWING
|
|
{long start_sec, start_usec;
|
|
long end_sec, end_usec;
|
|
sci_gettime(&start_sec, &start_usec);
|
|
#endif
|
|
if (gfxr_interpreter_calculate_pic(state, pic, unscaled_pic, flags,
|
|
default_palette, nr,
|
|
state->misc_payload)) {
|
|
gfxr_free_pic(state->driver, pic);
|
|
if (unscaled_pic)
|
|
gfxr_free_pic(state->driver, unscaled_pic);
|
|
|
|
return NULL;
|
|
}
|
|
#ifdef TIME_PICDRAWING
|
|
sci_gettime(&end_sec, &end_usec);
|
|
printf("\nTIME: %d for drawing pic.%03d\n",
|
|
(end_sec - start_sec) * 1000000 + (end_usec - start_usec), nr);
|
|
}
|
|
#endif
|
|
|
|
if (!res) {
|
|
res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t));
|
|
res->ID = GFXR_RES_ID(restype, nr);
|
|
res->lock_sequence_nr = state->options->buffer_pics_nr;
|
|
sbtree_set(tree, nr, (void *) res);
|
|
} else {
|
|
gfxr_free_pic(state->driver, res->scaled_data.pic);
|
|
if (res->unscaled_data.pic)
|
|
gfxr_free_pic(state->driver, res->unscaled_data.pic);
|
|
}
|
|
|
|
res->mode = hash;
|
|
res->scaled_data.pic = pic;
|
|
res->unscaled_data.pic = unscaled_pic;
|
|
} else {
|
|
res->lock_sequence_nr = state->options->buffer_pics_nr; /* Update lock counter */
|
|
}
|
|
|
|
must_post_process_pic = res->scaled_data.pic->visual_map->data == NULL;
|
|
/* If the pic was only just drawn, we'll have to antialiase and endianness-adjust it now */
|
|
|
|
npic = gfxr_pic_xlate_common(res, maps,
|
|
scaled || state->options->pic0_unscaled,
|
|
0, state->driver->mode,
|
|
state->options->pic_xlate_filter, 0,
|
|
state->options);
|
|
|
|
|
|
if (must_post_process_pic) {
|
|
|
|
if (scaled || state->options->pic0_unscaled && maps & GFX_MASK_VISUAL)
|
|
gfxr_antialiase(npic->visual_map, state->driver->mode,
|
|
state->options->pic0_antialiasing);
|
|
|
|
gfxr_endianness_adjust(npic->visual_map, state->driver->mode);
|
|
}
|
|
|
|
return npic;
|
|
}
|
|
|
|
|
|
static void
|
|
set_pic_id(gfx_resource_t *res, int id) {
|
|
if (res->scaled_data.pic) {
|
|
gfxr_pic_t *pic = res->scaled_data.pic;
|
|
pic->control_map->ID = id;
|
|
pic->priority_map->ID = id;
|
|
pic->visual_map->ID = id;
|
|
}
|
|
|
|
if (res->unscaled_data.pic) {
|
|
gfxr_pic_t *pic = res->unscaled_data.pic;
|
|
pic->control_map->ID = id;
|
|
pic->priority_map->ID = id;
|
|
pic->visual_map->ID = id;
|
|
}
|
|
}
|
|
|
|
static int
|
|
get_pic_id(gfx_resource_t *res) {
|
|
if (res->scaled_data.pic)
|
|
return res->scaled_data.pic->visual_map->ID;
|
|
else
|
|
return res->unscaled_data.pic->visual_map->ID;
|
|
}
|
|
|
|
static void
|
|
_gfxr_unscale_pixmap_index_data(gfx_pixmap_t *pxm, gfx_mode_t *mode) {
|
|
int xmod = mode->xfact; /* Step size horizontally */
|
|
int ymod = pxm->index_xl * mode->yfact; /* Vertical step size */
|
|
int maxpos = pxm->index_xl * pxm->index_yl;
|
|
int pos;
|
|
byte *dest = pxm->index_data;
|
|
|
|
if (!(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX))
|
|
return; /* It's not scaled! */
|
|
|
|
for (pos = 0; pos < maxpos; pos += ymod) {
|
|
int c;
|
|
|
|
for (c = 0; c < pxm->index_xl; c += xmod)
|
|
* dest++ = pxm->index_data[pos + c]; /* No overwrite since
|
|
** line and offset
|
|
** readers move much
|
|
** faster
|
|
** (proof by in-
|
|
** duction, trivial
|
|
** and left to the
|
|
** reader) */
|
|
}
|
|
|
|
pxm->index_xl /= mode->xfact;
|
|
pxm->index_yl /= mode->yfact;
|
|
pxm->flags &= ~GFX_PIXMAP_FLAG_SCALED_INDEX;
|
|
}
|
|
|
|
|
|
gfxr_pic_t *
|
|
gfxr_add_to_pic(gfx_resstate_t *state, int old_nr, int new_nr, int maps, int flags,
|
|
int old_default_palette, int default_palette, int scaled) {
|
|
gfx_resource_type_t restype = GFX_RESOURCE_TYPE_PIC;
|
|
sbtree_t *tree = state->resource_trees[restype];
|
|
gfxr_pic_t *pic = NULL;
|
|
gfx_resource_t *res = NULL;
|
|
int hash = gfxr_interpreter_options_hash(restype, state->version,
|
|
state->options,
|
|
state->misc_payload, 0);
|
|
int need_unscaled = !(state->options->pic0_unscaled)
|
|
&& (state->driver->mode->xfact != 1 || state->driver->mode->yfact != 1);
|
|
|
|
if (!tree) {
|
|
GFXERROR("No pics registered\n");
|
|
return NULL;
|
|
}
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, old_nr);
|
|
|
|
if (!res ||
|
|
(res->mode != MODE_INVALID
|
|
&& res->mode != hash)) {
|
|
gfxr_get_pic(state, old_nr, 0, flags, old_default_palette, scaled);
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, old_nr);
|
|
|
|
if (!res) {
|
|
GFXWARN("Attempt to add pic %d to non-existing pic %d\n", new_nr, old_nr);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (state->options->pic0_unscaled) /* Unscale priority map, if we scaled it earlier */
|
|
_gfxr_unscale_pixmap_index_data(res->scaled_data.pic->priority_map, state->driver->mode);
|
|
|
|
if (scaled) {
|
|
res->lock_sequence_nr = state->options->buffer_pics_nr;
|
|
|
|
gfxr_interpreter_calculate_pic(state, res->scaled_data.pic, need_unscaled ? res->unscaled_data.pic : NULL,
|
|
flags | DRAWPIC01_FLAG_OVERLAID_PIC,
|
|
default_palette, new_nr, state->misc_payload);
|
|
}
|
|
|
|
res->mode = MODE_INVALID; /* Invalidate */
|
|
|
|
if (state->options->pic0_unscaled) /* Scale priority map again, if needed */
|
|
res->scaled_data.pic->priority_map = gfx_pixmap_scale_index_data(res->scaled_data.pic->priority_map, state->driver->mode);
|
|
{
|
|
int old_ID = get_pic_id(res);
|
|
set_pic_id(res, GFXR_RES_ID(restype, new_nr)); /* To ensure that our graphical translation optoins work properly */
|
|
pic = gfxr_pic_xlate_common(res, maps, scaled, 1, state->driver->mode,
|
|
state->options->pic_xlate_filter, 1,
|
|
state->options);
|
|
set_pic_id(res, old_ID);
|
|
}
|
|
|
|
if (scaled || state->options->pic0_unscaled && maps & GFX_MASK_VISUAL)
|
|
gfxr_antialiase(pic->visual_map, state->driver->mode,
|
|
state->options->pic0_antialiasing);
|
|
|
|
return pic;
|
|
}
|
|
|
|
|
|
gfxr_view_t *
|
|
gfxr_get_view(gfx_resstate_t *state, int nr, int *loop, int *cel, int palette) {
|
|
gfx_resource_type_t restype = GFX_RESOURCE_TYPE_VIEW;
|
|
sbtree_t *tree = state->resource_trees[restype];
|
|
gfx_resource_t *res = NULL;
|
|
int hash = gfxr_interpreter_options_hash(restype, state->version,
|
|
state->options, state->misc_payload,
|
|
palette);
|
|
gfxr_view_t *view = NULL;
|
|
gfxr_loop_t *loop_data = NULL;
|
|
gfx_pixmap_t *cel_data = NULL;
|
|
|
|
if (!tree)
|
|
return NULL;
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, nr);
|
|
|
|
if (!res || res->mode != hash) {
|
|
view = gfxr_interpreter_get_view(state, nr, state->misc_payload, palette);
|
|
|
|
if (!view)
|
|
return NULL;
|
|
|
|
if (!res) {
|
|
res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t));
|
|
res->scaled_data.view = NULL;
|
|
res->ID = GFXR_RES_ID(restype, nr);
|
|
res->lock_sequence_nr = state->tag_lock_counter;
|
|
res->mode = hash;
|
|
sbtree_set(tree, nr, (void *) res);
|
|
} else {
|
|
gfxr_free_view(state->driver, res->unscaled_data.view);
|
|
}
|
|
|
|
res->mode = hash;
|
|
res->unscaled_data.view = view;
|
|
|
|
} else {
|
|
res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */
|
|
view = res->unscaled_data.view;
|
|
}
|
|
|
|
if (*loop < 0)
|
|
*loop = 0;
|
|
else
|
|
if (*loop >= view->loops_nr)
|
|
*loop = view->loops_nr - 1;
|
|
|
|
if (*loop < 0) {
|
|
GFXWARN("View %d has no loops\n", nr);
|
|
return NULL;
|
|
}
|
|
|
|
loop_data = view->loops + (*loop);
|
|
if (loop_data == NULL) {
|
|
GFXWARN("Trying to load invalid loop %d of view %d\n", *loop, nr);
|
|
return NULL;
|
|
}
|
|
|
|
if (*cel < 0) {
|
|
sciprintf("Resetting cel! %d\n", *cel);
|
|
*cel = 0;
|
|
} else
|
|
if (*cel >= loop_data->cels_nr)
|
|
*cel = loop_data->cels_nr - 1;
|
|
|
|
if (*cel < 0) {
|
|
GFXWARN("View %d loop %d has no cels\n", nr, *loop);
|
|
return NULL;
|
|
}
|
|
|
|
cel_data = loop_data->cels[*cel];
|
|
if (loop_data == NULL) {
|
|
GFXWARN("Trying to load invalid view/loop/cel %d/%d/%d\n", nr, *loop, *cel);
|
|
return NULL;
|
|
}
|
|
|
|
if (!cel_data->data) {
|
|
gfx_get_res_config(state->options, cel_data);
|
|
gfx_xlate_pixmap(cel_data, state->driver->mode, state->options->view_xlate_filter);
|
|
gfxr_endianness_adjust(cel_data, state->driver->mode);
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
extern gfx_bitmap_font_t gfxfont_5x8;
|
|
extern gfx_bitmap_font_t gfxfont_6x10;
|
|
|
|
gfx_bitmap_font_t *
|
|
gfxr_get_font(gfx_resstate_t *state, int nr, int scaled) {
|
|
gfx_resource_type_t restype = GFX_RESOURCE_TYPE_FONT;
|
|
sbtree_t *tree = NULL;
|
|
gfx_resource_t *res = NULL;
|
|
int hash;
|
|
|
|
if (nr == GFX_FONT_BUILTIN_5x8)
|
|
return &gfxfont_5x8;
|
|
else if (nr == GFX_FONT_BUILTIN_6x10)
|
|
return &gfxfont_6x10;
|
|
|
|
tree = state->resource_trees[restype];
|
|
|
|
hash = gfxr_interpreter_options_hash(restype, state->version,
|
|
state->options, state->misc_payload, 0);
|
|
|
|
if (!tree)
|
|
return NULL;
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, nr);
|
|
|
|
if (!res || res->mode != hash) {
|
|
gfx_bitmap_font_t *font = gfxr_interpreter_get_font(state, nr,
|
|
state->misc_payload);
|
|
|
|
if (!font)
|
|
return NULL;
|
|
|
|
if (!res) {
|
|
res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t));
|
|
res->scaled_data.font = NULL;
|
|
res->ID = GFXR_RES_ID(restype, nr);
|
|
res->lock_sequence_nr = state->tag_lock_counter;
|
|
res->mode = hash;
|
|
sbtree_set(tree, nr, (void *) res);
|
|
} else {
|
|
gfxr_free_font(res->unscaled_data.font);
|
|
}
|
|
|
|
res->unscaled_data.font = font;
|
|
|
|
return font;
|
|
} else {
|
|
res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */
|
|
if (res->unscaled_data.pointer)
|
|
return res->unscaled_data.font;
|
|
else
|
|
return res->scaled_data.font;
|
|
}
|
|
}
|
|
|
|
|
|
gfx_pixmap_t *
|
|
gfxr_get_cursor(gfx_resstate_t *state, int nr) {
|
|
gfx_resource_type_t restype = GFX_RESOURCE_TYPE_CURSOR;
|
|
sbtree_t *tree = state->resource_trees[restype];
|
|
gfx_resource_t *res = NULL;
|
|
int hash = gfxr_interpreter_options_hash(restype, state->version,
|
|
state->options, state->misc_payload, 0);
|
|
|
|
if (!tree)
|
|
return NULL;
|
|
|
|
res = (gfx_resource_t *) sbtree_get(tree, nr);
|
|
|
|
if (!res || res->mode != hash) {
|
|
gfx_pixmap_t *cursor = gfxr_interpreter_get_cursor(state, nr,
|
|
state->misc_payload);
|
|
|
|
if (!cursor)
|
|
return NULL;
|
|
|
|
if (!res) {
|
|
res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t));
|
|
res->scaled_data.pointer = NULL;
|
|
res->ID = GFXR_RES_ID(restype, nr);
|
|
res->lock_sequence_nr = state->tag_lock_counter;
|
|
res->mode = hash;
|
|
sbtree_set(tree, nr, (void *) res);
|
|
} else {
|
|
gfx_free_pixmap(state->driver, res->unscaled_data.pointer);
|
|
}
|
|
gfx_get_res_config(state->options, cursor);
|
|
gfx_xlate_pixmap(cursor, state->driver->mode, state->options->cursor_xlate_filter);
|
|
gfxr_endianness_adjust(cursor, state->driver->mode);
|
|
|
|
res->unscaled_data.pointer = cursor;
|
|
|
|
return cursor;
|
|
} else {
|
|
res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */
|
|
return res->unscaled_data.pointer;
|
|
}
|
|
}
|