mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 14:50:17 +00:00
87bfde321f
svn-id: r38332
537 lines
13 KiB
C++
537 lines
13 KiB
C++
#include "common/scummsys.h"
|
|
#include "common/system.h"
|
|
#include "common/events.h"
|
|
|
|
#include "sci/include/gfx_driver.h"
|
|
#include "sci/include/gfx_tools.h"
|
|
|
|
struct _scummvm_driver_state {
|
|
gfx_pixmap_t *priority[2];
|
|
byte *visual[3];
|
|
byte *pointer_data[2];
|
|
int xsize, ysize;
|
|
//int buckystate;
|
|
bool update_screen;
|
|
bool update_mouse;
|
|
};
|
|
|
|
#define S ((struct _scummvm_driver_state *)(drv->state))
|
|
|
|
static int
|
|
scummvm_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) {
|
|
int i;
|
|
|
|
if (!drv->state) // = S
|
|
drv->state = new _scummvm_driver_state;
|
|
if (!drv->state)
|
|
return GFX_FATAL;
|
|
|
|
S->xsize = xfact * 320;
|
|
S->ysize = yfact * 200;
|
|
|
|
S->pointer_data[0] = NULL;
|
|
S->pointer_data[1] = NULL;
|
|
//S->buckystate = 0;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
S->priority[i] = gfx_pixmap_alloc_index_data(gfx_new_pixmap(S->xsize, S->ysize, GFX_RESID_NONE, -i, -777));
|
|
if (!S->priority[i]) {
|
|
printf("Out of memory: Could not allocate priority maps! (%dx%d)\n",
|
|
S->xsize, S->ysize);
|
|
return GFX_FATAL;
|
|
}
|
|
}
|
|
// create the visual buffers
|
|
for (i = 0; i < 3; i++) {
|
|
S->visual[i] = NULL;
|
|
S->visual[i] = new byte[S->xsize * S->ysize];
|
|
if (!S->visual[i]) {
|
|
printf("Out of memory: Could not allocate visual buffers! (%dx%d)\n",
|
|
S->xsize, S->ysize);
|
|
return GFX_FATAL;
|
|
}
|
|
memset(S->visual[i], 0, S->xsize * S->ysize);
|
|
}
|
|
|
|
drv->mode = gfx_new_mode(xfact, yfact, bytespp,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0, 256, 0);
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
static int
|
|
scummvm_init(struct _gfx_driver *drv) {
|
|
return scummvm_init_specific(drv, 1, 1, GFX_COLOR_MODE_INDEX);
|
|
}
|
|
|
|
static void
|
|
scummvm_exit(struct _gfx_driver *drv) {
|
|
int i;
|
|
if (S) {
|
|
for (i = 0; i < 2; i++) {
|
|
gfx_free_pixmap(drv, S->priority[i]);
|
|
S->priority[i] = NULL;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
delete[] S->visual[i];
|
|
S->visual[i] = NULL;
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
if (S->pointer_data[i]) {
|
|
delete[] S->pointer_data[i];
|
|
S->pointer_data[i] = NULL;
|
|
}
|
|
|
|
delete S;
|
|
}
|
|
}
|
|
|
|
|
|
// Drawing operations
|
|
|
|
/* This code shamelessly lifted from the SDL_gfxPrimitives package */
|
|
static void
|
|
lineColor2(byte *dst, int16 x1, int16 y1, int16 x2, int16 y2, uint32 color) {
|
|
int pixx, pixy;
|
|
int x, y;
|
|
int dx, dy;
|
|
int sx, sy;
|
|
int swaptmp;
|
|
uint8 *pixel;
|
|
|
|
dx = x2 - x1;
|
|
dy = y2 - y1;
|
|
sx = (dx >= 0) ? 1 : -1;
|
|
sy = (dy >= 0) ? 1 : -1;
|
|
|
|
dx = sx * dx + 1;
|
|
dy = sy * dy + 1;
|
|
pixx = 1;
|
|
pixy = 320;
|
|
pixel = ((uint8*)dst) + pixx * (int)x1 + pixy * (int)y1;
|
|
pixx *= sx;
|
|
pixy *= sy;
|
|
if (dx < dy) {
|
|
swaptmp = dx;
|
|
dx = dy;
|
|
dy = swaptmp;
|
|
swaptmp = pixx;
|
|
pixx = pixy;
|
|
pixy = swaptmp;
|
|
}
|
|
|
|
/* Draw */
|
|
x = 0;
|
|
y = 0;
|
|
for (; x < dx; x++, pixel += pixx) {
|
|
*pixel = color;
|
|
y += dy;
|
|
if (y >= dx) {
|
|
y -= dx;
|
|
pixel += pixy;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
scummvm_draw_line(struct _gfx_driver *drv, point_t start, point_t end,
|
|
gfx_color_t color,
|
|
gfx_line_mode_t line_mode, gfx_line_style_t line_style) {
|
|
uint32 scolor = color.visual.global_index;
|
|
int xsize = S->xsize;
|
|
int ysize = S->ysize;
|
|
|
|
if (color.mask & GFX_MASK_VISUAL) {
|
|
point_t nstart, nend;
|
|
|
|
nstart.x = start.x;
|
|
nstart.y = start.y;
|
|
nend.x = end.x;
|
|
nend.y = end.y;
|
|
|
|
if (nstart.x < 0)
|
|
nstart.x = 0;
|
|
if (nend.x < 0)
|
|
nstart.x = 0;
|
|
if (nstart.y < 0)
|
|
nstart.y = 0;
|
|
if (nend.y < 0)
|
|
nend.y = 0;
|
|
if (nstart.x > xsize)
|
|
nstart.x = xsize;
|
|
if (nend.x >= xsize)
|
|
nend.x = xsize - 1;
|
|
if (nstart.y > ysize)
|
|
nstart.y = ysize;
|
|
if (nend.y >= ysize)
|
|
nend.y = ysize - 1;
|
|
|
|
lineColor2(S->visual[1], (int16)nstart.x, (int16)nstart.y,
|
|
(int16)nend.x, (int16)nend.y, scolor);
|
|
|
|
if (color.mask & GFX_MASK_PRIORITY) {
|
|
gfx_draw_line_pixmap_i(S->priority[0], nstart, nend,
|
|
color.priority);
|
|
}
|
|
}
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
static int
|
|
scummvm_draw_filled_rect(struct _gfx_driver *drv, rect_t rect,
|
|
gfx_color_t color1, gfx_color_t color2,
|
|
gfx_rectangle_fill_t shade_mode) {
|
|
if (color1.mask & GFX_MASK_VISUAL) {
|
|
for (int i = rect.y; i < rect.y + rect.yl; i++) {
|
|
memset(S->visual[1] + i * S->xsize + rect.x, color1.visual.global_index, rect.xl);
|
|
}
|
|
}
|
|
|
|
if (color1.mask & GFX_MASK_PRIORITY)
|
|
gfx_draw_box_pixmap_i(S->priority[0], rect, color1.priority);
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
|
|
// Pixmap operations
|
|
|
|
static int
|
|
scummvm_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority,
|
|
rect_t src, rect_t dest, gfx_buffer_t buffer) {
|
|
int bufnr = (buffer == GFX_BUFFER_STATIC) ? 2 : 1;
|
|
int pribufnr = bufnr - 1;
|
|
|
|
if (dest.xl != src.xl || dest.yl != src.yl) {
|
|
printf("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n",
|
|
src.xl, src.yl, dest.xl, dest.yl);
|
|
return GFX_ERROR;
|
|
}
|
|
|
|
gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest,
|
|
S->visual[bufnr], S->xsize,
|
|
S->priority[pribufnr]->index_data,
|
|
S->priority[pribufnr]->index_xl, 1, 0);
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
static int
|
|
scummvm_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm,
|
|
gfx_map_mask_t map) {
|
|
if (src.x < 0 || src.y < 0) {
|
|
printf("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y);
|
|
return GFX_ERROR;
|
|
}
|
|
|
|
if (!pxm->data) {
|
|
printf("Attempt to grab pixmap to unallocated memory\n");
|
|
return GFX_ERROR;
|
|
}
|
|
|
|
switch (map) {
|
|
|
|
case GFX_MASK_VISUAL:
|
|
pxm->xl = src.xl;
|
|
pxm->yl = src.yl;
|
|
for (int i = 0; i < src.yl; i++) {
|
|
memcpy(pxm->data + i * src.xl, S->visual[1] + (i + src.y) * S->xsize + src.x, src.xl);
|
|
}
|
|
break;
|
|
|
|
case GFX_MASK_PRIORITY:
|
|
printf("FIXME: priority map grab not implemented yet!\n");
|
|
break;
|
|
|
|
default:
|
|
printf("Attempt to grab pixmap from invalid map 0x%02x\n", map);
|
|
return GFX_ERROR;
|
|
}
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
|
|
// Buffer operations
|
|
|
|
static int
|
|
scummvm_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) {
|
|
//TODO
|
|
int data_source = (buffer == GFX_BUFFER_BACK) ? 2 : 1;
|
|
int data_dest = data_source - 1;
|
|
|
|
/*
|
|
if (src.x != dest.x || src.y != dest.y) {
|
|
printf("Updating %d (%d,%d)(%dx%d) to (%d,%d) on %d\n", buffer, src.x, src.y,
|
|
src.xl, src.yl, dest.x, dest.y, data_dest);
|
|
} else {
|
|
printf("Updating %d (%d,%d)(%dx%d) to %d\n", buffer, src.x, src.y, src.xl, src.yl, data_dest);
|
|
}
|
|
*/
|
|
|
|
switch (buffer) {
|
|
case GFX_BUFFER_BACK:
|
|
//memcpy(S->visual[data_dest], S->visual[data_source],
|
|
// S->xsize * S->ysize);
|
|
for (int i = 0; i < src.yl; i++) {
|
|
memcpy(S->visual[data_dest] + (dest.y + i) * S->xsize + dest.x,
|
|
S->visual[data_source] + (src.y + i) * S->xsize + src.x, src.xl);
|
|
}
|
|
|
|
if ((src.x == dest.x) && (src.y == dest.y))
|
|
gfx_copy_pixmap_box_i(S->priority[0], S->priority[1], src);
|
|
break;
|
|
case GFX_BUFFER_FRONT:
|
|
memcpy(S->visual[data_dest], S->visual[data_source],
|
|
S->xsize * S->ysize);
|
|
|
|
g_system->copyRectToScreen(S->visual[data_dest] + src.x + src.y * S->xsize,
|
|
S->xsize, dest.x, dest.y, src.xl, src.yl);
|
|
/*
|
|
g_system->copyRectToScreen(S->visual[data_dest],
|
|
S->xsize, 0, 0, S->xsize, S->ysize);
|
|
*/
|
|
S->update_screen = true;
|
|
break;
|
|
default:
|
|
GFXERROR("Invalid buffer %d in update!\n", buffer);
|
|
return GFX_ERROR;
|
|
}
|
|
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
static int
|
|
scummvm_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) {
|
|
memcpy(S->visual[2], pic->data, S->xsize * S->ysize);
|
|
/*gfx_crossblit_pixmap(drv->mode, pic, 0, rect, rect,
|
|
S->visual[2], S->xsize,
|
|
S->priority[1]->index_data,
|
|
S->priority[1]->index_xl, 1, 0);*/
|
|
|
|
gfx_copy_pixmap_box_i(S->priority[1], priority, gfx_rect(0, 0, S->xsize, S->ysize));
|
|
|
|
return GFX_OK;
|
|
}
|
|
|
|
|
|
// Mouse pointer operations
|
|
|
|
static int
|
|
scummvm_set_pointer(struct _gfx_driver *drv, gfx_pixmap_t *pointer) {
|
|
if (pointer == NULL) {
|
|
g_system->showMouse(false);
|
|
} else {
|
|
g_system->setMouseCursor(pointer->index_data, pointer->xl, pointer->yl, pointer->xoffset, pointer->yoffset);
|
|
g_system->showMouse(true);
|
|
}
|
|
|
|
// Pointer pixmap or mouse position has changed
|
|
S->update_mouse = true;
|
|
return GFX_OK;
|
|
}
|
|
|
|
|
|
// Palette operations
|
|
|
|
static int
|
|
scummvm_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) {
|
|
byte color[] = {red, green, blue, 255};
|
|
g_system->setPalette(color, index, 1);
|
|
return GFX_OK;
|
|
}
|
|
|
|
|
|
// Event management
|
|
|
|
static sci_event_t
|
|
scummvm_get_event(struct _gfx_driver *drv) {
|
|
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) {
|
|
found = em->pollEvent(ev);
|
|
p = ev.mouse;
|
|
drv->pointer_x = p.x;
|
|
drv->pointer_y = p.y;
|
|
S->update_mouse = true;
|
|
}
|
|
|
|
// Update the screen here, since it's called very often
|
|
if (S->update_mouse)
|
|
g_system->warpMouse(drv->pointer_x, drv->pointer_y);
|
|
if (S->update_screen || S->update_mouse) {
|
|
g_system->updateScreen();
|
|
S->update_screen = false;
|
|
S->update_mouse = false;
|
|
}
|
|
|
|
if (found && !ev.synthetic && ev.type != Common::EVENT_MOUSEMOVE) {
|
|
int modifiers;
|
|
if (ev.type == Common::EVENT_KEYDOWN)
|
|
modifiers = ev.kbd.flags;
|
|
else
|
|
modifiers = em->getModifierState();
|
|
|
|
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);
|
|
//TODO: SCI_EVM_SCRLOCK SCI_EVM_NUMLOCK SCI_EVM_CAPSLOCK SCI_EVM_INSERT
|
|
|
|
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 = (input.data - Common::KEYCODE_F1 + SCI_K_F1) << 8;
|
|
if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT))
|
|
input.character = input.data + ((SCI_K_SHIFT_F1 - SCI_K_F1) << 8);
|
|
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;
|
|
//TODO: SCI_K_CENTER
|
|
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;
|
|
}
|
|
|
|
static int
|
|
scummvm_usec_sleep(struct _gfx_driver *drv, long usecs) {
|
|
g_system->delayMillis(usecs / 1000);
|
|
return GFX_OK;
|
|
}
|
|
|
|
gfx_driver_t
|
|
gfx_driver_scummvm = {
|
|
"ScummVM",
|
|
"0.1",
|
|
SCI_GFX_DRIVER_MAGIC,
|
|
SCI_GFX_DRIVER_VERSION,
|
|
NULL,
|
|
0, 0,
|
|
GFX_CAPABILITY_MOUSE_POINTER | GFX_CAPABILITY_COLOR_MOUSE_POINTER | GFX_CAPABILITY_MOUSE_SUPPORT | GFX_CAPABILITY_FINE_LINES | GFX_CAPABILITY_WINDOWED,
|
|
0,
|
|
NULL,
|
|
scummvm_init_specific,
|
|
scummvm_init,
|
|
scummvm_exit,
|
|
scummvm_draw_line,
|
|
scummvm_draw_filled_rect,
|
|
NULL,
|
|
NULL,
|
|
scummvm_draw_pixmap,
|
|
scummvm_grab_pixmap,
|
|
scummvm_update,
|
|
scummvm_set_static_buffer,
|
|
scummvm_set_pointer,
|
|
scummvm_set_palette,
|
|
scummvm_get_event,
|
|
scummvm_usec_sleep,
|
|
NULL
|
|
};
|