2009-02-17 15:17:01 +00:00
|
|
|
/* 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$
|
|
|
|
*
|
|
|
|
*/
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Graphical operations, called from the widget state manager
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-24 05:39:10 +00:00
|
|
|
#include "sci/sci_memory.h"
|
2009-02-24 20:39:34 +00:00
|
|
|
#include "sci/gfx/operations.h"
|
2009-03-08 08:15:56 +00:00
|
|
|
#include "sci/gfx/font.h"
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 22:00:24 +00:00
|
|
|
#include "common/system.h"
|
2009-03-07 19:23:32 +00:00
|
|
|
#include "common/events.h"
|
2009-02-21 22:00:24 +00:00
|
|
|
|
2009-02-21 10:23:36 +00:00
|
|
|
namespace Sci {
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
#define PRECISE_PRIORITY_MAP // Duplicate all operations on the local priority map as appropriate
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-22 13:11:43 +00:00
|
|
|
#undef GFXW_DEBUG_DIRTY
|
2009-02-21 08:47:07 +00:00
|
|
|
// Enable to debug stuff relevant for dirty rectsin widget management
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
#ifdef GFXW_DEBUG_DIRTY
|
2009-02-21 14:11:41 +00:00
|
|
|
# define DDIRTY fprintf(stderr, "%s:%5d| ", __FILE__, __LINE__); fprintf
|
2009-02-15 06:10:59 +00:00
|
|
|
#else
|
|
|
|
# define DDIRTY if (0) fprintf
|
|
|
|
#endif
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Default color maps
|
2009-02-15 06:10:59 +00:00
|
|
|
#define DEFAULT_COLORS_NR 16
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
gfx_pixmap_color_t default_colors[DEFAULT_COLORS_NR] = {{GFX_COLOR_SYSTEM, 0x00, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0x00, 0xaa},
|
|
|
|
{GFX_COLOR_SYSTEM, 0x00, 0xaa, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0xaa},
|
|
|
|
{GFX_COLOR_SYSTEM, 0xaa, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0x00, 0xaa},
|
|
|
|
{GFX_COLOR_SYSTEM, 0xaa, 0x55, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0xaa, 0xaa},
|
|
|
|
{GFX_COLOR_SYSTEM, 0x55, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0x55, 0xff},
|
|
|
|
{GFX_COLOR_SYSTEM, 0x55, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0xff, 0xff},
|
|
|
|
{GFX_COLOR_SYSTEM, 0xff, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0x55, 0xff},
|
|
|
|
{GFX_COLOR_SYSTEM, 0xff, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0xff, 0xff}
|
2009-02-21 08:47:07 +00:00
|
|
|
}; // "Normal" EGA
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
#define POINTER_VISIBLE_BUT_CLIPPED 2
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Performs basic checks that apply to most functions
|
2009-02-15 06:10:59 +00:00
|
|
|
#define BASIC_CHECKS(error_retval) \
|
|
|
|
if (!state) { \
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Null state!\n"); \
|
2009-02-15 06:10:59 +00:00
|
|
|
return error_retval; \
|
|
|
|
} \
|
|
|
|
if (!state->driver) { \
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("GFX driver invalid!\n"); \
|
2009-02-15 06:10:59 +00:00
|
|
|
return error_retval; \
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// How to determine whether colors have to be allocated
|
2009-02-15 06:10:59 +00:00
|
|
|
#define PALETTE_MODE state->driver->mode->palette
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
//#define GFXOP_DEBUG_DIRTY
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Internal operations
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void _gfxop_scale_rect(rect_t *rect, gfx_mode_t *mode) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int xfact = mode->xfact;
|
|
|
|
int yfact = mode->yfact;
|
|
|
|
|
|
|
|
rect->x *= xfact;
|
|
|
|
rect->y *= yfact;
|
|
|
|
rect->xl *= xfact;
|
|
|
|
rect->yl *= yfact;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void _gfxop_scale_point(Common::Point *point, gfx_mode_t *mode) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int xfact = mode->xfact;
|
|
|
|
int yfact = mode->yfact;
|
|
|
|
|
|
|
|
point->x *= xfact;
|
|
|
|
point->y *= yfact;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int _gfxop_clip(rect_t *rect, rect_t clipzone) {
|
|
|
|
// Returns 1 if nothing is left */
|
2009-02-15 06:10:59 +00:00
|
|
|
#if 0
|
2009-02-15 22:33:36 +00:00
|
|
|
printf("Clipping (%d, %d) size (%d, %d) by (%d,%d)(%d,%d)\n", rect->x, rect->y, rect->xl, rect->yl,
|
|
|
|
clipzone.x, clipzone.y, clipzone.xl, clipzone.yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (rect->x < clipzone.x) {
|
|
|
|
rect->xl -= (clipzone.x - rect->x);
|
|
|
|
rect->x = clipzone.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rect->y < clipzone.y) {
|
|
|
|
rect->yl -= (clipzone.y - rect->y);
|
|
|
|
rect->y = clipzone.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rect->x + rect->xl > clipzone.x + clipzone.xl)
|
|
|
|
rect->xl = (clipzone.x + clipzone.xl) - rect->x;
|
|
|
|
|
|
|
|
if (rect->y + rect->yl > clipzone.y + clipzone.yl)
|
|
|
|
rect->yl = (clipzone.y + clipzone.yl) - rect->y;
|
|
|
|
|
|
|
|
if (rect->xl < 0)
|
|
|
|
rect->xl = 0;
|
|
|
|
if (rect->yl < 0)
|
|
|
|
rect->yl = 0;
|
|
|
|
|
|
|
|
#if 0
|
2009-02-15 22:33:36 +00:00
|
|
|
printf(" => (%d, %d) size (%d, %d)\n", rect->x, rect->y, rect->xl, rect->yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
#endif
|
|
|
|
return (rect->xl <= 0 || rect->yl <= 0);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_grab_pixmap(gfx_state_t *state, gfx_pixmap_t **pxmp, int x, int y,
|
|
|
|
int xl, int yl, int priority, rect_t *zone) {
|
|
|
|
// Returns 1 if the resulting data size was zero, GFX_OK or an error code otherwise */
|
2009-02-15 06:10:59 +00:00
|
|
|
int xfact = state->driver->mode->xfact;
|
|
|
|
int yfact = state->driver->mode->yfact;
|
|
|
|
int unscaled_xl = (xl + xfact - 1) / xfact;
|
|
|
|
int unscaled_yl = (yl + yfact - 1) / yfact;
|
|
|
|
*zone = gfx_rect(x, y, xl, yl);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (_gfxop_clip(zone, gfx_rect(0, 0, 320 * state->driver->mode->xfact, 200 * state->driver->mode->yfact)))
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
|
|
|
|
if (!*pxmp)
|
|
|
|
*pxmp = gfx_new_pixmap(unscaled_xl, unscaled_yl, GFX_RESID_NONE, 0, 0);
|
|
|
|
else
|
|
|
|
if (xl * yl > (*pxmp)->xl * (*pxmp)->yl) {
|
|
|
|
gfx_pixmap_free_data(*pxmp);
|
|
|
|
(*pxmp)->data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*pxmp)->data) {
|
|
|
|
(*pxmp)->index_xl = unscaled_xl + 1;
|
|
|
|
(*pxmp)->index_yl = unscaled_yl + 1;
|
|
|
|
gfx_pixmap_alloc_data(*pxmp, state->driver->mode);
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
return state->driver->grab_pixmap(state->driver, *zone, *pxmp, priority ? GFX_MASK_PRIORITY : GFX_MASK_VISUAL);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define DRAW_LOOP(condition) \
|
|
|
|
{ \
|
|
|
|
rect_t drawrect = gfx_rect(pos.x, pos.y, pxm->index_xl, pxm->index_yl); \
|
|
|
|
int offset, base_offset; \
|
|
|
|
int read_offset, base_read_offset; \
|
|
|
|
int x,y; \
|
|
|
|
\
|
|
|
|
if (!pxm->index_data) { \
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXERROR("Attempt to draw control color %d on pixmap %d/%d/%d without index data", color, pxm->ID, pxm->loop, pxm->cel); \
|
2009-02-15 06:10:59 +00:00
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
if (_gfxop_clip(&drawrect, gfx_rect(0, 0, 320, 200))) \
|
|
|
|
return; \
|
|
|
|
\
|
|
|
|
offset = base_offset = drawrect.x + drawrect.y * 320; \
|
|
|
|
read_offset = base_read_offset = (drawrect.x - pos.x) + ((drawrect.y - pos.y) * pxm->index_xl); \
|
|
|
|
\
|
|
|
|
for (y = 0; y < drawrect.yl; y++) { \
|
|
|
|
for (x = 0; x < drawrect.xl; x++) \
|
|
|
|
if (pxm->index_data[read_offset++] != pxm->color_key) { \
|
|
|
|
if (condition) \
|
|
|
|
map->index_data[offset++] = color; \
|
|
|
|
else \
|
|
|
|
++offset; \
|
2009-02-21 08:47:07 +00:00
|
|
|
} else \
|
|
|
|
++offset; \
|
2009-02-15 06:10:59 +00:00
|
|
|
\
|
|
|
|
offset = base_offset += 320; \
|
|
|
|
read_offset = base_read_offset += pxm->index_xl; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void _gfxop_draw_control(gfx_pixmap_t *map, gfx_pixmap_t *pxm, int color, Common::Point pos)
|
|
|
|
DRAW_LOOP(1) // Always draw
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
#ifdef PRECISE_PRIORITY_MAP
|
2009-02-21 08:47:07 +00:00
|
|
|
static void _gfxop_draw_priority(gfx_pixmap_t *map, gfx_pixmap_t *pxm, int color, Common::Point pos)
|
|
|
|
DRAW_LOOP(map->index_data[offset] < color) // Draw only lower priority
|
2009-02-15 06:10:59 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef DRAW_LOOP
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_install_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm) {
|
2009-03-08 20:17:01 +00:00
|
|
|
if (!driver->mode->palette) return GFX_OK;
|
|
|
|
if (!pxm->palette) return GFX_OK;
|
|
|
|
|
|
|
|
assert(pxm->palette->getParent() == driver->mode->palette);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
if (!driver->mode->palette->isDirty()) return GFX_OK;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
// TODO: We probably want to only update the colours used by this pixmap
|
|
|
|
// here. This will require updating the 'dirty' system.
|
|
|
|
for (unsigned int i = 0; i < driver->mode->palette->size(); ++i) {
|
|
|
|
const PaletteEntry& c = (*driver->mode->palette)[i];
|
|
|
|
driver->set_palette(driver, i, c.r, c.g, c.b);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-03-08 20:17:01 +00:00
|
|
|
|
|
|
|
driver->install_palette(driver, driver->mode->palette);
|
|
|
|
driver->mode->palette->markClean();
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_draw_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm, int priority, int control,
|
2009-02-22 13:11:43 +00:00
|
|
|
rect_t src, rect_t dest, rect_t clip, int static_buf, gfx_pixmap_t *control_map, gfx_pixmap_t *priority_map) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int error;
|
|
|
|
rect_t clipped_dest = gfx_rect(dest.x, dest.y, dest.xl, dest.yl);
|
|
|
|
|
|
|
|
if (control >= 0 || priority >= 0) {
|
2009-02-21 08:47:07 +00:00
|
|
|
Common::Point original_pos = Common::Point(dest.x / driver->mode->xfact, dest.y / driver->mode->yfact);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (control >= 0)
|
|
|
|
_gfxop_draw_control(control_map, pxm, control, original_pos);
|
|
|
|
|
|
|
|
#ifdef PRECISE_PRIORITY_MAP
|
|
|
|
if (priority >= 0)
|
|
|
|
_gfxop_draw_priority(priority_map, pxm, priority, original_pos);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_gfxop_clip(&clipped_dest, clip))
|
|
|
|
return GFX_OK;
|
|
|
|
|
|
|
|
src.x += clipped_dest.x - dest.x;
|
|
|
|
src.y += clipped_dest.y - dest.y;
|
|
|
|
src.xl = clipped_dest.xl;
|
|
|
|
src.yl = clipped_dest.yl;
|
|
|
|
|
|
|
|
error = _gfxop_install_pixmap(driver, pxm);
|
2009-02-21 08:47:07 +00:00
|
|
|
if (error)
|
|
|
|
return error;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
DDIRTY(stderr, "\\-> Drawing to actual %d %d %d %d\n", clipped_dest.x / driver->mode->xfact,
|
|
|
|
clipped_dest.y / driver->mode->yfact, clipped_dest.xl / driver->mode->xfact, clipped_dest.yl / driver->mode->yfact);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
error = driver->draw_pixmap(driver, pxm, priority, src, clipped_dest, static_buf ? GFX_BUFFER_STATIC : GFX_BUFFER_BACK);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (error) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("driver->draw_pixmap() returned error!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return error;
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-25 19:28:20 +00:00
|
|
|
static void _gfxop_full_pointer_refresh(gfx_state_t *state) {
|
|
|
|
state->pointer_pos.x = state->driver->pointer_x / state->driver->mode->xfact;
|
|
|
|
state->pointer_pos.y = state->driver->pointer_y / state->driver->mode->yfact;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_buffer_propagate_box(gfx_state_t *state, rect_t box, gfx_buffer_t buffer);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
gfx_pixmap_t *_gfxr_get_cel(gfx_state_t *state, int nr, int *loop, int *cel, int palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfxr_view_t *view = gfxr_get_view(state->resstate, nr, loop, cel, palette);
|
|
|
|
gfxr_loop_t *indexed_loop;
|
|
|
|
|
|
|
|
if (!view)
|
|
|
|
return NULL;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (*loop >= view->loops_nr || *loop < 0) {
|
|
|
|
GFXWARN("Attempt to get cel from loop %d/%d inside view %d\n", *loop, view->loops_nr, nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
indexed_loop = view->loops + *loop;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (*cel >= indexed_loop->cels_nr || *cel < 0) {
|
|
|
|
GFXWARN("Attempt to get cel %d/%d from view %d/%d\n", *cel, indexed_loop->cels_nr, nr, *loop);
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
return indexed_loop->cels[*cel]; // Yes, view->cels uses a malloced pointer list.
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
//** Dirty rectangle operations **
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static inline int _gfxop_update_box(gfx_state_t *state, rect_t box) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval;
|
|
|
|
_gfxop_scale_rect(&box, state->driver->mode);
|
|
|
|
|
|
|
|
if ((retval = _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_FRONT))) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXERROR("Error occured while propagating box (%d,%d,%d,%d) to front buffer\n", box.x, box.y, box.xl, box.yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 22:06:42 +00:00
|
|
|
static gfx_dirty_rect_t *_rect_create(rect_t box) {
|
|
|
|
gfx_dirty_rect_t *rect;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 22:06:42 +00:00
|
|
|
rect = (gfx_dirty_rect_t *)sci_malloc(sizeof(gfx_dirty_rect_t));
|
2009-02-15 06:10:59 +00:00
|
|
|
rect->next = NULL;
|
|
|
|
rect->rect = box;
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
gfx_dirty_rect_t *gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy) {
|
2009-02-15 06:10:59 +00:00
|
|
|
if (box.xl < 0) {
|
|
|
|
box.x += box.xl;
|
|
|
|
box.xl = - box.xl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (box.yl < 0) {
|
|
|
|
box.y += box.yl;
|
|
|
|
box.yl = - box.yl;
|
|
|
|
}
|
|
|
|
#ifdef GFXOP_DEBUG_DIRTY
|
2009-02-21 14:11:41 +00:00
|
|
|
fprintf(stderr, "Adding new dirty (%d %d %d %d)\n",
|
|
|
|
GFX_PRINT_RECT(box));
|
2009-02-15 06:10:59 +00:00
|
|
|
#endif
|
|
|
|
if (_gfxop_clip(&box, gfx_rect(0, 0, 320, 200)))
|
|
|
|
return base;
|
|
|
|
|
|
|
|
switch (strategy) {
|
|
|
|
|
|
|
|
case GFXOP_DIRTY_FRAMES_ONE:
|
|
|
|
if (base)
|
|
|
|
base->rect = gfx_rects_merge(box, base->rect);
|
|
|
|
else
|
|
|
|
base = _rect_create(box);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GFXOP_DIRTY_FRAMES_CLUSTERS: {
|
2009-02-21 22:06:42 +00:00
|
|
|
gfx_dirty_rect_t **rectp = &(base);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
while (*rectp) {
|
|
|
|
if (gfx_rects_overlap((*rectp)->rect, box)) {
|
2009-02-21 22:06:42 +00:00
|
|
|
gfx_dirty_rect_t *next = (*rectp)->next;
|
2009-02-15 06:10:59 +00:00
|
|
|
box = gfx_rects_merge((*rectp)->rect, box);
|
|
|
|
free(*rectp);
|
|
|
|
*rectp = next;
|
|
|
|
} else
|
|
|
|
rectp = &((*rectp)->next);
|
|
|
|
}
|
|
|
|
*rectp = _rect_create(box);
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
GFXERROR("Attempt to use invalid dirty frame mode %d!\nPlease refer to gfx_options.h.", strategy);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void _gfxop_add_dirty(gfx_state_t *state, rect_t box) {
|
2009-02-15 06:10:59 +00:00
|
|
|
if (state->disable_dirty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
state->dirty_rects = gfxdr_add_dirty(state->dirty_rects, box, state->options->dirty_frames);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static inline void _gfxop_add_dirty_x(gfx_state_t *state, rect_t box) {
|
|
|
|
// Extends the box size by one before adding (used for lines)
|
2009-02-15 06:10:59 +00:00
|
|
|
if (box.xl < 0)
|
|
|
|
box.xl--;
|
|
|
|
else
|
|
|
|
box.xl++;
|
|
|
|
|
|
|
|
if (box.yl < 0)
|
|
|
|
box.yl--;
|
|
|
|
else
|
|
|
|
box.yl++;
|
|
|
|
|
|
|
|
_gfxop_add_dirty(state, box);
|
|
|
|
}
|
|
|
|
|
2009-02-21 22:06:42 +00:00
|
|
|
static int _gfxop_clear_dirty_rec(gfx_state_t *state, gfx_dirty_rect_t *rect) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
if (!rect)
|
|
|
|
return GFX_OK;
|
|
|
|
|
|
|
|
#ifdef GFXOP_DEBUG_DIRTY
|
2009-02-21 14:11:41 +00:00
|
|
|
fprintf(stderr, "\tClearing dirty (%d %d %d %d)\n",
|
|
|
|
GFX_PRINT_RECT(rect->rect));
|
2009-02-15 06:10:59 +00:00
|
|
|
#endif
|
|
|
|
if (!state->fullscreen_override)
|
|
|
|
retval = _gfxop_update_box(state, rect->rect);
|
|
|
|
else
|
|
|
|
retval = GFX_OK;
|
|
|
|
|
|
|
|
retval |= _gfxop_clear_dirty_rec(state, rect->next);
|
|
|
|
|
|
|
|
free(rect);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
//** Exported operations **
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void init_aux_pixmap(gfx_pixmap_t **pixmap) {
|
2009-02-15 06:10:59 +00:00
|
|
|
*pixmap = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, GFX_RESID_NONE, 0, 0));
|
2009-03-08 20:17:01 +00:00
|
|
|
// FIXME: don't duplicate this palette for every aux_pixmap
|
|
|
|
(*pixmap)->palette = new Palette(default_colors, DEFAULT_COLORS_NR);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_init_common(gfx_state_t *state, gfx_options_t *options, void *misc_payload) {
|
2009-03-08 20:17:01 +00:00
|
|
|
gfxr_init_static_palette();
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
state->options = options;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (!((state->resstate = gfxr_new_resource_manager(state->version, state->options, state->driver, misc_payload)))) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Failed to initialize resource manager!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_FATAL;
|
|
|
|
}
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
int size;
|
|
|
|
state->static_palette = gfxr_interpreter_get_static_palette(state->resstate, state->version, &size, misc_payload);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
state->visible_map = GFX_MASK_VISUAL;
|
2009-02-21 08:47:07 +00:00
|
|
|
state->fullscreen_override = NULL; // No magical override
|
2009-02-15 06:10:59 +00:00
|
|
|
gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200));
|
|
|
|
|
|
|
|
init_aux_pixmap(&(state->control_map));
|
|
|
|
init_aux_pixmap(&(state->priority_map));
|
|
|
|
init_aux_pixmap(&(state->static_priority_map));
|
|
|
|
|
|
|
|
state->options = options;
|
|
|
|
state->disable_dirty = 0;
|
2009-03-07 19:23:32 +00:00
|
|
|
state->_events.clear();
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
state->pic = state->pic_unscaled = NULL;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
state->pic_nr = -1; // Set background pic number to an invalid value
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
state->tag_mode = 0;
|
|
|
|
|
|
|
|
state->dirty_rects = NULL;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_init_default(gfx_state_t *state, gfx_options_t *options, void *misc_info) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
if (state->driver->init(state->driver))
|
|
|
|
return GFX_FATAL;
|
|
|
|
|
|
|
|
return _gfxop_init_common(state, options, misc_info);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_init(gfx_state_t *state, int xfact, int yfact, gfx_color_mode_t bpp,
|
2009-02-22 13:11:43 +00:00
|
|
|
gfx_options_t *options, void *misc_info) {
|
2009-02-15 22:33:36 +00:00
|
|
|
int color_depth = bpp ? bpp : 1;
|
2009-02-15 06:10:59 +00:00
|
|
|
int initialized = 0;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (!state->driver->init_specific(state->driver, xfact, yfact, color_depth))
|
|
|
|
initialized = 1;
|
|
|
|
else
|
|
|
|
color_depth++;
|
|
|
|
} while (!initialized && color_depth < 9 && !bpp);
|
|
|
|
|
|
|
|
if (!initialized)
|
|
|
|
return GFX_FATAL;
|
|
|
|
|
|
|
|
return _gfxop_init_common(state, options, misc_info);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_parameter(gfx_state_t *state, char *attribute, char *value) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
return state->driver->set_parameter(state->driver, attribute, value);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_exit(gfx_state_t *state) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
gfxr_free_resource_manager(state->driver, state->resstate);
|
|
|
|
|
|
|
|
if (state->control_map) {
|
|
|
|
gfx_free_pixmap(state->driver, state->control_map);
|
|
|
|
state->control_map = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->priority_map) {
|
|
|
|
gfx_free_pixmap(state->driver, state->priority_map);
|
|
|
|
state->priority_map = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->static_priority_map) {
|
|
|
|
gfx_free_pixmap(state->driver, state->static_priority_map);
|
|
|
|
state->static_priority_map = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->driver->exit(state->driver);
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_scan_one_bitmask(gfx_pixmap_t *pixmap, rect_t zone) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval = 0;
|
|
|
|
int pixmap_xscale = pixmap->index_xl / 320;
|
|
|
|
int pixmap_yscale = pixmap->index_yl / 200;
|
|
|
|
int line_width = pixmap_yscale * pixmap->index_xl;
|
|
|
|
int startindex = (line_width * zone.y) + (zone.x * pixmap_xscale);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
startindex += pixmap_xscale >> 1; // Center on X
|
|
|
|
startindex += (pixmap_yscale >> 1) * pixmap->index_xl; // Center on Y
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (_gfxop_clip(&zone, gfx_rect(0, 0, pixmap->index_xl, pixmap->index_yl)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (zone.yl--) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < (zone.xl * pixmap_xscale); i += pixmap_xscale)
|
|
|
|
retval |= (1 << ((pixmap->index_data[startindex + i]) & 0xf));
|
|
|
|
|
|
|
|
startindex += line_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_scan_bitmask(gfx_state_t *state, rect_t area, gfx_map_mask_t map) {
|
2009-02-15 22:33:36 +00:00
|
|
|
gfxr_pic_t *pic = (state->pic_unscaled) ? state->pic_unscaled : state->pic;
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
_gfxop_clip(&area, gfx_rect(0, 10, 320, 200));
|
|
|
|
|
|
|
|
if (area.xl <= 0
|
2009-02-15 22:33:36 +00:00
|
|
|
|| area.yl <= 0)
|
2009-02-15 06:10:59 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (map & GFX_MASK_VISUAL)
|
|
|
|
retval |= _gfxop_scan_one_bitmask(pic->visual_map, area);
|
|
|
|
|
|
|
|
if (map & GFX_MASK_PRIORITY)
|
|
|
|
retval |= _gfxop_scan_one_bitmask(state->priority_map, area);
|
|
|
|
if (map & GFX_MASK_CONTROL)
|
|
|
|
retval |= _gfxop_scan_one_bitmask(state->control_map, area);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MIN_X 0
|
|
|
|
#define MIN_Y 0
|
|
|
|
#define MAX_X 319
|
|
|
|
#define MAX_Y 199
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_clip_zone(gfx_state_t *state, rect_t zone) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int xfact, yfact;
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
DDIRTY(stderr, "-- Setting clip zone %d %d %d %d\n", GFX_PRINT_RECT(zone));
|
|
|
|
|
|
|
|
xfact = state->driver->mode->xfact;
|
|
|
|
yfact = state->driver->mode->yfact;
|
|
|
|
|
|
|
|
if (zone.x < MIN_X) {
|
|
|
|
zone.xl -= (zone.x - MIN_X);
|
|
|
|
zone.x = MIN_X;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zone.y < MIN_Y) {
|
|
|
|
zone.yl -= (zone.y - MIN_Y);
|
|
|
|
zone.y = MIN_Y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zone.x + zone.xl > MAX_X)
|
|
|
|
zone.xl = MAX_X + 1 - zone.x;
|
|
|
|
|
|
|
|
if (zone.y + zone.yl > MAX_Y)
|
|
|
|
zone.yl = MAX_Y + 1 - zone.y;
|
|
|
|
|
|
|
|
memcpy(&(state->clip_zone_unscaled), &zone, sizeof(rect_t));
|
|
|
|
|
|
|
|
state->clip_zone.x = state->clip_zone_unscaled.x * xfact;
|
|
|
|
state->clip_zone.y = state->clip_zone_unscaled.y * yfact;
|
|
|
|
state->clip_zone.xl = state->clip_zone_unscaled.xl * xfact;
|
|
|
|
state->clip_zone.yl = state->clip_zone_unscaled.yl * yfact;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_color(gfx_state_t *state, gfx_color_t *color, int r, int g, int b, int a, int priority, int control) {
|
|
|
|
int mask = ((r >= 0 && g >= 0 && b >= 0) ? GFX_MASK_VISUAL : 0) | ((priority >= 0) ? GFX_MASK_PRIORITY : 0)
|
2009-02-15 22:33:36 +00:00
|
|
|
| ((control >= 0) ? GFX_MASK_CONTROL : 0);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (PALETTE_MODE && a >= GFXOP_ALPHA_THRESHOLD)
|
|
|
|
mask &= ~GFX_MASK_VISUAL;
|
|
|
|
|
|
|
|
color->mask = mask;
|
|
|
|
|
|
|
|
color->priority = priority;
|
|
|
|
color->control = control;
|
|
|
|
|
|
|
|
if (mask & GFX_MASK_VISUAL) {
|
|
|
|
color->visual.r = r;
|
|
|
|
color->visual.g = g;
|
|
|
|
color->visual.b = b;
|
|
|
|
color->alpha = a;
|
|
|
|
|
|
|
|
if (PALETTE_MODE) {
|
2009-03-08 20:17:01 +00:00
|
|
|
color->visual.parent_index = state->driver->mode->palette->findNearbyColor(r,g,b,true);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-03-03 14:27:49 +00:00
|
|
|
// Wrapper for gfxop_set_color
|
|
|
|
int gfxop_set_color(gfx_state_t *state, gfx_color_t *colorOut, gfx_color_t &colorIn) {
|
|
|
|
if (colorIn.mask & GFX_MASK_VISUAL)
|
|
|
|
return gfxop_set_color(state, colorOut, colorIn.visual.r, colorIn.visual.g, colorIn.visual.b,
|
|
|
|
colorIn.alpha, colorIn.priority, colorIn.control);
|
|
|
|
else
|
|
|
|
return gfxop_set_color(state, colorOut, -1, -1, -1, colorIn.alpha,
|
|
|
|
colorIn.priority, colorIn.control);
|
|
|
|
}
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
int gfxop_set_system_color(gfx_state_t *state, unsigned int index, gfx_color_t *color) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (!PALETTE_MODE)
|
|
|
|
return GFX_OK;
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
if (index >= state->driver->mode->palette->size()) {
|
|
|
|
GFXERROR("Attempt to set invalid color index %02x as system color\n", color->visual.parent_index);
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
state->driver->mode->palette->makeSystemColor(index, color->visual);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_free_color(gfx_state_t *state, gfx_color_t *color) {
|
2009-03-08 20:17:01 +00:00
|
|
|
// FIXME: implement. (And call in the appropriate places!)
|
2009-03-08 20:43:36 +00:00
|
|
|
return GFX_OK;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Generic drawing operations
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int line_check_bar(int *start, int *length, int clipstart, int cliplength) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int overlength;
|
|
|
|
|
|
|
|
if (*start < clipstart) {
|
|
|
|
*length -= (clipstart - *start);
|
|
|
|
*start = clipstart;
|
|
|
|
}
|
|
|
|
|
|
|
|
overlength = 1 + (*start + *length) - (clipstart + cliplength);
|
|
|
|
|
|
|
|
if (overlength > 0)
|
|
|
|
*length -= overlength;
|
|
|
|
|
|
|
|
return (*length < 0);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void clip_line_partial(float *start, float *end, float delta_val, float pos_val, float start_val, float end_val) {
|
2009-02-15 06:10:59 +00:00
|
|
|
float my_start = (start_val - pos_val) * delta_val;
|
|
|
|
float my_end = (end_val - pos_val) * delta_val;
|
|
|
|
|
|
|
|
if (my_end < *end)
|
|
|
|
*end = my_end;
|
|
|
|
if (my_start > *start)
|
|
|
|
*start = my_start;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int line_clip(rect_t *line, rect_t clip, int xfact, int yfact) {
|
|
|
|
// returns 1 if nothing is left, or 0 if part of the line is in the clip window
|
|
|
|
// Compensate for line thickness (should match precisely)
|
2009-02-15 06:10:59 +00:00
|
|
|
clip.xl -= xfact;
|
|
|
|
clip.yl -= yfact;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (!line->xl) { // vbar
|
2009-02-15 06:10:59 +00:00
|
|
|
if (line->x < clip.x || line->x >= (clip.x + clip.xl))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return line_check_bar(&(line->y), &(line->yl), clip.y, clip.yl);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
} else {
|
|
|
|
if (!line->yl) {// hbar
|
2009-02-15 22:33:36 +00:00
|
|
|
if (line->y < clip.y || line->y >= (clip.y + clip.yl))
|
|
|
|
return 1;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
return line_check_bar(&(line->x), &(line->xl), clip.x, clip.xl);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
} else { // "normal" line
|
2009-02-15 22:33:36 +00:00
|
|
|
float start = 0.0, end = 1.0;
|
2009-02-21 08:47:07 +00:00
|
|
|
float xv = (float)line->xl;
|
|
|
|
float yv = (float)line->yl;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
if (line->xl < 0)
|
2009-02-21 08:47:07 +00:00
|
|
|
clip_line_partial(&start, &end, (float)(1.0 / xv), (float)line->x, (float)(clip.x + clip.xl), (float)clip.x);
|
2009-02-15 22:33:36 +00:00
|
|
|
else
|
2009-02-21 08:47:07 +00:00
|
|
|
clip_line_partial(&start, &end, (float)(1.0 / xv), (float)line->x, (float)clip.x, (float)(clip.x + clip.xl));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
if (line->yl < 0)
|
2009-02-21 08:47:07 +00:00
|
|
|
clip_line_partial(&start, &end, (float)(1.0 / yv), (float)line->y, (float)(clip.y + clip.yl), (float)clip.y);
|
2009-02-15 22:33:36 +00:00
|
|
|
else
|
2009-02-21 08:47:07 +00:00
|
|
|
clip_line_partial(&start, &end, (float)(1.0 / yv), (float)line->y, (float)clip.y, (float)(clip.y + clip.yl));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
line->x += (int)(xv * start);
|
|
|
|
line->y += (int)(yv * start);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
line->xl = (int)(xv * (end - start));
|
|
|
|
line->yl = (int)(yv * (end - start));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
return (start > 1.0 || end < 0.0);
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
}
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int point_clip(Common::Point *start, Common::Point *end, rect_t clip, int xfact, int yfact) {
|
2009-02-15 06:10:59 +00:00
|
|
|
rect_t line = gfx_rect(start->x, start->y, end->x - start->x, end->y - start->y);
|
|
|
|
int retval = line_clip(&line, clip, xfact, yfact);
|
|
|
|
|
|
|
|
start->x = line.x;
|
|
|
|
start->y = line.y;
|
|
|
|
|
|
|
|
end->x = line.x + line.xl;
|
|
|
|
end->y = line.y + line.yl;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static void draw_line_to_control_map(gfx_state_t *state, Common::Point start, Common::Point end, gfx_color_t color) {
|
2009-02-15 06:10:59 +00:00
|
|
|
if (color.mask & GFX_MASK_CONTROL)
|
|
|
|
if (!point_clip(&start, &end, state->clip_zone_unscaled, 0, 0))
|
|
|
|
gfx_draw_line_pixmap_i(state->control_map, start, end, color.control);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int simulate_stippled_line_draw(gfx_driver_t *driver, int skipone, Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode) {
|
|
|
|
// Draws a stippled line if this isn't supported by the driver (skipone is ignored ATM)
|
2009-02-15 06:10:59 +00:00
|
|
|
int xl = end.x - start.x;
|
|
|
|
int yl = end.y - start.y;
|
2009-02-15 22:33:36 +00:00
|
|
|
int stepwidth = (xl) ? driver->mode->xfact : driver->mode->yfact;
|
|
|
|
int dbl_stepwidth = 2 * stepwidth;
|
|
|
|
int linelength = (line_mode == GFX_LINE_MODE_FINE) ? stepwidth - 1 : 0;
|
2009-02-15 06:10:59 +00:00
|
|
|
int *posvar;
|
|
|
|
int length;
|
|
|
|
int delta;
|
|
|
|
int length_left;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (!xl) { // xl = 0, so we move along yl
|
2009-02-17 19:15:37 +00:00
|
|
|
posvar = (int *) &start.y;
|
2009-02-15 06:10:59 +00:00
|
|
|
length = yl;
|
2009-02-15 22:33:36 +00:00
|
|
|
delta = (yl < 0) ? -dbl_stepwidth : dbl_stepwidth;
|
2009-02-15 06:10:59 +00:00
|
|
|
} else {
|
2009-02-21 08:47:07 +00:00
|
|
|
assert(!yl); // We don't do diagonals; that's not needed ATM.
|
2009-02-17 19:15:37 +00:00
|
|
|
posvar = (int *) &start.x;
|
2009-02-15 06:10:59 +00:00
|
|
|
length = xl;
|
2009-02-15 22:33:36 +00:00
|
|
|
delta = (xl < 0) ? -dbl_stepwidth : dbl_stepwidth;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
length_left = length;
|
|
|
|
|
|
|
|
if (skipone) {
|
|
|
|
length_left -= stepwidth;
|
|
|
|
*posvar += stepwidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
length /= delta;
|
|
|
|
|
|
|
|
length_left -= length * dbl_stepwidth;
|
|
|
|
|
|
|
|
if (xl)
|
|
|
|
xl = linelength;
|
|
|
|
else
|
|
|
|
yl = linelength;
|
|
|
|
|
|
|
|
while (length--) {
|
|
|
|
int retval;
|
2009-02-17 19:15:37 +00:00
|
|
|
Common::Point nextpos = Common::Point(start.x + xl, start.y + yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if ((retval = driver->draw_line(driver, start, nextpos, color, line_mode, GFX_LINE_STYLE_NORMAL))) {
|
|
|
|
GFXERROR("Failed to draw partial stippled line (%d,%d) -- (%d,%d)\n", start.x, start.y, nextpos.x, nextpos.y);
|
2009-02-15 06:10:59 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
*posvar += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length_left) {
|
|
|
|
int retval;
|
2009-02-17 19:15:37 +00:00
|
|
|
Common::Point nextpos;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (length_left > stepwidth)
|
|
|
|
length_left = stepwidth;
|
|
|
|
|
|
|
|
if (xl)
|
|
|
|
xl = length_left;
|
|
|
|
else
|
|
|
|
if (yl)
|
|
|
|
yl = length_left;
|
|
|
|
|
2009-02-17 19:15:37 +00:00
|
|
|
nextpos = Common::Point(start.x + xl, start.y + yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if ((retval = driver->draw_line(driver, start, nextpos, color, line_mode, GFX_LINE_STYLE_NORMAL))) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXERROR("Failed to draw partial stippled line (%d,%d) -- (%d,%d)\n", start.x, start.y, nextpos.x, nextpos.y);
|
2009-02-15 06:10:59 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_draw_line_clipped(gfx_state_t *state, Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode,
|
2009-02-22 13:11:43 +00:00
|
|
|
gfx_line_style_t line_style) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval;
|
2009-02-21 08:47:07 +00:00
|
|
|
int skipone = (start.x ^ end.y) & 1; // Used for simulated line stippling
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// First, make sure that the line is normalized
|
2009-02-15 06:10:59 +00:00
|
|
|
if (start.y > end.y) {
|
2009-02-17 19:15:37 +00:00
|
|
|
Common::Point swap = start;
|
2009-02-15 06:10:59 +00:00
|
|
|
start = end;
|
|
|
|
end = swap;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start.x < state->clip_zone.x
|
2009-02-15 22:33:36 +00:00
|
|
|
|| start.y < state->clip_zone.y
|
|
|
|
|| end.x >= (state->clip_zone.x + state->clip_zone.xl)
|
|
|
|
|| end.y >= (state->clip_zone.y + state->clip_zone.yl))
|
2009-02-21 08:47:07 +00:00
|
|
|
if (point_clip(&start, &end, state->clip_zone, state->driver->mode->xfact - 1, state->driver->mode->yfact - 1))
|
|
|
|
return GFX_OK; // Clipped off
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (line_style == GFX_LINE_STYLE_STIPPLED) {
|
|
|
|
if (start.x != end.x && start.y != end.y) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXWARN("Attempt to draw stippled line which is neither an hbar nor a vbar: (%d,%d) -- (%d,%d)\n", start.x, start.y, end.x, end.y);
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
if (!(state->driver->capabilities & GFX_CAPABILITY_STIPPLED_LINES))
|
|
|
|
return simulate_stippled_line_draw(state->driver, skipone, start, end, color, line_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((retval = state->driver->draw_line(state->driver, start, end, color, line_mode, line_style))) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXERROR("Failed to draw line (%d,%d) -- (%d,%d)\n", start.x, start.y, end.x, end.y);
|
2009-02-15 06:10:59 +00:00
|
|
|
return retval;
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_line(gfx_state_t *state, Common::Point start, Common::Point end,
|
2009-02-22 13:11:43 +00:00
|
|
|
gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int xfact, yfact;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
_gfxop_add_dirty_x(state, gfx_rect(start.x, start.y, end.x - start.x, end.y - start.y));
|
|
|
|
|
|
|
|
xfact = state->driver->mode->xfact;
|
|
|
|
yfact = state->driver->mode->yfact;
|
|
|
|
|
|
|
|
draw_line_to_control_map(state, start, end, color);
|
|
|
|
|
|
|
|
_gfxop_scale_point(&start, state->driver->mode);
|
|
|
|
_gfxop_scale_point(&end, state->driver->mode);
|
|
|
|
|
|
|
|
if (line_mode == GFX_LINE_MODE_FINE) {
|
|
|
|
start.x += xfact >> 1;
|
|
|
|
start.y += yfact >> 1;
|
|
|
|
|
|
|
|
end.x += xfact >> 1;
|
|
|
|
end.y += yfact >> 1;
|
|
|
|
}
|
2009-03-03 14:27:49 +00:00
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
if (color.visual.parent_index == GFX_COLOR_INDEX_UNMAPPED)
|
2009-03-03 14:27:49 +00:00
|
|
|
gfxop_set_color(state, &color, color);
|
2009-02-15 06:10:59 +00:00
|
|
|
return _gfxop_draw_line_clipped(state, start, end, color, line_mode, line_style);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_rectangle(gfx_state_t *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval = 0;
|
|
|
|
int xfact, yfact;
|
|
|
|
int xunit, yunit;
|
|
|
|
int x, y, xl, yl;
|
2009-02-17 19:15:37 +00:00
|
|
|
Common::Point upper_left_u, upper_right_u, lower_left_u, lower_right_u;
|
|
|
|
Common::Point upper_left, upper_right, lower_left, lower_right;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
xfact = state->driver->mode->xfact;
|
|
|
|
yfact = state->driver->mode->yfact;
|
|
|
|
|
2009-02-17 22:53:09 +00:00
|
|
|
if (line_mode == GFX_LINE_MODE_FINE) {
|
2009-02-15 06:10:59 +00:00
|
|
|
xunit = yunit = 1;
|
|
|
|
xl = 1 + (rect.xl - 1) * xfact;
|
|
|
|
yl = 1 + (rect.yl - 1) * yfact;
|
|
|
|
x = rect.x * xfact + (xfact - 1);
|
|
|
|
y = rect.y * yfact + (yfact - 1);
|
|
|
|
} else {
|
|
|
|
xunit = xfact;
|
|
|
|
yunit = yfact;
|
|
|
|
xl = rect.xl * xfact;
|
|
|
|
yl = rect.yl * yfact;
|
|
|
|
x = rect.x * xfact;
|
|
|
|
y = rect.y * yfact;
|
|
|
|
}
|
|
|
|
|
2009-02-17 19:15:37 +00:00
|
|
|
upper_left_u = Common::Point(rect.x, rect.y);
|
|
|
|
upper_right_u = Common::Point(rect.x + rect.xl, rect.y);
|
|
|
|
lower_left_u = Common::Point(rect.x, rect.y + rect.yl);
|
|
|
|
lower_right_u = Common::Point(rect.x + rect.xl, rect.y + rect.yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-17 19:15:37 +00:00
|
|
|
upper_left = Common::Point(x, y);
|
|
|
|
upper_right = Common::Point(x + xl, y);
|
|
|
|
lower_left = Common::Point(x, y + yl);
|
|
|
|
lower_right = Common::Point(x + xl, y + yl);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-22 13:11:43 +00:00
|
|
|
#define PARTIAL_LINE(pt1, pt2) \
|
2009-02-15 06:10:59 +00:00
|
|
|
retval |= _gfxop_draw_line_clipped(state, pt1, pt2, color, line_mode, line_style); \
|
|
|
|
draw_line_to_control_map(state, pt1##_u, pt2##_u, color); \
|
2009-02-21 08:47:07 +00:00
|
|
|
_gfxop_add_dirty_x(state, gfx_rect(pt1##_u.x, pt1##_u.y, pt2##_u.x - pt1##_u.x, pt2##_u.y - pt1##_u.y))
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
PARTIAL_LINE(upper_left, upper_right);
|
|
|
|
PARTIAL_LINE(upper_right, lower_right);
|
|
|
|
PARTIAL_LINE(lower_right, lower_left);
|
|
|
|
PARTIAL_LINE(lower_left, upper_left);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
#undef PARTIAL_LINE
|
|
|
|
if (retval) {
|
|
|
|
GFXERROR("Failed to draw rectangle (%d,%d)+(%d,%d)\n", rect.x, rect.y, rect.xl, rect.yl);
|
|
|
|
return retval;
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define COLOR_MIX(type, dist) ((color1.type * dist) + (color2.type * (1.0 - dist)))
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_box(gfx_state_t *state, rect_t box, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_driver_t *drv = state->driver;
|
2009-02-21 08:47:07 +00:00
|
|
|
int reverse = 0; // switch color1 and color2
|
|
|
|
float mod_offset = 0.0, mod_breadth = 1.0; // 0.0 to 1.0: Color adjustment
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_rectangle_fill_t driver_shade_type;
|
|
|
|
rect_t new_box;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (PALETTE_MODE || !(state->driver->capabilities & GFX_CAPABILITY_SHADING))
|
|
|
|
shade_type = GFX_BOX_SHADE_FLAT;
|
|
|
|
|
|
|
|
|
|
|
|
_gfxop_add_dirty(state, box);
|
|
|
|
|
|
|
|
if (color1.mask & GFX_MASK_CONTROL) {
|
2009-02-21 08:47:07 +00:00
|
|
|
// Write control block, clipped by 320x200
|
2009-02-15 06:10:59 +00:00
|
|
|
memcpy(&new_box, &box, sizeof(rect_t));
|
|
|
|
_gfxop_clip(&new_box, gfx_rect(0, 0, 320, 200));
|
|
|
|
|
|
|
|
gfx_draw_box_pixmap_i(state->control_map, new_box, color1.control);
|
|
|
|
}
|
|
|
|
|
|
|
|
_gfxop_scale_rect(&box, state->driver->mode);
|
|
|
|
|
|
|
|
if (!(color1.mask & (GFX_MASK_VISUAL | GFX_MASK_PRIORITY)))
|
2009-02-21 08:47:07 +00:00
|
|
|
return GFX_OK;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (box.xl <= 1 || box.yl <= 1) {
|
|
|
|
GFXDEBUG("Attempt to draw box with size %dx%d\n", box.xl, box.yl);
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&new_box, &box, sizeof(rect_t));
|
|
|
|
if (_gfxop_clip(&new_box, state->clip_zone))
|
|
|
|
return GFX_OK;
|
|
|
|
|
|
|
|
switch (shade_type) {
|
|
|
|
|
|
|
|
case GFX_BOX_SHADE_FLAT:
|
|
|
|
driver_shade_type = GFX_SHADE_FLAT;
|
|
|
|
break;
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
case GFX_BOX_SHADE_LEFT:
|
|
|
|
reverse = 1;
|
2009-02-15 06:10:59 +00:00
|
|
|
case GFX_BOX_SHADE_RIGHT:
|
|
|
|
driver_shade_type = GFX_SHADE_HORIZONTALLY;
|
2009-02-15 22:33:36 +00:00
|
|
|
mod_offset = (float)(((new_box.x - box.x) * 1.0) / (box.xl * 1.0));
|
|
|
|
mod_breadth = (float)((new_box.xl * 1.0) / (box.xl * 1.0));
|
2009-02-15 06:10:59 +00:00
|
|
|
break;
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
case GFX_BOX_SHADE_UP:
|
|
|
|
reverse = 1;
|
2009-02-15 06:10:59 +00:00
|
|
|
case GFX_BOX_SHADE_DOWN:
|
|
|
|
driver_shade_type = GFX_SHADE_VERTICALLY;
|
2009-02-15 22:33:36 +00:00
|
|
|
mod_offset = (float)(((new_box.y - box.y) * 1.0) / (box.yl * 1.0));
|
|
|
|
mod_breadth = (float)((new_box.yl * 1.0) / (box.yl * 1.0));
|
2009-02-15 06:10:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
GFXERROR("Invalid shade type: %d\n", shade_type);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (reverse)
|
2009-02-15 22:33:36 +00:00
|
|
|
mod_offset = (float)(1.0 - (mod_offset + mod_breadth));
|
2009-02-21 08:47:07 +00:00
|
|
|
// Reverse offset if we have to interpret colors inversely
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-03-01 04:07:04 +00:00
|
|
|
if (shade_type == GFX_BOX_SHADE_FLAT) {
|
2009-03-08 13:43:11 +00:00
|
|
|
color1.priority = 0;
|
|
|
|
color1.control = 0;
|
2009-03-08 20:17:01 +00:00
|
|
|
if (color1.visual.parent_index == GFX_COLOR_INDEX_UNMAPPED)
|
2009-03-03 14:27:49 +00:00
|
|
|
gfxop_set_color(state, &color1, color1);
|
2009-02-15 06:10:59 +00:00
|
|
|
return drv->draw_filled_rect(drv, new_box, color1, color1, GFX_SHADE_FLAT);
|
2009-03-01 04:07:04 +00:00
|
|
|
} else {
|
2009-02-15 06:10:59 +00:00
|
|
|
if (PALETTE_MODE) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXWARN("Attempting to draw shaded box in palette mode!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-03-08 20:17:01 +00:00
|
|
|
gfx_color_t draw_color1; // CHECKME
|
|
|
|
gfx_color_t draw_color2;
|
|
|
|
gfxop_set_color(state, &draw_color1, 0, 0, 0, 0, 0, 0);
|
|
|
|
gfxop_set_color(state, &draw_color2, 0, 0, 0, 0, 0, 0);
|
2009-02-15 23:49:42 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
draw_color1.mask = draw_color2.mask = color1.mask;
|
|
|
|
draw_color1.priority = draw_color2.priority = color1.priority;
|
|
|
|
|
|
|
|
if (draw_color1.mask & GFX_MASK_VISUAL) {
|
2009-02-21 21:16:41 +00:00
|
|
|
draw_color1.visual.r = (uint8) COLOR_MIX(visual.r, mod_offset);
|
|
|
|
draw_color1.visual.g = (uint8) COLOR_MIX(visual.g, mod_offset);
|
|
|
|
draw_color1.visual.b = (uint8) COLOR_MIX(visual.b, mod_offset);
|
|
|
|
draw_color1.alpha = (uint8) COLOR_MIX(alpha, mod_offset);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
mod_offset += mod_breadth;
|
|
|
|
|
2009-02-21 21:16:41 +00:00
|
|
|
draw_color2.visual.r = (uint8) COLOR_MIX(visual.r, mod_offset);
|
|
|
|
draw_color2.visual.g = (uint8) COLOR_MIX(visual.g, mod_offset);
|
|
|
|
draw_color2.visual.b = (uint8) COLOR_MIX(visual.b, mod_offset);
|
|
|
|
draw_color2.alpha = (uint8) COLOR_MIX(alpha, mod_offset);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
if (reverse)
|
|
|
|
return drv->draw_filled_rect(drv, new_box, draw_color2, draw_color1, driver_shade_type);
|
|
|
|
else
|
|
|
|
return drv->draw_filled_rect(drv, new_box, draw_color1, draw_color2, driver_shade_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef COLOR_MIX
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_fill_box(gfx_state_t *state, rect_t box, gfx_color_t color) {
|
2009-02-15 06:10:59 +00:00
|
|
|
return gfxop_draw_box(state, box, color, color, GFX_BOX_SHADE_FLAT);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_buffer_propagate_box(gfx_state_t *state, rect_t box, gfx_buffer_t buffer) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int error;
|
|
|
|
|
|
|
|
if (_gfxop_clip(&box, gfx_rect(0, 0, 320 * state->driver->mode->xfact, 200 * state->driver->mode->yfact)))
|
|
|
|
return GFX_OK;
|
|
|
|
|
2009-02-17 19:15:37 +00:00
|
|
|
if ((error = state->driver->update(state->driver, box, Common::Point(box.x, box.y), buffer))) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXERROR("Error occured while updating region (%d,%d,%d,%d) in buffer %d\n", box.x, box.y, box.xl, box.yl, buffer);
|
2009-02-15 06:10:59 +00:00
|
|
|
return error;
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-22 13:11:43 +00:00
|
|
|
extern int sci0_palette;
|
2009-02-21 08:47:07 +00:00
|
|
|
|
|
|
|
int gfxop_clear_box(gfx_state_t *state, rect_t box) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
_gfxop_add_dirty(state, box);
|
|
|
|
DDIRTY(stderr, "[] clearing box %d %d %d %d\n", GFX_PRINT_RECT(box));
|
2009-02-21 08:47:07 +00:00
|
|
|
if (box.x == 29 && box.y == 77 && (sci0_palette == 1)) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BREAKPOINT();
|
|
|
|
}
|
|
|
|
|
|
|
|
_gfxop_clip(&box, gfx_rect(0, 0, 320, 200));
|
|
|
|
#ifdef PRECISE_PRIORITY_MAP
|
|
|
|
if (state->pic_unscaled)
|
|
|
|
gfx_copy_pixmap_box_i(state->priority_map, state->static_priority_map, box);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
_gfxop_scale_rect(&box, state->driver->mode);
|
|
|
|
|
|
|
|
return _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_BACK);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_visible_map(gfx_state_t *state, gfx_map_mask_t visible_map) {
|
2009-02-15 06:10:59 +00:00
|
|
|
switch (visible_map) {
|
|
|
|
|
|
|
|
case GFX_MASK_VISUAL:
|
|
|
|
state->fullscreen_override = NULL;
|
|
|
|
if (visible_map != state->visible_map) {
|
|
|
|
rect_t rect = gfx_rect(0, 0, 320, 200);
|
|
|
|
gfxop_clear_box(state, rect);
|
|
|
|
gfxop_update_box(state, rect);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GFX_MASK_PRIORITY:
|
|
|
|
state->fullscreen_override = state->priority_map;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GFX_MASK_CONTROL:
|
|
|
|
state->fullscreen_override = state->control_map;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-02-21 14:11:41 +00:00
|
|
|
fprintf(stderr, "Invalid display map %d selected!\n", visible_map);
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->visible_map = visible_map;
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_update(gfx_state_t *state) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
retval = _gfxop_clear_dirty_rec(state, state->dirty_rects);
|
|
|
|
|
|
|
|
state->dirty_rects = NULL;
|
|
|
|
|
|
|
|
if (state->fullscreen_override) {
|
2009-02-21 08:47:07 +00:00
|
|
|
// We've been asked to re-draw the active full-screen image, essentially.
|
2009-02-15 06:10:59 +00:00
|
|
|
rect_t rect = gfx_rect(0, 0, 320, 200);
|
|
|
|
gfx_xlate_pixmap(state->fullscreen_override, state->driver->mode, GFX_XLATE_FILTER_NONE);
|
2009-02-17 19:15:37 +00:00
|
|
|
gfxop_draw_pixmap(state, state->fullscreen_override, rect, Common::Point(0, 0));
|
2009-02-15 06:10:59 +00:00
|
|
|
retval |= _gfxop_update_box(state, rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Clearing the dirty rectangles failed!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (state->tag_mode) {
|
2009-02-21 08:47:07 +00:00
|
|
|
// This usually happens after a pic and all resources have been drawn
|
2009-02-15 06:10:59 +00:00
|
|
|
gfxr_free_tagged_resources(state->driver, state->resstate);
|
|
|
|
state->tag_mode = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_update_box(gfx_state_t *state, rect_t box) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (state->disable_dirty)
|
|
|
|
_gfxop_update_box(state, box);
|
|
|
|
else
|
|
|
|
_gfxop_add_dirty(state, box);
|
|
|
|
|
|
|
|
return gfxop_update(state);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_enable_dirty_frames(gfx_state_t *state) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
state->disable_dirty = 0;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_disable_dirty_frames(gfx_state_t *state) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
state->disable_dirty = 1;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Pointer and IO ops
|
2009-02-24 20:50:09 +00:00
|
|
|
int gfxop_sleep(gfx_state_t *state, uint32 msecs) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
2009-02-24 20:33:31 +00:00
|
|
|
uint32 time;
|
2009-02-24 20:50:09 +00:00
|
|
|
const uint32 wakeup_time = g_system->getMillis() + msecs;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-24 20:33:31 +00:00
|
|
|
while (true) {
|
2009-02-25 18:23:28 +00:00
|
|
|
// let backend process events and update the screen
|
|
|
|
gfxop_get_event(state, SCI_EVT_PEEK);
|
|
|
|
g_system->updateScreen();
|
2009-02-21 22:00:24 +00:00
|
|
|
time = g_system->getMillis();
|
2009-02-25 18:23:28 +00:00
|
|
|
if (time + 10 < wakeup_time) {
|
|
|
|
g_system->delayMillis(10);
|
|
|
|
} else {
|
|
|
|
if (time < wakeup_time)
|
|
|
|
g_system->delayMillis(wakeup_time - time);
|
2009-02-24 20:33:31 +00:00
|
|
|
break;
|
2009-02-25 18:23:28 +00:00
|
|
|
}
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-24 20:33:31 +00:00
|
|
|
return GFX_OK;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int _gfxop_set_pointer(gfx_state_t *state, gfx_pixmap_t *pxm) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
2009-02-17 22:53:09 +00:00
|
|
|
state->driver->set_pointer(state->driver, pxm);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_pointer_cursor(gfx_state_t *state, int nr) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_pixmap_t *new_pointer = NULL;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (nr == GFXOP_NO_POINTER)
|
|
|
|
new_pointer = NULL;
|
|
|
|
else {
|
|
|
|
new_pointer = gfxr_get_cursor(state->resstate, nr);
|
|
|
|
|
|
|
|
if (!new_pointer) {
|
|
|
|
GFXWARN("Attempt to set invalid pointer #%d\n", nr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return _gfxop_set_pointer(state, new_pointer);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_pointer_view(gfx_state_t *state, int nr, int loop, int cel, Common::Point *hotspot) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int real_loop = loop;
|
|
|
|
int real_cel = cel;
|
|
|
|
gfx_pixmap_t *new_pointer = NULL;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
new_pointer = _gfxr_get_cel(state, nr, &real_loop, &real_cel, 0); // FIXME: For now, don't palettize pointers
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
if (hotspot) {
|
2009-02-15 06:10:59 +00:00
|
|
|
new_pointer->xoffset = hotspot->x;
|
|
|
|
new_pointer->yoffset = hotspot->y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!new_pointer) {
|
|
|
|
GFXWARN("Attempt to set invalid pointer #%d\n", nr);
|
|
|
|
return GFX_ERROR;
|
2009-02-15 22:33:36 +00:00
|
|
|
} else {
|
2009-02-15 06:10:59 +00:00
|
|
|
if (real_loop != loop || real_cel != cel) {
|
2009-02-21 08:47:07 +00:00
|
|
|
GFXDEBUG("Changed loop/cel from %d/%d to %d/%d in view %d\n", loop, cel, real_loop, real_cel, nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
return _gfxop_set_pointer(state, new_pointer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_set_pointer_position(gfx_state_t *state, Common::Point pos) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
state->pointer_pos = pos;
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
if (pos.x > 320 || pos.y > 200) {
|
2009-02-15 06:10:59 +00:00
|
|
|
GFXWARN("Attempt to place pointer at invalid coordinates (%d, %d)\n", pos.x, pos.y);
|
2009-02-21 08:47:07 +00:00
|
|
|
return 0; // Not fatal
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
state->driver->pointer_x = pos.x * state->driver->mode->xfact;
|
|
|
|
state->driver->pointer_y = pos.y * state->driver->mode->yfact;
|
2009-02-25 19:28:46 +00:00
|
|
|
g_system->warpMouse(state->driver->pointer_x, state->driver->pointer_y);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SCANCODE_ROWS_NR 3
|
|
|
|
|
|
|
|
struct scancode_row {
|
|
|
|
int offset;
|
|
|
|
const char *keys;
|
|
|
|
} scancode_rows[SCANCODE_ROWS_NR] = {
|
|
|
|
{0x10, "QWERTYUIOP[]"},
|
|
|
|
{0x1e, "ASDFGHJKL;'\\"},
|
|
|
|
{0x2c, "ZXCVBNM,./"}
|
|
|
|
};
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_scancode(int ch) {
|
|
|
|
// Calculates a PC keyboard scancode from a character */
|
2009-02-15 06:10:59 +00:00
|
|
|
int row;
|
|
|
|
int c = toupper((char)ch);
|
|
|
|
|
|
|
|
for (row = 0; row < SCANCODE_ROWS_NR; row++) {
|
|
|
|
const char *keys = scancode_rows[row].keys;
|
|
|
|
int offset = scancode_rows[row].offset;
|
|
|
|
|
|
|
|
while (*keys) {
|
|
|
|
if (*keys == c)
|
|
|
|
return offset << 8;
|
|
|
|
|
|
|
|
offset++;
|
|
|
|
keys++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
return ch;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int _gfxop_shiftify(int c) {
|
2009-02-15 06:10:59 +00:00
|
|
|
char shifted_numbers[] = ")!@#$%^&*(";
|
2009-02-15 22:33:36 +00:00
|
|
|
|
|
|
|
if (c < 256) {
|
2009-02-15 06:10:59 +00:00
|
|
|
c = toupper((char)c);
|
|
|
|
|
|
|
|
if (c >= 'A' && c <= 'Z')
|
|
|
|
return c;
|
|
|
|
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
return shifted_numbers[c-'0'];
|
2009-02-15 22:33:36 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
switch (c) {
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_TAB:
|
2009-02-15 22:33:36 +00:00
|
|
|
return SCI_K_SHIFT_TAB;
|
|
|
|
case ']':
|
|
|
|
return '}';
|
|
|
|
case '[':
|
|
|
|
return '{';
|
|
|
|
case '`':
|
|
|
|
return '~';
|
|
|
|
case '-':
|
|
|
|
return '_';
|
|
|
|
case '=':
|
|
|
|
return '+';
|
|
|
|
case ';':
|
|
|
|
return ':';
|
|
|
|
case '\'':
|
|
|
|
return '"';
|
|
|
|
case '\\':
|
|
|
|
return '|';
|
|
|
|
case ',':
|
|
|
|
return '<';
|
|
|
|
case '.':
|
|
|
|
return '>';
|
|
|
|
case '/':
|
|
|
|
return '?';
|
|
|
|
default:
|
2009-02-21 08:47:07 +00:00
|
|
|
return c; // No match
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
switch (c) {
|
|
|
|
case SCI_K_F1 :
|
|
|
|
return SCI_K_SHIFT_F1;
|
|
|
|
case SCI_K_F2 :
|
|
|
|
return SCI_K_SHIFT_F2;
|
|
|
|
case SCI_K_F3 :
|
|
|
|
return SCI_K_SHIFT_F3;
|
|
|
|
case SCI_K_F4 :
|
|
|
|
return SCI_K_SHIFT_F4;
|
|
|
|
case SCI_K_F5 :
|
|
|
|
return SCI_K_SHIFT_F5;
|
|
|
|
case SCI_K_F6 :
|
|
|
|
return SCI_K_SHIFT_F6;
|
|
|
|
case SCI_K_F7 :
|
|
|
|
return SCI_K_SHIFT_F7;
|
|
|
|
case SCI_K_F8 :
|
|
|
|
return SCI_K_SHIFT_F8;
|
|
|
|
case SCI_K_F9 :
|
|
|
|
return SCI_K_SHIFT_F9;
|
|
|
|
case SCI_K_F10 :
|
|
|
|
return SCI_K_SHIFT_F10;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_numlockify(int c) {
|
2009-02-15 06:10:59 +00:00
|
|
|
switch (c) {
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_DELETE:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '.';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_INSERT:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '0';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_END:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '1';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_DOWN:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '2';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_PGDOWN:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '3';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_LEFT:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '4';
|
|
|
|
case SCI_K_CENTER:
|
|
|
|
return '5';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_RIGHT:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '6';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_HOME:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '7';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_UP:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '8';
|
2009-02-25 19:52:17 +00:00
|
|
|
case SCI_K_PGUP:
|
2009-02-15 22:33:36 +00:00
|
|
|
return '9';
|
|
|
|
default:
|
2009-02-21 08:47:07 +00:00
|
|
|
return c; // Unchanged
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-07 19:23:32 +00:00
|
|
|
static sci_event_t scummvm_get_event(gfx_driver_t *drv) {
|
|
|
|
static int _modifierStates = 0; // FIXME: EVIL HACK
|
|
|
|
sci_event_t input = { SCI_EVT_NONE, 0, 0, 0 };
|
|
|
|
|
|
|
|
Common::EventManager *em = g_system->getEventManager();
|
|
|
|
Common::Event ev;
|
|
|
|
|
|
|
|
bool found = em->pollEvent(ev);
|
|
|
|
Common::Point p = ev.mouse;
|
|
|
|
|
|
|
|
// Don't generate events for mouse movement
|
|
|
|
while (found && ev.type == Common::EVENT_MOUSEMOVE) {
|
|
|
|
drv->pointer_x = ev.mouse.x;
|
|
|
|
drv->pointer_y = ev.mouse.y;
|
|
|
|
found = em->pollEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found && !ev.synthetic && ev.type != Common::EVENT_MOUSEMOVE) {
|
|
|
|
int modifiers = em->getModifierState();
|
|
|
|
|
|
|
|
// We add the modifier key status to buckybits
|
|
|
|
// SDL sends a keydown event if a modifier key is turned on and a keyup event if it's off
|
|
|
|
//
|
2009-03-07 19:24:31 +00:00
|
|
|
// FIXME: This code is semi-bogus. It only records the modifier key being *pressed*.
|
|
|
|
// It does not track correctly whether capslock etc. is active. To do that, we
|
|
|
|
// would have to record the fact that the modifier was pressed in global var,
|
|
|
|
// and also watch for Common::EVENT_KEYUP events.
|
|
|
|
// But this is still not quite good enough, because not all events might
|
|
|
|
// pass through here (e.g. the GUI might be running with its own event loop).
|
|
|
|
//
|
|
|
|
// The best solution likely would be to add code to the EventManager class
|
|
|
|
// for tracking which keys are pressed and which are not...
|
2009-03-07 19:23:32 +00:00
|
|
|
if (ev.type == Common::EVENT_KEYDOWN || ev.type == Common::EVENT_KEYUP) {
|
2009-03-07 19:24:31 +00:00
|
|
|
switch (ev.kbd.keycode) {
|
2009-03-07 19:23:32 +00:00
|
|
|
case Common::KEYCODE_CAPSLOCK:
|
|
|
|
if (ev.type == Common::EVENT_KEYDOWN) {
|
|
|
|
_modifierStates |= SCI_EVM_CAPSLOCK;
|
|
|
|
} else {
|
|
|
|
_modifierStates &= ~SCI_EVM_CAPSLOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_NUMLOCK:
|
|
|
|
if (ev.type == Common::EVENT_KEYDOWN) {
|
|
|
|
_modifierStates |= SCI_EVM_NUMLOCK;
|
|
|
|
} else {
|
|
|
|
_modifierStates &= ~SCI_EVM_NUMLOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_SCROLLOCK:
|
|
|
|
if (ev.type == Common::EVENT_KEYDOWN) {
|
|
|
|
_modifierStates |= SCI_EVM_SCRLOCK;
|
|
|
|
} else {
|
|
|
|
_modifierStates &= ~SCI_EVM_SCRLOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//TODO: SCI_EVM_INSERT
|
|
|
|
|
|
|
|
input.buckybits =
|
|
|
|
((modifiers & Common::KBD_ALT) ? SCI_EVM_ALT : 0) |
|
|
|
|
((modifiers & Common::KBD_CTRL) ? SCI_EVM_CTRL : 0) |
|
|
|
|
((modifiers & Common::KBD_SHIFT) ? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0) |
|
|
|
|
_modifierStates;
|
|
|
|
|
|
|
|
switch (ev.type) {
|
|
|
|
// Keyboard events
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
|
|
input.data = ev.kbd.keycode;
|
|
|
|
input.character = ev.kbd.ascii;
|
|
|
|
|
|
|
|
if (!(input.data & 0xFF00)) {
|
|
|
|
// Directly accept most common keys without conversion
|
|
|
|
input.type = SCI_EVT_KEYBOARD;
|
|
|
|
if (input.data == Common::KEYCODE_TAB) {
|
|
|
|
// Tab
|
|
|
|
input.type = SCI_EVT_KEYBOARD;
|
|
|
|
input.data = SCI_K_TAB;
|
|
|
|
if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT))
|
|
|
|
input.character = SCI_K_SHIFT_TAB;
|
|
|
|
else
|
|
|
|
input.character = SCI_K_TAB;
|
|
|
|
}
|
|
|
|
} else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) {
|
|
|
|
// F1-F10
|
|
|
|
input.type = SCI_EVT_KEYBOARD;
|
|
|
|
// SCI_K_F1 == 59 << 8
|
|
|
|
// SCI_K_SHIFT_F1 == 84 << 8
|
|
|
|
input.data = SCI_K_F1 + ((input.data - Common::KEYCODE_F1)<<8);
|
|
|
|
if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT))
|
|
|
|
input.character = input.data + SCI_K_SHIFT_F1 - SCI_K_F1;
|
|
|
|
else
|
|
|
|
input.character = input.data;
|
|
|
|
} else {
|
|
|
|
// Special keys that need conversion
|
|
|
|
input.type = SCI_EVT_KEYBOARD;
|
|
|
|
switch (ev.kbd.keycode) {
|
|
|
|
case Common::KEYCODE_UP:
|
|
|
|
input.data = SCI_K_UP;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_DOWN:
|
|
|
|
input.data = SCI_K_DOWN;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_RIGHT:
|
|
|
|
input.data = SCI_K_RIGHT;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_LEFT:
|
|
|
|
input.data = SCI_K_LEFT;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_INSERT:
|
|
|
|
input.data = SCI_K_INSERT;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_HOME:
|
|
|
|
input.data = SCI_K_HOME;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_END:
|
|
|
|
input.data = SCI_K_END;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_PAGEUP:
|
|
|
|
input.data = SCI_K_PGUP;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_PAGEDOWN:
|
|
|
|
input.data = SCI_K_PGDOWN;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_DELETE:
|
|
|
|
input.data = SCI_K_DELETE;
|
|
|
|
break;
|
|
|
|
// Keypad keys
|
|
|
|
case Common::KEYCODE_KP8: // up
|
|
|
|
if (!(_modifierStates & SCI_EVM_NUMLOCK))
|
|
|
|
input.data = SCI_K_UP;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_KP2: // down
|
|
|
|
if (!(_modifierStates & SCI_EVM_NUMLOCK))
|
|
|
|
input.data = SCI_K_DOWN;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_KP6: // right
|
|
|
|
if (!(_modifierStates & SCI_EVM_NUMLOCK))
|
|
|
|
input.data = SCI_K_RIGHT;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_KP4: // left
|
|
|
|
if (!(_modifierStates & SCI_EVM_NUMLOCK))
|
|
|
|
input.data = SCI_K_LEFT;
|
|
|
|
break;
|
|
|
|
case Common::KEYCODE_KP5: // center
|
|
|
|
if (!(_modifierStates & SCI_EVM_NUMLOCK))
|
|
|
|
input.data = SCI_K_CENTER;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
input.type = SCI_EVT_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
input.character = input.data;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Mouse events
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
|
|
input.type = SCI_EVT_MOUSE_PRESS;
|
|
|
|
input.data = 1;
|
|
|
|
drv->pointer_x = p.x;
|
|
|
|
drv->pointer_y = p.y;
|
|
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
|
|
input.type = SCI_EVT_MOUSE_PRESS;
|
|
|
|
input.data = 2;
|
|
|
|
drv->pointer_x = p.x;
|
|
|
|
drv->pointer_y = p.y;
|
|
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONUP:
|
|
|
|
input.type = SCI_EVT_MOUSE_RELEASE;
|
|
|
|
input.data = 1;
|
|
|
|
drv->pointer_x = p.x;
|
|
|
|
drv->pointer_y = p.y;
|
|
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONUP:
|
|
|
|
input.type = SCI_EVT_MOUSE_RELEASE;
|
|
|
|
input.data = 2;
|
|
|
|
drv->pointer_x = p.x;
|
|
|
|
drv->pointer_y = p.y;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Misc events
|
|
|
|
case Common::EVENT_QUIT:
|
|
|
|
input.type = SCI_EVT_QUIT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
sci_event_t gfxop_get_event(gfx_state_t *state, unsigned int mask) {
|
2009-02-15 23:49:42 +00:00
|
|
|
sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 };
|
2009-02-25 18:23:28 +00:00
|
|
|
sci_event_t event = { 0, 0, 0, 0 };
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
BASIC_CHECKS(error_event);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-25 18:59:00 +00:00
|
|
|
// Update the screen here, since it's called very often
|
|
|
|
g_system->updateScreen();
|
|
|
|
|
2009-02-25 18:23:28 +00:00
|
|
|
// Get all queued events from graphics driver
|
|
|
|
do {
|
2009-03-07 19:23:32 +00:00
|
|
|
event = scummvm_get_event(state->driver);
|
|
|
|
if (event.type != SCI_EVT_NONE)
|
|
|
|
state->_events.push_back(event);
|
2009-02-26 12:10:11 +00:00
|
|
|
} while (event.type != SCI_EVT_NONE);
|
2009-02-25 18:23:28 +00:00
|
|
|
|
|
|
|
// Search for matching event in queue
|
2009-03-07 19:23:32 +00:00
|
|
|
Common::List<sci_event_t>::iterator iter = state->_events.begin();
|
|
|
|
while (iter != state->_events.end() && !((*iter).type & mask))
|
2009-02-25 18:23:28 +00:00
|
|
|
++iter;
|
|
|
|
|
2009-03-07 19:23:32 +00:00
|
|
|
if (iter != state->_events.end()) {
|
2009-02-25 18:23:28 +00:00
|
|
|
// Event found
|
|
|
|
event = *iter;
|
|
|
|
|
|
|
|
// If not peeking at the queue, remove the event
|
|
|
|
if (!(mask & SCI_EVT_PEEK)) {
|
2009-03-07 19:23:32 +00:00
|
|
|
state->_events.erase(iter);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-02-26 12:10:11 +00:00
|
|
|
} else {
|
|
|
|
// No event found: we must return a SCI_EVT_NONE event.
|
|
|
|
|
|
|
|
// Because event.type is SCI_EVT_NONE already here,
|
|
|
|
// there is no need to change it.
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-18 12:26:37 +00:00
|
|
|
if (event.type == SCI_EVT_KEYBOARD) {
|
2009-02-21 08:47:07 +00:00
|
|
|
// Do we still have to translate the key?
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
event.character = event.data;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Scancodify if appropriate
|
2009-02-15 06:10:59 +00:00
|
|
|
if (event.buckybits & SCI_EVM_ALT)
|
|
|
|
event.character = _gfxop_scancode(event.character);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Shift if appropriate
|
|
|
|
else if (((event.buckybits & (SCI_EVM_RSHIFT | SCI_EVM_LSHIFT)) && !(event.buckybits & SCI_EVM_CAPSLOCK))
|
|
|
|
|| (!(event.buckybits & (SCI_EVM_RSHIFT | SCI_EVM_LSHIFT)) && (event.buckybits & SCI_EVM_CAPSLOCK)))
|
2009-02-15 06:10:59 +00:00
|
|
|
event.character = _gfxop_shiftify(event.character);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Numlockify if appropriate
|
2009-02-15 06:10:59 +00:00
|
|
|
else if (event.buckybits & SCI_EVM_NUMLOCK)
|
|
|
|
event.data = _gfxop_numlockify(event.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// View operations
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_lookup_view_get_loops(gfx_state_t *state, int nr) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int loop = 0, cel = 0;
|
|
|
|
gfxr_view_t *view = NULL;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
view = gfxr_get_view(state->resstate, nr, &loop, &cel, 0);
|
|
|
|
|
|
|
|
if (!view) {
|
2009-02-15 20:40:49 +00:00
|
|
|
GFXWARN("Attempt to retrieve number of loops from invalid view %d\n", nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return view->loops_nr;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_lookup_view_get_cels(gfx_state_t *state, int nr, int loop) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int real_loop = loop, cel = 0;
|
|
|
|
gfxr_view_t *view = NULL;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
view = gfxr_get_view(state->resstate, nr, &real_loop, &cel, 0);
|
|
|
|
|
|
|
|
if (!view) {
|
2009-02-15 20:40:49 +00:00
|
|
|
GFXWARN("Attempt to retrieve number of cels from invalid/broken view %d\n", nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
return 0;
|
|
|
|
} else if (real_loop != loop) {
|
|
|
|
GFXWARN("Loop number was corrected from %d to %d in view %d\n", loop, real_loop, nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return view->loops[real_loop].cels_nr;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_check_cel(gfx_state_t *state, int nr, int *loop, int *cel) {
|
2009-02-15 22:33:36 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!gfxr_get_view(state->resstate, nr, loop, cel, 0)) {
|
|
|
|
GFXWARN("Attempt to verify loop/cel values for invalid view %d\n", nr);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_overflow_cel(gfx_state_t *state, int nr, int *loop, int *cel) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int loop_v = *loop;
|
|
|
|
int cel_v = *cel;
|
2009-02-15 22:33:36 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!gfxr_get_view(state->resstate, nr, &loop_v, &cel_v, 0)) {
|
|
|
|
GFXWARN("Attempt to verify loop/cel values for invalid view %d\n", nr);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loop_v != *loop)
|
|
|
|
*loop = 0;
|
|
|
|
|
|
|
|
if (loop_v != *loop
|
2009-02-15 22:33:36 +00:00
|
|
|
|| cel_v != *cel)
|
2009-02-15 06:10:59 +00:00
|
|
|
*cel = 0;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_get_cel_parameters(gfx_state_t *state, int nr, int loop, int cel, int *width, int *height, Common::Point *offset) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfxr_view_t *view = NULL;
|
|
|
|
gfx_pixmap_t *pxm = NULL;
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
if (!(view = gfxr_get_view(state->resstate, nr, &loop, &cel, 0))) {
|
|
|
|
GFXWARN("Attempt to get cel parameters for invalid view %d\n", nr);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
pxm = view->loops[loop].cels[cel];
|
|
|
|
*width = pxm->index_xl;
|
|
|
|
*height = pxm->index_yl;
|
|
|
|
offset->x = pxm->xoffset;
|
|
|
|
offset->y = pxm->yoffset;
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_draw_cel_buffer(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int static_buf, int palette) {
|
2009-02-15 22:33:36 +00:00
|
|
|
int priority = (color.mask & GFX_MASK_PRIORITY) ? color.priority : -1;
|
|
|
|
int control = (color.mask & GFX_MASK_CONTROL) ? color.control : -1;
|
2009-02-15 06:10:59 +00:00
|
|
|
gfxr_view_t *view = NULL;
|
|
|
|
gfx_pixmap_t *pxm = NULL;
|
|
|
|
int old_x, old_y;
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (!(view = gfxr_get_view(state->resstate, nr, &loop, &cel, palette))) {
|
|
|
|
GFXWARN("Attempt to draw loop/cel %d/%d in invalid view %d\n", loop, cel, nr);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
pxm = view->loops[loop].cels[cel];
|
|
|
|
|
|
|
|
old_x = pos.x -= pxm->xoffset;
|
|
|
|
old_y = pos.y -= pxm->yoffset;
|
|
|
|
|
|
|
|
pos.x *= state->driver->mode->xfact;
|
|
|
|
pos.y *= state->driver->mode->yfact;
|
|
|
|
|
|
|
|
if (!static_buf)
|
|
|
|
_gfxop_add_dirty(state, gfx_rect(old_x, old_y, pxm->index_xl, pxm->index_yl));
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
return _gfxop_draw_pixmap(state->driver, pxm, priority, control, gfx_rect(0, 0, pxm->xl, pxm->yl),
|
|
|
|
gfx_rect(pos.x, pos.y, pxm->xl, pxm->yl), state->clip_zone, static_buf , state->control_map,
|
|
|
|
static_buf ? state->static_priority_map : state->priority_map);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_cel(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
return _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 0, palette);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_cel_static(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int retval;
|
|
|
|
rect_t oldclip = state->clip_zone;
|
|
|
|
|
|
|
|
state->clip_zone = gfx_rect_fullscreen;
|
|
|
|
_gfxop_scale_rect(&(state->clip_zone), state->driver->mode);
|
2009-02-21 08:47:07 +00:00
|
|
|
retval = gfxop_draw_cel_static_clipped(state, nr, loop, cel, pos, color, palette);
|
|
|
|
// Except that the area it's clipped against is... unusual ;-)
|
2009-02-15 06:10:59 +00:00
|
|
|
state->clip_zone = oldclip;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_cel_static_clipped(gfx_state_t *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
return _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 1, palette);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Pic operations
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
static int _gfxop_set_pic(gfx_state_t *state) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_copy_pixmap_box_i(state->control_map, state->pic->control_map, gfx_rect(0, 0, 320, 200));
|
2009-02-15 22:33:36 +00:00
|
|
|
gfx_copy_pixmap_box_i(state->priority_map, state->pic_unscaled->priority_map, gfx_rect(0, 0, 320, 200));
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_copy_pixmap_box_i(state->static_priority_map, state->pic_unscaled->priority_map, gfx_rect(0, 0, 320, 200));
|
|
|
|
|
|
|
|
_gfxop_install_pixmap(state->driver, state->pic->visual_map);
|
|
|
|
|
|
|
|
if (state->options->pic0_unscaled)
|
|
|
|
state->pic->priority_map = gfx_pixmap_scale_index_data(state->pic->priority_map, state->driver->mode);
|
|
|
|
return state->driver->set_static_buffer(state->driver, state->pic->visual_map, state->pic->priority_map);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
void *gfxop_get_pic_metainfo(gfx_state_t *state) {
|
2009-02-15 22:33:36 +00:00
|
|
|
return (state->pic) ? state->pic->internal : NULL;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_new_pic(gfx_state_t *state, int nr, int flags, int default_palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
gfxr_tag_resources(state->resstate);
|
|
|
|
state->tag_mode = 1;
|
|
|
|
state->palette_nr = default_palette;
|
|
|
|
|
|
|
|
state->pic = gfxr_get_pic(state->resstate, nr, GFX_MASK_VISUAL, flags, default_palette, 1);
|
|
|
|
|
|
|
|
if (state->driver->mode->xfact == 1 && state->driver->mode->yfact == 1)
|
|
|
|
state->pic_unscaled = state->pic;
|
|
|
|
else
|
|
|
|
state->pic_unscaled = gfxr_get_pic(state->resstate, nr, GFX_MASK_VISUAL, flags, default_palette, 0);
|
|
|
|
|
|
|
|
if (!state->pic || !state->pic_unscaled) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Could not retrieve background pic %d!\n", nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
if (state->pic) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR(" -- Inconsistency: scaled pic _was_ retrieved!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (state->pic_unscaled) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR(" -- Inconsistency: unscaled pic _was_ retrieved!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
state->pic = state->pic_unscaled = NULL;
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->pic_nr = nr;
|
|
|
|
|
|
|
|
return _gfxop_set_pic(state);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_add_to_pic(gfx_state_t *state, int nr, int flags, int default_palette) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
if (!state->pic) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Attempt to add to pic with no pic active!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
if (!(state->pic = gfxr_add_to_pic(state->resstate, state->pic_nr, nr, GFX_MASK_VISUAL, flags, state->palette_nr, default_palette, 1))) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Could not add pic #%d to pic #%d!\n", state->pic_nr, nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
2009-02-21 08:47:07 +00:00
|
|
|
state->pic_unscaled = gfxr_add_to_pic(state->resstate, state->pic_nr, nr, GFX_MASK_VISUAL, flags,
|
|
|
|
state->palette_nr, default_palette, 1);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return _gfxop_set_pic(state);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
// Text operations
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_get_font_height(gfx_state_t *state, int font_nr) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_bitmap_font_t *font;
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
font = gfxr_get_font(state->resstate, font_nr, 0);
|
|
|
|
if (!font)
|
|
|
|
return GFX_ERROR;
|
|
|
|
|
|
|
|
return font->line_height;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_get_text_params(gfx_state_t *state, int font_nr, const char *text, int maxwidth, int *width, int *height, int text_flags,
|
|
|
|
int *lines_nr, int *lineheight, int *lastline_width) {
|
2009-02-15 06:10:59 +00:00
|
|
|
text_fragment_t *textsplits;
|
|
|
|
gfx_bitmap_font_t *font;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
|
|
|
|
|
|
|
font = gfxr_get_font(state->resstate, font_nr, 0);
|
|
|
|
|
|
|
|
if (!font) {
|
|
|
|
GFXERROR("Attempt to calculate text size with invalid font #%d\n", font_nr);
|
|
|
|
*width = *height = 0;
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
textsplits = gfxr_font_calculate_size(font, maxwidth, text, width, height, lines_nr, lineheight, lastline_width,
|
|
|
|
(state->options->workarounds & GFX_WORKAROUND_WHITESPACE_COUNT) | text_flags);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!textsplits) {
|
|
|
|
GFXERROR("Could not calculate text size!");
|
|
|
|
*width = *height = 0;
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(textsplits);
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
gfx_text_handle_t *gfxop_new_text(gfx_state_t *state, int font_nr, char *text, int maxwidth, gfx_alignment_t halign,
|
|
|
|
gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, gfx_color_t bg_color, int flags) {
|
2009-02-15 23:49:42 +00:00
|
|
|
gfx_text_handle_t *handle;
|
|
|
|
gfx_bitmap_font_t *font;
|
2009-03-03 14:27:49 +00:00
|
|
|
int i, error = 0;
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(NULL);
|
|
|
|
|
2009-03-03 14:27:49 +00:00
|
|
|
// mapping text colors to palette
|
|
|
|
error |= gfxop_set_color(state, &color1, color1);
|
|
|
|
error |= gfxop_set_color(state, &color2, color2);
|
|
|
|
error |= gfxop_set_color(state, &bg_color, bg_color);
|
|
|
|
if (error) {
|
|
|
|
GFXERROR("Unable to set up colors");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
font = gfxr_get_font(state->resstate, font_nr, 0);
|
|
|
|
|
|
|
|
if (!font) {
|
|
|
|
GFXERROR("Attempt to draw text with invalid font #%d\n", font_nr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
handle = (gfx_text_handle_t *)sci_malloc(sizeof(gfx_text_handle_t));
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
handle->text = (char *)sci_malloc(strlen(text) + 1);
|
2009-02-15 06:10:59 +00:00
|
|
|
strcpy(handle->text, text);
|
|
|
|
handle->halign = halign;
|
|
|
|
handle->valign = valign;
|
|
|
|
handle->line_height = font->line_height;
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
handle->lines = gfxr_font_calculate_size(font, maxwidth, handle->text, &(handle->width), &(handle->height), &(handle->lines_nr),
|
|
|
|
NULL, NULL, ((state->options->workarounds & GFX_WORKAROUND_WHITESPACE_COUNT) ?
|
|
|
|
GFXR_FONT_FLAG_COUNT_WHITESPACE : 0) | flags);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!handle->lines) {
|
|
|
|
free(handle->text);
|
|
|
|
free(handle);
|
|
|
|
GFXERROR("Could not calculate text parameters in font #%d\n", font_nr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & GFXR_FONT_FLAG_NO_NEWLINES) {
|
|
|
|
handle->lines_nr = 1;
|
|
|
|
handle->lines->length = strlen(text);
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
handle->text_pixmaps = (gfx_pixmap_t **)sci_malloc(sizeof(gfx_pixmap_t *) * handle->lines_nr);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
for (i = 0; i < handle->lines_nr; i++) {
|
|
|
|
int chars_nr = handle->lines[i].length;
|
|
|
|
|
|
|
|
handle->text_pixmaps[i] = gfxr_draw_font(font, handle->lines[i].offset, chars_nr,
|
2009-03-03 14:27:49 +00:00
|
|
|
(color1.mask & GFX_MASK_VISUAL) ? &color1.visual : NULL,
|
|
|
|
(color2.mask & GFX_MASK_VISUAL) ? &color2.visual : NULL,
|
|
|
|
(bg_color.mask & GFX_MASK_VISUAL) ? &bg_color.visual : NULL);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!handle->text_pixmaps[i]) {
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
gfx_free_pixmap(state->driver, handle->text_pixmaps[j]);
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-17 13:51:52 +00:00
|
|
|
free(handle->text_pixmaps);
|
|
|
|
free(handle->text);
|
|
|
|
free(handle->lines);
|
2009-02-15 06:10:59 +00:00
|
|
|
GFXERROR("Failed to draw text pixmap for line %d/%d\n", i, handle->lines_nr);
|
2009-02-17 13:51:52 +00:00
|
|
|
free(handle);
|
2009-02-15 06:10:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handle->font = font;
|
|
|
|
|
2009-02-15 22:33:36 +00:00
|
|
|
handle->priority = (color1.mask & GFX_MASK_PRIORITY) ? color1.priority : -1;
|
|
|
|
handle->control = (color1.mask & GFX_MASK_CONTROL) ? color1.control : -1;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_free_text(gfx_state_t *state, gfx_text_handle_t *handle) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int j;
|
|
|
|
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
if (handle->text_pixmaps) {
|
|
|
|
for (j = 0; j < handle->lines_nr; j++)
|
|
|
|
gfx_free_pixmap(state->driver, handle->text_pixmaps[j]);
|
|
|
|
free(handle->text_pixmaps);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(handle->text);
|
|
|
|
free(handle->lines);
|
|
|
|
free(handle);
|
2009-02-21 08:47:07 +00:00
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_text(gfx_state_t *state, gfx_text_handle_t *handle, rect_t zone) {
|
2009-02-15 06:10:59 +00:00
|
|
|
int line_height;
|
|
|
|
rect_t pos;
|
|
|
|
int i;
|
|
|
|
BASIC_CHECKS(GFX_FATAL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
if (!handle) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Attempt to draw text with NULL handle!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!handle->lines_nr) {
|
|
|
|
GFXDEBUG("Skipping draw_text operation because number of lines is zero\n");
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
_gfxop_scale_rect(&zone, state->driver->mode);
|
|
|
|
|
|
|
|
line_height = handle->line_height * state->driver->mode->yfact;
|
|
|
|
|
|
|
|
pos.y = zone.y;
|
|
|
|
|
|
|
|
switch (handle->valign) {
|
|
|
|
|
|
|
|
case ALIGN_TOP:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALIGN_CENTER:
|
|
|
|
pos.y += (zone.yl - (line_height * handle->lines_nr)) >> 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALIGN_BOTTOM:
|
|
|
|
pos.y += (zone.yl - (line_height * handle->lines_nr));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Invalid vertical alignment %d!\n", handle->valign);
|
2009-02-21 08:47:07 +00:00
|
|
|
return GFX_FATAL; // Internal error...
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < handle->lines_nr; i++) {
|
|
|
|
|
|
|
|
gfx_pixmap_t *pxm = handle->text_pixmaps[i];
|
|
|
|
|
|
|
|
if (!pxm->data) {
|
|
|
|
gfx_xlate_pixmap(pxm, state->driver->mode, state->options->text_xlate_filter);
|
2009-02-21 08:47:07 +00:00
|
|
|
gfxr_endianness_adjust(pxm, state->driver->mode); // FIXME: resmgr layer!
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
if (!pxm) {
|
|
|
|
GFXERROR("Could not find text pixmap %d/%d\n", i, handle->lines_nr);
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos.x = zone.x;
|
|
|
|
|
|
|
|
switch (handle->halign) {
|
|
|
|
|
|
|
|
case ALIGN_LEFT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALIGN_CENTER:
|
|
|
|
pos.x += (zone.xl - pxm->xl) >> 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ALIGN_RIGHT:
|
|
|
|
pos.x += (zone.xl - pxm->xl);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Invalid vertical alignment %d!\n", handle->valign);
|
2009-02-21 08:47:07 +00:00
|
|
|
return GFX_FATAL; // Internal error...
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pos.xl = pxm->xl;
|
|
|
|
pos.yl = pxm->yl;
|
|
|
|
|
|
|
|
_gfxop_add_dirty(state, pos);
|
|
|
|
_gfxop_draw_pixmap(state->driver, pxm, handle->priority, handle->control,
|
2009-02-21 08:47:07 +00:00
|
|
|
gfx_rect(0, 0, pxm->xl, pxm->yl), pos, state->clip_zone, 0, state->control_map, state->priority_map);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
pos.y += line_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
gfx_pixmap_t *gfxop_grab_pixmap(gfx_state_t *state, rect_t area) {
|
2009-02-15 06:10:59 +00:00
|
|
|
gfx_pixmap_t *pixmap = NULL;
|
2009-02-21 08:47:07 +00:00
|
|
|
rect_t resultzone; // Ignored for this application
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(NULL);
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
_gfxop_scale_rect(&area, state->driver->mode);
|
|
|
|
if (_gfxop_grab_pixmap(state, &pixmap, area.x, area.y, area.xl, area.yl, 0, &resultzone))
|
2009-02-21 08:47:07 +00:00
|
|
|
return NULL; // area CUT the visual screen had a null or negative size
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
return pixmap;
|
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_draw_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm, rect_t zone, Common::Point pos) {
|
2009-02-15 06:10:59 +00:00
|
|
|
rect_t target;
|
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
|
|
|
|
if (!pxm) {
|
2009-02-21 14:11:41 +00:00
|
|
|
GFXERROR("Attempt to draw NULL pixmap!\n");
|
2009-02-15 06:10:59 +00:00
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-02-25 19:28:20 +00:00
|
|
|
_gfxop_full_pointer_refresh(state);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
|
|
|
target = gfx_rect(pos.x, pos.y, zone.xl, zone.yl);
|
|
|
|
|
|
|
|
_gfxop_add_dirty(state, target);
|
|
|
|
|
|
|
|
if (!pxm) {
|
|
|
|
GFXERROR("Attempt to draw_pixmap with pxm=NULL\n");
|
|
|
|
return GFX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
_gfxop_scale_rect(&zone, state->driver->mode);
|
|
|
|
_gfxop_scale_rect(&target, state->driver->mode);
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
return _gfxop_draw_pixmap(state->driver, pxm, -1, -1, zone, target, gfx_rect(0, 0, 320*state->driver->mode->xfact,
|
2009-02-15 22:33:36 +00:00
|
|
|
200*state->driver->mode->yfact), 0, NULL, NULL);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-02-21 08:47:07 +00:00
|
|
|
int gfxop_free_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm) {
|
2009-02-15 06:10:59 +00:00
|
|
|
BASIC_CHECKS(GFX_ERROR);
|
|
|
|
gfx_free_pixmap(state->driver, pxm);
|
|
|
|
return GFX_OK;
|
|
|
|
}
|
2009-02-21 10:23:36 +00:00
|
|
|
|
|
|
|
} // End of namespace Sci
|