mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 09:49:14 +00:00
425 lines
9.9 KiB
C++
425 lines
9.9 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "sci/gfx/gfx_system.h"
|
|
#include "sci/gfx/gfx_resource.h"
|
|
#include "sci/gfx/gfx_tools.h"
|
|
|
|
namespace Sci {
|
|
|
|
gfx_mode_t mode_1x1_color_index = { /* Fake 1x1 mode */
|
|
/* xfact */ 1, /* yfact */ 1,
|
|
/* bytespp */ 1,
|
|
/* flags */ 0,
|
|
/* palette */ NULL,
|
|
|
|
/* color masks */ 0, 0, 0, 0,
|
|
/* color shifts */ 0, 0, 0, 0
|
|
};
|
|
|
|
|
|
static void gfxr_free_loop(gfx_driver_t *driver, gfxr_loop_t *loop) {
|
|
int i;
|
|
|
|
if (loop->cels) {
|
|
for (i = 0; i < loop->cels_nr; i++)
|
|
if (loop->cels[i])
|
|
gfx_free_pixmap(driver, loop->cels[i]);
|
|
|
|
free(loop->cels);
|
|
}
|
|
}
|
|
|
|
void gfxr_free_view(gfx_driver_t *driver, gfxr_view_t *view) {
|
|
int i;
|
|
|
|
if (view->colors && !(view->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE))
|
|
free(view->colors);
|
|
|
|
if (view->loops) {
|
|
for (i = 0; i < view->loops_nr; i++)
|
|
gfxr_free_loop(driver, view->loops + i);
|
|
|
|
free(view->loops);
|
|
}
|
|
free(view);
|
|
}
|
|
|
|
static void pixmap_endianness_reverse_2_simple(byte *data, int area) {
|
|
int c;
|
|
|
|
for (c = 0; c < area; c++) {
|
|
byte val = *data;
|
|
*data = data[1];
|
|
data[1] = val;
|
|
|
|
data += 2;
|
|
}
|
|
}
|
|
|
|
static void pixmap_endianness_reverse_2(byte *data, int area) {
|
|
int c;
|
|
int sl = sizeof(unsigned long);
|
|
|
|
for (c = 0; c < (area & ~(sl - 1)); c += (sl >> 1)) {
|
|
unsigned long temp;
|
|
|
|
memcpy(&temp, data, sl);
|
|
|
|
// The next line will give warnings on 32 bit archs, but that's OK.
|
|
#if SIZEOF_LONG < 8
|
|
temp = 0;
|
|
#else
|
|
temp = ((temp & 0xff00ff00ff00ff00l) >> 8)
|
|
| ((temp & 0x00ff00ff00ff00ffl) << 8);
|
|
#endif
|
|
|
|
memcpy(data, &temp, sl);
|
|
|
|
data += sl;
|
|
}
|
|
|
|
pixmap_endianness_reverse_2_simple(data, area & (sl - 1));
|
|
}
|
|
|
|
static void pixmap_endianness_reverse_3_simple(byte *data, int area) {
|
|
int c;
|
|
|
|
for (c = 0; c < area; c++) {
|
|
byte val0 = data[0];
|
|
|
|
data[0] = data[2];
|
|
data[2] = val0;
|
|
|
|
data += 3;
|
|
}
|
|
}
|
|
|
|
static void pixmap_endianness_reverse_4_simple(byte *data, int area) {
|
|
int c;
|
|
|
|
for (c = 0; c < area; c++) {
|
|
byte val0 = data[0];
|
|
byte val1 = data[1];
|
|
|
|
data[0] = data[3];
|
|
data[3] = val0;
|
|
|
|
data[1] = data[2];
|
|
data[2] = val1;
|
|
|
|
data += 4;
|
|
}
|
|
}
|
|
|
|
static void pixmap_endianness_reverse_4(byte *data, int area) {
|
|
int c;
|
|
int sl = sizeof(unsigned long);
|
|
|
|
for (c = 0; c < (area & ~(sl - 1)); c += (sl >> 2)) {
|
|
unsigned long temp;
|
|
|
|
memcpy(&temp, data, sl);
|
|
|
|
// The next lines will give warnings on 32 bit archs, but that's OK.
|
|
#if SIZEOF_LONG < 8
|
|
temp = 0l;
|
|
#else
|
|
temp = ((temp & 0xffff0000ffff0000l) >> 16)
|
|
| ((temp & 0x0000ffff0000ffffl) << 16);
|
|
temp = ((temp & 0xff00ff00ff00ff00l) >> 8)
|
|
| ((temp & 0x00ff00ff00ff00ffl) << 8);
|
|
#endif
|
|
|
|
memcpy(data, &temp, sl);
|
|
|
|
data += sl;
|
|
}
|
|
|
|
pixmap_endianness_reverse_4_simple(data, area & (sl - 1));
|
|
}
|
|
|
|
gfx_pixmap_t *gfxr_endianness_adjust(gfx_pixmap_t *pixmap, gfx_mode_t *mode) {
|
|
int bytespp;
|
|
byte *data;
|
|
|
|
if (!pixmap || !pixmap->data || !mode) {
|
|
GFXERROR("gfxr_endianness_adjust(): Invoked with invalid values\n");
|
|
BREAKPOINT();
|
|
return NULL;
|
|
}
|
|
|
|
if (!(mode->flags & GFX_MODE_FLAG_REVERSE_ENDIAN))
|
|
return pixmap;
|
|
|
|
bytespp = mode->bytespp;
|
|
|
|
data = pixmap->data;
|
|
|
|
switch (bytespp) {
|
|
case 1:
|
|
break;
|
|
|
|
case 2:
|
|
pixmap_endianness_reverse_2(data, pixmap->xl * pixmap->yl);
|
|
break;
|
|
|
|
case 3:
|
|
pixmap_endianness_reverse_3_simple(data, pixmap->xl * pixmap->yl);
|
|
break;
|
|
|
|
case 4:
|
|
pixmap_endianness_reverse_4(data, pixmap->xl * pixmap->yl);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "gfxr_endianness_adjust(): Cannot adjust endianness for %d bytespp!\n", bytespp);
|
|
return NULL;
|
|
}
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
} // End of namespace Sci
|
|
|
|
// Now construct the pixmap scaling functions
|
|
#define EXTRA_BYTE_OFFSET 0
|
|
#define SIZETYPE uint8
|
|
#define FUNCNAME _gfx_xlate_pixmap_unfiltered_1
|
|
#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_1
|
|
#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_1
|
|
#define COPY_BYTES 1
|
|
#include "gfx_pixmap_scale.cpp"
|
|
#undef COPY_BYTES
|
|
|
|
#define SIZETYPE uint16
|
|
#define FUNCNAME _gfx_xlate_pixmap_unfiltered_2
|
|
#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_2
|
|
#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_2
|
|
#define COPY_BYTES 2
|
|
#include "gfx_pixmap_scale.cpp"
|
|
#undef COPY_BYTES
|
|
|
|
#ifdef SCUMM_BIG_ENDIAN
|
|
# undef EXTRA_BYTE_OFFSET
|
|
# define EXTRA_BYTE_OFFSET 1
|
|
#endif // SCUMM_BIG_ENDIAN
|
|
#define SIZETYPE uint32
|
|
#define FUNCNAME _gfx_xlate_pixmap_unfiltered_3
|
|
#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_3
|
|
#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_3
|
|
#define COPY_BYTES 3
|
|
#include "gfx_pixmap_scale.cpp"
|
|
#undef COPY_BYTES
|
|
#ifdef SCUMM_BIG_ENDIAN
|
|
# undef EXTRA_BYTE_OFFSET
|
|
# define EXTRA_BYTE_OFFSET 0
|
|
#endif // SCUMM_BIG_ENDIAN
|
|
|
|
#define SIZETYPE uint32
|
|
#define FUNCNAME _gfx_xlate_pixmap_unfiltered_4
|
|
#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_4
|
|
#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_4
|
|
#define COPY_BYTES 4
|
|
#include "gfx_pixmap_scale.cpp"
|
|
#undef COPY_BYTES
|
|
#undef EXTRA_BYTE_OFFSET
|
|
#undef SIZETYPE
|
|
|
|
namespace Sci {
|
|
|
|
static inline void _gfx_xlate_pixmap_unfiltered(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) {
|
|
switch (mode->bytespp) {
|
|
|
|
case 1:
|
|
_gfx_xlate_pixmap_unfiltered_1(mode, pxm, scale);
|
|
break;
|
|
|
|
case 2:
|
|
_gfx_xlate_pixmap_unfiltered_2(mode, pxm, scale);
|
|
break;
|
|
|
|
case 3:
|
|
_gfx_xlate_pixmap_unfiltered_3(mode, pxm, scale);
|
|
break;
|
|
|
|
case 4:
|
|
_gfx_xlate_pixmap_unfiltered_4(mode, pxm, scale);
|
|
break;
|
|
|
|
default:
|
|
GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp);
|
|
|
|
}
|
|
|
|
if (pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) {
|
|
pxm->xl = pxm->index_xl;
|
|
pxm->yl = pxm->index_yl;
|
|
} else {
|
|
pxm->xl = pxm->index_xl * mode->xfact;
|
|
pxm->yl = pxm->index_yl * mode->yfact;
|
|
}
|
|
}
|
|
|
|
static inline void _gfx_xlate_pixmap_linear(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) {
|
|
if (mode->palette || !scale) { // fall back to unfiltered
|
|
_gfx_xlate_pixmap_unfiltered(mode, pxm, scale);
|
|
return;
|
|
}
|
|
|
|
pxm->xl = pxm->index_xl * mode->xfact;
|
|
pxm->yl = pxm->index_yl * mode->yfact;
|
|
|
|
switch (mode->bytespp) {
|
|
|
|
case 1:
|
|
_gfx_xlate_pixmap_linear_1(mode, pxm, scale);
|
|
break;
|
|
|
|
case 2:
|
|
_gfx_xlate_pixmap_linear_2(mode, pxm, scale);
|
|
break;
|
|
|
|
case 3:
|
|
_gfx_xlate_pixmap_linear_3(mode, pxm, scale);
|
|
break;
|
|
|
|
case 4:
|
|
_gfx_xlate_pixmap_linear_4(mode, pxm, scale);
|
|
break;
|
|
|
|
default:
|
|
GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static inline void _gfx_xlate_pixmap_trilinear(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) {
|
|
if (mode->palette || !scale) { // fall back to unfiltered
|
|
_gfx_xlate_pixmap_unfiltered(mode, pxm, scale);
|
|
return;
|
|
}
|
|
|
|
pxm->xl = pxm->index_xl * mode->xfact;
|
|
pxm->yl = pxm->index_yl * mode->yfact;
|
|
|
|
switch (mode->bytespp) {
|
|
case 1:
|
|
_gfx_xlate_pixmap_trilinear_1(mode, pxm, scale);
|
|
break;
|
|
|
|
case 2:
|
|
_gfx_xlate_pixmap_trilinear_2(mode, pxm, scale);
|
|
break;
|
|
|
|
case 3:
|
|
_gfx_xlate_pixmap_trilinear_3(mode, pxm, scale);
|
|
break;
|
|
|
|
case 4:
|
|
_gfx_xlate_pixmap_trilinear_4(mode, pxm, scale);
|
|
break;
|
|
|
|
default:
|
|
GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp);
|
|
|
|
}
|
|
}
|
|
|
|
void gfx_xlate_pixmap(gfx_pixmap_t *pxm, gfx_mode_t *mode, gfx_xlate_filter_t filter) {
|
|
int was_allocated = 0;
|
|
|
|
if (mode->palette && !(pxm->flags & GFX_PIXMAP_FLAG_PALETTE_ALLOCATED)) {
|
|
int i;
|
|
|
|
for (i = 0; i < pxm->colors_nr; i++) {
|
|
if (gfx_alloc_color(mode->palette, pxm->colors + i) < 0) {
|
|
GFXWARN("Failed to allocate color %d/%d in pixmap (color %02x/%02x/%02x)!\n",
|
|
i, pxm->colors_nr, pxm->colors[i].r, pxm->colors[i].g, pxm->colors[i].b);
|
|
pxm->colors[i].global_index = 0;
|
|
}
|
|
/*
|
|
GFXDEBUG("alloc(%02x/%02x/%02x) -> %d\n", pxm->colors[i].r, pxm->colors[i].g, pxm->colors[i].b, pxm->colors[i].global_index);
|
|
*/
|
|
}
|
|
|
|
pxm->flags |= GFX_PIXMAP_FLAG_PALETTE_ALLOCATED;
|
|
}
|
|
|
|
|
|
if (!pxm->data) {
|
|
pxm->data = (byte*)sci_malloc(mode->xfact * mode->yfact * pxm->index_xl * pxm->index_yl * mode->bytespp + 1);
|
|
// +1: Eases coying on BE machines in 24 bpp packed mode
|
|
// Assume that memory, if allocated already, will be sufficient
|
|
|
|
// Allocate alpha map
|
|
if (!mode->alpha_mask && pxm->colors_nr < GFX_PIC_COLORS)
|
|
pxm->alpha_map = (byte*)sci_malloc(mode->xfact * mode->yfact * pxm->index_xl * pxm->index_yl + 1);
|
|
} else
|
|
was_allocated = 1;
|
|
|
|
switch (filter) {
|
|
case GFX_XLATE_FILTER_NONE:
|
|
_gfx_xlate_pixmap_unfiltered(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX));
|
|
break;
|
|
|
|
case GFX_XLATE_FILTER_LINEAR:
|
|
_gfx_xlate_pixmap_linear(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX));
|
|
break;
|
|
|
|
case GFX_XLATE_FILTER_TRILINEAR:
|
|
_gfx_xlate_pixmap_trilinear(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX));
|
|
break;
|
|
|
|
default:
|
|
GFXERROR("Attempt to filter pixmap %04x in invalid mode #%d\n", pxm->ID, filter);
|
|
|
|
if (!was_allocated) {
|
|
if (!mode->alpha_mask && pxm->colors_nr < GFX_PIC_COLORS)
|
|
free(pxm->alpha_map);
|
|
free(pxm->data);
|
|
}
|
|
}
|
|
}
|
|
|
|
void gfxr_free_pic(gfx_driver_t *driver, gfxr_pic_t *pic) {
|
|
gfx_free_pixmap(driver, pic->visual_map);
|
|
gfx_free_pixmap(driver, pic->priority_map);
|
|
gfx_free_pixmap(driver, pic->control_map);
|
|
pic->visual_map = NULL;
|
|
pic->priority_map = NULL;
|
|
pic->control_map = NULL;
|
|
if (pic->internal)
|
|
free(pic->internal);
|
|
pic->internal = NULL;
|
|
if (pic->undithered_buffer)
|
|
free(pic->undithered_buffer);
|
|
pic->undithered_buffer = 0;
|
|
free(pic);
|
|
}
|
|
|
|
} // End of namespace Sci
|