mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-09 19:32:11 +00:00
ae1b03a1f5
svn-id: r13624
549 lines
12 KiB
C++
549 lines
12 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2004 The ScummVM project
|
|
*
|
|
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*
|
|
*/
|
|
#include "reinherit.h"
|
|
|
|
#include <SDL.h>
|
|
#include <limits.h>
|
|
|
|
/*
|
|
* Begin module component
|
|
\*--------------------------------------------------------------------------*/
|
|
#include "sysgfx.h"
|
|
|
|
namespace Saga {
|
|
|
|
R_SYSGFX_MODULE SGfxModule;
|
|
|
|
static SDL_Color cur_pal[R_PAL_ENTRIES];
|
|
|
|
int SYSGFX_Init(R_SYSGFX_INIT * gfx_init)
|
|
{
|
|
SDL_Surface *sdl_screen;
|
|
R_SURFACE r_screen;
|
|
|
|
SDL_Surface *sdl_back_buf;
|
|
R_SURFACE r_back_buf;
|
|
|
|
int result;
|
|
Uint32 flags;
|
|
|
|
assert(gfx_init != NULL);
|
|
|
|
if (gfx_init->fullscreen) {
|
|
flags = SDL_FULLSCREEN | SDL_HWPALETTE;
|
|
} else {
|
|
flags = SDL_HWPALETTE;
|
|
}
|
|
|
|
/* Test video mode availability
|
|
* \*------------------------------------------------------------- */
|
|
result = SDL_VideoModeOK(gfx_init->screen_w,
|
|
gfx_init->screen_h, gfx_init->screen_bpp, flags);
|
|
if (result == 0) {
|
|
R_printf(R_STDERR,
|
|
"Requested video mode (%d x %d @ %d bpp) "
|
|
"is unavailable.\n",
|
|
gfx_init->screen_w,
|
|
gfx_init->screen_h, gfx_init->screen_bpp);
|
|
|
|
return R_FAILURE;
|
|
}
|
|
|
|
/* Set the video mode
|
|
* \*------------------------------------------------------------- */
|
|
sdl_screen = SDL_SetVideoMode(gfx_init->screen_w,
|
|
gfx_init->screen_h, gfx_init->screen_bpp, flags);
|
|
if (sdl_screen == NULL) {
|
|
|
|
R_printf(R_STDERR,
|
|
"Unable to set video mode (%d x %d @ %d bpp).\n",
|
|
gfx_init->screen_w,
|
|
gfx_init->screen_h, gfx_init->screen_bpp);
|
|
|
|
R_printf(R_STDERR, "SDL reports: %s\n", SDL_GetError());
|
|
|
|
return R_FAILURE;
|
|
}
|
|
|
|
R_printf(R_STDOUT,
|
|
"Set video mode: (%d x %d @ %d bpp)\n",
|
|
sdl_screen->w, sdl_screen->h, sdl_screen->format->BitsPerPixel);
|
|
|
|
/* Convert sdl surface data to R surface data */
|
|
r_screen.buf = (uchar *)sdl_screen->pixels;
|
|
r_screen.buf_w = sdl_screen->w;
|
|
r_screen.buf_h = sdl_screen->h;
|
|
r_screen.buf_pitch = sdl_screen->pitch;
|
|
r_screen.bpp = gfx_init->screen_bpp;
|
|
|
|
r_screen.clip_rect.left = 0;
|
|
r_screen.clip_rect.top = 0;
|
|
r_screen.clip_rect.right = sdl_screen->w - 1;
|
|
r_screen.clip_rect.bottom = sdl_screen->h - 1;
|
|
|
|
r_screen.impl_src = sdl_screen;
|
|
|
|
/* Create the back buffer
|
|
* \*------------------------------------------------------------- */
|
|
sdl_back_buf = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
gfx_init->backbuf_w,
|
|
gfx_init->backbuf_h, gfx_init->backbuf_bpp, 0, 0, 0, 0);
|
|
if (sdl_back_buf == NULL) {
|
|
|
|
R_printf(R_STDERR,
|
|
"Unable to create back buffer (%d x %d @ %d bpp).\n",
|
|
gfx_init->backbuf_w,
|
|
gfx_init->backbuf_h, gfx_init->backbuf_bpp);
|
|
|
|
R_printf(R_STDERR, "SDL reports: %s.\n", SDL_GetError());
|
|
|
|
return R_FAILURE;
|
|
}
|
|
|
|
/* Convert sdl surface data to R surface data
|
|
* \*------------------------------------------------------------- */
|
|
r_back_buf.buf = (uchar *)sdl_back_buf->pixels;
|
|
r_back_buf.buf_w = sdl_back_buf->w;
|
|
r_back_buf.buf_h = sdl_back_buf->h;
|
|
r_back_buf.buf_pitch = sdl_back_buf->pitch;
|
|
r_back_buf.bpp = gfx_init->backbuf_bpp;
|
|
|
|
r_back_buf.clip_rect.left = 0;
|
|
r_back_buf.clip_rect.top = 0;
|
|
r_back_buf.clip_rect.right = sdl_back_buf->w - 1;
|
|
r_back_buf.clip_rect.bottom = sdl_back_buf->h - 1;
|
|
|
|
r_back_buf.impl_src = sdl_back_buf;
|
|
|
|
/* Set module data
|
|
* \*------------------------------------------------------------- */
|
|
SGfxModule.sdl_screen = sdl_screen;
|
|
SGfxModule.r_screen = r_screen;
|
|
SGfxModule.sdl_back_buf = sdl_back_buf;
|
|
SGfxModule.r_back_buf = r_back_buf;
|
|
|
|
SGfxModule.init = 1;
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
R_SURFACE *SYSGFX_GetScreenSurface(void)
|
|
{
|
|
return &SGfxModule.r_screen;
|
|
}
|
|
|
|
R_SURFACE *SYSGFX_GetBackBuffer(void)
|
|
{
|
|
return &SGfxModule.r_back_buf;
|
|
}
|
|
|
|
int SYSGFX_LockSurface(R_SURFACE * surface)
|
|
{
|
|
int result;
|
|
|
|
assert(surface != NULL);
|
|
|
|
result = SDL_LockSurface((SDL_Surface *) surface->impl_src);
|
|
|
|
return (result == 0) ? R_SUCCESS : R_FAILURE;
|
|
}
|
|
|
|
int SYSGFX_UnlockSurface(R_SURFACE * surface)
|
|
{
|
|
assert(surface != NULL);
|
|
|
|
SDL_UnlockSurface((SDL_Surface *) surface->impl_src);
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
R_SURFACE *SYSGFX_FormatToDisplay(R_SURFACE * surface)
|
|
{
|
|
R_SURFACE *new_r_surface;
|
|
SDL_Surface *new_sdl_surface;
|
|
|
|
new_r_surface = (R_SURFACE *)malloc(sizeof *new_r_surface);
|
|
if (new_r_surface == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
new_sdl_surface = SDL_DisplayFormat((SDL_Surface *)surface->impl_src);
|
|
if (new_sdl_surface == NULL) {
|
|
free(new_r_surface);
|
|
return NULL;
|
|
}
|
|
|
|
new_r_surface->buf = (uchar *)new_sdl_surface->pixels;
|
|
new_r_surface->buf_w = new_sdl_surface->w;
|
|
new_r_surface->buf_h = new_sdl_surface->h;
|
|
new_r_surface->buf_pitch = new_sdl_surface->pitch;
|
|
new_r_surface->bpp = new_sdl_surface->format->BitsPerPixel;
|
|
|
|
new_r_surface->clip_rect.left = 0;
|
|
new_r_surface->clip_rect.top = 0;
|
|
new_r_surface->clip_rect.right = new_sdl_surface->w - 1;
|
|
new_r_surface->clip_rect.bottom = new_sdl_surface->h - 1;
|
|
|
|
new_r_surface->impl_src = new_sdl_surface;
|
|
|
|
return new_r_surface;
|
|
}
|
|
|
|
R_SURFACE *SYSGFX_CreateSurface(int w, int h, int bpp)
|
|
{
|
|
R_SURFACE *new_surface;
|
|
SDL_Surface *new_sdl_surface;
|
|
|
|
assert(bpp == 8); /* 16bpp not supported, maybe not necessary? */
|
|
assert((w > 0) && (h > 0));
|
|
|
|
new_surface = (R_SURFACE *)malloc(sizeof *new_surface);
|
|
if (new_surface == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
new_sdl_surface =
|
|
SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0);
|
|
if (new_sdl_surface == NULL) {
|
|
|
|
free(new_surface);
|
|
return NULL;
|
|
}
|
|
|
|
new_surface->buf_w = new_sdl_surface->w;
|
|
new_surface->buf_h = new_sdl_surface->h;
|
|
new_surface->buf_pitch = new_sdl_surface->pitch;
|
|
new_surface->bpp = new_sdl_surface->format->BitsPerPixel;
|
|
|
|
new_surface->clip_rect.left = 0;
|
|
new_surface->clip_rect.top = 0;
|
|
new_surface->clip_rect.right = w - 1;
|
|
new_surface->clip_rect.bottom = h - 1;
|
|
|
|
new_surface->impl_src = new_sdl_surface;
|
|
|
|
return new_surface;
|
|
}
|
|
|
|
int SYSGFX_DestroySurface(R_SURFACE * surface)
|
|
{
|
|
SDL_FreeSurface((SDL_Surface *) surface->impl_src);
|
|
|
|
free(surface);
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
int SYSGFX_GetWhite(void)
|
|
{
|
|
return SGfxModule.white_index;
|
|
}
|
|
|
|
int SYSGFX_GetBlack(void)
|
|
{
|
|
return SGfxModule.black_index;
|
|
}
|
|
|
|
int SYSGFX_MatchColor(unsigned long colormask)
|
|
{
|
|
|
|
int i;
|
|
|
|
int red = (colormask & 0x0FF0000UL) >> 16;
|
|
int green = (colormask & 0x000FF00UL) >> 8;
|
|
int blue = colormask & 0x00000FFUL;
|
|
|
|
int dr;
|
|
int dg;
|
|
int db;
|
|
|
|
long color_delta;
|
|
long best_delta = LONG_MAX;
|
|
int best_index = 0;
|
|
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
dr = cur_pal[i].r - red;
|
|
dr = ABS(dr);
|
|
|
|
dg = cur_pal[i].g - green;
|
|
dg = ABS(dg);
|
|
|
|
db = cur_pal[i].b - blue;
|
|
db = ABS(db);
|
|
|
|
#if R_COLORSEARCH_SQUARE
|
|
color_delta = (long)((dr * dr) * R_RED_WEIGHT +
|
|
(dg * dg) * R_GREEN_WEIGHT + (db * db) * R_BLUE_WEIGHT);
|
|
#else
|
|
color_delta = (long)(dr * R_RED_WEIGHT +
|
|
dg * R_GREEN_WEIGHT + db * R_BLUE_WEIGHT);
|
|
#endif
|
|
if (color_delta == 0) {
|
|
return i;
|
|
}
|
|
|
|
if (color_delta < best_delta) {
|
|
best_delta = color_delta;
|
|
best_index = i;
|
|
}
|
|
}
|
|
|
|
return best_index;
|
|
}
|
|
|
|
int SYSGFX_SetPalette(R_SURFACE *surface, PALENTRY *pal)
|
|
{
|
|
|
|
uchar red;
|
|
uchar green;
|
|
uchar blue;
|
|
|
|
int color_delta;
|
|
int best_wdelta = 0;
|
|
int best_windex = 0;
|
|
int best_bindex = 0;
|
|
int best_bdelta = 1000;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
red = pal[i].red;
|
|
cur_pal[i].r = red;
|
|
|
|
color_delta = red;
|
|
|
|
green = pal[i].green;
|
|
cur_pal[i].g = green;
|
|
|
|
color_delta += green;
|
|
|
|
blue = pal[i].blue;
|
|
cur_pal[i].b = blue;
|
|
|
|
color_delta += blue;
|
|
|
|
if (color_delta < best_bdelta) {
|
|
best_bindex = i;
|
|
best_bdelta = color_delta;
|
|
}
|
|
|
|
if (color_delta > best_wdelta) {
|
|
best_windex = i;
|
|
best_wdelta = color_delta;
|
|
}
|
|
}
|
|
|
|
/* Set whitest and blackest color indices */
|
|
SGfxModule.white_index = best_windex;
|
|
SGfxModule.black_index = best_bindex;
|
|
|
|
/* If the screen surface is palettized, set the screen palette.
|
|
* If the screen surface is not palettized, set the palette of
|
|
* the surface parameter */
|
|
if (SGfxModule.r_screen.bpp < 16) {
|
|
|
|
SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
|
|
R_PAL_ENTRIES);
|
|
} else {
|
|
|
|
SDL_SetColors((SDL_Surface *) surface->impl_src,
|
|
cur_pal, 0, R_PAL_ENTRIES);
|
|
}
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
int SYSGFX_GetCurrentPal(PALENTRY * src_pal)
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
src_pal[i].red = cur_pal[i].r;
|
|
src_pal[i].green = cur_pal[i].g;
|
|
src_pal[i].blue = cur_pal[i].b;
|
|
}
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
int SYSGFX_PalToBlack(R_SURFACE * surface, PALENTRY * src_pal, double percent)
|
|
{
|
|
|
|
int i;
|
|
|
|
/*int fade_max = 255; */
|
|
int new_entry;
|
|
|
|
double fpercent;
|
|
|
|
if (percent > 1.0) {
|
|
percent = 1.0;
|
|
}
|
|
|
|
/* Exponential fade */
|
|
fpercent = percent * percent;
|
|
|
|
fpercent = 1.0 - fpercent;
|
|
|
|
/* Use the correct percentage change per frame for each palette entry */
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
new_entry = (int)(src_pal[i].red * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].r = 0;
|
|
} else {
|
|
cur_pal[i].r = (uchar) new_entry;
|
|
}
|
|
|
|
new_entry = (int)(src_pal[i].green * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].g = 0;
|
|
} else {
|
|
cur_pal[i].g = (uchar) new_entry;
|
|
}
|
|
|
|
new_entry = (int)(src_pal[i].blue * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].b = 0;
|
|
} else {
|
|
cur_pal[i].b = (uchar) new_entry;
|
|
}
|
|
}
|
|
|
|
/* If the screen surface is palettized, set the screen palette.
|
|
* If the screen surface is not palettized, set the palette of
|
|
* the surface parameter */
|
|
if (SGfxModule.r_screen.bpp < 16) {
|
|
|
|
SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
|
|
R_PAL_ENTRIES);
|
|
} else {
|
|
|
|
SDL_SetColors((SDL_Surface *) surface->impl_src,
|
|
cur_pal, 0, R_PAL_ENTRIES);
|
|
}
|
|
|
|
return R_SUCCESS;
|
|
|
|
}
|
|
|
|
int SYSGFX_BlackToPal(R_SURFACE * surface, PALENTRY * src_pal, double percent)
|
|
{
|
|
|
|
int new_entry;
|
|
double fpercent;
|
|
|
|
int color_delta;
|
|
int best_wdelta = 0;
|
|
int best_windex = 0;
|
|
int best_bindex = 0;
|
|
int best_bdelta = 1000;
|
|
|
|
int i;
|
|
|
|
if (percent > 1.0) {
|
|
percent = 1.0;
|
|
}
|
|
|
|
/* Exponential fade */
|
|
fpercent = percent * percent;
|
|
|
|
fpercent = 1.0 - fpercent;
|
|
|
|
/* Use the correct percentage change per frame for each palette entry */
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
new_entry = (int)(src_pal[i].red - src_pal[i].red * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].r = 0;
|
|
} else {
|
|
cur_pal[i].r = (uchar) new_entry;
|
|
}
|
|
|
|
new_entry =
|
|
(int)(src_pal[i].green - src_pal[i].green * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].g = 0;
|
|
} else {
|
|
cur_pal[i].g = (uchar) new_entry;
|
|
}
|
|
|
|
new_entry =
|
|
(int)(src_pal[i].blue - src_pal[i].blue * fpercent);
|
|
|
|
if (new_entry < 0) {
|
|
cur_pal[i].b = 0;
|
|
} else {
|
|
cur_pal[i].b = (uchar) new_entry;
|
|
}
|
|
}
|
|
|
|
/* Find the best white and black color indices again */
|
|
if (percent >= 1.0) {
|
|
|
|
for (i = 0; i < R_PAL_ENTRIES; i++) {
|
|
|
|
color_delta = cur_pal[i].r;
|
|
color_delta += cur_pal[i].g;
|
|
color_delta += cur_pal[i].b;
|
|
|
|
if (color_delta < best_bdelta) {
|
|
best_bindex = i;
|
|
best_bdelta = color_delta;
|
|
}
|
|
|
|
if (color_delta > best_wdelta) {
|
|
best_windex = i;
|
|
best_wdelta = color_delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If the screen surface is palettized, set the screen palette.
|
|
* If the screen surface is not palettized, set the palette of
|
|
* the surface parameter */
|
|
if (SGfxModule.r_screen.bpp < 16) {
|
|
|
|
SDL_SetColors(SGfxModule.sdl_screen, cur_pal, 0,
|
|
R_PAL_ENTRIES);
|
|
} else {
|
|
|
|
SDL_SetColors((SDL_Surface *) surface->impl_src,
|
|
cur_pal, 0, R_PAL_ENTRIES);
|
|
}
|
|
|
|
return R_SUCCESS;
|
|
}
|
|
|
|
} // End of namespace Saga
|
|
|